Skip to content

dotnet build/test precursor #69

dotnet build/test precursor

dotnet build/test precursor #69

name: CI/CD Build, Test and Deploy
on:
pull_request:
branches:
- main
paths:
- .github/workflows/gtc-rg-semkernel-api-ci-cd.yml
- src/**
- .github/workflows/gtc-rg-semkernel-iac.yml
- .azure/**/*.bicep
- .azure/**/*.bicepparams
push:
branches:
- main
paths:
- .github/workflows/gtc-rg-semkernel-api-ci-cd.yml
- src/**
- .github/workflows/gtc-rg-semkernel-iac.yml
- .azure/**/*.bicep
- .azure/**/*.bicepparams
workflow_dispatch:
inputs:
environment:
description: 'Environment to run'
required: true
default: 'development'
mode:
description: 'Running mode'
permissions:
actions: read
id-token: write
contents: read
security-events: write
jobs:
ci:
name: 'CI Build, Test, Code QL, Publish'
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
environment: development
strategy:
matrix:
DOTNET_VERSION: ['9.x']
env:
AZURE_WEBAPP_NAME: api-semkernel-dev-001
AZURE_WEBAPP_PACKAGE_PATH: '.'
AZURE_RG_NAME: 'gtc-rg-devtest-semkernel-dev-001'
RUNTIME_ENV: 'Development'
SRC_PATH: './src'
SRC_SLN: 'SemanticKernelMicroservice.sln'
API_PATH: 'Presentation.WebApi'
API_PROJECT: 'Presentation.WebApi.csproj'
TEST_PATH: 'Tests.Specs.Integration'
TEST_PROJECT: 'Tests.Specs.Integration.csproj'
SCRIPTS_PATH: './.github/scripts'
steps:
- name: checkout
uses: actions/checkout@v3
- name: dotnet version ${{ matrix.DOTNET_VERSION }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ matrix.DOTNET_VERSION }}
- name: Set-Version.ps1
run: |
$version = ${{ env.SCRIPTS_PATH }}/Set-Version.ps1 -Path ${{ env.SRC_PATH }} -VersionToReplace 1.0.0
echo $version
echo "VERSION=$version" >> $GITHUB_ENV
shell: pwsh
- name: pipeline configuration secrets
run: |
echo "ASPNETCORE_ENVIRONMENT=${{ env.RUNTIME_ENV }}" >> $GITHUB_ENV
echo "AZURE_FUNCTIONS_ENVIRONMENT=${{ env.RUNTIME_ENV }}" >> $GITHUB_ENV
echo "OpenAI:ApiKey=${{ secrets.OPENAI_APIKEY }}" >> $GITHUB_ENV
shell: pwsh
- name: App Settings Variable Substitution
uses: microsoft/variable-substitution@v1
with:
files: '${{ env.SRC_PATH }}/${{ env.API_PATH }}/appsettings.json, ${{ env.SRC_PATH }}/${{ env.API_PATH }}/appsettings.${{ env.RUNTIME_ENV }}.json, ${{ env.SRC_PATH }}/${{ env.TEST_PATH }}/appsettings.test.json'
env:
OpenAI.ApiKey: ${{ secrets.OPENAI_APIKEY }}
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: csharp
- name: Build
run: |
dotnet build ${{ env.SRC_PATH }}/${{ env.SRC_SLN }} --configuration Release
shell: pwsh
- name: Test
run: |
mkdir -p TestResults-${{ matrix.DOTNET_VERSION }}
dotnet test ${{ env.SRC_PATH }}/${{ env.TEST_PATH }}/${{ env.TEST_PROJECT }} --logger "trx;LogFileName=test_results.trx" --results-directory TestResults-${{ matrix.DOTNET_VERSION }} --verbosity normal
shell: pwsh
- name: Upload test results
uses: actions/upload-artifact@v4
with:
name: test-results-dotnet-${{ matrix.DOTNET_VERSION }}
path: TestResults-${{ matrix.DOTNET_VERSION }}
if: ${{ always() }}
- name: Run Coverage Script
run: |
pwsh ${{ env.SRC_PATH }}/Get-CodeCoverage.ps1 `
-TestProjectFilter '${{ env.TEST_PROJECT }}' `
-ProdPackagesOnly `
-ProductionAssemblies Cannery.Insights.Core.Application Cannery.Insights.Presentation.WebApi Cannery.Insights.Presentation.Blazor
shell: pwsh
- name: Upload Coverage Report
uses: actions/upload-artifact@v4
with:
name: coverage-report-${{ matrix.DOTNET_VERSION }}
path: ${{ env.SRC_PATH }}/TestResults/Reports/**/index.html
if: ${{ always() }}
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
cd:
name: 'CD Deploy .NET'
runs-on: ubuntu-latest
needs: ci
if: |
github.event_name == 'push' &&
contains(github.ref, 'refs/tags/deploy')
environment: development
strategy:
matrix:
DOTNET_VERSION: ['9.x']
env:
AZURE_WEBAPP_NAME: api-semkernel-dev-001
AZURE_WEBAPP_PACKAGE_PATH: '.'
AZURE_RG_NAME: 'gtc-rg-devtest-semkernel-dev-001'
RUNTIME_ENV: 'Development'
SRC_PATH: './src'
SRC_SLN: 'SemanticKernelMicroservice.sln'
API_PATH: 'Presentation.WebApi'
API_PROJECT: 'Presentation.WebApi.csproj'
APPI_NAME: 'appi-semkernel-dev-001'
INFRA_PATH: 'Infrastructure.SqlServer'
INFRA_PROJECT: 'Infrastructure.SqlServer.csproj'
INFRA_DBCONTEXT: 'SemanticKernelContext'
TEST_PATH: 'Tests.Specs.Integration'
TEST_PROJECT: 'Tests.Specs.Integration.csproj'
SCRIPTS_PATH: './.github/scripts'
SQL_NAME: 'sql-semkernel-dev-001'
SQLDB_NAME: 'sqldb-semkernel-dev-001'
AZURE_CRED: '{"clientId":"${{ secrets.AZURE_CLIENT_ID }}","subscriptionId":"${{ secrets.SUBSCRIPTION_ID }}","tenantId":"${{ secrets.AZURE_TENANT_ID }}"}'
steps:
- name: checkout
uses: actions/checkout@v3
- name: dotnet version ${{ matrix.DOTNET_VERSION }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ matrix.DOTNET_VERSION }}
- name: Set-Version.ps1
run: |
$version = ${{ env.SCRIPTS_PATH }}/Set-Version.ps1 -Path ${{ env.SRC_PATH }} -VersionToReplace 1.0.0
echo $version
echo "VERSION=$version" >> $GITHUB_ENV
shell: pwsh
- name: pipeline configuration secrets
run: |
echo "ASPNETCORE_ENVIRONMENT=${{ env.RUNTIME_ENV }}" >> $GITHUB_ENV
echo "AZURE_FUNCTIONS_ENVIRONMENT=${{ env.RUNTIME_ENV }}" >> $GITHUB_ENV
echo "OpenAI:ApiKey=${{ secrets.OPENAI_APIKEY }}" >> $GITHUB_ENV
shell: pwsh
- name: App Settings Variable Substitution
uses: microsoft/variable-substitution@v1
with:
files: '${{ env.SRC_PATH }}/${{ env.API_PATH }}/appsettings.json, ${{ env.SRC_PATH }}/${{ env.API_PATH }}/appsettings.${{ env.RUNTIME_ENV }}.json, ${{ env.SRC_PATH }}/${{ env.TEST_PATH }}/appsettings.test.json'
env:
OpenAI.ApiKey: ${{ secrets.OPENAI_APIKEY }}
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: csharp
- name: Build
run: |
dotnet build ${{ env.SRC_PATH }}/${{ env.SRC_SLN }} --configuration Release
shell: pwsh
- name: Test
run: |
mkdir -p TestResults-${{ matrix.DOTNET_VERSION }}
dotnet test ${{ env.SRC_PATH }}/${{ env.TEST_PATH }}/${{ env.TEST_PROJECT }} --logger "trx;LogFileName=test_results.trx" --results-directory TestResults-${{ matrix.DOTNET_VERSION }} --verbosity normal
shell: pwsh
- name: Upload test results
uses: actions/upload-artifact@v4
with:
name: test-results-dotnet-${{ matrix.DOTNET_VERSION }}
path: TestResults-${{ matrix.DOTNET_VERSION }}
if: ${{ always() }}
- name: Run Coverage Script
run: |
pwsh ${{ env.SRC_PATH }}/Get-CodeCoverage.ps1 `
-TestProjectFilter '${{ env.TEST_PROJECT }}' `
-ProdPackagesOnly `
-ProductionAssemblies Cannery.Insights.Core.Application Cannery.Insights.Presentation.WebApi Cannery.Insights.Presentation.Blazor
shell: pwsh
- name: Upload Coverage Report
uses: actions/upload-artifact@v4
with:
name: coverage-report-${{ matrix.DOTNET_VERSION }}
path: ${{ env.SRC_PATH }}/TestResults/Reports/**/index.html
if: ${{ always() }}
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
- name: Publish
run: |
dotnet publish ${{ env.SRC_PATH }}/${{ env.API_PATH }}/${{ env.API_PROJECT }} --configuration Release -o ${{ env.AZURE_WEBAPP_NAME }}
shell: pwsh
- name: az login
uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: get publish profile
id: publishprofile
uses: aliencube/publish-profile-actions@v1
env:
AZURE_CREDENTIALS: ${{ env.AZURE_CRED }}
with:
resourceGroupName: ${{ env.AZURE_RG_NAME }}
appName: ${{ env.AZURE_WEBAPP_NAME }}
- name: functionapp deploy
uses: Azure/functions-action@v1
with:
app-name: ${{ env.AZURE_WEBAPP_NAME }}
package: '${{ env.AZURE_WEBAPP_PACKAGE_PATH }}/${{ env.AZURE_WEBAPP_NAME }}'
publish-profile: ${{ steps.publishprofile.outputs.profile }}
if: ${{ false }}
- name: webapps deploy
uses: azure/webapps-deploy@v2
with:
app-name: ${{ env.AZURE_WEBAPP_NAME }}
publish-profile: ${{ steps.publishprofile.outputs.profile }}
package: '${{ env.AZURE_WEBAPP_PACKAGE_PATH }}/${{ env.AZURE_WEBAPP_NAME }}'
#slot-name: staging
- name: Reset publish profile
uses: aliencube/publish-profile-actions@v1
env:
AZURE_CREDENTIALS: ${{ secrets.AZURE_CRED }}
with:
resourceGroupName: ${{ env.AZURE_RG_NAME }}
appName: ${{ env.AZURE_WEBAPP_NAME }}
reset: true
# Get instrumentation key: az monitor app-insights component show --app <app-name> -g <rg-name>
# Get connection: az monitor app-insights component show -g ${{ env.AZURE_RG_NAME }} --app ${{ env.APPI_NAME }}
- name: ${{ env.AZURE_WEBAPP_NAME }} app settings
run: |
az config set extension.use_dynamic_install=yes_without_prompt
$TEMP_JSON = az monitor app-insights component show -g ${{ env.AZURE_RG_NAME }} --app ${{ env.APPI_NAME }} | ConvertFrom-Json
$INSTR_KEY = $TEMP_JSON.instrumentationKey
$CONN_STR = $TEMP_JSON.connectionString
az webapp config appsettings set -g ${{ env.AZURE_RG_NAME }} -n ${{ env.AZURE_WEBAPP_NAME }} --settings APPINSIGHTS_INSTRUMENTATIONKEY=$INSTR_KEY
az webapp config appsettings set -g ${{ env.AZURE_RG_NAME }} -n ${{ env.AZURE_WEBAPP_NAME }} --settings APPLICATIONINSIGHTS_CONNECTION_STRING=$CONN_STR
az webapp config appsettings set -g ${{ env.AZURE_RG_NAME }} -n ${{ env.AZURE_WEBAPP_NAME }} --settings ASPNETCORE_ENVIRONMENT=${{ env.RUNTIME_ENV }}
shell: pwsh
# Get Azure SQL DB Conenction: az sql db show-connection-string --client ado.net --server ${{ env.SQL_NAME }} --name ${{ env.SQLDB_NAME }} -o tsv
- name: ${{ env.AZURE_WEBAPP_NAME }} connection strings
run: |
$TEMP_STR=az sql db show-connection-string --client ado.net --server ${{ env.SQL_NAME }} --name ${{ env.SQLDB_NAME }} -o tsv
$TEMP_STR=$TEMP_STR.replace("<username>", "${{ secrets.SQL_ADMIN_USER }}")
$TEMP_STR=$TEMP_STR.replace("<password>", "${{ secrets.SQL_ADMIN_PASSWORD }}")
az webapp config connection-string set -g ${{ env.AZURE_RG_NAME }} -n ${{ env.AZURE_WEBAPP_NAME }} -t SQLServer --settings DefaultConnection=$TEMP_STR
shell: pwsh
- name: ${{ env.AZURE_WEBAPP_NAME }} dotnet ef migrations
run: |
$TEMP_STR=az sql db show-connection-string --client ado.net --server ${{ env.SQL_NAME }} --name ${{ env.SQLDB_NAME }} -o tsv
$TEMP_STR=$TEMP_STR.replace("<username>", "${{ secrets.SQL_ADMIN_USER }}")
$TEMP_STR=$TEMP_STR.replace("<password>", "${{ secrets.SQL_ADMIN_PASSWORD }}")
dotnet tool install --global dotnet-ef
dotnet tool restore
dotnet ef migrations add v${{ env.VERSION }} --project ${{ env.SRC_PATH }}/${{ env.INFRA_PATH }}/${{ env.INFRA_PROJECT }} --startup-project ${{ env.SRC_PATH }}/${{ env.API_PATH }}/${{ env.API_PROJECT }} --context ${{ env.INFRA_DBCONTEXT }}
dotnet ef migrations script --project ${{ env.SRC_PATH }}/${{ env.INFRA_PATH }}/${{ env.INFRA_PROJECT }} --startup-project ${{ env.SRC_PATH }}/${{ env.API_PATH }}/${{ env.API_PROJECT }} --context ${{ env.INFRA_DBCONTEXT }} --output ${{ github.workspace }}/sql/migrations.sql --idempotent
dotnet ef database update --project ${{ env.SRC_PATH }}/${{ env.INFRA_PATH }}/${{ env.INFRA_PROJECT }} --startup-project ${{ env.SRC_PATH }}/${{ env.API_PATH }}/${{ env.API_PROJECT }} --context ${{ env.INFRA_DBCONTEXT }} --connection $TEMP_STR
shell: pwsh
- name: Swap to production slot
run: |
az webapp deployment slot swap --resource-group ${{ env.AZURE_RG_NAME }} --name ${{ env.AZURE_WEBAPP_NAME }} --slot staging --target-slot production
echo "Swap finished. App Service Application URL: https://$(az webapp show --resource-group ${{ env.AZURE_RG_NAME }} --name ${{ env.AZURE_WEBAPP_NAME }} --query hostNames[0] -o tsv)"
if: ${{ false }}