diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9632daabc..7cbd9ee1c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,24 +12,30 @@ on: branches: [ "main" ] workflow_dispatch: inputs: - configuration: - description: 'Build Configuration' + deploy_packages: + description: 'deploy_packages: If the created package should be deployed (additional manual approval required by a release admin)' + type: boolean + default: false required: true - default: 'Debug' - type: choice - options: - - Debug - - Release - production_release: - description: 'If the build produces a production package' + is_production_release: + description: 'is_production_release: Whether the release is a production release and not a pre-releaae (enabling this will update change log, increases version and tags commit)' type: boolean default: false required: true - version_suffix: - description: 'Suffix for the NuGet packages (without leading -). Build ID will be appended. Use "-" to force empty.' + custom_version_suffix: + description: 'custom_version_suffix: Custom suffix for the NuGet packages (without leading -) for non-production releases. Default: empty for production release, "ci" for other runs. The build ID is always appended.' + required: false + custom_configuration: + description: 'custom_configuration: Custom build configuration. Default: "Debug" for CI builds, "Release" for deployments.' required: false + default: 'Default' + type: choice + options: + - Default + - Debug + - Release specs_filter: - description: 'Filter for Specs execution (e.g. Category=basicExecution)' + description: 'specs_filter: Filter for Specs execution (e.g. Category=basicExecution)' required: false permissions: @@ -45,78 +51,137 @@ jobs: runs-on: ubuntu-latest outputs: + product_version_prefix: ${{ steps.versions.outputs.product_version_prefix }} product_version_suffix: ${{ steps.versions.outputs.product_version_suffix }} + product_main_version: ${{ steps.versions.outputs.product_main_version }} + product_patch_version: ${{ steps.versions.outputs.product_patch_version }} + product_full_version: ${{ steps.versions.outputs.product_full_version }} product_configuration: ${{ steps.versions.outputs.product_configuration }} - build_params: ${{ steps.versions.outputs.build_params }} - test_params: ${{ steps.versions.outputs.test_params }} - specs_filter: ${{ steps.versions.outputs.specs_filter }} - gh_logger_settings: ${{ steps.versions.outputs.gh_logger_settings }} + deploy_packages: ${{ steps.versions.outputs.deploy_packages }} + is_production_release: ${{ steps.versions.outputs.is_production_release }} + + build_params: ${{ steps.build_params.outputs.build_params }} + test_params: ${{ steps.build_params.outputs.test_params }} + specs_filter: ${{ steps.build_params.outputs.specs_filter }} steps: - uses: actions/checkout@v4 - with: - fetch-depth: 0 # avoid shallow clone so nbgv can do its work. - id: versions name: Calculate versions shell: pwsh - env: - APPINSIGHTS_KEY: ${{ secrets.APPINSIGHTS_KEY }} run: | - $productionReleaseSetting = "${{ inputs.production_release }}" - $productionRelease = $false - if ($productionReleaseSetting -eq 'true') { - $productionRelease = $true + $deployPackages = $false + if ("${{ inputs.deploy_packages }}" -eq 'true') { + $deployPackages = $true } - Write-Output "Production release: $productionRelease" + Write-Output "deploy_packages=$($deployPackages.ToString().ToLowerInvariant())" >> $env:GITHUB_OUTPUT + Write-Output "Deploy packages: $deployPackages" - $versionSuffix = "${{ inputs.version_suffix }}" - if ($versionSuffix -eq "") { - $date = [datetime]::Today - $dateString = $date.ToString('yyyyMMdd') - $versionSuffix = "ci$dateString-${env:GITHUB_RUN_NUMBER}" + $isProductionRelease = $false + if ("${{ inputs.is_production_release }}" -eq 'true') { + $isProductionRelease = $true } - elseif ($versionSuffix -eq "-") { - $versionSuffix = "" + Write-Output "is_production_release=$($isProductionRelease.ToString().ToLowerInvariant())" >> $env:GITHUB_OUTPUT + Write-Output "Is production release: $isProductionRelease" + + $versionSuffix = "${{ inputs.custom_version_suffix }}" + if ($isProductionRelease){ + if ($versionSuffix -ne "") { + throw "The 'custom_version_suffix' setting cannot be used for production releases." + } } else { + if ($versionSuffix -eq "") { + $date = [datetime]::Today + $dateString = $date.ToString('yyyyMMdd') + $versionSuffix = "ci$dateString-${env:GITHUB_RUN_NUMBER}" + } + else { $versionSuffix = "$versionSuffix-${env:GITHUB_RUN_NUMBER}" + } } Write-Output "product_version_suffix=$versionSuffix" >> $env:GITHUB_OUTPUT - Write-Output "Product Suffix: $versionSuffix" + Write-Output "Product Version Suffix: $versionSuffix" - $productConfig = "${{ inputs.configuration }}" - if ($productConfig -eq "") { + $productConfig = "${{ inputs.custom_configuration }}" + if (($productConfig -eq "Default") -or ($productConfig -eq "")) { + if ($deployPackages){ + $productConfig = "Release" + } + else { $productConfig = "Debug" + } } Write-Output "product_configuration=$productConfig" >> $env:GITHUB_OUTPUT Write-Output "Product Configuration: $productConfig" - $specsFilter = "${{ inputs.specs_filter }}" - if ($specsFilter -ne "") { - $specsFilter = "&$specsFilter" - } - else { - $specsFilter = $env:SPECS_FILTER + $buildPropsXml = [xml](Get-Content Directory.Build.props) + $versionPrefix = $($buildPropsXml.Project.PropertyGroup.VersionPrefix)[1].Trim() + Write-Output "product_version_prefix=$versionPrefix" >> $env:GITHUB_OUTPUT + Write-Output "Product Version Prefix: $versionPrefix" + + $mainVersion = &{$versionPrefix -match '^\d+\.\d+' > $null; $matches[0]} + Write-Output "product_main_version=$mainVersion" >> $env:GITHUB_OUTPUT + Write-Output "Product Main Version: $mainVersion" + + $patchVersion = &{$versionPrefix -match '\d+$' > $null; $matches[0]} + Write-Output "product_patch_version=$patchVersion" >> $env:GITHUB_OUTPUT + Write-Output "Product Patch Version: $patchVersion" + + $fullVersion = $versionPrefix + if ($versionSuffix -ne "") { + $fullVersion = "$fullVersion-$versionSuffix" } - Write-Output "specs_filter=$specsFilter" >> $env:GITHUB_OUTPUT - Write-Output "Specs Filter: $specsFilter" + Write-Output "product_full_version=$fullVersion" >> $env:GITHUB_OUTPUT + Write-Output "Product Full Version: $fullVersion" + - id: build_params + name: Calculate build parameters + shell: pwsh + env: + APPINSIGHTS_KEY: ${{ secrets.APPINSIGHTS_KEY }} + run: | + # Load version fields to variables + $versionSuffix = '${{ steps.versions.outputs.product_version_suffix }}' + $productConfig = '${{ steps.versions.outputs.product_configuration }}' + $deployPackages = '${{ steps.versions.outputs.deploy_packages }}' -eq 'true' + # Calculate 'build_params' $buildParams = "-p:VersionSuffix=$versionSuffix -c $productConfig" Write-Output "build_params=$buildParams" >> $env:GITHUB_OUTPUT Write-Output "Build Params: $buildParams" + # Calculate 'main_build_params' $mainBuildParams = $buildParams - if ($productionRelease) { + if ($deployPackages) { $mainBuildParams = "$mainBuildParams -p:AppInsightsInstrumentationKey=$env:APPINSIGHTS_KEY" - Write-Output "Main Build Params Updated for Production" + Write-Output "Main Build Params Updated for Deployment" } Write-Output "main_build_params=$mainBuildParams" >> $env:GITHUB_OUTPUT - + + # Calculate 'test_params' $gitHubActionsLoggerSettings = '"GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true;annotations.titleFormat=[@traits.Category] @test;annotations.messageFormat=@error\n@trace"' $testParams = "--no-build --verbosity normal -c $productConfig --logger $gitHubActionsLoggerSettings -- RunConfiguration.CollectSourceInformation=true RunConfiguration.TreatNoTestsAsError=true" Write-Output "test_params=$testParams" >> $env:GITHUB_OUTPUT Write-Output "Test Params: $testParams" + # Calculate 'specs_filter' + $specsFilter = "${{ inputs.specs_filter }}" + if ($specsFilter -ne "") { + $specsFilter = "&$specsFilter" + } + else { + $specsFilter = $env:SPECS_FILTER + } + Write-Output "specs_filter=$specsFilter" >> $env:GITHUB_OUTPUT + Write-Output "Specs Filter: $specsFilter" + + - name: Update Changelog + shell: pwsh + run: | + $releaseDate = [System.DateTime]::Today.ToString("yyyy-MM-dd") + $newHeading = "# v${{ steps.versions.outputs.product_full_version }} - $releaseDate" + $content = [System.IO.File]::ReadAllText("CHANGELOG.md").Replace("# [vNext]",$newHeading) + [System.IO.File]::WriteAllText("CHANGELOG.md", $content) - name: Restore dependencies run: dotnet restore - name: Install Test Report Dependencies @@ -126,26 +191,28 @@ jobs: dotnet add ./Tests/Reqnroll.GeneratorTests/Reqnroll.GeneratorTests.csproj package GitHubActionsTestLogger dotnet add ./Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator.Tests/Reqnroll.TestProjectGenerator.Tests.csproj package GitHubActionsTestLogger - name: Build - run: dotnet build --no-restore ${{ steps.versions.outputs.main_build_params }} + run: dotnet build --no-restore ${{ steps.build_params.outputs.main_build_params }} - name: Runtime Tests - run: dotnet test ./Tests/Reqnroll.RuntimeTests/Reqnroll.RuntimeTests.csproj --logger "trx;LogFileName=runtimetests-results.trx" ${{ steps.versions.outputs.test_params }} + run: dotnet test ./Tests/Reqnroll.RuntimeTests/Reqnroll.RuntimeTests.csproj --logger "trx;LogFileName=${{ github.workspace }}/TestResults/runtimetests-results.trx" ${{ steps.build_params.outputs.test_params }} - name: Generator Tests - run: dotnet test ./Tests/Reqnroll.GeneratorTests/Reqnroll.GeneratorTests.csproj --logger "trx;LogFileName=generatortests-results.trx" ${{ steps.versions.outputs.test_params }} + run: dotnet test ./Tests/Reqnroll.GeneratorTests/Reqnroll.GeneratorTests.csproj --logger "trx;LogFileName=${{ github.workspace }}/TestResults/generatortests-results.trx" ${{ steps.build_params.outputs.test_params }} - name: Plugin Tests - run: dotnet test ./Tests/Reqnroll.PluginTests/Reqnroll.PluginTests.csproj --logger "trx;LogFileName=plugintests-results.trx" ${{ steps.versions.outputs.test_params }} + run: dotnet test ./Tests/Reqnroll.PluginTests/Reqnroll.PluginTests.csproj --logger "trx;LogFileName=${{ github.workspace }}/TestResults/plugintests-results.trx" ${{ steps.build_params.outputs.test_params }} - name: TestProjectGenerator Tests - run: dotnet test ./Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator.Tests/Reqnroll.TestProjectGenerator.Tests.csproj --logger "trx;LogFileName=testprjgentests-results.trx" ${{ steps.versions.outputs.test_params }} - - name: Upload packages - uses: actions/upload-artifact@v4 - with: - name: packages - path: "GeneratedNuGetPackages/**/*.*nupkg" + run: dotnet test ./Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator.Tests/Reqnroll.TestProjectGenerator.Tests.csproj --logger "trx;LogFileName=${{ github.workspace }}/TestResults/testprjgentests-results.trx" ${{ steps.build_params.outputs.test_params }} - name: Upload TRX files uses: actions/upload-artifact@v4 if: always() with: - name: build-trx - path: "**/*.trx" + name: build-trx-v${{ steps.versions.outputs.product_full_version }} + if-no-files-found: error + path: "TestResults/*.trx" + - name: Upload packages + uses: actions/upload-artifact@v4 + with: + name: packages-v${{ steps.versions.outputs.product_full_version }} + if-no-files-found: error + path: "GeneratedNuGetPackages/${{ steps.versions.outputs.product_configuration }}/*.*nupkg" specs: runs-on: ubuntu-latest @@ -153,8 +220,6 @@ jobs: steps: - uses: actions/checkout@v4 - with: - fetch-depth: 0 # avoid shallow clone so nbgv can do its work. - name: Restore dependencies run: dotnet restore - name: Install Test Report Dependencies @@ -164,13 +229,14 @@ jobs: run: dotnet build --no-restore ${{ needs.build.outputs.build_params }} - name: Specs shell: pwsh - run: dotnet test ./Tests/Reqnroll.Specs/Reqnroll.Specs.csproj --filter "Category!=quarantaine{{ needs.build.outputs.specs_filter }}" --logger "trx;LogFileName=specs-results.trx" ${{ needs.build.outputs.test_params }} + run: dotnet test ./Tests/Reqnroll.Specs/Reqnroll.Specs.csproj --filter "Category!=quarantaine{{ needs.build.outputs.specs_filter }}" --logger "trx;LogFileName=${{ github.workspace }}/TestResults/specs-results.trx" ${{ needs.build.outputs.test_params }} - name: Upload TRX files uses: actions/upload-artifact@v4 if: always() with: - name: specs-trx - path: "**/specs-results.trx" + name: specs-trx-v${{ needs.build.outputs.product_full_version }} + if-no-files-found: error + path: "TestResults/specs-results.trx" system-tests-windows: runs-on: windows-latest @@ -178,8 +244,6 @@ jobs: steps: - uses: actions/checkout@v4 - with: - fetch-depth: 0 # avoid shallow clone so nbgv can do its work. - name: .NET Information run: | dotnet --list-sdks @@ -193,13 +257,14 @@ jobs: run: dotnet build --no-restore ${{ needs.build.outputs.build_params }} - name: System Tests shell: pwsh - run: dotnet test ./Tests/Reqnroll.SystemTests/Reqnroll.SystemTests.csproj --logger "trx;LogFileName=systemtests-windows-results.trx" ${{ needs.build.outputs.test_params }} + run: dotnet test ./Tests/Reqnroll.SystemTests/Reqnroll.SystemTests.csproj --logger "trx;LogFileName=${{ github.workspace }}/TestResults/systemtests-windows-results.trx" ${{ needs.build.outputs.test_params }} - name: Upload Test Result TRX Files uses: actions/upload-artifact@v4 if: always() with: - name: systemtests-windows-trx - path: "**/*.trx" + name: systemtests-windows-trx-v${{ needs.build.outputs.product_full_version }} + if-no-files-found: error + path: "TestResults/*.trx" system-tests-linux: @@ -208,8 +273,6 @@ jobs: steps: - uses: actions/checkout@v4 - with: - fetch-depth: 0 # avoid shallow clone so nbgv can do its work. - name: .NET Information run: | dotnet --list-sdks @@ -223,11 +286,100 @@ jobs: run: dotnet build --no-restore ${{ needs.build.outputs.build_params }} - name: System Tests shell: pwsh - run: dotnet test ./Tests/Reqnroll.SystemTests/Reqnroll.SystemTests.csproj --filter "TestCategory!=MsBuild&TestCategory!=Net481" --logger "trx;LogFileName=systemtests-linux-results.trx" ${{ needs.build.outputs.test_params }} + run: dotnet test ./Tests/Reqnroll.SystemTests/Reqnroll.SystemTests.csproj --filter "TestCategory!=MsBuild&TestCategory!=Net481" --logger "trx;LogFileName=${{ github.workspace }}/TestResults/systemtests-linux-results.trx" ${{ needs.build.outputs.test_params }} - name: Upload Test Result TRX Files uses: actions/upload-artifact@v4 if: always() with: - name: systemtests-linux-trx - path: "**/*.trx" - \ No newline at end of file + name: systemtests-linux-trx-v${{ needs.build.outputs.product_full_version }} + if-no-files-found: error + path: "TestResults/*.trx" + + release: + runs-on: ubuntu-latest + needs: [build, specs, system-tests-windows, system-tests-linux] + environment: production_environment + if: github.ref == 'refs/heads/main' && needs.build.outputs.deploy_packages == 'true' + permissions: + # Give the default GITHUB_TOKEN write permission to commit and push the + # added or changed files to the repository. + contents: write + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # avoid shallow clone git commit + ref: ${{ github.head_ref }} + ssh-key: ${{secrets.RELEASE_GIT_SSH_KEY}} + - uses: actions/download-artifact@v4 + with: + name: packages-v${{ needs.build.outputs.product_full_version }} + path: release_packages + - name: Deploy NuGet packages + env: + NUGET_PUBLISH_KEY: ${{ secrets.NUGET_PUBLISH_KEY }} + shell: pwsh + run: | + Write-Output "Deploying v${{ needs.build.outputs.product_full_version }} (v${{ needs.build.outputs.product_main_version }}) packages to nuget.org" + ls ${{ github.workspace }}/release_packages + ${{ github.workspace }}/.github/workflows/publish_packages.ps1 -packagesDir ${{ github.workspace }}/release_packages + + - name: Calculate Next Version + if: needs.build.outputs.is_production_release == 'true' + id: next_version + shell: pwsh + run: | + $patchVersion = "${{ needs.build.outputs.product_patch_version }}" + $nextPatch = [int]$patchVersion + 1 + $nextVersion = "${{ needs.build.outputs.product_main_version }}.$nextPatch" + Write-Output "product_next_version=$nextVersion" >> $env:GITHUB_OUTPUT + Write-Output "Product Next Version: $nextVersion" + + - name: Bump Version + if: needs.build.outputs.is_production_release == 'true' + shell: pwsh + run: | + [System.IO.File]::WriteAllText("Directory.Build.props", [System.IO.File]::ReadAllText("Directory.Build.props").Replace("${{ needs.build.outputs.product_version_prefix }}", "${{ steps.next_version.outputs.product_next_version }}")) + + - name: Update Changelog + if: needs.build.outputs.is_production_release == 'true' + id: changelog + shell: pwsh + run: | + $newHeading = "# [vNext]$([Environment]::NewLine)$([Environment]::NewLine)## Improvements:$([Environment]::NewLine)$([Environment]::NewLine)## Bug fixes:$([Environment]::NewLine)$([Environment]::NewLine)*Contributors of this release (in alphabetical order):* $([Environment]::NewLine)$([Environment]::NewLine)" + $releaseDate = [System.DateTime]::Today.ToString("yyyy-MM-dd") + $releaseTitle = "v${{ needs.build.outputs.product_full_version }} - $releaseDate" + $newHeading = $newHeading + "# $releaseTitle" + $content = [System.IO.File]::ReadAllText("CHANGELOG.md").Replace("# [vNext]",$newHeading) + [System.IO.File]::WriteAllText("CHANGELOG.md", $content) + Write-Output "New Heading:" + Write-Output $newHeading + + # calculate release notes + $match = [System.Text.RegularExpressions.Regex]::Match($content, "(?ms)^# .*?^# (?[^\r\n]*?)\s*$\s*(?<notes>.*?)\s*(?:^# |\Z)") + $releaseNotes = $(if ($match.Success) { $match.Groups["notes"].Value } else { "N/A" }) + [System.IO.File]::WriteAllText("release_notes.txt", $releaseNotes) + Write-Output "release_title=$releaseTitle" >> $env:GITHUB_OUTPUT + Write-Output "release_notes_file=release_notes.txt" >> $env:GITHUB_OUTPUT + + - name: Update changes in GitHub repository + if: needs.build.outputs.is_production_release == 'true' + run: | + git status + git config --global user.name 'Reqnroll CI' + git config --global user.email 'ci@reqnroll.net' + git tag v${{ needs.build.outputs.product_full_version }} + git push origin tag v${{ needs.build.outputs.product_full_version }} + git add -u + git commit -m '[automated commit] bump version after release of ${{ needs.build.outputs.product_full_version }}' + git push + + - name: Create GitHub Release + if: needs.build.outputs.is_production_release == 'true' + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create "v${{ needs.build.outputs.product_full_version }}" \ + --verify-tag \ + --title="${{ steps.changelog.outputs.release_title }}" \ + --notes-file="${{ steps.changelog.outputs.release_notes_file }}" diff --git a/.github/workflows/publish_packages.ps1 b/.github/workflows/publish_packages.ps1 new file mode 100644 index 000000000..491be654d --- /dev/null +++ b/.github/workflows/publish_packages.ps1 @@ -0,0 +1,55 @@ +param ( + [Parameter(Mandatory)] + $packagesDir +) + +function Start-Section($sectionName) { + Write-Output '' + Write-Output "*** $sectionName ***" +} + +function Confirm-Exit-Code($commandName, $cmdOutput = "") { + Write-Debug "$cmdOutput (exit code: $LASTEXITCODE)" + if ($LASTEXITCODE -ne 0) { + $fc = $host.UI.RawUI.ForegroundColor + $host.UI.RawUI.ForegroundColor = "Yellow" + Write-Output $cmdOutput + $host.UI.RawUI.ForegroundColor = "Red" + Write-Output 'error' " FAILED: ${commandName} ($LASTEXITCODE)" + $host.UI.RawUI.ForegroundColor = $fc + if (-not ($LASTEXITCODE -gt 0)) { + Exit 100 + } + Exit $LASTEXITCODE + } + Write-Output "$commandName done." +} + +function Publish-Packages-To-NuGet($settings) { + Start-Section 'Publish Packages to NuGet.org' + $files = Join-Path $settings.OutputDir '*.nupkg' -Resolve + foreach ($file in $files) { + Write-Output "Uploading $file" + Write-Output "dotnet nuget push $file -k $env:NUGET_PUBLISH_KEY -s https://api.nuget.org/v3/index.json --no-symbols --skip-duplicate" + dotnet nuget push $file -k $env:NUGET_PUBLISH_KEY -s https://api.nuget.org/v3/index.json --no-symbols --skip-duplicate + Confirm-Exit-Code "upload $file" + } +} + +function Publish-Symbol-Packages-To-NuGet($settings) { + Start-Section 'Publish Symbol Packages to NuGet.org' + $files = Join-Path $settings.OutputDir '*.snupkg' -Resolve + foreach ($file in $files) { + Write-Output "Uploading $file" + Write-Output "dotnet nuget push $file -k $env:NUGET_PUBLISH_KEY -s https://api.nuget.org/v3/index.json --skip-duplicate" + dotnet nuget push $file -k $env:NUGET_PUBLISH_KEY -s https://api.nuget.org/v3/index.json --skip-duplicate + Confirm-Exit-Code "upload $file" + } +} + +$settings = [PSCustomObject]@{ + OutputDir = $packagesDir +} + +Publish-Packages-To-NuGet $settings +Publish-Symbol-Packages-To-NuGet $settings \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 4cf7e0240..39b71e551 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,5 +10,6 @@ "cSpell.words": [ "Quickstart", "Reqnroll" - ] + ], + "markdown.extension.toc.updateOnSave": false } \ No newline at end of file diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 000000000..36ed34693 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,67 @@ +# Releasing + +This document describes how to make a release using GitHub Actions. + +There are two parts to making a release: + +* [Prepare the release](#prepare-the-release) +* [Make the release](#make-the-release) + +If you're making a major or minor release it is recommended to discuss it with the other contributors upfront (e.g. on Discord). + +## Prepare the release + +Anyone with permission to push to the `main` branch can prepare a release. + +1. Add new information to `CHANGELOG.md`. Ideally the `CHANGELOG.md` should be up-to-date, but sometimes there will be accidental omissions when merging PRs. + * Use `git log --format=format:"* %s (%an)" --reverse <last-version-tag>..HEAD` to list all commits since the last release. + * Add changelog details under the `# [vNext]` heading; the release process will update this heading when it makes the release +1. Check & update contributors list (if applicable) + * List recent contributors: + ``` + git log --format=format:"%an <%ae>" --reverse <last-version-tag>..HEAD | grep -vEi "(renovate|dependabot|Snyk)" | sort| uniq -i + ``` + * Update contributors if necessary at the `Contributors of this release` part of the `# [vNext]` heading +1. The release process by default assumes the new releases to be patch releases, and whenever we merge a change that would require a minor or even major version number based on [semver](https://semver.org/), we update the version at that time accordingly. When preparing the release you just need to double-check if the version is correct. You can find the current version number in the `Directory.Build.props` file. + +## Make the release + +Only people in group [release-managers](https://github.com/orgs/reqnroll/teams/release-managers) can make releases and only from the `main` branch. + +### Making a preview release + +Preview releases (aka pre-releases) are releases with a version number containing a version suffix, i.e. `1.2.3-pre1234`. + +Every CI build produces a set of pre-release packages with version numbers as `1.2.3-ciYYYYMMDD-BBB`, where `YYYYMMDD` refers to the date and `BBB` is the build number. We never publish these CI build packages but they can be used for exploratory testing. + +We generally try to avoid publishing pre-releases, but if necessary, they shoud follow the version schema as `1.2.3-preYYYYMMDD-BBB`. + +To release such a preview release, the following steps has to be done: + +1. Open the CI workflow at GitHub: https://github.com/reqnroll/Reqnroll/actions/workflows/ci.yml +1. Choose the "Run workflow" button to trigger the release with the following settings: + * `deploy_packages`: checked + * `is_production_release`: not checked + * `custom_version_suffix`: set it to `preYYYYMMDD`, where `YYYYMMDD` refers to the current date, e.g. `pre20240515` + * `custom_configuration`: leave it on default +1. The CI workflow runs and ideally passes all core and testing jobs, but will stop for approval before running the `release` job. +1. Make sure everything is OK. You can even donwload the packages to be published for a smoke test if necessary. +1. If everything is fine, approve the deployment job. +1. The job will publish the packages (but do not change the version or the changelog as this is only a preview release) + +### Making a production release + +Production releases (or just releases) are intended to use for any users. Their version number does not contain a version suffix. + +To release such a preview release, the following steps has to be done: + +1. Open the CI workflow at GitHub: https://github.com/reqnroll/Reqnroll/actions/workflows/ci.yml +1. Choose the "Run workflow" button to trigger the release with the following settings: + * `deploy_packages`: checked + * `is_production_release`: checked + * `custom_version_suffix`: leave it empty + * `custom_configuration`: leave it on default +1. The CI workflow runs and ideally passes all core and testing jobs, but will stop for approval before running the `release` job. +1. Make sure everything is OK. You can even donwload the packages to be published for a smoke test if necessary. +1. If everything is fine, approve the deployment job. +1. The job will publish the packages, tag the current commit and create a new commit with the updated version number and changelog header. diff --git a/Reqnroll.sln b/Reqnroll.sln index 521df415a..9d5be6e1d 100644 --- a/Reqnroll.sln +++ b/Reqnroll.sln @@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution CONTRIBUTING.md = CONTRIBUTING.md LICENSE = LICENSE README.md = README.md + RELEASING.md = RELEASING.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{0359B7D7-7E29-48E9-8DF9-7D1FACFA5CFA}" diff --git a/Reqnroll/Reqnroll.csproj b/Reqnroll/Reqnroll.csproj index 544e8628d..22b524d82 100644 --- a/Reqnroll/Reqnroll.csproj +++ b/Reqnroll/Reqnroll.csproj @@ -46,8 +46,6 @@ <ItemGroup> <Compile Include="$(ProjectDir)Analytics/AppInsights/AppInsightsInstrumentationKey.cs" /> </ItemGroup> - - <ReplaceTextInFileTask Condition="'$(BuildingInsideVisualStudio)' != 'true'" InputFile="$(MSBuildThisFileDirectory)\..\CHANGELOG.md" OutputFile="$(MSBuildThisFileDirectory)\..\CHANGELOG.md" TextToReplace="[vNext]" TextToReplaceWith="v$(Version) - $([System.DateTime]::Now.ToString('yyyy-MM-dd'))" WriteOnlyWhenChanged="true" /> </Target> </Project>