From 92061e6259ae07bc4048b05af51191b3a1831d87 Mon Sep 17 00:00:00 2001 From: Diego Santo Date: Tue, 22 Apr 2025 21:31:56 -0300 Subject: [PATCH 01/14] feat: insert option to choose http method --- Functions/Client.cs | 61 +++++++++++++++++++----------- Functions/InvokeFunctionOptions.cs | 16 +++++--- FunctionsTests/ClientTests.cs | 40 +++++++++++--------- 3 files changed, 72 insertions(+), 45 deletions(-) diff --git a/Functions/Client.cs b/Functions/Client.cs index 16dc389..988e3bb 100644 --- a/Functions/Client.cs +++ b/Functions/Client.cs @@ -1,16 +1,16 @@ -using Newtonsoft.Json; -using Supabase.Core; -using Supabase.Core.Extensions; -using Supabase.Functions.Interfaces; -using Supabase.Functions.Responses; -using System; +using System; using System.Collections.Generic; using System.Net.Http; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using System.Web; +using Newtonsoft.Json; +using Supabase.Core; +using Supabase.Core.Extensions; using Supabase.Functions.Exceptions; +using Supabase.Functions.Interfaces; +using Supabase.Functions.Responses; [assembly: InternalsVisibleTo("FunctionsTests")] @@ -24,7 +24,7 @@ public partial class Client : IFunctionsClient /// /// Function that can be set to return dynamic headers. - /// + /// /// Headers specified in the method parameters will ALWAYS take precedence over headers returned by this function. /// public Func>? GetHeaders { get; set; } @@ -45,8 +45,11 @@ public Client(string baseUrl) /// Anon Key. /// Options /// - public async Task RawInvoke(string functionName, string? token = null, - InvokeFunctionOptions? options = null) + public async Task RawInvoke( + string functionName, + string? token = null, + InvokeFunctionOptions? options = null + ) { var url = $"{_baseUrl}/{functionName}"; @@ -60,8 +63,11 @@ public async Task RawInvoke(string functionName, string? token = nu /// Anon Key. /// Options /// - public async Task Invoke(string functionName, string? token = null, - InvokeFunctionOptions? options = null) + public async Task Invoke( + string functionName, + string? token = null, + InvokeFunctionOptions? options = null + ) { var url = $"{_baseUrl}/{functionName}"; var response = await HandleRequest(url, token, options); @@ -77,8 +83,12 @@ public async Task Invoke(string functionName, string? token = null, /// Anon Key. /// Options /// - public async Task Invoke(string functionName, string? token = null, - InvokeFunctionOptions? options = null) where T : class + public async Task Invoke( + string functionName, + string? token = null, + InvokeFunctionOptions? options = null + ) + where T : class { var url = $"{_baseUrl}/{functionName}"; var response = await HandleRequest(url, token, options); @@ -96,8 +106,11 @@ public async Task Invoke(string functionName, string? token = null, /// /// /// - private async Task HandleRequest(string url, string? token = null, - InvokeFunctionOptions? options = null) + private async Task HandleRequest( + string url, + string? token = null, + InvokeFunctionOptions? options = null + ) { options ??= new InvokeFunctionOptions(); @@ -118,21 +131,24 @@ private async Task HandleRequest(string url, string? token builder.Query = query.ToString(); - using var requestMessage = new HttpRequestMessage(HttpMethod.Post, builder.Uri); - requestMessage.Content = new StringContent(JsonConvert.SerializeObject(options.Body), Encoding.UTF8, - "application/json"); + using var requestMessage = new HttpRequestMessage(options.HttpMethod, builder.Uri); + requestMessage.Content = new StringContent( + JsonConvert.SerializeObject(options.Body), + Encoding.UTF8, + "application/json" + ); foreach (var kvp in options.Headers) { requestMessage.Headers.TryAddWithoutValidation(kvp.Key, kvp.Value); } - + if (_httpClient.Timeout != options.HttpTimeout) { _httpClient = new HttpClient(); _httpClient.Timeout = options.HttpTimeout; } - + var response = await _httpClient.SendAsync(requestMessage); if (response.IsSuccessStatusCode && !response.Headers.Contains("x-relay-error")) @@ -143,10 +159,11 @@ private async Task HandleRequest(string url, string? token { Content = content, Response = response, - StatusCode = (int)response.StatusCode + StatusCode = (int)response.StatusCode, }; exception.AddReason(); throw exception; } } -} \ No newline at end of file +} + diff --git a/Functions/InvokeFunctionOptions.cs b/Functions/InvokeFunctionOptions.cs index b4252f4..0b526e1 100644 --- a/Functions/InvokeFunctionOptions.cs +++ b/Functions/InvokeFunctionOptions.cs @@ -1,6 +1,7 @@ using System; -using Newtonsoft.Json; using System.Collections.Generic; +using System.Net.Http; +using Newtonsoft.Json; namespace Supabase.Functions { @@ -8,7 +9,7 @@ public partial class Client { /// /// Options that can be supplied to a function invocation. - /// + /// /// Note: If Headers.Authorization is set, it can be later overriden if a token is supplied in the method call. /// public class InvokeFunctionOptions @@ -16,8 +17,8 @@ public class InvokeFunctionOptions /// /// Headers to be included on the request. /// - public Dictionary Headers { get; set; } = new Dictionary(); - + public Dictionary Headers { get; set; } = + new Dictionary(); /// /// Body of the Request @@ -30,6 +31,11 @@ public class InvokeFunctionOptions /// https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.timeout?view=net-8.0#remarks /// public TimeSpan HttpTimeout { get; set; } = TimeSpan.FromSeconds(100); + + /// + /// Http method of the Request + /// + public HttpMethod HttpMethod { get; set; } = HttpMethod.Post; } } -} \ No newline at end of file +} diff --git a/FunctionsTests/ClientTests.cs b/FunctionsTests/ClientTests.cs index 06c4a8a..addd4b5 100644 --- a/FunctionsTests/ClientTests.cs +++ b/FunctionsTests/ClientTests.cs @@ -28,37 +28,38 @@ public async Task Invokes() { const string function = "hello"; - var result = await _client.Invoke(function, _token, new InvokeFunctionOptions - { - Body = new Dictionary + var result = await _client.Invoke( + function, + _token, + new InvokeFunctionOptions { - {"name", "supabase" } + Body = new Dictionary { { "name", "supabase" } }, } - }); + ); Assert.IsTrue(result.Contains("supabase")); - - var result2 = await _client.Invoke>(function, _token, new InvokeFunctionOptions - { - Body = new Dictionary + var result2 = await _client.Invoke>( + function, + _token, + new InvokeFunctionOptions { - { "name", "functions" } + Body = new Dictionary { { "name", "functions" } }, } - }); + ); Assert.IsInstanceOfType(result2, typeof(Dictionary)); Assert.IsTrue(result2.ContainsKey("message")); Assert.IsTrue(result2["message"].Contains("functions")); - - var result3 = await _client.RawInvoke(function, _token, new InvokeFunctionOptions - { - Body = new Dictionary + var result3 = await _client.RawInvoke( + function, + _token, + new InvokeFunctionOptions { - { "name", "functions" } + Body = new Dictionary { { "name", "functions" } }, } - }); + ); var bytes = await result3.ReadAsByteArrayAsync(); @@ -71,7 +72,10 @@ private static string GenerateToken(string secret) var tokenDescriptor = new SecurityTokenDescriptor { - SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256Signature) + SigningCredentials = new SigningCredentials( + signingKey, + SecurityAlgorithms.HmacSha256Signature + ), }; var tokenHandler = new JwtSecurityTokenHandler(); From 91a45164d4df2341a4b4abdfe27be9f79dcf9056 Mon Sep 17 00:00:00 2001 From: Diego Santo Date: Tue, 22 Apr 2025 22:17:55 -0300 Subject: [PATCH 02/14] feat: implement partially the region --- Functions/InvokeFunctionOptions.cs | 59 ++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/Functions/InvokeFunctionOptions.cs b/Functions/InvokeFunctionOptions.cs index 0b526e1..24c818d 100644 --- a/Functions/InvokeFunctionOptions.cs +++ b/Functions/InvokeFunctionOptions.cs @@ -37,5 +37,64 @@ public class InvokeFunctionOptions /// public HttpMethod HttpMethod { get; set; } = HttpMethod.Post; } + + /// + /// Define the region for requests + /// + public class FunctionRegion : IEquatable + { + private string _region; + + /// + /// Define the region for requests + /// + public FunctionRegion(string region) + { + _region = region; + } + + /// + /// Check if the object is identical to the reference passed + /// + public override bool Equals(object obj) + { + return obj is FunctionRegion r && Equals(r); + } + + /// + /// Generate Hash code + /// + public override int GetHashCode() + { + return _region.GetHashCode(); + } + + /// + /// Check if the object is identical to the reference passed + /// + public bool Equals(FunctionRegion other) + { + return _region == other._region; + } + + /// + /// Overloading the operator == + /// + public static bool operator ==(FunctionRegion left, FunctionRegion right) => + Equals(left, right); + + /// + /// Overloading the operator != + /// + public static bool operator !=(FunctionRegion left, FunctionRegion right) => + !Equals(left, right); + + public static explicit operator string(FunctionRegion region) => region.ToString(); + + public static explicit operator FunctionRegion(string region) => + new FunctionRegion(region); + + public override string? ToString() => _region; + } } } From 6e1a601fc65e7359925dc1d6af924d083da4dde4 Mon Sep 17 00:00:00 2001 From: Diego Santo Date: Fri, 25 Apr 2025 23:15:30 -0300 Subject: [PATCH 03/14] feat: implement region option --- Functions/Client.cs | 6 ++++- Functions/InvokeFunctionOptions.cs | 41 +++++++++++++++++++++++++++++- FunctionsTests/ClientTests.cs | 22 +++++++++++++--- supabase/functions/hello/index.ts | 13 +++++++--- 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/Functions/Client.cs b/Functions/Client.cs index 988e3bb..6ed1cac 100644 --- a/Functions/Client.cs +++ b/Functions/Client.cs @@ -126,6 +126,11 @@ private async Task HandleRequest( options.Headers["X-Client-Info"] = Util.GetAssemblyVersion(typeof(Client)); + if (options.FunctionRegion != FunctionRegion.Any) + { + options.Headers["x-region"] = options.FunctionRegion.ToString(); + } + var builder = new UriBuilder(url); var query = HttpUtility.ParseQueryString(builder.Query); @@ -166,4 +171,3 @@ private async Task HandleRequest( } } } - diff --git a/Functions/InvokeFunctionOptions.cs b/Functions/InvokeFunctionOptions.cs index 24c818d..db709f4 100644 --- a/Functions/InvokeFunctionOptions.cs +++ b/Functions/InvokeFunctionOptions.cs @@ -36,6 +36,11 @@ public class InvokeFunctionOptions /// Http method of the Request /// public HttpMethod HttpMethod { get; set; } = HttpMethod.Post; + + /// + /// Region of the request + /// + public FunctionRegion FunctionRegion { get; set; } = FunctionRegion.Any; } /// @@ -45,6 +50,40 @@ public class FunctionRegion : IEquatable { private string _region; + public static FunctionRegion Any { get; } = new FunctionRegion("any"); + + public static FunctionRegion ApNortheast1 { get; } = + new FunctionRegion("ap-northeast-1"); + + public static FunctionRegion ApNortheast2 { get; } = + new FunctionRegion("ap-northeast-2"); + + public static FunctionRegion ApSouth1 { get; } = new FunctionRegion("ap-south-1"); + + public static FunctionRegion ApSoutheast1 { get; } = + new FunctionRegion("ap-southeast-1"); + + public static FunctionRegion ApSoutheast2 { get; } = + new FunctionRegion("ap-southeast-2"); + + public static FunctionRegion CaCentral1 { get; } = new FunctionRegion("ca-central-1"); + + public static FunctionRegion EuCentral1 { get; } = new FunctionRegion("eu-central-1"); + + public static FunctionRegion EuWest1 { get; } = new FunctionRegion("eu-west-1"); + + public static FunctionRegion EuWest2 { get; } = new FunctionRegion("eu-west-2"); + + public static FunctionRegion EuWest3 { get; } = new FunctionRegion("eu-west-3"); + + public static FunctionRegion SaEast1 { get; } = new FunctionRegion("sa-east-1"); + + public static FunctionRegion UsEast1 { get; } = new FunctionRegion("us-east-1"); + + public static FunctionRegion UsWest1 { get; } = new FunctionRegion("us-west-1"); + + public static FunctionRegion UsWest2 { get; } = new FunctionRegion("us-west-2"); + /// /// Define the region for requests /// @@ -94,7 +133,7 @@ public bool Equals(FunctionRegion other) public static explicit operator FunctionRegion(string region) => new FunctionRegion(region); - public override string? ToString() => _region; + public override string ToString() => _region; } } } diff --git a/FunctionsTests/ClientTests.cs b/FunctionsTests/ClientTests.cs index addd4b5..78bbbcd 100644 --- a/FunctionsTests/ClientTests.cs +++ b/FunctionsTests/ClientTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; +using System.Net.Http; using System.Text; using System.Threading.Tasks; using Microsoft.IdentityModel.Tokens; @@ -19,8 +20,8 @@ public class ClientTests [TestInitialize] public void Initialize() { - _token = GenerateToken("37c304f8-51aa-419a-a1af-06154e63707a"); - _client = new Client("http://localhost:9000"); + _token = GenerateToken("super-secret-jwt-token-with-at-least-32-characters-long"); + _client = new Client("http://localhost:54321/functions/v1"); } [TestMethod("Invokes a function.")] @@ -34,6 +35,7 @@ public async Task Invokes() new InvokeFunctionOptions { Body = new Dictionary { { "name", "supabase" } }, + HttpMethod = HttpMethod.Post, } ); @@ -45,6 +47,7 @@ public async Task Invokes() new InvokeFunctionOptions { Body = new Dictionary { { "name", "functions" } }, + HttpMethod = HttpMethod.Post, } ); @@ -58,12 +61,25 @@ public async Task Invokes() new InvokeFunctionOptions { Body = new Dictionary { { "name", "functions" } }, + HttpMethod = HttpMethod.Post, } ); var bytes = await result3.ReadAsByteArrayAsync(); Assert.IsInstanceOfType(bytes, typeof(byte[])); + + var result4 = await _client.Invoke( + function, + _token, + new InvokeFunctionOptions + { + Body = [], + HttpMethod = HttpMethod.Get, + } + ); + + Assert.IsTrue(result4.Contains(function)); } private static string GenerateToken(string secret) @@ -83,4 +99,4 @@ private static string GenerateToken(string secret) return tokenHandler.WriteToken(securityToken); } } -} +} \ No newline at end of file diff --git a/supabase/functions/hello/index.ts b/supabase/functions/hello/index.ts index 820653e..09b19bb 100644 --- a/supabase/functions/hello/index.ts +++ b/supabase/functions/hello/index.ts @@ -6,12 +6,19 @@ import { serve } from "https://deno.land/std@0.131.0/http/server.ts" console.log("Hello from Functions!") -serve(async (req) => { - const { name } = await req.json() +serve(async (req: Request) => { + let value = req.url.substring(req.url.lastIndexOf("/") + 1) + if (req.body != null) { + const { name } = await req.json() + value = name + } + const data = { - message: `Hello ${name}!`, + message: `Hello ${value}!`, } + console.log("response", JSON.stringify(data)) + return new Response( JSON.stringify(data), { headers: { "Content-Type": "application/json" } }, From 9a25bc32f0ce87e10fed6781db61e9665b69384c Mon Sep 17 00:00:00 2001 From: Diego Santo Date: Fri, 25 Apr 2025 23:26:57 -0300 Subject: [PATCH 04/14] chore: change build to supabase stack --- .github/workflows/build-and-test.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 401338e..d31e317 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -24,8 +24,15 @@ jobs: - name: Build run: dotnet build --configuration Release --no-restore - - name: Initialize Testing Stack - run: docker-compose up -d + - uses: supabase/setup-cli@v1 + with: + version: latest + + - name: Start supabase + run: supabase start + +# - name: Initialize Testing Stack +# run: docker-compose up -d - name: Test run: dotnet test --no-restore From fb3fe6a8221bb42bcf4c813c01695df5c857809c Mon Sep 17 00:00:00 2001 From: Diego Santo Date: Fri, 25 Apr 2025 23:39:07 -0300 Subject: [PATCH 05/14] chore: documentation method to avoid github warnings --- Functions/InvokeFunctionOptions.cs | 51 ++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/Functions/InvokeFunctionOptions.cs b/Functions/InvokeFunctionOptions.cs index db709f4..6958621 100644 --- a/Functions/InvokeFunctionOptions.cs +++ b/Functions/InvokeFunctionOptions.cs @@ -50,38 +50,83 @@ public class FunctionRegion : IEquatable { private string _region; + /// + /// Empty region + /// public static FunctionRegion Any { get; } = new FunctionRegion("any"); + /// + /// Represents the region "ap-northeast-1" for function requests. + /// public static FunctionRegion ApNortheast1 { get; } = new FunctionRegion("ap-northeast-1"); + /// + /// Represents the "ap-northeast-2" region for function invocation. + /// public static FunctionRegion ApNortheast2 { get; } = new FunctionRegion("ap-northeast-2"); + /// + /// Represents the "ap-south-1" region used for requests. + /// public static FunctionRegion ApSouth1 { get; } = new FunctionRegion("ap-south-1"); + /// + /// Represents the region "ap-southeast-1" for function invocation. + /// public static FunctionRegion ApSoutheast1 { get; } = new FunctionRegion("ap-southeast-1"); + /// + /// Represents the "ap-southeast-2" region for requests. + /// public static FunctionRegion ApSoutheast2 { get; } = new FunctionRegion("ap-southeast-2"); + /// + /// Represents the Canada (Central) region for requests. + /// public static FunctionRegion CaCentral1 { get; } = new FunctionRegion("ca-central-1"); + /// + /// Represents the "eu-central-1" region for function invocation. + /// public static FunctionRegion EuCentral1 { get; } = new FunctionRegion("eu-central-1"); + /// + /// Represents the "eu-west-1" function region for requests. + /// public static FunctionRegion EuWest1 { get; } = new FunctionRegion("eu-west-1"); + /// + /// Represents the "eu-west-2" region for function invocation requests. + /// public static FunctionRegion EuWest2 { get; } = new FunctionRegion("eu-west-2"); + /// + /// Represents the AWS region 'eu-west-3'. + /// public static FunctionRegion EuWest3 { get; } = new FunctionRegion("eu-west-3"); + /// + /// Represents the South America (São Paulo) region for requests. + /// public static FunctionRegion SaEast1 { get; } = new FunctionRegion("sa-east-1"); + /// + /// Represents the "us-east-1" region for function requests. + /// public static FunctionRegion UsEast1 { get; } = new FunctionRegion("us-east-1"); + /// + /// Represents the us-west-1 region for function requests. + /// public static FunctionRegion UsWest1 { get; } = new FunctionRegion("us-west-1"); + /// + /// Represents the "us-west-2" region for requests. + /// public static FunctionRegion UsWest2 { get; } = new FunctionRegion("us-west-2"); /// @@ -128,8 +173,14 @@ public bool Equals(FunctionRegion other) public static bool operator !=(FunctionRegion left, FunctionRegion right) => !Equals(left, right); + /// + /// Overloads the explicit cast operator to convert a FunctionRegion object to a string. + /// public static explicit operator string(FunctionRegion region) => region.ToString(); + /// + /// Overloads the explicit cast operator to convert a string to a FunctionRegion object. + /// public static explicit operator FunctionRegion(string region) => new FunctionRegion(region); From bd9463835f021d543c9162c62980d57124a68ba0 Mon Sep 17 00:00:00 2001 From: Diego Santo Date: Sat, 26 Apr 2025 17:38:34 -0300 Subject: [PATCH 06/14] chore: update readme --- README.md | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ce7bf1d..27995c4 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,7 @@ -

- -

- -

- - - - -

+# Supabase.Functions + +[![Build and Test](https://github.com/supabase-community/functions-csharp/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/supabase-community/functions-csharp/actions/workflows/build-and-test.yml) +[![NuGet](https://img.shields.io/nuget/vpre/Supabase.Functions)](https://www.nuget.com/packages/Supabase.Functions/) --- From 5f00b2ba7c4f2111dcb90ba103e6bf66838925f6 Mon Sep 17 00:00:00 2001 From: Diego Santo Date: Sat, 26 Apr 2025 18:06:51 -0300 Subject: [PATCH 07/14] chore: add release-please --- .github/workflows/release-please.yml | 21 +++++++++++++++++++++ .github/workflows/release.yml | 15 +++++++++++---- .release-please-manifest.json | 3 +++ Functions/Functions.csproj | 6 ++++-- release-please-config.json | 16 ++++++++++++++++ 5 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/release-please.yml create mode 100644 .release-please-manifest.json create mode 100644 release-please-config.json diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 0000000..e4abbfe --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,21 @@ +on: + push: + branches: + - master + - release/* + +permissions: + contents: write + pull-requests: write + +name: release-please + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - uses: googleapis/release-please-action@v4 + with: + target-branch: ${{ github.ref_name }} + manifest-file: .release-please-manifest.json + config-file: release-please-config.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cd21e83..b186590 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,12 +1,19 @@ name: Publish NuGet Package on: - push: - branches: - - release/* # Default release branch + workflow_run: + workflows: ["release-please"] + branches: [master] + types: + - completed + +# push: +# branches: +# - release/* # Default release branch jobs: publish: + if: ${{ startsWith(github.event.head_commit.message, 'chore(main)') && github.ref == 'refs/heads/main' && github.event_name == 'push' && github.repository_owner == 'supabase' && github.event.workflow_run.conclusion == 'success' }} name: build, pack & publish runs-on: ubuntu-latest steps: @@ -24,7 +31,7 @@ jobs: check-name: build-and-test repo-token: ${{ secrets.GITHUB_TOKEN }} wait-interval: 10 - + - name: Restore dependencies run: dotnet restore diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..895bf0e --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "2.0.0" +} diff --git a/Functions/Functions.csproj b/Functions/Functions.csproj index eec4ade..4108d70 100644 --- a/Functions/Functions.csproj +++ b/Functions/Functions.csproj @@ -16,8 +16,10 @@ https://avatars.githubusercontent.com/u/54469796?s=200&v=4 https://github.com/supabase-community/functions-csharp supabase, functions + 2.0.0 2.0.0 + true icon.png README.md @@ -31,7 +33,7 @@ - 2.0.0 + 2.0.0 $(VersionPrefix)-$(VersionSuffix) $(VersionPrefix) @@ -46,4 +48,4 @@ - \ No newline at end of file + diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..d93bd7d --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,16 @@ +{ + "packages": { + ".": { + "changelog-path": "CHANGELOG.md", + "bump-minor-pre-major": false, + "bump-patch-for-minor-pre-major": false, + "draft": false, + "prerelease": false, + "release-type": "simple", + "extra-files": [ + "Functions/Functions.csproj" + ] + } + }, + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json" +} From c9611c068cb7e0dd560d8441977c25d2d257fa32 Mon Sep 17 00:00:00 2001 From: Diego Santo Date: Tue, 29 Apr 2025 19:48:04 -0300 Subject: [PATCH 08/14] fix: remove some validation for workflow publish --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b186590..e481411 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ on: jobs: publish: - if: ${{ startsWith(github.event.head_commit.message, 'chore(main)') && github.ref == 'refs/heads/main' && github.event_name == 'push' && github.repository_owner == 'supabase' && github.event.workflow_run.conclusion == 'success' }} + if: ${{ github.repository_owner == 'supabase' && github.event.workflow_run.conclusion == 'success' }} name: build, pack & publish runs-on: ubuntu-latest steps: From 43186f2f95004682cc3848cd37ce715223262d02 Mon Sep 17 00:00:00 2001 From: Diego Santo Date: Wed, 30 Apr 2025 18:40:13 -0300 Subject: [PATCH 09/14] chore: add doc comment --- Functions/InvokeFunctionOptions.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Functions/InvokeFunctionOptions.cs b/Functions/InvokeFunctionOptions.cs index 6958621..911dd83 100644 --- a/Functions/InvokeFunctionOptions.cs +++ b/Functions/InvokeFunctionOptions.cs @@ -184,6 +184,10 @@ public bool Equals(FunctionRegion other) public static explicit operator FunctionRegion(string region) => new FunctionRegion(region); + /// + /// Returns a string representation of the FunctionRegion instance. + /// + /// A string that represents the current FunctionRegion instance. public override string ToString() => _region; } } From dcb30388eb70a4ddbee6aedad39c6ad71cfd46cf Mon Sep 17 00:00:00 2001 From: Diego Santo Date: Mon, 5 May 2025 19:11:01 -0300 Subject: [PATCH 10/14] feat: insert region on client's constructor --- Functions/Client.cs | 15 +++++++++++---- Functions/InvokeFunctionOptions.cs | 6 +++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Functions/Client.cs b/Functions/Client.cs index 6ed1cac..0c572b4 100644 --- a/Functions/Client.cs +++ b/Functions/Client.cs @@ -10,7 +10,6 @@ using Supabase.Core.Extensions; using Supabase.Functions.Exceptions; using Supabase.Functions.Interfaces; -using Supabase.Functions.Responses; [assembly: InternalsVisibleTo("FunctionsTests")] @@ -21,6 +20,7 @@ public partial class Client : IFunctionsClient { private HttpClient _httpClient = new HttpClient(); private readonly string _baseUrl; + private FunctionRegion _region; /// /// Function that can be set to return dynamic headers. @@ -33,9 +33,11 @@ public partial class Client : IFunctionsClient /// Initializes a functions client /// /// - public Client(string baseUrl) + /// + public Client(string baseUrl, FunctionRegion? region = null) { _baseUrl = baseUrl; + _region = region ?? FunctionRegion.Any; } /// @@ -126,9 +128,14 @@ private async Task HandleRequest( options.Headers["X-Client-Info"] = Util.GetAssemblyVersion(typeof(Client)); - if (options.FunctionRegion != FunctionRegion.Any) + if (options.FunctionRegion != null) { - options.Headers["x-region"] = options.FunctionRegion.ToString(); + _region = options.FunctionRegion; + } + + if (_region != FunctionRegion.Any) + { + options.Headers["x-region"] = _region.ToString(); } var builder = new UriBuilder(url); diff --git a/Functions/InvokeFunctionOptions.cs b/Functions/InvokeFunctionOptions.cs index 911dd83..e85a2bb 100644 --- a/Functions/InvokeFunctionOptions.cs +++ b/Functions/InvokeFunctionOptions.cs @@ -40,7 +40,7 @@ public class InvokeFunctionOptions /// /// Region of the request /// - public FunctionRegion FunctionRegion { get; set; } = FunctionRegion.Any; + public FunctionRegion? FunctionRegion { get; set; } = null; } /// @@ -48,7 +48,7 @@ public class InvokeFunctionOptions /// public class FunctionRegion : IEquatable { - private string _region; + private readonly string _region; /// /// Empty region @@ -170,7 +170,7 @@ public bool Equals(FunctionRegion other) /// /// Overloading the operator != /// - public static bool operator !=(FunctionRegion left, FunctionRegion right) => + public static bool operator !=(FunctionRegion? left, FunctionRegion? right) => !Equals(left, right); /// From 4234fac07a41afd88fc57ac5673ee4ea1fedccb6 Mon Sep 17 00:00:00 2001 From: Diego Santo Date: Mon, 5 May 2025 19:11:52 -0300 Subject: [PATCH 11/14] chore: change validation on publish --- .github/workflows/release.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e481411..a63ff99 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,11 +1,17 @@ name: Publish NuGet Package on: - workflow_run: - workflows: ["release-please"] - branches: [master] + pull_request: types: - - completed + - closed + branches: + - "master" + +# workflow_run: +# workflows: ["release-please"] +# branches: [master] +# types: +# - completed # push: # branches: @@ -13,7 +19,7 @@ on: jobs: publish: - if: ${{ github.repository_owner == 'supabase' && github.event.workflow_run.conclusion == 'success' }} + if: ${{ github.event.pull_request.merged == true && github.repository_owner == 'diegofesanto' && startsWith(github.event.head_commit.message, 'chore(master)') && github.ref == 'refs/heads/master' && github.event_name == 'push' }} name: build, pack & publish runs-on: ubuntu-latest steps: From 1ca2c1cbc78b89b46bc360e81cb0d0e81410d366 Mon Sep 17 00:00:00 2001 From: Diego Santo Date: Fri, 9 May 2025 22:42:42 -0300 Subject: [PATCH 12/14] chore: unify workflows similar used in python --- .github/workflows/release-please.yml | 21 ----------------- .github/workflows/release.yml | 34 +++++++++++++++------------- 2 files changed, 18 insertions(+), 37 deletions(-) delete mode 100644 .github/workflows/release-please.yml diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml deleted file mode 100644 index e4abbfe..0000000 --- a/.github/workflows/release-please.yml +++ /dev/null @@ -1,21 +0,0 @@ -on: - push: - branches: - - master - - release/* - -permissions: - contents: write - pull-requests: write - -name: release-please - -jobs: - release-please: - runs-on: ubuntu-latest - steps: - - uses: googleapis/release-please-action@v4 - with: - target-branch: ${{ github.ref_name }} - manifest-file: .release-please-manifest.json - config-file: release-please-config.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a63ff99..106d39f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,25 +1,27 @@ -name: Publish NuGet Package +name: Release - Publish NuGet Package on: - pull_request: - types: - - closed + push: branches: - - "master" - -# workflow_run: -# workflows: ["release-please"] -# branches: [master] -# types: -# - completed - -# push: -# branches: -# - release/* # Default release branch + - master jobs: + release-please: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + issues: write + steps: + - uses: googleapis/release-please-action@v4 + with: + target-branch: ${{ github.ref_name }} + manifest-file: .release-please-manifest.json + config-file: release-please-config.json + publish: - if: ${{ github.event.pull_request.merged == true && github.repository_owner == 'diegofesanto' && startsWith(github.event.head_commit.message, 'chore(master)') && github.ref == 'refs/heads/master' && github.event_name == 'push' }} + needs: release-please + if: ${{ github.repository_owner == 'supabase-community' && startsWith(github.event.head_commit.message, 'chore(master)') && github.ref == 'refs/heads/master' && github.event_name == 'push' }} name: build, pack & publish runs-on: ubuntu-latest steps: From e72c47e750ab1a2bc4b9e62b1656553556e40e71 Mon Sep 17 00:00:00 2001 From: Diego Santo Date: Sat, 10 May 2025 11:04:01 -0300 Subject: [PATCH 13/14] fix: change _region to immutable --- Functions/Client.cs | 9 +++++---- Functions/InvokeFunctionOptions.cs | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Functions/Client.cs b/Functions/Client.cs index 0c572b4..3e2cd17 100644 --- a/Functions/Client.cs +++ b/Functions/Client.cs @@ -20,7 +20,7 @@ public partial class Client : IFunctionsClient { private HttpClient _httpClient = new HttpClient(); private readonly string _baseUrl; - private FunctionRegion _region; + private readonly FunctionRegion _region; /// /// Function that can be set to return dynamic headers. @@ -128,14 +128,15 @@ private async Task HandleRequest( options.Headers["X-Client-Info"] = Util.GetAssemblyVersion(typeof(Client)); - if (options.FunctionRegion != null) + var region = options.FunctionRegion; + if (region == null) { - _region = options.FunctionRegion; + region = _region; } if (_region != FunctionRegion.Any) { - options.Headers["x-region"] = _region.ToString(); + options.Headers["x-region"] = region.ToString(); } var builder = new UriBuilder(url); diff --git a/Functions/InvokeFunctionOptions.cs b/Functions/InvokeFunctionOptions.cs index e85a2bb..cf27f1f 100644 --- a/Functions/InvokeFunctionOptions.cs +++ b/Functions/InvokeFunctionOptions.cs @@ -164,7 +164,7 @@ public bool Equals(FunctionRegion other) /// /// Overloading the operator == /// - public static bool operator ==(FunctionRegion left, FunctionRegion right) => + public static bool operator ==(FunctionRegion? left, FunctionRegion? right) => Equals(left, right); /// From 134e294e32d341a73e9fa084b435af53efdf1c4e Mon Sep 17 00:00:00 2001 From: Diego Santo Date: Sun, 11 May 2025 11:52:15 -0300 Subject: [PATCH 14/14] fix: change to use local region var --- Functions/Client.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Functions/Client.cs b/Functions/Client.cs index 3e2cd17..d158e72 100644 --- a/Functions/Client.cs +++ b/Functions/Client.cs @@ -134,7 +134,7 @@ private async Task HandleRequest( region = _region; } - if (_region != FunctionRegion.Any) + if (region != FunctionRegion.Any) { options.Headers["x-region"] = region.ToString(); }