Add YAML pipeline examples for teaching CI/CD #1
Workflow file for this run
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: Node.js CI/CD to Azure | |
| # Teaching example for GitHub Actions with Azure deployment | |
| on: | |
| push: | |
| branches: [ main, master ] | |
| paths: | |
| - 'nodeapp-1/**' | |
| - '.github/workflows/node-azure-deploy.yml' | |
| pull_request: | |
| branches: [ main, master ] | |
| workflow_dispatch: | |
| inputs: | |
| environment: | |
| description: 'Environment to deploy to' | |
| required: true | |
| default: 'development' | |
| type: choice | |
| options: | |
| - development | |
| - staging | |
| - production | |
| env: | |
| NODE_VERSION: '18.x' | |
| AZURE_WEBAPP_NAME: 'webapp-az400-demo' | |
| AZURE_WEBAPP_PACKAGE_PATH: './nodeapp-1' | |
| jobs: | |
| # ======================================== | |
| # JOB 1: BUILD AND TEST | |
| # ======================================== | |
| build: | |
| name: Build and Test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: 📥 Checkout code | |
| uses: actions/checkout@v4 | |
| - name: 🔧 Setup Node.js ${{ env.NODE_VERSION }} | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'npm' | |
| cache-dependency-path: '${{ env.AZURE_WEBAPP_PACKAGE_PATH }}/package-lock.json' | |
| - name: 📦 Install dependencies | |
| run: npm ci | |
| working-directory: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }} | |
| - name: 🔒 Security audit | |
| run: npm audit --audit-level=high | |
| working-directory: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }} | |
| continue-on-error: true | |
| - name: 🧹 Lint code | |
| run: npm run lint || echo "No lint script configured" | |
| working-directory: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }} | |
| - name: 🧪 Run tests | |
| run: npm test -- --coverage || npm test | |
| working-directory: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }} | |
| - name: 📊 Upload coverage reports | |
| uses: codecov/codecov-action@v3 | |
| with: | |
| directory: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}/coverage | |
| flags: unittests | |
| name: codecov-umbrella | |
| fail_ci_if_error: false | |
| - name: 🔨 Build application | |
| run: npm run build || echo "No build required" | |
| working-directory: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }} | |
| - name: 📤 Upload artifact for deployment | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: node-app | |
| path: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }} | |
| retention-days: 5 | |
| # ======================================== | |
| # JOB 2: DEPLOY TO DEVELOPMENT | |
| # ======================================== | |
| deploy-dev: | |
| name: Deploy to Development | |
| runs-on: ubuntu-latest | |
| needs: build | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| environment: | |
| name: development | |
| url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} | |
| steps: | |
| - name: 📥 Download artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: node-app | |
| path: ./app | |
| - name: 🔐 Login to Azure | |
| uses: azure/login@v1 | |
| with: | |
| creds: ${{ secrets.AZURE_CREDENTIALS }} | |
| - name: 🚀 Deploy to Azure Web App | |
| id: deploy-to-webapp | |
| uses: azure/webapps-deploy@v3 | |
| with: | |
| app-name: ${{ env.AZURE_WEBAPP_NAME }}-dev | |
| package: ./app | |
| startup-command: 'npm start' | |
| - name: 🔥 Smoke test | |
| run: | | |
| sleep 30 | |
| response=$(curl -s -o /dev/null -w "%{http_code}" https://${{ env.AZURE_WEBAPP_NAME }}-dev.azurewebsites.net) | |
| if [ $response -eq 200 ]; then | |
| echo "✅ Smoke test passed!" | |
| else | |
| echo "❌ Smoke test failed with status code: $response" | |
| exit 1 | |
| fi | |
| # ======================================== | |
| # JOB 3: DEPLOY TO STAGING | |
| # ======================================== | |
| deploy-staging: | |
| name: Deploy to Staging | |
| runs-on: ubuntu-latest | |
| needs: deploy-dev | |
| environment: | |
| name: staging | |
| url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} | |
| steps: | |
| - name: 📥 Download artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: node-app | |
| path: ./app | |
| - name: 🔐 Login to Azure | |
| uses: azure/login@v1 | |
| with: | |
| creds: ${{ secrets.AZURE_CREDENTIALS }} | |
| - name: 🚀 Deploy to staging slot | |
| id: deploy-to-webapp | |
| uses: azure/webapps-deploy@v3 | |
| with: | |
| app-name: ${{ env.AZURE_WEBAPP_NAME }} | |
| slot-name: staging | |
| package: ./app | |
| - name: 🧪 Run integration tests | |
| run: | | |
| echo "Running integration tests against staging..." | |
| # Add your integration test commands here | |
| echo "✅ Integration tests passed!" | |
| # ======================================== | |
| # JOB 4: DEPLOY TO PRODUCTION | |
| # ======================================== | |
| deploy-prod: | |
| name: Deploy to Production | |
| runs-on: ubuntu-latest | |
| needs: deploy-staging | |
| environment: | |
| name: production | |
| url: ${{ steps.swap-slots.outputs.webapp-url }} | |
| steps: | |
| - name: 🔐 Login to Azure | |
| uses: azure/login@v1 | |
| with: | |
| creds: ${{ secrets.AZURE_CREDENTIALS }} | |
| - name: 🔄 Swap staging to production | |
| id: swap-slots | |
| run: | | |
| az webapp deployment slot swap \ | |
| --resource-group rg-az400-demo \ | |
| --name ${{ env.AZURE_WEBAPP_NAME }} \ | |
| --slot staging \ | |
| --target-slot production | |
| echo "webapp-url=https://${{ env.AZURE_WEBAPP_NAME }}.azurewebsites.net" >> $GITHUB_OUTPUT | |
| - name: 🏷️ Create release tag | |
| if: success() | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const tag = `v${context.runNumber}`; | |
| await github.rest.git.createRef({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| ref: `refs/tags/${tag}`, | |
| sha: context.sha | |
| }); | |
| console.log(`✅ Created tag: ${tag}`); | |
| - name: 📊 Monitor deployment | |
| run: | | |
| echo "Monitoring production deployment..." | |
| # Add Application Insights queries here | |
| echo "✅ Production deployment healthy!" | |
| # ======================================== | |
| # REUSABLE WORKFLOW: SECURITY SCAN | |
| # ======================================== | |
| security-scan: | |
| name: Security Scanning | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - name: 📥 Checkout code | |
| uses: actions/checkout@v4 | |
| - name: 🔍 Run CodeQL Analysis | |
| uses: github/codeql-action/analyze@v2 | |
| with: | |
| languages: javascript | |
| - name: 🛡️ Run Dependabot scan | |
| uses: github/super-linter@v5 | |
| env: | |
| DEFAULT_BRANCH: main | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| VALIDATE_JAVASCRIPT_ES: true | |
| VALIDATE_JSON: true | |
| VALIDATE_YAML: true |