From e6fa5d69e9d70614ab960d8956eb2623cd313623 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 2 Sep 2026 13:52:11 +0000
Subject: [PATCH 1/5] Document sheet helper APIs
Co-authored-by: SteveWinward <2002602+SteveWinward@users.noreply.github.com>
---
src/GoogleSheetsWrapper/SheetExporter.cs | 30 +++----
.../SheetFieldAttributeUtils.cs | 40 +++++-----
src/GoogleSheetsWrapper/SheetHelper.cs | 80 +++++++++----------
src/GoogleSheetsWrapper/SheetRange.cs | 46 +++++------
.../Utils/PhoneNumberParsing.cs | 18 ++---
5 files changed, 107 insertions(+), 107 deletions(-)
diff --git a/src/GoogleSheetsWrapper/SheetExporter.cs b/src/GoogleSheetsWrapper/SheetExporter.cs
index 17d2598..4fca382 100644
--- a/src/GoogleSheetsWrapper/SheetExporter.cs
+++ b/src/GoogleSheetsWrapper/SheetExporter.cs
@@ -18,9 +18,9 @@ public class SheetExporter
///
/// Constructor
///
- ///
- ///
- ///
+ /// The identifier of the spreadsheet to export.
+ /// The service account email used for authentication.
+ /// The tab to export.
public SheetExporter(string spreadsheetID, string serviceAccountEmail, string tabName)
{
_sheetHelper = new SheetHelper(spreadsheetID, serviceAccountEmail, tabName);
@@ -29,16 +29,16 @@ public SheetExporter(string spreadsheetID, string serviceAccountEmail, string ta
///
/// Constructor
///
- ///
+ /// The initialized sheet helper to use for export operations.
public SheetExporter(SheetHelper sheetHelper)
{
_sheetHelper = sheetHelper;
}
///
- ///
+ /// Initializes the underlying sheet helper using service account credentials.
///
- ///
+ /// Service account credentials in JSON format.
public void Init(string jsonCredentials)
{
_sheetHelper.Init(jsonCredentials);
@@ -47,9 +47,9 @@ public void Init(string jsonCredentials)
///
/// Exports the current Google Sheet tab to a CSV file
///
- ///
- ///
- ///
+ /// The range to export.
+ /// The destination stream for the CSV content.
+ /// The delimiter used between CSV fields.
public void ExportAsCsv(SheetRange range, Stream stream, string delimiter = ",")
{
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
@@ -63,9 +63,9 @@ public void ExportAsCsv(SheetRange range, Stream stream, string delimiter = ",")
///
/// Exports the current Google Sheet tab to a CSV file. This override lets you explicitly specify the CsvConfiguration object for the CsvHelper library.
///
- ///
- ///
- ///
+ /// The range to export.
+ /// The destination stream for the CSV content.
+ /// The CsvHelper settings used to generate the CSV content.
public void ExportAsCsv(SheetRange range, Stream stream, CsvConfiguration csvConfiguration)
{
var rows = _sheetHelper.GetRowsFormatted(range);
@@ -84,10 +84,10 @@ public void ExportAsCsv(SheetRange range, Stream stream, CsvConfiguration csvCon
}
///
- /// Exports the current Google Sheet tab to a CSV file
+ /// Exports the specified Google Sheet range to an Excel workbook.
///
- ///
- ///
+ /// The range to export.
+ /// The destination stream for the Excel workbook.
public void ExportAsExcel(SheetRange range, Stream stream)
{
var rows = _sheetHelper.GetRowsFormatted(range);
diff --git a/src/GoogleSheetsWrapper/SheetFieldAttributeUtils.cs b/src/GoogleSheetsWrapper/SheetFieldAttributeUtils.cs
index e0008d9..533d303 100644
--- a/src/GoogleSheetsWrapper/SheetFieldAttributeUtils.cs
+++ b/src/GoogleSheetsWrapper/SheetFieldAttributeUtils.cs
@@ -14,12 +14,12 @@ namespace GoogleSheetsWrapper
public class SheetFieldAttributeUtils
{
///
- ///
+ /// Populates the attributed properties of a record from a row returned by Google Sheets.
///
- ///
- ///
- ///
- ///
+ /// The record type to populate.
+ /// The record instance to populate.
+ /// The source row values.
+ /// The one-based column index represented by the first value in .
///
public static void PopulateRecord(T record, IList row, int minColumnId = 1) where T : BaseRecord
{
@@ -99,11 +99,11 @@ public static void PopulateRecord(T record, IList row, int minColumnI
///
/// Converts the objects values to CellData object for Google Sheets API
///
- ///
- ///
- ///
- ///
- ///
+ /// The record type containing the property.
+ /// The record that provides the property value.
+ /// The sheet metadata that defines the cell format.
+ /// The property to convert.
+ /// A Google Sheets cell containing the property's value and formatting.
///
public static CellData GetCellDataForSheetField(T record, SheetFieldAttribute attribute, PropertyInfo property)
{
@@ -238,11 +238,11 @@ public static CellData GetCellDataForSheetField(T record, SheetFieldAttribute
}
///
- ///
+ /// Gets the one-based sheet column index associated with a record property.
///
- ///
- ///
- ///
+ /// The record type that declares the property.
+ /// An expression that selects the attributed property.
+ /// The property's configured column index.
public static int GetColumnId(Expression> expression) where T : BaseRecord
{
var attribute = GetSheetFieldAttribute(expression);
@@ -251,20 +251,20 @@ public static int GetColumnId(Expression> expression) where T
}
///
- ///
+ /// Gets all sheet field metadata declared by a record type, ordered by column index.
///
- ///
- ///
+ /// The record type to inspect.
+ /// The sheet field attributes and their associated properties.
public static SortedDictionary GetAllSheetFieldAttributes()
{
return GetAllSheetFieldAttributes(typeof(T));
}
///
- ///
+ /// Gets all sheet field metadata declared by a type, ordered by column index.
///
- ///
- ///
+ /// The type to inspect.
+ /// The sheet field attributes and their associated properties.
public static SortedDictionary GetAllSheetFieldAttributes(Type type)
{
var result = new SortedDictionary(new SheetFieldAttributeComparer());
diff --git a/src/GoogleSheetsWrapper/SheetHelper.cs b/src/GoogleSheetsWrapper/SheetHelper.cs
index 4df669d..0560c1f 100644
--- a/src/GoogleSheetsWrapper/SheetHelper.cs
+++ b/src/GoogleSheetsWrapper/SheetHelper.cs
@@ -38,7 +38,7 @@ public class SheetHelper
public string ServiceAccountEmail { get; set; }
///
- ///
+ /// OAuth scopes requested when authenticating with the Google Sheets API.
///
public string[] Scopes { get; set; } = { SheetsService.Scope.Spreadsheets };
@@ -55,9 +55,9 @@ public class SheetHelper
///
/// Constructor
///
- ///
- ///
- ///
+ /// The identifier of the spreadsheet to access.
+ /// The service account email used to impersonate an account.
+ /// The tab to select after initialization.
public SheetHelper(string spreadsheetID, string serviceAccountEmail, string tabName)
{
SpreadsheetID = spreadsheetID;
@@ -68,7 +68,7 @@ public SheetHelper(string spreadsheetID, string serviceAccountEmail, string tabN
///
/// Initializes the SheetHelper object
///
- ///
+ /// Service account credentials in JSON format.
public void Init(string jsonCredentials)
{
Init(jsonCredentials, default);
@@ -77,8 +77,8 @@ public void Init(string jsonCredentials)
///
/// Initializes the SheetHelper object with authentication
///
- ///
- ///
+ /// Service account credentials in JSON format.
+ /// Factory used to create HTTP clients for API requests.
public void Init(string jsonCredentials, Google.Apis.Http.IHttpClientFactory httpClientFactory)
{
var credential = (ServiceAccountCredential)
@@ -121,7 +121,7 @@ protected void EnsureServiceInitialized()
///
/// Set the tab to the specified newTabName value
///
- ///
+ /// The existing tab to select, or the name of a tab to create.
public void UpdateTabName(string newTabName)
{
EnsureServiceInitialized();
@@ -156,7 +156,7 @@ public void UpdateTabName(string newTabName)
///
/// Returns a list of all tab names in the Google Spreadsheet
///
- ///
+ /// The titles of all tabs in the spreadsheet.
public List GetAllTabNames()
{
EnsureServiceInitialized();
@@ -173,10 +173,10 @@ public List GetAllTabNames()
///
/// Return a collection of rows for a given SheetRange input
///
- ///
- ///
- ///
- ///
+ /// The range to retrieve.
+ /// How cell values are returned by the API.
+ /// How date and time values are returned by the API.
+ /// The values in the requested rows, or an empty collection when no values exist.
public IList> GetRows(SheetRange range,
ValueRenderOptionEnum valueRenderOption = ValueRenderOptionEnum.UNFORMATTEDVALUE,
DateTimeRenderOptionEnum dateTimeRenderOption = DateTimeRenderOptionEnum.SERIALNUMBER)
@@ -206,8 +206,8 @@ public IList> GetRows(SheetRange range,
///
/// Return a collection of rows formatted values for a given SheetRange input
///
- ///
- ///
+ /// The range to retrieve.
+ /// The formatted values in the requested rows, or an empty collection when no values exist.
public IList> GetRowsFormatted(SheetRange range)
{
EnsureServiceInitialized();
@@ -235,8 +235,8 @@ public IList> GetRowsFormatted(SheetRange range)
///
/// Clears values from a spreadsheet (NOTE: All other properties of the cell (such as formatting, data validation, etc..) are kept.)
///
- ///
- ///
+ /// The range whose values should be cleared.
+ /// The API response describing the cleared range.
public ClearValuesResponse ClearRange(SheetRange range)
{
EnsureServiceInitialized();
@@ -252,8 +252,8 @@ public ClearValuesResponse ClearRange(SheetRange range)
///
/// Deletes a specified column
///
- ///
- ///
+ /// The one-based index of the column to delete.
+ /// The response from the batch update operation.
public BatchUpdateSpreadsheetResponse DeleteColumn(int col)
{
EnsureServiceInitialized();
@@ -284,8 +284,8 @@ public BatchUpdateSpreadsheetResponse DeleteColumn(int col)
///
/// Deletes a specified column
///
- ///
- ///
+ /// The letter-based column identifier to delete.
+ /// The response from the batch update operation.
public BatchUpdateSpreadsheetResponse DeleteColumn(string columnLetter)
{
EnsureServiceInitialized();
@@ -298,8 +298,8 @@ public BatchUpdateSpreadsheetResponse DeleteColumn(string columnLetter)
///
/// Deletes a specified row
///
- ///
- ///
+ /// The one-based index of the row to delete.
+ /// The response from the batch update operation.
public BatchUpdateSpreadsheetResponse DeleteRow(int row)
{
EnsureServiceInitialized();
@@ -328,11 +328,11 @@ public BatchUpdateSpreadsheetResponse DeleteRow(int row)
}
///
- ///
+ /// Deletes all rows in the inclusive range.
///
- ///
- ///
- ///
+ /// The one-based index of the first row to delete.
+ /// The one-based index of the last row to delete.
+ /// The response from the batch update operation.
public BatchUpdateSpreadsheetResponse DeleteRows(int startRow, int endRow)
{
EnsureServiceInitialized();
@@ -363,8 +363,8 @@ public BatchUpdateSpreadsheetResponse DeleteRows(int startRow, int endRow)
///
/// Inserts a blank new column using the column index as the id (NOTE: 1 is the first index for the column based index)
///
- ///
- ///
+ /// The one-based index where the column is inserted.
+ /// The response from the batch update operation.
public BatchUpdateSpreadsheetResponse InsertBlankColumn(int column)
{
EnsureServiceInitialized();
@@ -401,8 +401,8 @@ public BatchUpdateSpreadsheetResponse InsertBlankColumn(int column)
///
/// Inserts a blank new column using a letter notation (i.e. B2 as the column id)
///
- ///
- ///
+ /// The letter-based column identifier where the column is inserted.
+ /// The response from the batch update operation.
public BatchUpdateSpreadsheetResponse InsertBlankColumn(string columnLetter)
{
EnsureServiceInitialized();
@@ -415,8 +415,8 @@ public BatchUpdateSpreadsheetResponse InsertBlankColumn(string columnLetter)
///
/// Inserts a new blank row
///
- ///
- ///
+ /// The one-based index where the row is inserted.
+ /// The response from the batch update operation.
public BatchUpdateSpreadsheetResponse InsertBlankRow(int row)
{
EnsureServiceInitialized();
@@ -455,12 +455,12 @@ public BatchUpdateSpreadsheetResponse InsertBlankRow(int row)
///
/// This is useful to avoid throttling limits with the Google Sheets API
///
- ///
+ /// The cell ranges and data to update.
/// Allows you to specify what fields you want to update in the BatchUpdate call,
/// defaults to userEnteredValue to keep existing cell styles, use "*" to update all properties here.
/// Other valid field mask values are: dataSourceFormula, dataSourceTable, dataValidation, effectiveFormat, effectiveValue, formattedValue, hyperlink, note, pivotTable, textFormatRuns, userEnteredFormat, userEnteredValue
///
- ///
+ /// The response from the batch update operation.
public BatchUpdateSpreadsheetResponse BatchUpdate(List updates, string fieldMask = "userEnteredValue")
{
EnsureServiceInitialized();
@@ -554,15 +554,15 @@ public class SheetHelper : SheetHelper where T : BaseRecord
///
///
///
- ///
+ /// The tab to which records are appended.
public SheetHelper(string spreadsheetID, string serviceAccountEmail, string tabName)
: base(spreadsheetID, serviceAccountEmail, tabName) { }
///
/// Adds a record to the next row in the Google Sheet tab
///
- ///
- ///
+ /// The record to append.
+ /// The response from the batch update operation.
public BatchUpdateSpreadsheetResponse AppendRow(T record)
{
EnsureServiceInitialized();
@@ -573,8 +573,8 @@ public BatchUpdateSpreadsheetResponse AppendRow(T record)
///
/// Adds mulitlpe rows to the next row in the Google Sheets tab
///
- ///
- ///
+ /// The records to append.
+ /// The response from the batch update operation.
public BatchUpdateSpreadsheetResponse AppendRows(IList records)
{
EnsureServiceInitialized();
diff --git a/src/GoogleSheetsWrapper/SheetRange.cs b/src/GoogleSheetsWrapper/SheetRange.cs
index ba8d540..fdd14ad 100644
--- a/src/GoogleSheetsWrapper/SheetRange.cs
+++ b/src/GoogleSheetsWrapper/SheetRange.cs
@@ -10,12 +10,12 @@ namespace GoogleSheetsWrapper
public class SheetRange : IEquatable
{
///
- /// Is this A1 notation?
+ /// Gets the range expressed in A1 notation when the range has an end column.
///
public string A1Notation { get; private set; }
///
- /// Is this R1C1 notation?
+ /// Gets the range expressed in R1C1 notation.
///
public string R1C1Notation { get; private set; }
@@ -95,11 +95,11 @@ private static readonly List aToZ
///
/// Row and column numbers are 1 based indexes
///
- ///
- ///
- ///
- ///
- ///
+ /// The optional sheet tab name.
+ /// The one-based index of the first column.
+ /// The one-based index of the first row.
+ /// The optional one-based index of the last column.
+ /// The optional one-based index of the last row.
public SheetRange(string tabName, int startColumn, int startRow, int? endColumn = null, int? endRow = null)
{
_startColumn = startColumn;
@@ -114,7 +114,7 @@ public SheetRange(string tabName, int startColumn, int startRow, int? endColumn
///
/// Create a SheetRange from an A1 notation or an R1C1 notation
///
- ///
+ /// A valid A1 or R1C1 range expression.
public SheetRange(string rangeValue)
{
SheetRange range;
@@ -146,8 +146,8 @@ public SheetRange(string rangeValue)
///
/// columnId is a 1 based index
///
- ///
- ///
+ /// The one-based column index.
+ /// The corresponding A1 column letters.
public static string GetLettersFromColumnID(int columnID)
{
var block = columnID - 1;
@@ -169,8 +169,8 @@ public static string GetLettersFromColumnID(int columnID)
///
/// The resulting column id is on a 1 based index (i.e. A => 1)
///
- ///
- ///
+ /// The A1 column letters to convert.
+ /// The corresponding one-based column index.
public static int GetColumnIDFromLetters(string letters)
{
var result = 0;
@@ -245,10 +245,10 @@ private void UpdateFieldAndNotiationProperties(ref T currentValue, T newValue
#region IEquatable Interface Implementation
///
- ///
+ /// Calculates a hash code from the range coordinates and tab name.
///
- ///
- ///
+ /// The range for which to calculate a hash code.
+ /// A hash code for the specified range.
public static int GetHashCode(SheetRange obj)
{
return HashCode.Combine(
@@ -260,10 +260,10 @@ public static int GetHashCode(SheetRange obj)
}
///
- ///
+ /// Determines whether this range has the same coordinates and notation as another range.
///
- ///
- ///
+ /// The range to compare with this instance.
+ /// when the ranges are equal; otherwise, .
public bool Equals(SheetRange other)
{
return
@@ -279,19 +279,19 @@ public bool Equals(SheetRange other)
}
///
- ///
+ /// Determines whether this range equals another object.
///
- ///
- ///
+ /// The object to compare with this instance.
+ /// when the object is an equal range; otherwise, .
public override bool Equals(object obj)
{
return Equals((SheetRange)obj);
}
///
- ///
+ /// Returns a hash code based on the range coordinates and tab name.
///
- ///
+ /// A hash code for this range.
public override int GetHashCode()
{
return GetHashCode(this);
diff --git a/src/GoogleSheetsWrapper/Utils/PhoneNumberParsing.cs b/src/GoogleSheetsWrapper/Utils/PhoneNumberParsing.cs
index 94a6de2..91fa87b 100644
--- a/src/GoogleSheetsWrapper/Utils/PhoneNumberParsing.cs
+++ b/src/GoogleSheetsWrapper/Utils/PhoneNumberParsing.cs
@@ -9,30 +9,30 @@ namespace GoogleSheetsWrapper.Utils
public class PhoneNumberParsing
{
///
- ///
+ /// Removes a leading United States country code and all non-numeric characters.
///
- ///
- ///
+ /// The phone number to normalize.
+ /// The normalized phone number containing digits only.
public static string RemoveUSInterationalPhoneCode(string number)
{
return RemoveExtraCharactersFromPhoneNumber(number.Replace("+1", ""));
}
///
- ///
+ /// Removes all non-numeric characters from a phone number.
///
- ///
- ///
+ /// The phone number to normalize.
+ /// The phone number containing digits only.
public static string RemoveExtraCharactersFromPhoneNumber(string number)
{
return Regex.Replace(number, @"[^\d]", "");
}
///
- ///
+ /// Converts a normalized United States phone number to a numeric value.
///
- ///
- ///
+ /// The phone number to convert.
+ /// The numeric phone number without its country code.
public static long ConvertToLong(string number)
{
var numberAsString = RemoveExtraCharactersFromPhoneNumber(number.Replace("+1", ""));
From 9729df7642071a6e12cdcffea4f9849c1e2b58ed Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 2 Sep 2026 13:53:37 +0000
Subject: [PATCH 2/5] Fix sheet helper documentation typo
Co-authored-by: SteveWinward <2002602+SteveWinward@users.noreply.github.com>
---
src/GoogleSheetsWrapper/SheetHelper.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/GoogleSheetsWrapper/SheetHelper.cs b/src/GoogleSheetsWrapper/SheetHelper.cs
index 0560c1f..d8f56d1 100644
--- a/src/GoogleSheetsWrapper/SheetHelper.cs
+++ b/src/GoogleSheetsWrapper/SheetHelper.cs
@@ -571,7 +571,7 @@ public BatchUpdateSpreadsheetResponse AppendRow(T record)
}
///
- /// Adds mulitlpe rows to the next row in the Google Sheets tab
+ /// Adds multiple rows to the next row in the Google Sheets tab
///
/// The records to append.
/// The response from the batch update operation.
From 615cb9a6207c8fc4342a6615780b9711dbf8dd07 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 2 Sep 2026 13:57:09 +0000
Subject: [PATCH 3/5] Bump package minor version
Co-authored-by: SteveWinward <2002602+SteveWinward@users.noreply.github.com>
---
src/GoogleSheetsWrapper/GoogleSheetsWrapper.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/GoogleSheetsWrapper/GoogleSheetsWrapper.csproj b/src/GoogleSheetsWrapper/GoogleSheetsWrapper.csproj
index 9b22b33..a1b2ea0 100644
--- a/src/GoogleSheetsWrapper/GoogleSheetsWrapper.csproj
+++ b/src/GoogleSheetsWrapper/GoogleSheetsWrapper.csproj
@@ -8,7 +8,7 @@
https://github.com/SteveWinward/GoogleSheetsWrapper
LICENSE
https://github.com/SteveWinward/GoogleSheetsWrapper
- 2.0.26
+ 2.1.0
Google Sheets
README.md
A simple wrapper library that makes it easier to perform CRUD operations against Google Sheets spreadsheets.
From 80b02313e18c60b11f7cf8bfe70e83f0136c9595 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 2 Sep 2026 14:02:28 +0000
Subject: [PATCH 4/5] Set package version 2.0.27
Co-authored-by: SteveWinward <2002602+SteveWinward@users.noreply.github.com>
---
src/GoogleSheetsWrapper/GoogleSheetsWrapper.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/GoogleSheetsWrapper/GoogleSheetsWrapper.csproj b/src/GoogleSheetsWrapper/GoogleSheetsWrapper.csproj
index a1b2ea0..43e758f 100644
--- a/src/GoogleSheetsWrapper/GoogleSheetsWrapper.csproj
+++ b/src/GoogleSheetsWrapper/GoogleSheetsWrapper.csproj
@@ -8,7 +8,7 @@
https://github.com/SteveWinward/GoogleSheetsWrapper
LICENSE
https://github.com/SteveWinward/GoogleSheetsWrapper
- 2.1.0
+ 2.0.27
Google Sheets
README.md
A simple wrapper library that makes it easier to perform CRUD operations against Google Sheets spreadsheets.
From b3e0ac39275440480c3b708c44825f5760814027 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 2 Sep 2026 14:22:38 +0000
Subject: [PATCH 5/5] Clarify PhoneNumberParsing XML docs to match
implementation
Co-authored-by: SteveWinward <2002602+SteveWinward@users.noreply.github.com>
---
src/GoogleSheetsWrapper/Utils/PhoneNumberParsing.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/GoogleSheetsWrapper/Utils/PhoneNumberParsing.cs b/src/GoogleSheetsWrapper/Utils/PhoneNumberParsing.cs
index 91fa87b..f56c448 100644
--- a/src/GoogleSheetsWrapper/Utils/PhoneNumberParsing.cs
+++ b/src/GoogleSheetsWrapper/Utils/PhoneNumberParsing.cs
@@ -9,7 +9,7 @@ namespace GoogleSheetsWrapper.Utils
public class PhoneNumberParsing
{
///
- /// Removes a leading United States country code and all non-numeric characters.
+ /// Removes any occurrence of the United States country code ("+1") and all non-numeric characters.
///
/// The phone number to normalize.
/// The normalized phone number containing digits only.
@@ -32,7 +32,7 @@ public static string RemoveExtraCharactersFromPhoneNumber(string number)
/// Converts a normalized United States phone number to a numeric value.
///
/// The phone number to convert.
- /// The numeric phone number without its country code.
+ /// The numeric phone number with any occurrence of the United States country code ("+1") removed.
public static long ConvertToLong(string number)
{
var numberAsString = RemoveExtraCharactersFromPhoneNumber(number.Replace("+1", ""));