From d53b6ba0cc25f5bd0581f6980f8a4d3b8665a2c1 Mon Sep 17 00:00:00 2001 From: Benito Palacios Sanchez Date: Tue, 21 Nov 2023 11:02:07 +0100 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=90=9B=20Small=20fixes=20and=20improv?= =?UTF-8?q?ements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 5 -- CODE_OF_CONDUCT.md | 2 +- docs/template/public/main.css | 9 --- .../CakeArgumentsExtensions.cs | 61 +++++++++++++++++++ .../Dotnet/DotNetBuildContext.cs | 6 +- .../PleOpsBuildContext.cs | 26 +++----- ...e.Frosting.PleOps.Samples.PublicApp.csproj | 2 - ....Frosting.PleOps.Samples.PublicApp2.csproj | 3 - src/Directory.Build.props | 8 +-- src/Directory.Packages.props | 3 +- 10 files changed, 75 insertions(+), 50 deletions(-) create mode 100644 src/Cake.Frosting.PleOps.Recipe/CakeArgumentsExtensions.cs diff --git a/.editorconfig b/.editorconfig index b0cc862..4b9677f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -240,14 +240,9 @@ dotnet_diagnostic.IDE0045.severity = suggestion # Simplify ifs dotnet_diagnostic.IDE0046.severity = suggestion # Simplify ifs ### StyleCop -dotnet_diagnostic.SA1000.severity = none # false positive, space before parentheses in new() -dotnet_diagnostic.SA1009.severity = none # false positive with ()! for null checking -dotnet_diagnostic.SA1011.severity = none # False positive due to nullables dotnet_diagnostic.SA1101.severity = none # Do not force to prefix local calls with 'this' dotnet_diagnostic.SA1204.severity = suggestion # Static methods should be before non-static -dotnet_diagnostic.SA1313.severity = none # Pascal naming broken with records. dotnet_diagnostic.SA1500.severity = none # Allow inline braces -dotnet_diagnostic.SA1516.severity = none # Multiple blank lines - broken with top-level statements dotnet_diagnostic.SA1633.severity = none # No XML-format header in source files ### SonarAnalyzer diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 0fe241e..c30f261 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at benito356@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at . The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. diff --git a/docs/template/public/main.css b/docs/template/public/main.css index fca2c28..d262f7e 100644 --- a/docs/template/public/main.css +++ b/docs/template/public/main.css @@ -1,16 +1,7 @@ /* Changing the site font */ @import url("https://fonts.googleapis.com/css2?family=Nunito:wght@100;400;700&display=swap"); -/* @import url('https://fonts.googleapis.com/css2?family=Inconsolata&display=swap'); */ @import url("https://fonts.googleapis.com/css2?family=Fira Code&display=swap"); -/*@import url('https://fonts.cdnfonts.com/css/cascadia-code');*/ -/* @font-face { - font-family: 'Cascadia Code'; - font-style: normal; - font-weight: 100; - src: local('Cascadia Code'), url('https://fonts.cdnfonts.com/s/29131/Cascadia.woff') format('woff'); -} */ - :root { --bs-font-sans-serif: "Nunito"; --bs-font-monospace: "Fira Code"; diff --git a/src/Cake.Frosting.PleOps.Recipe/CakeArgumentsExtensions.cs b/src/Cake.Frosting.PleOps.Recipe/CakeArgumentsExtensions.cs new file mode 100644 index 0000000..3a44a46 --- /dev/null +++ b/src/Cake.Frosting.PleOps.Recipe/CakeArgumentsExtensions.cs @@ -0,0 +1,61 @@ +// Copyright (c) 2023 Benito Palacios SΓ‘nchez +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +namespace Cake.Frosting.PleOps.Recipe; + +using Cake.Core; + +/// +/// Extension methods for ICakeArguments class. +/// +public static class CakeArgumentsExtensions +{ + /// + /// Run the setter if the argument name is present. + /// + /// Cake argument handler. + /// Argument name. + /// Setter to run. + public static void SetIfPresent(this ICakeArguments handler, string argName, Action setter) + { + if (handler.HasArgument(argName)) { + setter(handler.GetArgument(argName)); + } + } + + /// + /// Run the setter if the argument name is present. + /// + /// Cake argument handler. + /// Argument name. + /// Setter to run. + public static void SetIfPresent(this ICakeArguments handler, string argName, Action setter) + { + if (handler.HasArgument(argName)) { + string valueText = handler.GetArgument(argName); + if (string.IsNullOrEmpty(valueText)) { + // If it's present but without value, assume is like a set -> true + setter(true); + } else { + bool value = bool.Parse(handler.GetArgument(argName)); + setter(value); + } + } + } +} diff --git a/src/Cake.Frosting.PleOps.Recipe/Dotnet/DotNetBuildContext.cs b/src/Cake.Frosting.PleOps.Recipe/Dotnet/DotNetBuildContext.cs index c287103..3932f44 100644 --- a/src/Cake.Frosting.PleOps.Recipe/Dotnet/DotNetBuildContext.cs +++ b/src/Cake.Frosting.PleOps.Recipe/Dotnet/DotNetBuildContext.cs @@ -146,10 +146,10 @@ public void ReadArguments(PleOpsBuildContext context) _ => throw new NotSupportedException("Unknown Cake verbosity"), }; - context.IfArgIsPresent("dotnet-configuration", x => Configuration = x); - context.IfArgIsPresent("dotnet-platform", x => Platform = x); + context.Arguments.SetIfPresent("dotnet-configuration", x => Configuration = x); + context.Arguments.SetIfPresent("dotnet-platform", x => Platform = x); - context.IfArgIsPresent("dotnet-test-filter", x => TestFilter = x); + context.Arguments.SetIfPresent("dotnet-test-filter", x => TestFilter = x); PreviewNuGetFeedToken = context.Environment.GetEnvironmentVariable("PREVIEW_NUGET_FEED_TOKEN"); StableNuGetFeedToken = context.Environment.GetEnvironmentVariable("STABLE_NUGET_FEED_TOKEN"); diff --git a/src/Cake.Frosting.PleOps.Recipe/PleOpsBuildContext.cs b/src/Cake.Frosting.PleOps.Recipe/PleOpsBuildContext.cs index 9dbb05a..92b13c8 100644 --- a/src/Cake.Frosting.PleOps.Recipe/PleOpsBuildContext.cs +++ b/src/Cake.Frosting.PleOps.Recipe/PleOpsBuildContext.cs @@ -154,30 +154,18 @@ public PleOpsBuildContext(ICakeContext context) IIssuesState IIssuesContext.State => IssuesContext.State; #endif - /// - /// Run the setter if the argument name is present. - /// - /// Argument name. - /// Setter to run. - public void IfArgIsPresent(string argName, Action setter) - { - if (Arguments.HasArgument(argName)) { - setter(Arguments.GetArgument(argName)); - } - } - /// /// Initialize the build context with command-line arguments if present. /// public virtual void ReadArguments() { - IfArgIsPresent("artifacts", x => ArtifactsPath = Path.GetFullPath(x)); - IfArgIsPresent("temp", x => TemporaryPath = Path.GetFullPath(x)); - IfArgIsPresent("version", x => Version = x); - WarningsAsErrors = WarningsAsErrors || Arguments.HasArgument("warn-as-error"); - IsIncrementalBuild = IsIncrementalBuild || Arguments.HasArgument("incremental"); - IfArgIsPresent("changelog-next", x => ChangelogNextFile = x); - IfArgIsPresent("changelog", x => ChangelogFile = x); + Arguments.SetIfPresent("artifacts", x => ArtifactsPath = Path.GetFullPath(x)); + Arguments.SetIfPresent("temp", x => TemporaryPath = Path.GetFullPath(x)); + Arguments.SetIfPresent("version", x => Version = x); + Arguments.SetIfPresent("warn-as-error", x => WarningsAsErrors = x); + Arguments.SetIfPresent("incremental", x => IsIncrementalBuild = x); + Arguments.SetIfPresent("changelog-next", x => ChangelogNextFile = x); + Arguments.SetIfPresent("changelog", x => ChangelogFile = x); DotNetContext.ReadArguments(this); DocFxContext.ReadArguments(this); diff --git a/src/Cake.Frosting.PleOps.Samples.PublicApp/Cake.Frosting.PleOps.Samples.PublicApp.csproj b/src/Cake.Frosting.PleOps.Samples.PublicApp/Cake.Frosting.PleOps.Samples.PublicApp.csproj index 0cb1f5a..251cd23 100644 --- a/src/Cake.Frosting.PleOps.Samples.PublicApp/Cake.Frosting.PleOps.Samples.PublicApp.csproj +++ b/src/Cake.Frosting.PleOps.Samples.PublicApp/Cake.Frosting.PleOps.Samples.PublicApp.csproj @@ -7,8 +7,6 @@ enable enable - - true diff --git a/src/Cake.Frosting.PleOps.Samples.PublicApp2/Cake.Frosting.PleOps.Samples.PublicApp2.csproj b/src/Cake.Frosting.PleOps.Samples.PublicApp2/Cake.Frosting.PleOps.Samples.PublicApp2.csproj index 4b168d0..a248cf5 100644 --- a/src/Cake.Frosting.PleOps.Samples.PublicApp2/Cake.Frosting.PleOps.Samples.PublicApp2.csproj +++ b/src/Cake.Frosting.PleOps.Samples.PublicApp2/Cake.Frosting.PleOps.Samples.PublicApp2.csproj @@ -9,9 +9,6 @@ enable enable - - true - diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 07b72cf..ca58ec7 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -7,12 +7,9 @@ true - + false - false @@ -55,6 +52,5 @@ - diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index e309d1e..66a62d3 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -8,8 +8,7 @@ - + - From d82e23f6ddb7871c2fea0d92f842236dcf2b365c Mon Sep 17 00:00:00 2001 From: Benito Palacios Sanchez Date: Tue, 21 Nov 2023 11:17:48 +0100 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=93=9A=20Improve=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 118 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 82 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 6602f1a..cec05af 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,87 @@ -# PleOps Cake recipe: a simple DevOps workflow [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://choosealicense.com/licenses/mit/) ![Build and release](https://github.com/pleonex/PleOps.Cake/workflows/Build%20and%20release/badge.svg?branch=main&event=push) +# PleOps Cake ![logo](./docs/images/logo_48.png) + + +

+ + Stable version + +   + + GitHub commits since latest release (by SemVer) + +   + + Build and release + +   + + MIT License + +   +

+ +Complete DevOps workflow and best-practices for .NET projects based on +[Cake](https://cakebuild.net/). + +- ♻️ DevOps best practices for a software project +- πŸ”§ Build, test and release tasks for .NET projects and documentation sites +- πŸ“š Documentation explaining the workflow +- πŸ“‹ [Template repository](https://github.com/pleonex/template-csharp) ready to + use + +## Tech stack + +- **Projects**: C# / .NET +- **Documentation**: DocFX, GitHub page +- **CI**: GitHub Actions +- **Release deployment**: NuGet feeds, GitHub + +## Get started + +Check out the [documentation site](https://www.pleonex.dev/PleOps.Cake/) to +start learning how to use the library. -Full automated build, test, stage and release pipeline for simple .NET projects -based on Cake. Check also the -[template repository](https://github.com/pleonex/template-csharp) to see the -pipeline in action! - -Tech stack: - -- Projects: C# / .NET -- Documentation: DocFX, GitHub page -- CI: GitHub Actions -- Release publication: NuGet feeds, GitHub - - -| Release | Package | -| ------- | ----------------------------------------------------------------- | -| Stable | [![Nuget](https://img.shields.io/nuget/v/Cake.Frosting.PleOps.Recipe?label=nuget.org&logo=nuget)](https://www.nuget.org/packages/Cake.Frosting.PleOps.Recipe) | -| Preview | [Azure Artifacts](https://dev.azure.com/benito356/NetDevOpsTest/_packaging?_a=feed&feed=PleOps) | - -## Requirements +Feel free to ask any question in the +[project discussion](https://github.com/pleonex/PleOps.Cake/discussions). + +## Usage + +The project ships a NuGet library with [Cake Frosting](https://cakebuild.net/) +tasks: + +- `Cake.Frosting.PleOps.Recipe`: + ![Package in NuGet](https://img.shields.io/nuget/v/Cake.Frosting.PleOps.Recipe?label=nuget.org&logo=nuget) + +To use it, create a new console application with the +[_Cake Frosting_ template](https://cakebuild.net/docs/getting-started/setting-up-a-new-frosting-project), +add a reference to this recipe NuGet and its tasks will be available to use. + +```cs +return new CakeHost() + .AddAssembly(typeof(Cake.Frosting.PleOps.Recipe.PleOpsBuildContext).Assembly) + .UseContext() + .UseLifetime() + .Run(args); + +[TaskName("Default")] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.Common.SetGitVersionTask))] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.Common.CleanArtifactsTask))] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.Dotnet.DotnetTasks.BuildProjectTask))] +public sealed class DefaultTask : FrostingTask +{ +} +``` -- .NET 8.0 SDK +> [!TIP] +> Find a detailed setup guide in the +> [documentation site](<[docs/articles/getting-started/tutorial.md](https://www.pleonex.dev/PleOps.Cake/docs/getting-started/tutorial.html)>). -## Preview versions +### Preview releases -To use a preview version, add a `nuget.config` file in the repository root -directory with the following content: +Preview releases are in an +[Azure DevOps NuGet feed](https://dev.azure.com/benito356/NetDevOpsTest/_packaging?_a=feed&feed=PleOps). +Add a `nuget.config` file in the repository root directory with the following +content: ```xml @@ -47,16 +103,6 @@ directory with the following content: ``` -## Documentation - -Feel free to ask any question in the -[project Discussion site!](https://github.com/pleonex/PleOps.Cake/discussions) - -Check the [documentation](https://www.pleonex.dev/PleOps.Cake/) for more -information. For reference, this is the general build and release pipeline. - -![release diagram](./docs/articles/workflows/images/release_automation.png) - ## Build The project requires to build .NET 8.0 SDK. @@ -64,8 +110,8 @@ The project requires to build .NET 8.0 SDK. To build, test and generate artifacts run: ```sh -# Build and run tests -dotnet run --project build/orchestrator -- --target=Default +# Build and run tests (with code coverage!) +dotnet run --project build/orchestrator # (Optional) Create bundles (nuget, zips, docs) dotnet run --project build/orchestrator -- --target=Bundle From 9db34938cdfead965fa8be87929035247204793d Mon Sep 17 00:00:00 2001 From: Benito Palacios Sanchez Date: Tue, 21 Nov 2023 11:22:26 +0100 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=90=9B=20Fix=20sample=20build=20syste?= =?UTF-8?q?m?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Cake.Frosting.PleOps.Samples.BuildSystem/Program.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Cake.Frosting.PleOps.Samples.BuildSystem/Program.cs b/src/Cake.Frosting.PleOps.Samples.BuildSystem/Program.cs index 8a4ac53..086b99f 100644 --- a/src/Cake.Frosting.PleOps.Samples.BuildSystem/Program.cs +++ b/src/Cake.Frosting.PleOps.Samples.BuildSystem/Program.cs @@ -20,6 +20,7 @@ using Cake.Core; using Cake.Core.Diagnostics; using Cake.Frosting; +using Cake.Frosting.PleOps.Recipe; using Cake.Frosting.PleOps.Recipe.Dotnet; return new CakeHost() @@ -60,7 +61,7 @@ public override void Setup(MyCustomContext context, ISetupContext info) // Update build parameters from command line arguments. context.ReadArguments(); - context.IfArgIsPresent("custom-setting", x => context.CustomSetting = x); + context.Arguments.SetIfPresent("custom-setting", x => context.CustomSetting = x); // HERE you can force values non-overridables. context.DotNetContext.Configuration = "Samples"; From 1736d88919bc55f8db0ad032447cb316294e6d2d Mon Sep 17 00:00:00 2001 From: Benito Palacios Sanchez Date: Tue, 21 Nov 2023 11:27:01 +0100 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=93=9A=20Improve=20READMEs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- docs/index.md | 71 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 53 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index cec05af..965169d 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ public sealed class DefaultTask : FrostingTask > [!TIP] > Find a detailed setup guide in the -> [documentation site](<[docs/articles/getting-started/tutorial.md](https://www.pleonex.dev/PleOps.Cake/docs/getting-started/tutorial.html)>). +> [documentation site](https://www.pleonex.dev/PleOps.Cake/docs/getting-started/tutorial.html). ### Preview releases diff --git a/docs/index.md b/docs/index.md index d667fa3..a92368b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,4 +1,24 @@ -# PleOps Cake +# PleOps Cake ![logo](./images/logo_48.png) + + +

+ + Stable version + +   + + GitHub commits since latest release (by SemVer) + +   + + Build and release + +   + + MIT License + +   +

Complete DevOps workflow and best-practices for .NET projects based on [Cake](https://cakebuild.net/). @@ -6,42 +26,55 @@ Complete DevOps workflow and best-practices for .NET projects based on - ♻️ DevOps best practices for a software project - πŸ”§ Build, test and release tasks for .NET projects and documentation sites - πŸ“š Documentation explaining the workflow -- [Template repository](https://github.com/pleonex/template-csharp) ready to use +- πŸ“‹ [Template repository](https://github.com/pleonex/template-csharp) ready to + use ## Tech stack -- Projects: C# / .NET -- Documentation: DocFX, GitHub page -- CI: GitHub Actions -- Release deployment: NuGet feeds, GitHub +- **Projects**: C# / .NET +- **Documentation**: DocFX, GitHub page +- **CI**: GitHub Actions +- **Release deployment**: NuGet feeds, GitHub ## Usage The project ships a NuGet library with [Cake Frosting](https://cakebuild.net/) -tasks: **`Cake.Frosting.PleOps.Recipe`**. +tasks: + +- `Cake.Frosting.PleOps.Recipe`: + ![Package in NuGet](https://img.shields.io/nuget/v/Cake.Frosting.PleOps.Recipe?label=nuget.org&logo=nuget) To use it, create a new console application with the [_Cake Frosting_ template](https://cakebuild.net/docs/getting-started/setting-up-a-new-frosting-project), add a reference to this recipe NuGet and its tasks will be available to use. -**More information in the -[setup guide](./articles/getting-started/tutorial.md).** +```cs +return new CakeHost() + .AddAssembly(typeof(Cake.Frosting.PleOps.Recipe.PleOpsBuildContext).Assembly) + .UseContext() + .UseLifetime() + .Run(args); -## Quick demo +[TaskName("Default")] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.Common.SetGitVersionTask))] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.Common.CleanArtifactsTask))] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.Dotnet.DotnetTasks.BuildProjectTask))] +public sealed class DefaultTask : FrostingTask +{ +} +``` -You can check this workflow from the -[template repository](https://github.com/pleonex/template-csharp). Just clone / -download it and run its build system: +Then just run the project to start the build system: ```bash -# Build and run tests (with code coverage!) dotnet run --project build/orchestrator - -# Create bundles (nuget, zips, docs) -dotnet run --project build/orchestrator -- --target=Bundle ``` -Commits will trigger a new continuous integration build with a similar output as -this: +Pushing commits will trigger a new continuous integration build with a similar +output as this: ![ci-output](./articles/getting-started/images/github-actions-summary.png) + +> [!TIP] +> Find a detailed setup guide in the +> [documentation site](articles/getting-started/tutorial.md).