Merge pull request #48 from danrayson/feature/46-small-ollama #44
This file contains hidden or 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: Deploy Staging | |
| on: | |
| push: | |
| branches: [develop] | |
| workflow_dispatch: | |
| inputs: | |
| imageTag: | |
| description: 'Docker image tag to deploy' | |
| required: false | |
| default: 'latest' | |
| env: | |
| AZURE_RESOURCE_GROUP: rg-raysoncv-staging | |
| LOCATION: uksouth | |
| ACR_NAME: acrraysoncvstaging | |
| API_IMAGE_NAME: raysoncv-api | |
| UI_IMAGE_NAME: raysoncv-ui | |
| OLLAMA_IMAGE_NAME: raysoncv-ollama | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| imageTag: ${{ steps.set-tag.outputs.imageTag }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup .NET SDK | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: '8.0.x' | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20.x' | |
| cache: 'npm' | |
| cache-dependency-path: Rayson.CV/UI/package-lock.json | |
| - name: Build API | |
| run: dotnet build Rayson.CV/Api/Presentation/Presentation.csproj --configuration Release | |
| - name: Install UI dependencies | |
| run: cd Rayson.CV/UI && npm ci | |
| - name: Build UI | |
| run: cd Rayson.CV/UI && npm run build | |
| - name: Set image tag | |
| id: set-tag | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ github.event.inputs.imageTag }}" ]; then | |
| echo "imageTag=${{ github.event.inputs.imageTag }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "imageTag=${{ github.sha }}" >> $GITHUB_OUTPUT | |
| fi | |
| deploy-core: | |
| runs-on: ubuntu-latest | |
| needs: build | |
| outputs: | |
| acrLoginServer: ${{ steps.deploy.outputs.acrLoginServer }} | |
| acrName: ${{ steps.deploy.outputs.acrName }} | |
| environmentId: ${{ steps.deploy.outputs.environmentId }} | |
| defaultDomain: ${{ steps.deploy.outputs.defaultDomain }} | |
| storageAccountName: ${{ steps.deploy.outputs.storageAccountName }} | |
| storageAccountKey: ${{ steps.deploy.outputs.storageAccountKey }} | |
| blobBaseUrl: ${{ steps.deploy.outputs.blobBaseUrl }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Azure Login | |
| uses: azure/login@v1 | |
| with: | |
| creds: ${{ secrets.AZURE_CREDENTIALS }} | |
| - name: Deploy core infrastructure | |
| id: deploy | |
| run: | | |
| az deployment sub create \ | |
| --name raysoncv-staging-core \ | |
| --location ${{ env.LOCATION }} \ | |
| --template-file infra/main-core.bicep \ | |
| --parameters location=${{ env.LOCATION }} \ | |
| resourceGroupName=${{ env.AZURE_RESOURCE_GROUP }} \ | |
| environmentName=staging \ | |
| acrName=${{ env.ACR_NAME }} | |
| ACR_LOGIN_SERVER=$(az deployment sub show --name raysoncv-staging-core --query properties.outputs.acrLoginServer.value --output tsv) | |
| ACR_NAME_OUT=$(az deployment sub show --name raysoncv-staging-core --query properties.outputs.acrName.value --output tsv) | |
| ENVIRONMENT_ID=$(az deployment sub show --name raysoncv-staging-core --query properties.outputs.environmentId.value --output tsv) | |
| DEFAULT_DOMAIN=$(az deployment sub show --name raysoncv-staging-core --query properties.outputs.defaultDomain.value --output tsv) | |
| STORAGE_ACCOUNT_NAME=$(az deployment sub show --name raysoncv-staging-core --query properties.outputs.storageAccountName.value --output tsv) | |
| STORAGE_ACCOUNT_KEY=$(az deployment sub show --name raysoncv-staging-core --query properties.outputs.storageAccountKey.value --output tsv) | |
| BLOB_BASE_URL=$(az deployment sub show --name raysoncv-staging-core --query properties.outputs.blobBaseUrl.value --output tsv) | |
| echo "acrLoginServer=$ACR_LOGIN_SERVER" >> $GITHUB_OUTPUT | |
| echo "acrName=$ACR_NAME_OUT" >> $GITHUB_OUTPUT | |
| echo "environmentId=$ENVIRONMENT_ID" >> $GITHUB_OUTPUT | |
| echo "defaultDomain=$DEFAULT_DOMAIN" >> $GITHUB_OUTPUT | |
| echo "storageAccountName=$STORAGE_ACCOUNT_NAME" >> $GITHUB_OUTPUT | |
| echo "storageAccountKey=$STORAGE_ACCOUNT_KEY" >> $GITHUB_OUTPUT | |
| echo "blobBaseUrl=$BLOB_BASE_URL" >> $GITHUB_OUTPUT | |
| push: | |
| runs-on: ubuntu-latest | |
| needs: [build, deploy-core] | |
| outputs: | |
| apiFqdn: ${{ steps.set-fqdn.outputs.apiFqdn }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Azure Login | |
| uses: azure/login@v1 | |
| with: | |
| creds: ${{ secrets.AZURE_CREDENTIALS }} | |
| - name: Login to Azure Container Registry | |
| run: az acr login --name ${{ env.ACR_NAME }} | |
| - name: Build and push API image | |
| run: | | |
| docker build \ | |
| -t ${{ needs.deploy-core.outputs.acrLoginServer }}/${{ env.API_IMAGE_NAME }}:${{ needs.build.outputs.imageTag }} \ | |
| -t ${{ needs.deploy-core.outputs.acrLoginServer }}/${{ env.API_IMAGE_NAME }}:latest \ | |
| ./Rayson.CV/Api | |
| docker push ${{ needs.deploy-core.outputs.acrLoginServer }}/${{ env.API_IMAGE_NAME }}:${{ needs.build.outputs.imageTag }} | |
| docker push ${{ needs.deploy-core.outputs.acrLoginServer }}/${{ env.API_IMAGE_NAME }}:latest | |
| - name: Build and push UI image | |
| run: | | |
| API_FQDN="ca-api-staging.${{ needs.deploy-core.outputs.defaultDomain }}" | |
| BLOB_URL="${{ needs.deploy-core.outputs.blobBaseUrl }}" | |
| docker build \ | |
| --build-arg VITE_API_BASE_URL=https://$API_FQDN/ \ | |
| --build-arg VITE_APP_DOWNLOAD_URL=$BLOB_URL \ | |
| -t ${{ needs.deploy-core.outputs.acrLoginServer }}/${{ env.UI_IMAGE_NAME }}:${{ needs.build.outputs.imageTag }} \ | |
| -t ${{ needs.deploy-core.outputs.acrLoginServer }}/${{ env.UI_IMAGE_NAME }}:latest \ | |
| ./Rayson.CV/UI | |
| docker push ${{ needs.deploy-core.outputs.acrLoginServer }}/${{ env.UI_IMAGE_NAME }}:${{ needs.build.outputs.imageTag }} | |
| docker push ${{ needs.deploy-core.outputs.acrLoginServer }}/${{ env.UI_IMAGE_NAME }}:latest | |
| echo "apiFqdn=$API_FQDN" >> $GITHUB_OUTPUT | |
| - name: Build and push Ollama image | |
| run: | | |
| docker build \ | |
| -t ${{ needs.deploy-core.outputs.acrLoginServer }}/${{ env.OLLAMA_IMAGE_NAME }}:${{ needs.build.outputs.imageTag }} \ | |
| -t ${{ needs.deploy-core.outputs.acrLoginServer }}/${{ env.OLLAMA_IMAGE_NAME }}:latest \ | |
| -f Rayson.CV/ollama.Dockerfile \ | |
| Rayson.CV | |
| docker push ${{ needs.deploy-core.outputs.acrLoginServer }}/${{ env.OLLAMA_IMAGE_NAME }}:${{ needs.build.outputs.imageTag }} | |
| docker push ${{ needs.deploy-core.outputs.acrLoginServer }}/${{ env.OLLAMA_IMAGE_NAME }}:latest | |
| - name: Set FQDN output | |
| id: set-fqdn | |
| run: | | |
| echo "apiFqdn=ca-api-staging.${{ needs.deploy-core.outputs.defaultDomain }}" >> $GITHUB_OUTPUT | |
| build-electron-linux: | |
| runs-on: ubuntu-latest | |
| needs: [build, deploy-core] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20.x' | |
| cache: 'npm' | |
| cache-dependency-path: Rayson.CV/UI/package-lock.json | |
| - name: Install dependencies | |
| run: cd Rayson.CV/UI && npm ci | |
| - name: Build Electron app | |
| run: cd Rayson.CV/UI && npm run electron:build -- --linux | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: electron-linux | |
| path: Rayson.CV/UI/build/*.AppImage | |
| build-electron-mac: | |
| runs-on: macos-latest | |
| needs: [build, deploy-core] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20.x' | |
| cache: 'npm' | |
| cache-dependency-path: Rayson.CV/UI/package-lock.json | |
| - name: Install dependencies | |
| run: cd Rayson.CV/UI && npm ci | |
| - name: Build Electron app | |
| run: cd Rayson.CV/UI && npm run electron:build -- --mac | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: electron-mac | |
| path: Rayson.CV/UI/build/*.dmg | |
| build-electron-windows: | |
| runs-on: windows-latest | |
| needs: [build, deploy-core] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20.x' | |
| cache: 'npm' | |
| cache-dependency-path: Rayson.CV/UI/package-lock.json | |
| - name: Install dependencies | |
| run: cd Rayson.CV/UI && npm ci | |
| - name: Build Electron app | |
| run: cd Rayson.CV/UI && npm run electron:build -- --win | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: electron-windows | |
| path: Rayson.CV/UI/build/*.exe | |
| upload-electron: | |
| runs-on: ubuntu-latest | |
| needs: [build-electron-linux, build-electron-mac, build-electron-windows, deploy-core] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Azure Login | |
| uses: azure/login@v1 | |
| with: | |
| creds: ${{ secrets.AZURE_CREDENTIALS }} | |
| - name: Wait for storage account | |
| run: | | |
| echo "Waiting for storage account to be ready..." | |
| until STORAGE_STATE=$(az storage account show \ | |
| --name strraysoncvstaging \ | |
| --resource-group ${{ env.AZURE_RESOURCE_GROUP }} \ | |
| --query "provisioningState" \ | |
| --output tsv 2>/dev/null) && [ "$STORAGE_STATE" = "Succeeded" ]; do | |
| echo "Storage account status: $STORAGE_STATE. Waiting..." | |
| sleep 5 | |
| done | |
| echo "Storage account is ready!" | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: List downloaded artifacts | |
| run: | | |
| echo "=== Linux ===" | |
| find artifacts/electron-linux -type f -exec ls -lh {} \; | |
| echo "=== macOS ===" | |
| find artifacts/electron-mac -type f -exec ls -lh {} \; | |
| echo "=== Windows ===" | |
| find artifacts/electron-windows -type f -exec ls -lh {} \; | |
| - name: Upload Linux app | |
| run: | | |
| FILE=$(ls artifacts/electron-linux/*.AppImage | head -1) | |
| echo "Uploading Linux: $FILE" | |
| az storage blob upload \ | |
| --container-name '$web' \ | |
| --file "$FILE" \ | |
| --name "RaysonCV.AppImage" \ | |
| --account-name ${{ needs.deploy-core.outputs.storageAccountName }} \ | |
| --account-key "${{ needs.deploy-core.outputs.storageAccountKey }}" \ | |
| --overwrite | |
| - name: Upload macOS app | |
| run: | | |
| FILE=$(ls artifacts/electron-mac/*.dmg | head -1) | |
| echo "Uploading macOS: $FILE" | |
| az storage blob upload \ | |
| --container-name '$web' \ | |
| --file "$FILE" \ | |
| --name "RaysonCV.dmg" \ | |
| --account-name ${{ needs.deploy-core.outputs.storageAccountName }} \ | |
| --account-key "${{ needs.deploy-core.outputs.storageAccountKey }}" \ | |
| --overwrite | |
| - name: Upload Windows app | |
| run: | | |
| FILE=$(ls artifacts/electron-windows/*.exe | head -1) | |
| echo "Uploading Windows: $FILE" | |
| az storage blob upload \ | |
| --container-name '$web' \ | |
| --file "$FILE" \ | |
| --name "RaysonCV-Setup.exe" \ | |
| --account-name ${{ needs.deploy-core.outputs.storageAccountName }} \ | |
| --account-key "${{ needs.deploy-core.outputs.storageAccountKey }}" \ | |
| --overwrite | |
| deploy-apps: | |
| runs-on: ubuntu-latest | |
| needs: [build, deploy-core, push] | |
| outputs: | |
| apiFqdn: ${{ steps.deploy.outputs.apiFqdn }} | |
| uiFqdn: ${{ steps.deploy.outputs.uiFqdn }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Azure Login | |
| uses: azure/login@v1 | |
| with: | |
| creds: ${{ secrets.AZURE_CREDENTIALS }} | |
| - name: Deploy container apps | |
| id: deploy | |
| run: | | |
| az deployment group create \ | |
| --name raysoncv-staging-apps \ | |
| --resource-group ${{ env.AZURE_RESOURCE_GROUP }} \ | |
| --template-file infra/main-apps.bicep \ | |
| --parameters location=${{ env.LOCATION }} \ | |
| environmentId=${{ needs.deploy-core.outputs.environmentId }} \ | |
| defaultDomain=${{ needs.deploy-core.outputs.defaultDomain }} \ | |
| acrLoginServer=${{ needs.deploy-core.outputs.acrLoginServer }} \ | |
| acrName=${{ needs.deploy-core.outputs.acrName }} \ | |
| imageTag=${{ needs.build.outputs.imageTag }} \ | |
| environmentName=staging \ | |
| blobBaseUrl="${{ needs.deploy-core.outputs.blobBaseUrl }}" | |
| API_FQDN=$(az deployment group show --name raysoncv-staging-apps --resource-group ${{ env.AZURE_RESOURCE_GROUP }} --query properties.outputs.apiFqdn.value --output tsv) | |
| UI_FQDN=$(az deployment group show --name raysoncv-staging-apps --resource-group ${{ env.AZURE_RESOURCE_GROUP }} --query properties.outputs.uiFqdn.value --output tsv) | |
| echo "apiFqdn=$API_FQDN" >> $GITHUB_OUTPUT | |
| echo "uiFqdn=$UI_FQDN" >> $GITHUB_OUTPUT | |
| - name: Deployment Summary | |
| run: | | |
| echo "## Deployment Complete" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Service | URL |" >> $GITHUB_STEP_SUMMARY | |
| echo "|---------|-----|" >> $GITHUB_STEP_SUMMARY | |
| echo "| API | https://${{ steps.deploy.outputs.apiFqdn }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| UI | https://${{ steps.deploy.outputs.uiFqdn }} |" >> $GITHUB_STEP_SUMMARY | |
| e2e-tests: | |
| runs-on: ubuntu-latest | |
| needs: deploy-apps | |
| if: github.event_name == 'push' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20.x' | |
| - name: Install dependencies | |
| run: cd Rayson.CV/Test/e2e && npm ci | |
| - name: Install Playwright browsers | |
| run: npx playwright install chromium | |
| - name: Run E2E tests | |
| working-directory: Rayson.CV/Test/e2e | |
| run: npm run e2e:staging | |
| env: | |
| E2E_API_URL: https://${{ needs.deploy-apps.outputs.apiFqdn }} | |
| E2E_UI_URL: https://${{ needs.deploy-apps.outputs.uiFqdn }} | |
| - name: Upload reports | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-report | |
| path: Rayson.CV/Test/e2e/reports/ |