{"id":20247667,"url":"https://github.com/postsharp/postsharp.engineering","last_synced_at":"2025-04-10T21:32:32.211Z","repository":{"id":37493665,"uuid":"434202756","full_name":"postsharp/PostSharp.Engineering","owner":"postsharp","description":"PostSharp.Engineering is the in-house multi-repo continuous build and integration framework used at PostSharp Technologies.","archived":false,"fork":false,"pushed_at":"2025-03-14T09:50:02.000Z","size":1936,"stargazers_count":6,"open_issues_count":1,"forks_count":0,"subscribers_count":4,"default_branch":"develop/2023.2","last_synced_at":"2025-03-24T18:52:37.085Z","etag":null,"topics":["continuous-integration"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/postsharp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-02T11:58:22.000Z","updated_at":"2025-03-24T06:01:03.000Z","dependencies_parsed_at":"2023-02-16T08:31:19.387Z","dependency_job_id":"4bb9e513-2602-4e5f-ac75-9cd20a2d35f7","html_url":"https://github.com/postsharp/PostSharp.Engineering","commit_stats":null,"previous_names":[],"tags_count":276,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/postsharp%2FPostSharp.Engineering","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/postsharp%2FPostSharp.Engineering/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/postsharp%2FPostSharp.Engineering/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/postsharp%2FPostSharp.Engineering/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/postsharp","download_url":"https://codeload.github.com/postsharp/PostSharp.Engineering/tar.gz/refs/heads/develop/2023.2","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248301780,"owners_count":21080949,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["continuous-integration"],"created_at":"2024-11-14T09:38:42.722Z","updated_at":"2025-04-10T21:32:32.188Z","avatar_url":"https://github.com/postsharp.png","language":"C#","readme":"# PostSharp Engineering\n\n## Table of contents\n\n- [PostSharp Engineering](#postsharp-engineering)\n  - [Table of contents](#table-of-contents)\n  - [Content](#content)\n  - [Concepts](#concepts)\n    - [Terminology](#terminology)\n    - [Build and testing locally](#build-and-testing-locally)\n    - [Versioning](#versioning)\n      - [Objectives](#objectives)\n      - [Configuring the version of the current product](#configuring-the-version-of-the-current-product)\n    - [Configuring the version of dependent products or packages.](#configuring-the-version-of-dependent-products-or-packages)\n    - [Using a local build of a referenced product](#using-a-local-build-of-a-referenced-product)\n  - [Installation](#installation)\n    - [Step 1. Edit global.json](#step-1-edit-globaljson)\n    - [Step 2. Packaging.props](#step-2-packagingprops)\n    - [Step 3. MainVersion.props](#step-3-mainversionprops)\n    - [Step 4. Versions.props](#step-4-versionsprops)\n    - [Step 5. Directory.Build.props](#step-5-directorybuildprops)\n    - [Step 6. Directory.Build.targets](#step-6-directorybuildtargets)\n    - [Step 7. Create the front-end build project](#step-7-create-the-front-end-build-project)\n    - [Step 8. Create Build.ps1, the front-end build script](#step-8-create-buildps1-the-front-end-build-script)\n    - [Step 9. Editing .gitignore](#step-9-editing-gitignore)\n  - [Build Concepts](#build-concepts)\n  - [Continuous integration](#continuous-integration)\n    - [Artifacts](#artifacts)\n    - [Commands](#commands)\n    - [Required environment variables](#required-environment-variables)\n\n## Overview\n\nThis repository contains build scripts and tools common to all Metalama repos. We released `PostSharp.Engineering` under an open-source license because it is a dependency of other open-source Metalama projects. Although you can use this project to build your own products, our intention is not to maintain a build framework for the general public, but an ad-hoc solution for our own needs.\n\nThis repo produces two NuGet packages:\n \n* _PostSharp.Engineering.BuildTools_ is meant to be added as a package reference from the facade C# build program.\n  \n* _PostSharp.Engineering.Sdk_ is meant to be used as an SDK project.\n\n  * `AssemblyMetadata.targets`: Adds package versions to assembly metadata.\n  * `BuildOptions.props`: Sets the compiler options like language version, nullability and other build options like output path.\n  * `TeamCity.targets`: Enables build and tests reporting to TeamCity.\n  * `SourceLink.props`: Enables SourceLink support.\n  * `Coverage.props`:\n    Enabled code coverage. This script should be imported in test projects only (not in projects being tested). This script\n    adds a package to _coverlet_ so there is no need to have in in test projects (and these references should be removed).\n  * `MetalamaBranding.props` and `PostSharpBranding.props`: Configure the proper icon for the nuget package.\n  * `PackagesConfig.targets`: Makes the Restore and Pack targets work for projects referencing NuGet using packages.config.\n  * `WebPublish.targets`: Configures the release build of web projects to be published as a zipped artifact.\n  * `TestsPublish.targets`: Configures the release build of test projects to be published as a zipped artifact.\n\nBoth packages must be used at the same time and the versions must match.\n\n## Concepts\n\n### Terminology\n\nA _product_ is almost a synonym for _repository__. There is a single product per repository, and the product name must be the same as the repository name. A product can contain several C# solutions.\n\n### Building and testing locally\n\nFor details, do `Build.ps1` in PowerShell and read the help.\n\n### Versioning\n\n#### Objectives\n\nA major goal of this SDK is to allow to build and test repositories that have references to other repositories _without_ having to publish the nuget package.\nThat is, it is possible and quite easy, with this SDK, to perform builds that reference local clones of repositories. All solutions or projects in the same product share have the same version.\n\n#### Configuring the version of the current product\n\nThe product package version and package version suffix configuration is centralized in the `eng\\MainVersion.props`\nscript via the `MainVersion` and `PackageVersionSuffix` properties, respectively. For RTM products, leave\nthe `PackageVersionSuffix` property value empty.\n\n### Configuring the version of dependent products or packages.\n\nPackage dependencies versions configuration is centralized in the `eng\\Versions.props` script. Each dependency version\nis configured in a property named `\u003c[DependencyName]Version\u003e`, eg. `\u003cSystemCollectionsImmutableVersion\u003e`.\n\nThis property value is then available in all MSBuild project files in the repository and can be used in\nthe `PackageReference` items. For example:\n\n```\n\u003cItemGroup\u003e\n    \u003cPackageReference Include=\"System.Collections.Immutable\" Version=\"$(SystemCollectionsImmutableVersion)\" /\u003e\n\u003c/ItemGroup\u003e\n```\n\n### Using a local build of a referenced product\n\nDependencies must be checked out under the same root directory (typically `c:\\src`) under their canonic name.\n\nThen, use `Build.ps1 dependencies set local \u003cDEPENDENCY\u003e` to specify which dependencies should be run locally.\n\nThis will generate `eng/Versions.g.props`, which you should have imported in `eng/Versions.props`.\n\n\n## Installation\n\nThe easiest way to get started is from this repo template: https://github.com/postsharp/PostSharp.Engineering.ProductTemplate.\n\n### Step 1. Edit global.json\n\nAdd or update the reference to `PostSharp.Engineering.Sdk` in `global.json`.\n\n```json\n{\n  \"sdk\": {\n    \"version\": \"5.0.206\",\n    \"rollForward\": \"disable\"\n  },\n  \"msbuild-sdks\": {\n    \"PostSharp.Engineering.Sdk\": \"1.0.0\"\n  }\n}\n```\n\n### Step 2. Packaging.props\n\n\nCreate `eng\\Packaging.props` file. The content should look like this:\n\n```xml\n\u003cProject\u003e\n\n    \u003c!-- Properties of NuGet packages--\u003e\n    \u003cPropertyGroup\u003e\n        \u003cAuthors\u003ePostSharp Technologies\u003c/Authors\u003e\n        \u003cPackageProjectUrl\u003ehttps://github.com/postsharp/Metalama\u003c/PackageProjectUrl\u003e\n        \u003cPackageTags\u003ePostSharp Metalama AOP\u003c/PackageTags\u003e\n        \u003cPackageRequireLicenseAcceptance\u003etrue\u003c/PackageRequireLicenseAcceptance\u003e\n        \u003cPackageIcon\u003ePostSharpIcon.png\u003c/PackageIcon\u003e\n        \u003cPackageLicenseFile\u003eLICENSE.md\u003c/PackageLicenseFile\u003e\n    \u003c/PropertyGroup\u003e\n\n    \u003c!-- Additional content of NuGet packages --\u003e\n    \u003cItemGroup\u003e\n        \u003cNone Include=\"$(MSBuildThisFileDirectory)..\\PostSharpIcon.png\" Visible=\"false\" Pack=\"true\" PackagePath=\"\" /\u003e\n        \u003cNone Include=\"$(MSBuildThisFileDirectory)..\\LICENSE.md\" Visible=\"false\" Pack=\"true\" PackagePath=\"\" /\u003e\n        \u003cNone Include=\"$(MSBuildThisFileDirectory)..\\THIRD-PARTY-NOTICES.TXT\" Visible=\"false\" Pack=\"true\" PackagePath=\"\" /\u003e\n    \u003c/ItemGroup\u003e\n\n\u003c/Project\u003e\n```\n\nMake sure that all the files referenced in the previous step exist, or modify the file.\n\n### Step 3. MainVersion.props\n\nCreate `eng\\MainVersion.props` file. The content should look like:\n\n```xml\n\u003cProject\u003e\n    \u003cPropertyGroup\u003e\n        \u003cMainVersion\u003e0.3.6\u003c/MainVersion\u003e\n        \u003cPackageVersionSuffix\u003e-preview\u003c/PackageVersionSuffix\u003e\n    \u003c/PropertyGroup\u003e\n\u003c/Project\u003e\n```\n\nAdditionally, there may be a property named `PatchVersion`, which may contain a version number with 4 components.\nThe `PatchVersion` property value MUST start with the value of the `MainVersion` property. The use case for this property is when a repo A has a version dependency on another repo B but we want to release a patch of repo B without releasing a new build of repo A.\n\n\n### Step 4. Versions.props\n\nCreate `eng\\Versions.props` file. The content should look like this (replace `My` by the name of the repo without dot):\n\n```xml\n\u003cProject\u003e\n\n    \u003c!-- Version of My. --\u003e\n    \u003cImport Project=\"MainVersion.props\" Condition=\"!Exists('MyVersion.props')\" /\u003e\n    \n    \u003cPropertyGroup\u003e\n        \u003cMyVersion\u003e$(MainVersion)$(PackageVersionSuffix)\u003c/MyVersion\u003e\n        \u003cMyAssemblyVersion\u003e$(MainVersion)\u003c/MyAssemblyVersion\u003e\n    \u003c/PropertyGroup\u003e\n\n    \u003c!-- Versions of dependencies --\u003e\n    \u003cPropertyGroup\u003e\n        \u003cRoslynVersion\u003e3.8.0\u003c/RoslynVersion\u003e\n        \u003cMetalamaCompilerVersion\u003e3.8.12-preview\u003c/MetalamaCompilerVersion\u003e\n        \u003cMicrosoftCSharpVersion\u003e4.7.0\u003c/MicrosoftCSharpVersion\u003e\n    \u003c/PropertyGroup\u003e\n\n    \u003c!-- Overrides by local settings --\u003e\n    \u003cImport Project=\"../artifacts/publish/private/MyVersion.props\" Condition=\"Exists('../artifacts/publish/private/MyVersion.props')\" /\u003e\n    \u003cImport Project=\"Dependencies.props\" Condition=\"Exists('Dependencies.props')\" /\u003e\n\n    \u003c!-- Other properties depending on the versions set above --\u003e\n    \u003cPropertyGroup\u003e\n        \u003cAssemblyVersion\u003e$(MyAssemblyVersion)\u003c/AssemblyVersion\u003e\n        \u003cVersion\u003e$(MyVersion)\u003c/Version\u003e\n    \u003c/PropertyGroup\u003e\n    \n\n\u003c/Project\u003e\n```\n\n### Step 5. Directory.Build.props\n\nAdd the following content to `Directory.Build.props`:\n\n```xml\n\u003cProject\u003e\n\n  \u003cPropertyGroup\u003e\n    \u003cRepoDirectory\u003e$(MSBuildThisFileDirectory)\u003c/RepoDirectory\u003e\n    \u003cRepoKind\u003eAzureRepos\u003c/RepoKind\u003e\n  \u003c/PropertyGroup\u003e\n\n  \u003cImport Project=\"eng\\Versions.props\" /\u003e\n  \u003cImport Project=\"eng\\Packaging.props\" /\u003e\n\n  \u003cImport Sdk=\"PostSharp.Engineering.Sdk\" Project=\"BuildOptions.props\" /\u003e\n  \u003cImport Sdk=\"PostSharp.Engineering.Sdk\" Project=\"CodeQuality.props\" /\u003e\n  \u003cImport Sdk=\"PostSharp.Engineering.Sdk\" Project=\"SourceLink.props\" /\u003e\n\n\u003c/Project\u003e\n```\n\n### Step 6. Directory.Build.targets\n\nAdd the following content to `Directory.Build.targets`:\n\n```xml\n\u003cProject\u003e\n\n  \u003cImport Sdk=\"PostSharp.Engineering.Sdk\"  Project=\"AssemblyMetadata.targets\" /\u003e\n  \u003cImport Sdk=\"PostSharp.Engineering.Sdk\"  Project=\"TeamCity.targets\" /\u003e\n\n\u003c/Project\u003e\n```\n\n### Step 7. Create the front-end build project\n\nCreate a file `eng\\src\\Build.csproj` with the following content:\n\n```xml\n\u003cProject Sdk=\"Microsoft.NET.Sdk\"\u003e\n\n    \u003cPropertyGroup\u003e\n        \u003cOutputType\u003eExe\u003c/OutputType\u003e\n        \u003cTargetFramework\u003enet6.0\u003c/TargetFramework\u003e\n        \u003cAssemblyName\u003eBuild\u003c/AssemblyName\u003e\n        \u003cGenerateDocumentationFile\u003efalse\u003c/GenerateDocumentationFile\u003e\n        \u003cLangVersion\u003elatest\u003c/LangVersion\u003e\n        \u003cNullable\u003eenable\u003c/Nullable\u003e\n        \u003cNoWarn\u003eSA0001;CS8002\u003c/NoWarn\u003e\n    \u003c/PropertyGroup\u003e\n\n    \u003cItemGroup\u003e\n        \u003cPackageReference Include=\"PostSharp.Engineering.BuildTools.csproj\" Version=\"$(PostSharpEngineeringVersion)\" /\u003e\n    \u003c/ItemGroup\u003e\n\n\u003c/Project\u003e\n```\n\nCreate also a file `eng\\src\\Program.cs` with content that varies according to your repo. You can use all the power of C#\nand PowerShell to customize the build. Note that in the `PublicArtifacts`, the strings `$(Configuration)`\nand `$(PackageVersion)`, and only those strings, are replaced by their value.\n\n```cs\nusing PostSharp.Engineering.BuildTools;\nusing PostSharp.Engineering.BuildTools.Commands.Build;\nusing Spectre.Console.Cli;\nusing System.Collections.Immutable;\n\nnamespace BuildMetalama\n{\n    internal class Program\n    {\n        private static int Main( string[] args )\n        {\n            var product = new Product\n            {\n                ProductName = \"Metalama\",\n                Solutions = ImmutableArray.Create\u003cSolution\u003e(\n                    new DotNetSolution( \"Metalama.sln\" )\n                    {\n                        SupportsTestCoverage = true\n                    },\n                    new DotNetSolution( \"Tests\\\\Metalama.Framework.TestApp\\\\Metalama.Framework.TestApp.sln\" )\n                    {\n                        IsTestOnly = true\n                    } ),\n                PublicArtifacts = ImmutableArray.Create(\n                    \"bin\\\\$(Configuration)\\\\Metalama.Framework.$(PackageVersion).nupkg\",\n                    \"bin\\\\$(Configuration)\\\\Metalama.TestFramework.$(PackageVersion).nupkg\",\n                    \"bin\\\\$(Configuration)\\\\Metalama.Framework.Redist.$(PackageVersion).nupkg\",\n                    \"bin\\\\$(Configuration)\\\\Metalama.Framework.Sdk.$(PackageVersion).nupkg\",\n                    \"bin\\\\$(Configuration)\\\\Metalama.Framework.Impl.$(PackageVersion).nupkg\",\n                    \"bin\\\\$(Configuration)\\\\Metalama.Framework.DesignTime.Contracts.$(PackageVersion).nupkg\" ),\n                 Dependencies = ImmutableArray.Create(\n                    new ProductDependency(\"Metalama.Compiler\"), \n                    new ProductDependency(\"PostSharp.Engineering.BuildTools\") )    \n            };\n            var commandApp = new CommandApp();\n            commandApp.AddProductCommands( product );\n\n            return commandApp.Run( args );\n        }\n    }\n}\n```\n\n### Step 8. Create Build.ps1, the front-end build script\n\nCreate `Build.ps1` file in the repo root directory. The content should look like:\n\n```powershell\nif ( $env:VisualStudioVersion -eq $null ) {\n    Import-Module \"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\Common7\\Tools\\Microsoft.VisualStudio.DevShell.dll\"\n    Enter-VsDevShell -VsInstallPath \"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\\" -StartInPath $(Get-Location)\n}\n\n\u0026 dotnet run --project \"$PSScriptRoot\\eng\\src\\Build.csproj\" -- $args\nexit $LASTEXITCODE\n```\n\n### Step 9. Editing .gitignore\n\nExclude this:\n\n```\nartifacts\neng/tools\n*.Import.props\n```\n\n## Build Concepts\n\nThe code in `Program.cs` uses the concepts described here.\n\n```mermaid\nclassDiagram\n\n  class Product {\n\n  }\n\n  class Solution {\n\n  }\n\n\n\n  Program o-- \"1\" Product \n  Product o-- \"*\" Solution\n  Product  o-- \"*\" DependencyDefinition\n  Product  o-- \"3\" BuildConfigurationInfo\n  BuildConfigurationInfo  o-- \"*\" IBuildTrigger\n  BuildConfigurationInfo o-- \"*\" Publisher\n  BuildConfigurationInfo o-- \"*\" Swapper\n  Swapper o-- \"*\" Tester\n  Solution \u003c|-- DotNetSolution\n  Solution \u003c|-- MSBuildSolution\n  Tester \u003c|-- VSTestTester\n  IBuildTrigger \u003c|-- NightlyBuildTrigger\n  IBuildTrigger \u003c|-- SourceBuildTrigger\n  Publisher \u003c|-- MSDeployPublisher\n  Publisher \u003c|-- NuGetPublisher\n  Publisher \u003c|-- VsixPublisher\n  \n\n```\n\n* _Program_ is your program, i.e. `BuildMyProduct`.\n* _Product_ is a unique instance configured by _Program_, the root object that defines the build for the whole repo.\n* _Solution_ represents a solution, project, or other build script in your repo. A solution is something that can be restored, built, packed, tested. Two standard implementations are _DotNetSolution_ and _MSBuildSolution_.\n* _BuildConfigurationInfo_ represents properties that are specific to a build configuration (i.e. _Debug_, _Release_ or _Public_) for the product.\n* _DependencyDefinition_ are dependencies to other repositories.\n* _Publisher_ is something that publishes, or deploys, an already-built artefact to a feed, marketplace, deployment slot, or anything. There are standard implementations for NuGet, VSIX, web sites.\n* _Swapper_ is something that swaps a staging deployment slot into the production deployment slot.\n* _Tester_ is a test suite, typically running against a staging deployment, that must execute successfully before the staging deployment is swapped into the production deployment.\n\n## Continuous integration\n\nWe use TeamCity as our CI/CD pipeline, and we use Kotlin scripts stored in the Git repo. For an example, see the `.teamcity` directory\nthe current repo.\n\n### Artifacts\n\nAll TeamCity artifacts are published under `artifacts/publish`. All build configurations should export and import these artifacts.\n\n### Commands\n\nAll TeamCity build configurations use the front-end `Build.ps1`:\n\n* Debug Build and Test: `Build.ps1 test --numbered  %build.number%`\n* Release Build and Test:  `Build.ps1 test --public --sign`\n* Publish to internal package sources:  `Build.ps1 publish`\n* Publish to internal _and_ public package source:  `Build.ps1 publish --public`\n\n### Required environment variables\n\n- SIGNSERVER_SECRET\n- INTERNAL_NUGET_PUSH_URL\n- INTERNAL_NUGET_API_KEY\n- NUGET_ORG_API_KEY\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpostsharp%2Fpostsharp.engineering","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpostsharp%2Fpostsharp.engineering","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpostsharp%2Fpostsharp.engineering/lists"}