From 1f72f7651a375a9db6632fc6a92977270a13832a Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 7 Dec 2024 14:40:39 +0100 Subject: [PATCH 01/12] Create MSBuild project with custom task --- src/Refitter.MSBuild/README.md | 178 ++++++++++++++++++ src/Refitter.MSBuild/Refitter.MSBuild.csproj | 30 +++ src/Refitter.MSBuild/Refitter.MSBuild.props | 11 ++ src/Refitter.MSBuild/Refitter.MSBuild.targets | 10 + src/Refitter.MSBuild/RefitterGenerateTask.cs | 103 ++++++++++ src/Refitter.sln | 6 + 6 files changed, 338 insertions(+) create mode 100644 src/Refitter.MSBuild/README.md create mode 100644 src/Refitter.MSBuild/Refitter.MSBuild.csproj create mode 100644 src/Refitter.MSBuild/Refitter.MSBuild.props create mode 100644 src/Refitter.MSBuild/Refitter.MSBuild.targets create mode 100644 src/Refitter.MSBuild/RefitterGenerateTask.cs diff --git a/src/Refitter.MSBuild/README.md b/src/Refitter.MSBuild/README.md new file mode 100644 index 00000000..e4af651c --- /dev/null +++ b/src/Refitter.MSBuild/README.md @@ -0,0 +1,178 @@ +## MSBuild Tasks for Refitter + +Refitter is available as custom MSBuild tasks that uses the [Refitter.Core](https://github.com/christianhelle/refitter/tree/main/src/Refitter.Core) library for generating a REST API Client using the [Refit](https://github.com/reactiveui/refit) library. Refitter can generate the Refit interface from OpenAPI specifications. Refitter could format the generated Refit interface to be managed by [Apizr](https://www.apizr.net) (v6+) and generate some registration helpers too. + + +### .Refitter File format + +The following is an example `.refitter` file + +```js +{ + "openApiPath": "/path/to/your/openAPI", // Required + "namespace": "Org.System.Service.Api.GeneratedCode", // Optional. Default=GeneratedCode + "naming": { + "useOpenApiTitle": false, // Optional. Default=true + "interfaceName": "MyApiClient" // Optional. Default=ApiClient + }, + "generateContracts": true, // Optional. Default=true + "generateXmlDocCodeComments": true, // Optional. Default=true + "generateStatusCodeComments": true, // Optional. Default=true + "addAutoGeneratedHeader": true, // Optional. Default=true + "addAcceptHeaders": true, // Optional. Default=true + "returnIApiResponse": false, // Optional. Default=false + "responseTypeOverride": { // Optional. Default={} + "File_Upload": "IApiResponse", + "File_Download": "System.Net.Http.HttpContent" + }, + "generateOperationHeaders": true, // Optional. Default=true + "typeAccessibility": "Public", // Optional. Values=Public|Internal. Default=Public + "useCancellationTokens": false, // Optional. Default=false + "useIsoDateFormat": false, // Optional. Default=false + "multipleInterfaces": "ByEndpoint", // Optional. May be one of "ByEndpoint" or "ByTag" + "generateDeprecatedOperations": false, // Optional. Default=true + "operationNameTemplate": "{operationName}Async", // Optional. Must contain {operationName} when multipleInterfaces != ByEndpoint + "optionalParameters": false, // Optional. Default=false + "outputFolder": "../CustomOutput" // Optional. Default=./Generated + "outputFilename": "RefitInterface.cs", // Optional. Default=Output.cs for CLI tool + "additionalNamespaces": [ // Optional + "Namespace1", + "Namespace2" + ], + "includeTags": [ // Optional. OpenAPI Tag to include when generating code + "Pet", + "Store", + "User" + ], + "includePathMatches": [ // Optional. Only include Paths that match the provided regular expression + "^/pet/.*", + "^/store/.*" + ], + "useDynamicQuerystringParameters": true, // Optional. Default=false + "usePolymorphicSerialization": false, // Optional. Default=false + "dependencyInjectionSettings": { // Optional + "baseUrl": "https://petstore3.swagger.io/api/v3", // Optional. Leave this blank to set the base address manually + "httpMessageHandlers": [ // Optional + "AuthorizationMessageHandler", + "TelemetryMessageHandler" + ], + "transientErrorHandler": "Polly", // Optional. Value=None|Polly|HttpResilience + "maxRetryCount": 3, // Optional. Default=6 + "firstBackoffRetryInSeconds": 0.5 // Optional. Default=1.0 + }, + "apizrSettings": { // Optional + "withRequestOptions": true, // Optional. Default=true + "withRegistrationHelper": true, // Optional. Default=false + "withCacheProvider": "InMemory", // Optional. Values=None|Akavache|MonkeyCache|InMemory|DistributedAsString|DistributedAsByteArray. Default=None + "withPriority": true, // Optional. Default=false + "withMediation": true, // Optional. Default=false + "withOptionalMediation": true, // Optional. Default=false + "withMappingProvider": "AutoMapper", // Optional. Values=None|AutoMapper|Mapster. Default=None + "withFileTransfer": true // Optional. Default=false + }, + "codeGeneratorSettings": { // Optional. Default settings are the values set in this example + "requiredPropertiesMustBeDefined": true, + "generateDataAnnotations": true, + "anyType": "object", + "dateType": "System.DateTimeOffset", + "dateTimeType": "System.DateTimeOffset", + "timeType": "System.TimeSpan", + "timeSpanType": "System.TimeSpan", + "arrayType": "System.Collections.Generic.ICollection", + "dictionaryType": "System.Collections.Generic.IDictionary", + "arrayInstanceType": "System.Collections.ObjectModel.Collection", + "dictionaryInstanceType": "System.Collections.Generic.Dictionary", + "arrayBaseType": "System.Collections.ObjectModel.Collection", + "dictionaryBaseType": "System.Collections.Generic.Dictionary", + "propertySetterAccessModifier": "", + "generateImmutableArrayProperties": false, + "generateImmutableDictionaryProperties": false, + "handleReferences": false, + "jsonSerializerSettingsTransformationMethod": null, + "generateJsonMethods": false, + "enforceFlagEnums": false, + "inlineNamedDictionaries": false, + "inlineNamedTuples": true, + "inlineNamedArrays": false, + "generateOptionalPropertiesAsNullable": false, + "generateNullableReferenceTypes": false, + "generateNativeRecords": false, + "generateDefaultValues": true, + "inlineNamedAny": false, + "excludedTypeNames": [ + "ExcludedTypeFoo", + "ExcludedTypeBar" + ] + } +} +``` + +- `openApiPath` - points to the OpenAPI Specifications file. This can be the path to a file stored on disk, relative to the `.refitter` file. This can also be a URL to a remote file that will be downloaded over HTTP/HTTPS +- `namespace` - the namespace used in the generated code. If not specified, this defaults to `GeneratedCode` +- `naming.useOpenApiTitle` - a boolean indicating whether the OpenApi title should be used. Default is `true` +- `naming.interfaceName` - the name of the generated interface. The generated code will automatically prefix this with `I` so if this set to `MyApiClient` then the generated interface is called `IMyApiClient`. Default is `ApiClient` +- `generateContracts` - a boolean indicating whether contracts should be generated. A use case for this is several API clients use the same contracts. Default is `true` +- `generateXmlDocCodeComments` - a boolean indicating whether XML doc comments should be generated. Default is `true` +- `addAutoGeneratedHeader` - a boolean indicating whether XML doc comments should be generated. Default is `true` +- `addAcceptHeaders` - a boolean indicating whether to add accept headers [Headers("Accept: application/json")]. Default is `true` +- `returnIApiResponse` - a boolean indicating whether to return `IApiResponse` objects. Default is `false` +- `responseTypeOverride` - a dictionary with operation ids (as specified in the OpenAPI document) and a particular return type to use. The types are wrapped in a task, but otherwise unmodified (so make sure to specify or import their namespaces). Default is `{}` +- `generateOperationHeaders` - a boolean indicating whether to use operation headers in the generated methods. Default is `true` +- `typeAccessibility` - the generated type accessibility. Possible values are `Public` and `Internal`. Default is `Public` +- `useCancellationTokens` - Use cancellation tokens in the generated methods. Default is `false` +- `useIsoDateFormat` - Set to `true` to explicitly format date query string parameters in ISO 8601 standard date format using delimiters (for example: 2023-06-15). Default is `false` +- `multipleInterfaces` - Set to `ByEndpoint` to generate an interface for each endpoint, or `ByTag` to group Endpoints by their Tag (like SwaggerUI groups them). +- `outputFolder` - a string describing a relative path to a desired output folder. Default is `./Generated` +- `outputFilename` - Output filename. Default is `Output.cs` when used from the CLI tool, otherwise its the .refitter filename. So `Petstore.refitter` becomes `Petstore.cs`. +- `additionalNamespaces` - A collection of additional namespaces to include in the generated file. A use case for this is when you want to reuse contracts from a different namespace than the generated code. Default is empty +- `includeTags` - A collection of tags to use a filter for including endpoints that contain this tag. +- `includePathMatches` - A collection of regular expressions used to filter paths. +- `generateDeprecatedOperations` - a boolean indicating whether deprecated operations should be generated or skipped. Default is `true` +- `operationNameTemplate` - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be `{operationName}Async` to suffix all method names with Async. When using `"multipleIinterfaces": "ByEndpoint"`, This is name of the Execute() method in the interface +- `optionalParameters` - Generate non-required parameters as nullable optional parameters +- `useDynamicQuerystringParameters`: Set to `true` to wrap multiple query parameters into a single complex one. Default is `false` (no wrapping). +- `dependencyInjectionSettings` - Setting this will generated extension methods to `IServiceCollection` for configuring Refit clients. See https://github.com/reactiveui/refit?tab=readme-ov-file#dynamic-querystring-parameters for more information. + - `baseUrl` - Used as the HttpClient base address. Leave this blank to manually set the base URL + - `httpMessageHandlers` - A collection of `HttpMessageHandler` that is added to the HttpClient pipeline + - `transientErrorHandler` - This is the transient error handler to use. Possible values are `None`, `Polly`, and `HttpResilience`. Default is `None` + - `maxRetryCount` - This is the max retry count used in the Polly retry policy. Default is 6 + - `firstBackoffRetryInSeconds` - This is the duration of the initial retry backoff. Default is 1 second +- `apizrSettings` - Setting this will format Refit interface to be managed by Apizr. See https://www.apizr.net for more information + - `withRequestOptions` - Tells if the Refit interface methods should have a final IApizrRequestOptions options parameter + - `withRegistrationHelper` - Tells if Refitter should generate Apizr registration helpers (extended with dependencyInjectionSettings set, otherwise static) + - `withCacheProvider` - Set the cache provider to be used + - `withPriority` - Tells if Apizr should handle request priority + - `withMediation` - Tells if Apizr should handle request mediation (extended only) + - `withOptionalMediation` - Tells if Apizr should handle optional request mediation (extended only) + - `withMappingProvider` - Set the mapping provider to be used + - `withFileTransfer` - Tells if Apizr should handle file transfer +- `codeGeneratorSettings` - Setting this allows customization of the NSwag generated types and contracts + - `requiredPropertiesMustBeDefined` - Default is true, + - `generateDataAnnotations` - Default is true, + - `anyType` - Default is `object`, + - `dateType` - Default is `System.DateTimeOffset`, + - `dateTimeType` - Default is `System.DateTimeOffset`, + - `timeType` - Default is `System.TimeSpan`, + - `timeSpanType` - Default is `System.TimeSpan`, + - `arrayType` - Default is `System.Collections.Generic.ICollection`, + - `dictionaryType` - Default is `System.Collections.Generic.IDictionary`, + - `arrayInstanceType` - Default is `System.Collections.ObjectModel.Collection`, + - `dictionaryInstanceType` - Default is `System.Collections.Generic.Dictionary`, + - `arrayBaseType` - Default is `System.Collections.ObjectModel.Collection`, + - `dictionaryBaseType` - Default is `System.Collections.Generic.Dictionary`, + - `propertySetterAccessModifier` - Default is ``, + - `generateImmutableArrayProperties` - Default is false, + - `generateImmutableDictionaryProperties` - Default is false, + - `handleReferences` - Default is false, + - `jsonSerializerSettingsTransformationMethod` - Default is null, + - `generateJsonMethods` - Default is false, + - `enforceFlagEnums` - Default is false, + - `inlineNamedDictionaries` - Default is false, + - `inlineNamedTuples` - Default is true, + - `inlineNamedArrays` - Default is false, + - `generateOptionalPropertiesAsNullable` - Default is false, + - `generateNullableReferenceTypes` - Default is false, + - `generateNativeRecords` - Default is false + - `generateDefaultValues` - Default is true + - `inlineNamedAny` - Default is false + - `excludedTypeNames` - Default is empty diff --git a/src/Refitter.MSBuild/Refitter.MSBuild.csproj b/src/Refitter.MSBuild/Refitter.MSBuild.csproj new file mode 100644 index 00000000..8111715d --- /dev/null +++ b/src/Refitter.MSBuild/Refitter.MSBuild.csproj @@ -0,0 +1,30 @@ +๏ปฟ + + + netstandard2.0 + Refitter MSBuild Tasks + Refitter.MSBuild + Refitter.MSBuild + Refitter.MSBuild + Refitter.MSBuild + A MSBuid task that uses Refitter for generating a REST API Client using the Refit library from OpenAPI specifications. + true + tasks + + + + + + + + + + + + + + + diff --git a/src/Refitter.MSBuild/Refitter.MSBuild.props b/src/Refitter.MSBuild/Refitter.MSBuild.props new file mode 100644 index 00000000..3860f56b --- /dev/null +++ b/src/Refitter.MSBuild/Refitter.MSBuild.props @@ -0,0 +1,11 @@ + + + + $(MSBuildThisFileDirectory)..\tasks + $(TaskFolder)\netstandard2.0\Refitter.MSBuild.dll + + + + + diff --git a/src/Refitter.MSBuild/Refitter.MSBuild.targets b/src/Refitter.MSBuild/Refitter.MSBuild.targets new file mode 100644 index 00000000..777951c0 --- /dev/null +++ b/src/Refitter.MSBuild/Refitter.MSBuild.targets @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/Refitter.MSBuild/RefitterGenerateTask.cs b/src/Refitter.MSBuild/RefitterGenerateTask.cs new file mode 100644 index 00000000..fc836fbb --- /dev/null +++ b/src/Refitter.MSBuild/RefitterGenerateTask.cs @@ -0,0 +1,103 @@ +using System.Diagnostics; +using MSBuildTask = Microsoft.Build.Utilities.Task; + +namespace Refitter.MSBuild; + +public class RefitterGenerateTask : MSBuildTask +{ + public string ProjectFileDirectory { get; set; } + + public override bool Execute() + { + TryLogCommandLine($"Starting {nameof(RefitterGenerateTask)}"); + TryLogCommandLine($"Looking for .refitter files under {ProjectFileDirectory}"); + + var files = Directory.GetFiles( + ProjectFileDirectory, + "*.refitter", + SearchOption.AllDirectories); + + TryLogCommandLine($"Found {files.Length} .refitter files..."); + + foreach (var file in files) + { + TryLogCommandLine($"Processing {file}"); + TryExecuteRefitter(file); + } + + return true; + } + + private void TryExecuteRefitter(string file) + { + try + { + StartProcess(file); + } + catch (Exception e) + { + TryLogErrorFromException(e); + } + } + + private void StartProcess(string file) + { + using var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "refitter", + Arguments = $"--settings-file {file}", + WorkingDirectory = Path.GetDirectoryName(file)!, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false, + CreateNoWindow = true, + } + }; + + process.ErrorDataReceived += (_, args) => TryLogError(args.Data); + process.OutputDataReceived += (_, args) => TryLogCommandLine(args.Data); + process.Start(); + process.BeginErrorReadLine(); + process.BeginOutputReadLine(); + process.WaitForExit(); + } + + private void TryLogErrorFromException(Exception e) + { + try + { + Log.LogErrorFromException(e); + } + catch + { + // Ignore + } + } + + private void TryLogCommandLine(string text) + { + try + { + Log.LogCommandLine(text); + } + catch + { + // ignore + } + } + + private void TryLogError(string text) + { + try + { + Log.LogError(text); + } + catch + { + // ignore + } + } +} diff --git a/src/Refitter.sln b/src/Refitter.sln index 29b0a310..2b369913 100644 --- a/src/Refitter.sln +++ b/src/Refitter.sln @@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Refitter.SourceGenerator", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Refitter.SourceGenerator.Tests", "Refitter.SourceGenerator.Tests\Refitter.SourceGenerator.Tests.csproj", "{AFF920A9-765D-4ABA-9BEF-2A5BE7A2AFAA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Refitter.MSBuild", "Refitter.MSBuild\Refitter.MSBuild.csproj", "{3CBC5045-9427-42D5-B71F-C25EAC86E042}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -39,6 +41,10 @@ Global {AFF920A9-765D-4ABA-9BEF-2A5BE7A2AFAA}.Debug|Any CPU.Build.0 = Debug|Any CPU {AFF920A9-765D-4ABA-9BEF-2A5BE7A2AFAA}.Release|Any CPU.ActiveCfg = Release|Any CPU {AFF920A9-765D-4ABA-9BEF-2A5BE7A2AFAA}.Release|Any CPU.Build.0 = Release|Any CPU + {3CBC5045-9427-42D5-B71F-C25EAC86E042}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3CBC5045-9427-42D5-B71F-C25EAC86E042}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3CBC5045-9427-42D5-B71F-C25EAC86E042}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3CBC5045-9427-42D5-B71F-C25EAC86E042}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 31d684c43a6b3d865414cd4d6b99bd0829fb4d48 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 7 Dec 2024 14:40:58 +0100 Subject: [PATCH 02/12] Create test project for MSBuild project --- test/MSBuild/Program.cs | 18 ++++++++++++++++++ test/MSBuild/Refitter.MSBuild.Tests.csproj | 17 +++++++++++++++++ test/MSBuild/build.ps1 | 17 +++++++++++++++++ test/MSBuild/petstore.refitter | 10 ++++++++++ 4 files changed, 62 insertions(+) create mode 100644 test/MSBuild/Program.cs create mode 100644 test/MSBuild/Refitter.MSBuild.Tests.csproj create mode 100644 test/MSBuild/build.ps1 create mode 100644 test/MSBuild/petstore.refitter diff --git a/test/MSBuild/Program.cs b/test/MSBuild/Program.cs new file mode 100644 index 00000000..8a64d5f0 --- /dev/null +++ b/test/MSBuild/Program.cs @@ -0,0 +1,18 @@ +๏ปฟ// See https://aka.ms/new-console-template for more information + +using Refit; +using Refitter.MSBuild.Tests.Petstore; + +var client = RestService.For("https://petstore3.swagger.io/api/v3"); +var pet = await client.GetPetById(1); + +Console.WriteLine($"Name: {pet.Name}"); +Console.WriteLine($"Status: {pet.Status}"); + +var pets = await client.FindPetsByStatus(Status.Available); +Console.WriteLine("Found " + pets.Count + " available pet(s)"); + +var taggedPets = await client.FindPetsByTags(["tag1Updated", "new"]); +Console.WriteLine("Found " + taggedPets.Count + " tagged pet(s)"); + +Console.WriteLine(); diff --git a/test/MSBuild/Refitter.MSBuild.Tests.csproj b/test/MSBuild/Refitter.MSBuild.Tests.csproj new file mode 100644 index 00000000..36282569 --- /dev/null +++ b/test/MSBuild/Refitter.MSBuild.Tests.csproj @@ -0,0 +1,17 @@ +๏ปฟ + + + Exe + net8.0 + enable + enable + + + + + + + + + + diff --git a/test/MSBuild/build.ps1 b/test/MSBuild/build.ps1 new file mode 100644 index 00000000..1a65170b --- /dev/null +++ b/test/MSBuild/build.ps1 @@ -0,0 +1,17 @@ +Remove-Item bin -Force -Recurse +Remove-Item obj -Force -Recurse +dotnet build-server shutdown +nuget locals global-packages -clear +Remove-Item ./refitter.msbuild -Recurse -Force +Remove-Item Refitter.MSBuild.*.nupkg -Force +Remove-Item Petstore.cs +dotnet clean -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj +dotnet restore ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj +dotnet build -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj +dotnet pack -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj -o . +nuget add .\Refitter.MSBuild.1.0.0.nupkg -source . +dotnet restore +dotnet add package Refitter.MSBuild -s . +dotnet build -v d -filelogger +dotnet remove package Refitter.MSBuild +Remove-Item Refitter.MSBuild.*.nupkg -Force \ No newline at end of file diff --git a/test/MSBuild/petstore.refitter b/test/MSBuild/petstore.refitter new file mode 100644 index 00000000..0bac6d1b --- /dev/null +++ b/test/MSBuild/petstore.refitter @@ -0,0 +1,10 @@ +{ + "openApiPath": "https://petstore3.swagger.io/api/v3/openapi.json", + "namespace": "Refitter.MSBuild.Tests.Petstore", + "outputFileName": "Petstore.cs", + "naming": { + "useOpenApiTitle": false, + "interfaceName": "SwaggerPetstore", + "filename": "SwaggerPetstore" + } +} From 2e9ec5bc21e2ffba0ff7115727ce010be9ceecf1 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 7 Dec 2024 16:07:06 +0100 Subject: [PATCH 03/12] Attempt to install Refitter CLI from MSBuild task --- src/Refitter.MSBuild/Refitter.MSBuild.props | 1 + src/Refitter.MSBuild/Refitter.MSBuild.targets | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Refitter.MSBuild/Refitter.MSBuild.props b/src/Refitter.MSBuild/Refitter.MSBuild.props index 3860f56b..6d6f41ca 100644 --- a/src/Refitter.MSBuild/Refitter.MSBuild.props +++ b/src/Refitter.MSBuild/Refitter.MSBuild.props @@ -3,6 +3,7 @@ $(MSBuildThisFileDirectory)..\tasks $(TaskFolder)\netstandard2.0\Refitter.MSBuild.dll + $(Version) + From 826afaf893b2eb3004c367b2bf3fa0281fbfbdaa Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 7 Dec 2024 16:07:26 +0100 Subject: [PATCH 04/12] Create MSBuild workflow --- .github/workflows/msbuild.yml | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/workflows/msbuild.yml diff --git a/.github/workflows/msbuild.yml b/.github/workflows/msbuild.yml new file mode 100644 index 00000000..0528aa53 --- /dev/null +++ b/.github/workflows/msbuild.yml @@ -0,0 +1,42 @@ +name: Build + +on: + workflow_dispatch: + push: + paths-ignore: + - '**/*' + - '!.github/workflows/msbuild.yml' + - '!src/**/*.csproj' + - '!src/**/*.cs' + branches: + - 'main' + pull_request: + paths-ignore: + - '**/*' + - '!.github/workflows/msbuild.yml' + - '!src/**/*.csproj' + - '!src/**/*.cs' + branches: + - '*' + +jobs: + build: + name: ๐Ÿ‘Œ Verify build + runs-on: ubuntu-latest + steps: + - name: ๐Ÿ›’ Checkout repository + uses: actions/checkout@v4 + - name: ๐Ÿ› ๏ธ Prepare + working-directory: test/MSBuild + run: | + dotnet restore ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj + dotnet build -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj + dotnet pack -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj -o + nuget add .\Refitter.MSBuild.1.0.0.nupkg -source . + dotnet add package Refitter.MSBuild -s . + - name: ๐Ÿ› ๏ธ Build + working-directory: test/MSBuild + run: dotnet build -v d -filelogger + - name: ๐Ÿงช Build Output + working-directory: test/MSBuild + run: cat msbuild.log From f7b1906123280e08d32da5d21c49f2521c30050c Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 7 Dec 2024 16:08:02 +0100 Subject: [PATCH 05/12] Ignore MSBuild test output --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 15e87d3c..64d61479 100644 --- a/.gitignore +++ b/.gitignore @@ -277,3 +277,4 @@ test/GeneratedCode/ test/Apizr/GeneratedCode test/MultipleFiles/**/*.cs test/HelloWorld/HelloWorld/Output.cs +test/MSBuild/refitter.msbuild/ From d49aa532a5707cc3ea55a832de1e6525e772be25 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 7 Dec 2024 16:12:03 +0100 Subject: [PATCH 06/12] Rename workflow from 'Build' to 'MSBuild' --- .github/workflows/msbuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/msbuild.yml b/.github/workflows/msbuild.yml index 0528aa53..848f397d 100644 --- a/.github/workflows/msbuild.yml +++ b/.github/workflows/msbuild.yml @@ -1,4 +1,4 @@ -name: Build +name: MSBuild on: workflow_dispatch: From 50e833516775d57e400dad9abc19949ccb5e6720 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 7 Dec 2024 16:12:29 +0100 Subject: [PATCH 07/12] Change build runner from Ubuntu to Windows for MSBuild workflow --- .github/workflows/msbuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/msbuild.yml b/.github/workflows/msbuild.yml index 848f397d..64e523cb 100644 --- a/.github/workflows/msbuild.yml +++ b/.github/workflows/msbuild.yml @@ -22,7 +22,7 @@ on: jobs: build: name: ๐Ÿ‘Œ Verify build - runs-on: ubuntu-latest + runs-on: windows-latest steps: - name: ๐Ÿ›’ Checkout repository uses: actions/checkout@v4 From 93433addc8165a07864c24985c7905c4168f2522 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 7 Dec 2024 17:10:01 +0100 Subject: [PATCH 08/12] Use refitter.dll included in package --- src/Refitter.MSBuild/Refitter.MSBuild.targets | 1 - src/Refitter.MSBuild/RefitterGenerateTask.cs | 12 +++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Refitter.MSBuild/Refitter.MSBuild.targets b/src/Refitter.MSBuild/Refitter.MSBuild.targets index 77a8bcfd..777951c0 100644 --- a/src/Refitter.MSBuild/Refitter.MSBuild.targets +++ b/src/Refitter.MSBuild/Refitter.MSBuild.targets @@ -1,7 +1,6 @@ - diff --git a/src/Refitter.MSBuild/RefitterGenerateTask.cs b/src/Refitter.MSBuild/RefitterGenerateTask.cs index fc836fbb..80d32b1e 100644 --- a/src/Refitter.MSBuild/RefitterGenerateTask.cs +++ b/src/Refitter.MSBuild/RefitterGenerateTask.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Reflection; using MSBuildTask = Microsoft.Build.Utilities.Task; namespace Refitter.MSBuild; @@ -17,7 +18,7 @@ public override bool Execute() "*.refitter", SearchOption.AllDirectories); - TryLogCommandLine($"Found {files.Length} .refitter files..."); + TryLogCommandLine($"Found {files.Length} .refitter files..."); foreach (var file in files) { @@ -42,12 +43,17 @@ private void TryExecuteRefitter(string file) private void StartProcess(string file) { + var assembly = Assembly.GetExecutingAssembly(); + var packageFolder = Path.GetDirectoryName(assembly.Location); + var refitterDll = $"{packageFolder}\\..\\refitter.dll"; + TryLogCommandLine("Starting " + refitterDll); + using var process = new Process { StartInfo = new ProcessStartInfo { - FileName = "refitter", - Arguments = $"--settings-file {file}", + FileName = "dotnet", + Arguments = $"{refitterDll} --settings-file {file}", WorkingDirectory = Path.GetDirectoryName(file)!, RedirectStandardOutput = true, RedirectStandardError = true, From 005632d1402564a69a582aa784d9e7450321f303 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 7 Dec 2024 17:22:34 +0100 Subject: [PATCH 09/12] Update MSBuild workflow to restore and build solution and project files --- .github/workflows/msbuild.yml | 5 +++-- test/MSBuild/build.ps1 | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/msbuild.yml b/.github/workflows/msbuild.yml index 64e523cb..c5a8cfaf 100644 --- a/.github/workflows/msbuild.yml +++ b/.github/workflows/msbuild.yml @@ -29,8 +29,9 @@ jobs: - name: ๐Ÿ› ๏ธ Prepare working-directory: test/MSBuild run: | - dotnet restore ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj - dotnet build -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj + dotnet restore ../../src/Refitter.sln + dotnet build -c release ../../src/Refitter/Refitter.csproj + dotnet build -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj -o dotnet pack -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj -o nuget add .\Refitter.MSBuild.1.0.0.nupkg -source . dotnet add package Refitter.MSBuild -s . diff --git a/test/MSBuild/build.ps1 b/test/MSBuild/build.ps1 index 1a65170b..cbf54717 100644 --- a/test/MSBuild/build.ps1 +++ b/test/MSBuild/build.ps1 @@ -5,8 +5,9 @@ nuget locals global-packages -clear Remove-Item ./refitter.msbuild -Recurse -Force Remove-Item Refitter.MSBuild.*.nupkg -Force Remove-Item Petstore.cs -dotnet clean -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj -dotnet restore ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj +dotnet restore ../../src/Refitter.sln +dotnet clean -c release ../../src/Refitter.sln +dotnet build -c release ../../src/Refitter/Refitter.csproj dotnet build -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj dotnet pack -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj -o . nuget add .\Refitter.MSBuild.1.0.0.nupkg -source . From cb08f508f6e85b0d2578aeff5f6acf7517bdb4f4 Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 7 Dec 2024 17:23:33 +0100 Subject: [PATCH 10/12] Rename workflow from 'MSBuild' to 'MSBuild Tasks' --- .github/workflows/msbuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/msbuild.yml b/.github/workflows/msbuild.yml index c5a8cfaf..e14acc37 100644 --- a/.github/workflows/msbuild.yml +++ b/.github/workflows/msbuild.yml @@ -1,4 +1,4 @@ -name: MSBuild +name: MSBuild Tasks on: workflow_dispatch: From a6b716046ea87779314f07ca78fd9bc232e7723b Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 7 Dec 2024 17:26:45 +0100 Subject: [PATCH 11/12] Fix MSBuild workflow to remove incorrect output directory flag in build command --- .github/workflows/msbuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/msbuild.yml b/.github/workflows/msbuild.yml index e14acc37..7564e36b 100644 --- a/.github/workflows/msbuild.yml +++ b/.github/workflows/msbuild.yml @@ -31,7 +31,7 @@ jobs: run: | dotnet restore ../../src/Refitter.sln dotnet build -c release ../../src/Refitter/Refitter.csproj - dotnet build -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj -o + dotnet build -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj dotnet pack -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj -o nuget add .\Refitter.MSBuild.1.0.0.nupkg -source . dotnet add package Refitter.MSBuild -s . From ed412695daad017ac9de4166a1231aa1557142ba Mon Sep 17 00:00:00 2001 From: Christian Helle Date: Sat, 7 Dec 2024 17:40:55 +0100 Subject: [PATCH 12/12] Fix output directory for dotnet pack command in MSBuild workflow --- .github/workflows/msbuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/msbuild.yml b/.github/workflows/msbuild.yml index 7564e36b..08a370e9 100644 --- a/.github/workflows/msbuild.yml +++ b/.github/workflows/msbuild.yml @@ -32,7 +32,7 @@ jobs: dotnet restore ../../src/Refitter.sln dotnet build -c release ../../src/Refitter/Refitter.csproj dotnet build -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj - dotnet pack -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj -o + dotnet pack -c release ../../src/Refitter.MSBuild/Refitter.MSBuild.csproj -o . nuget add .\Refitter.MSBuild.1.0.0.nupkg -source . dotnet add package Refitter.MSBuild -s . - name: ๐Ÿ› ๏ธ Build