Skip to content

Add YAML pipeline examples for teaching CI/CD #1

Add YAML pipeline examples for teaching CI/CD

Add YAML pipeline examples for teaching CI/CD #1

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