Feature Flags CI/CD #10120
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: "Feature Flags CI/CD" | |
on: | |
push: | |
schedule: | |
- cron: '0 5 * * *' | |
# Allows you to run this workflow manually from the Actions tab | |
workflow_dispatch: | |
env: | |
dotNetVersion: net8.0 | |
dotNetConfiguration: Release | |
dotNetSDKVersion: 8.0.x | |
dotNetSDKIncludePrerelease: false | |
runtimeTarget: win-x86 | |
jobs: | |
build: | |
runs-on: windows-latest | |
outputs: # https://stackoverflow.com/questions/59175332/using-output-from-a-previous-job-in-a-new-one-in-a-github-action | |
Version: ${{ steps.gitversion.outputs.nuGetVersionV2 }} | |
CommitsSinceVersionSource: ${{ steps.gitversion.outputs.CommitsSinceVersionSource }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 #fetch-depth is needed for GitVersion | |
# install and calculate the new version with GitVersion | |
- name: Install GitVersion | |
uses: gittools/actions/gitversion/setup@v1.2.0 | |
with: | |
versionSpec: '5.x' | |
- name: Determine Version | |
uses: gittools/actions/gitversion/execute@v1.2.0 | |
id: gitversion # step id used as reference for output values | |
- name: Display GitVersion outputs | |
run: | | |
echo "MajorMinorPatch: ${{ steps.gitversion.outputs.majorMinorPatch }}" | |
echo "NuGetVersionV2: ${{ steps.gitversion.outputs.nuGetVersionV2 }}" | |
echo "CommitsSinceVersionSource: ${{ steps.gitversion.outputs.CommitsSinceVersionSource }}" | |
# install dependencies, build, and test | |
- name: Setup Dotnet for use with actions | |
uses: actions/setup-dotnet@v4.0.1 | |
with: | |
dotnet-version: ${{ env.dotNetSDKVersion }} | |
include-prerelease: ${{ env.dotNetSDKIncludePrerelease }} | |
#Publish web and web service projects | |
- name: DotNet Publish Web Service | |
run: dotnet publish src/FeatureFlags.Service/FeatureFlags.Service.csproj --configuration ${{ env.dotNetConfiguration }} -p:Version=${{ steps.gitversion.outputs.nuGetVersionV2 }} --output ${{ github.workspace }}/webservice --runtime ${{env.runtimeTarget}} --self-contained false # --self-contained true --runtime ${{env.runtimeTarget}} | |
- name: DotNet Publish Web Site | |
run: dotnet publish src/FeatureFlags.Web/FeatureFlags.Web.csproj --configuration ${{ env.dotNetConfiguration }} -p:Version=${{ steps.gitversion.outputs.nuGetVersionV2 }} --output ${{ github.workspace }}/web --runtime ${{env.runtimeTarget}} --self-contained false # --self-contained true --runtime ${{env.runtimeTarget}} | |
- name: DotNet Publish Demo Web Site | |
run: dotnet publish src/FeatureFlagsDemo.Web/FeatureFlagsDemo.Web.csproj --configuration ${{ env.dotNetConfiguration }} -p:Version=${{ steps.gitversion.outputs.nuGetVersionV2 }} --output ${{ github.workspace }}/webDemo --runtime ${{env.runtimeTarget}} --self-contained false # --self-contained true --runtime ${{env.runtimeTarget}} | |
#Publish functional tests | |
- name: DotNet build functional tests | |
run: dotnet build src/FeatureFlags.FunctionalTests/FeatureFlags.FunctionalTests.csproj --configuration ${{ env.dotNetConfiguration }} --runtime ${{env.runtimeTarget}} #--self-contained false #--self-contained true --runtime ${{env.runtimeTarget}} | |
- name: DotNet Publish functional tests | |
run: dotnet publish src/FeatureFlags.FunctionalTests/FeatureFlags.FunctionalTests.csproj --configuration ${{ env.dotNetConfiguration }} --output ${{ github.workspace }}/functionalTests --runtime ${{env.runtimeTarget}} --self-contained false # --self-contained true --runtime ${{env.runtimeTarget}} | |
- name: Copy chromedriver for functional test | |
run: copy "src/FeatureFlags.FunctionalTests/bin/${{ env.dotNetConfiguration }}/${{ env.dotNetVersion }}/${{env.runtimeTarget}}/chromedriver.exe" "${{ github.workspace }}/functionalTests" | |
shell: powershell | |
- name: DotNet restore functional tests to get correct Newtonsoft version | |
run: dotnet restore src/FeatureFlags.FunctionalTests/FeatureFlags.FunctionalTests.csproj | |
- name: Copy new NewtonSoft version for functional test | |
run: copy "src/FeatureFlags.FunctionalTests/bin/${{ env.dotNetConfiguration }}/${{ env.dotNetVersion }}/${{env.runtimeTarget}}/Newtonsoft.Json.dll" "${{ github.workspace }}/functionalTests" | |
shell: powershell | |
#Publish build artifacts to GitHub | |
- name: Upload web service build artifacts back to GitHub | |
uses: actions/upload-artifact@v4 | |
with: | |
name: serviceapp | |
path: ${{ github.workspace }}/webservice | |
- name: Upload website build artifacts back to GitHub | |
uses: actions/upload-artifact@v4 | |
with: | |
name: webapp | |
path: ${{ github.workspace }}/web | |
- name: Upload website build artifacts back to GitHub | |
uses: actions/upload-artifact@v4 | |
with: | |
name: webappDemo | |
path: ${{ github.workspace }}/webDemo | |
- name: Upload function test build artifacts back to GitHub | |
uses: actions/upload-artifact@v4 | |
with: | |
name: functionaltests | |
path: ${{ github.workspace }}/functionalTests | |
test: | |
runs-on: windows-latest | |
permissions: | |
actions: read | |
steps: | |
- uses: actions/checkout@v4 | |
# install dependencies, build, and test | |
- name: Setup Dotnet for use with actions | |
uses: actions/setup-dotnet@v4.0.1 | |
with: | |
dotnet-version: ${{ env.dotNetSDKVersion }} | |
include-prerelease: ${{ env.dotNetSDKIncludePrerelease }} | |
# Test service | |
- name: Variable Substitution appsettings file for tests | |
uses: microsoft/variable-substitution@v1 | |
with: | |
files: 'src/FeatureFlags.Tests/appsettings.json' | |
env: | |
AppSettings.ClientSecret: "${{ secrets.ClientSecret }}" | |
- name: Build automated tests project | |
run: dotnet build src/FeatureFlags.Tests/FeatureFlags.Tests.csproj --configuration ${{ env.dotNetConfiguration }} | |
- name: Run automated unit and integration tests | |
run: dotnet test src/FeatureFlags.Tests/FeatureFlags.Tests.csproj --configuration ${{ env.dotNetConfiguration }} --settings:./src/FeatureFlags.Tests/CodeCoverage.runsettings #/p:CollectCoverage=true /p:CoverletOutput=TestResults/ /p:CoverletOutputFormat=lcov | |
- name: Publish coverage report to coveralls.io | |
uses: coverallsapp/github-action@master | |
if: 0 == 1 | |
with: | |
github-token: ${{ secrets.GITHUB_TOKEN }} | |
path-to-lcov: src/FeatureFlags.Tests/TestResults/coverage.info | |
#Deploy the artifacts to Azure | |
deploy: | |
runs-on: windows-2022 | |
needs: [build, test] | |
steps: | |
# Install SDK for Selenium/Functional tests | |
- name: Setup Dotnet for use with actions | |
uses: actions/setup-dotnet@v4.0.1 | |
with: | |
dotnet-version: ${{ env.dotNetSDKVersion }} | |
include-prerelease: ${{ env.dotNetSDKIncludePrerelease }} | |
# Login with the secret SP details | |
- name: Log into Azure | |
uses: azure/login@v2 | |
with: | |
creds: ${{ secrets.AZURE_SP }} | |
- name: Deployment setup PowerShell script | |
run: | | |
Write-Host "Starting deployment" | |
Write-Host "Continuing deployment" | |
shell: powershell | |
#Download the artifacts from GitHub | |
- name: Download serviceapp artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: serviceapp | |
path: serviceapp | |
- name: Download webapp artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: webapp | |
path: webapp | |
- name: Download webappDemo artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: webappDemo | |
path: webappDemo | |
- name: Download functionaltests artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: functionaltests | |
path: functionaltests | |
#Deploy service and website to Azure staging slots | |
- name: Deploy web service to Azure WebApp | |
uses: Azure/webapps-deploy@v3 | |
with: | |
app-name: featureflags-prod-eu-service | |
package: serviceapp | |
#slot-name: staging | |
- name: Set service secrets | |
run: az webapp config appsettings set --name "featureflags-prod-eu-service" --resource-group "FeatureFlags" --settings "AppSettings:ClientSecret=${{ secrets.ClientSecret }}" #--slot staging | |
- name: Deploy website to Azure WebApp | |
uses: Azure/webapps-deploy@v3 | |
with: | |
app-name: featureflags-prod-eu-web | |
package: webapp | |
#slot-name: staging | |
- name: Deploy website demo to Azure WebApp | |
uses: Azure/webapps-deploy@v3 | |
with: | |
app-name: featureflagsdemo-prod-eu-web | |
package: webappDemo | |
#slot-name: staging | |
# Run functional tests on staging slots | |
- name: Functional Tests | |
if: 1 == 0 | |
run: | | |
$vsTestConsoleExe = "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Common7\\IDE\\Extensions\\TestPlatform\\vstest.console.exe" | |
$targetTestDll = "functionaltests\FeatureFlags.FunctionalTests.dll" | |
$testRunSettings = "/Settings:`"functionaltests\test.runsettings`" " | |
$parameters = " -- ServiceUrl=""https://featureflags-prod-eu-service.azurewebsites.net/"" WebsiteUrl=""https://featureflags-prod-eu-web.azurewebsites.net/"" " | |
#Note that the `" is an escape character to quote strings, and the `& is needed to start the command | |
$command = "`& `"$vsTestConsoleExe`" `"$targetTestDll`" $testRunSettings $parameters " | |
Write-Host "$command" | |
Invoke-Expression $command | |
shell: powershell | |
sonarCloud: | |
name: Run SonarCloud analysis | |
runs-on: ubuntu-latest | |
if: github.ref == 'refs/heads/main' | |
steps: | |
- name: Run Sonarcloud test | |
uses: samsmithnz/SamsDotNetSonarCloudAction@v2 | |
with: | |
projects: 'src/FeatureFlags.Service/FeatureFlags.Service.csproj,src/FeatureFlags.ConsoleApp/FeatureFlags.ConsoleApp.csproj,src/FeatureFlags.FunctionalTests/FeatureFlags.FunctionalTests.csproj,src/FeatureFlags.Models/FeatureFlags.Models.csproj,src/FeatureFlags.Tests/FeatureFlags.Tests.csproj,src/FeatureFlags.Web/FeatureFlags.Web.csproj,src/FeatureFlagsDemo.Web/FeatureFlagsDemo.Web.csproj' | |
dotnet-version: '8.0.x' | |
sonarcloud-organization: samsmithnz-github | |
sonarcloud-project: samsmithnz_SamsFeatureFlags | |
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
#Deploy the artifacts to Azure | |
release: | |
runs-on: ubuntu-latest # Note, Azure CLI requires a Linux runner... | |
needs: | |
- build | |
- deploy | |
- sonarCloud | |
#Only deploy if running off the main branch - we don't want to deploy off feature branches | |
if: github.ref == 'refs/heads/main' | |
steps: | |
- name: Display GitVersion outputs | |
run: | | |
echo "Version: ${{ needs.build.outputs.Version }}" | |
echo "CommitsSinceVersionSource: ${{ needs.build.outputs.CommitsSinceVersionSource }}" | |
- name: Create Release | |
id: create_release | |
uses: actions/create-release@v1 | |
if: needs.build.outputs.CommitsSinceVersionSource > 0 #Only create a release if there has been a commit change | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token | |
with: | |
tag_name: "v${{ needs.build.outputs.Version }}" | |
release_name: "v${{ needs.build.outputs.Version }}" | |
# Login with the secret SP details | |
- name: Log into Azure | |
if: 0==1 | |
uses: azure/login@v2 | |
with: | |
creds: ${{ secrets.AZURE_SP }} | |
#Swap staging slots with prod | |
- name: Swap web service staging slot to production | |
if: 0==1 | |
uses: Azure/cli@v2.0.0 | |
with: | |
inlineScript: az webapp deployment slot swap --resource-group FeatureFlags --name featureflags-prod-eu-service --slot staging --target-slot production | |
- name: Swap web site staging slot to production | |
if: 0==1 | |
uses: Azure/cli@v2.0.0 | |
with: | |
inlineScript: az webapp deployment slot swap --resource-group FeatureFlags --name featureflags-prod-eu-web --slot staging --target-slot production | |