feat: implement comprehensive environment configuration system #1
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: Nx Smart Deploy | ||
| on: | ||
| push: | ||
| branches: [main] | ||
| pull_request: | ||
| branches: [main] | ||
| workflow_dispatch: | ||
| inputs: | ||
| force_build_all: | ||
| description: 'Force build all projects' | ||
| required: false | ||
| default: 'false' | ||
| type: boolean | ||
| run_e2e: | ||
| description: 'Run e2e tests' | ||
| required: false | ||
| default: 'false' | ||
| type: boolean | ||
| env: | ||
| NX_CLOUD_DISTRIBUTED_EXECUTION: true | ||
| NX_CLOUD_DISTRIBUTED_EXECUTION_AGENT_COUNT: 3 | ||
| NX_BRANCH: ${{ github.event.number || github.ref_name }} | ||
| NX_RUN_GROUP: ${{ github.run_id }} | ||
| HUSKY: 0 | ||
| NODE_OPTIONS: --max-old-space-size=4096 | ||
| # Set DOCS_ENV for proper environment detection (main branch = production) | ||
| DOCS_ENV: ${{ | ||
| github.event_name == 'pull_request' && 'preview' || | ||
| 'production' | ||
| }} | ||
| # Fallback environment variables for sites that need them | ||
| SITE_TITLE: IFLA Standards Portal | ||
| SITE_TAGLINE: International Federation of Library Associations and Institutions | ||
| permissions: | ||
| contents: read | ||
| pages: write | ||
| id-token: write | ||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
| jobs: | ||
| setup: | ||
| name: Setup and Analysis | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| has-affected-projects: ${{ steps.affected.outputs.has-affected-projects }} | ||
| affected-projects: ${{ steps.affected.outputs.affected-projects }} | ||
| should-deploy: ${{ steps.should-deploy.outputs.should-deploy }} | ||
| should-run-e2e: ${{ steps.should-deploy.outputs.should-run-e2e }} | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Derive appropriate SHAs for base and head for `nx affected` commands | ||
| uses: nrwl/nx-set-shas@v4 | ||
| - name: Setup pnpm | ||
| uses: pnpm/action-setup@v4 | ||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '22' | ||
| cache: 'pnpm' | ||
| - name: Install dependencies | ||
| run: pnpm install --no-frozen-lockfile | ||
| - name: Check affected projects | ||
| id: affected | ||
| run: | | ||
| # Get affected projects for build target | ||
| affected=$(npx nx print-affected --select=projects --type=app 2>/dev/null || echo "") | ||
| if [ -n "$affected" ] && [ "$affected" != "" ]; then | ||
| echo "has-affected-projects=true" >> $GITHUB_OUTPUT | ||
| echo "affected-projects=$affected" >> $GITHUB_OUTPUT | ||
| echo "📦 Affected projects: $affected" | ||
| else | ||
| echo "has-affected-projects=false" >> $GITHUB_OUTPUT | ||
| echo "affected-projects=" >> $GITHUB_OUTPUT | ||
| echo "📦 No affected projects found" | ||
| fi | ||
| - name: Determine deployment and testing strategy | ||
| id: should-deploy | ||
| run: | | ||
| should_deploy="false" | ||
| should_run_e2e="false" | ||
| # Deploy on main branch pushes or manual trigger | ||
| if [[ "${{ github.ref }}" == "refs/heads/main" ]] || [[ "${{ github.event.inputs.force_build_all }}" == "true" ]]; then | ||
| should_deploy="true" | ||
| fi | ||
| # Run E2E on main, manual trigger, or if explicitly requested | ||
| if [[ "${{ github.ref }}" == "refs/heads/main" ]] || [[ "${{ github.event.inputs.run_e2e }}" == "true" ]]; then | ||
| should_run_e2e="true" | ||
| fi | ||
| echo "should-deploy=$should_deploy" >> $GITHUB_OUTPUT | ||
| echo "should-run-e2e=$should_run_e2e" >> $GITHUB_OUTPUT | ||
| echo "🚀 Should deploy: $should_deploy" | ||
| echo "🧪 Should run e2e: $should_run_e2e" | ||
| ci: | ||
| name: Nx Cloud - Main Job | ||
| runs-on: ubuntu-latest | ||
| needs: [setup] | ||
| if: needs.setup.outputs.has-affected-projects == 'true' || github.event.inputs.force_build_all == 'true' | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Derive appropriate SHAs for base and head for `nx affected` commands | ||
| uses: nrwl/nx-set-shas@v4 | ||
| - name: Setup pnpm | ||
| uses: pnpm/action-setup@v4 | ||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '22' | ||
| cache: 'pnpm' | ||
| - name: Install dependencies | ||
| run: pnpm install --no-frozen-lockfile | ||
| - name: Start CI run | ||
| run: 'npx nx-cloud start-ci-run --stop-agents-after="build" --agent-count=3' | ||
| - name: Run commands in parallel | ||
| run: | | ||
| pids=() | ||
| if [ "${{ github.event.inputs.force_build_all }}" == "true" ]; then | ||
| # Force build all projects | ||
| echo "🔄 Force building all projects" | ||
| npx nx run-many --target=typecheck --all --parallel=3 --ci --verbose & pids+=($!) | ||
| npx nx run-many --target=lint --all --parallel=3 --ci --verbose & pids+=($!) | ||
| npx nx run-many --target=test --all --parallel=3 --ci --verbose & pids+=($!) | ||
| npx nx run-many --target=build --all --parallel=3 --ci --verbose & pids+=($!) | ||
| else | ||
| # Run only affected | ||
| echo "🎯 Running affected projects only" | ||
| npx nx affected --target=typecheck --parallel=3 --ci --verbose & pids+=($!) | ||
| npx nx affected --target=lint --parallel=3 --ci --verbose & pids+=($!) | ||
| npx nx affected --target=test --parallel=3 --ci --verbose & pids+=($!) | ||
| npx nx affected --target=build --parallel=3 --ci --verbose & pids+=($!) | ||
| fi | ||
| # Wait for all jobs to complete | ||
| for pid in "${pids[@]}"; do | ||
| wait $pid | ||
| done | ||
| - name: Upload build artifacts | ||
| if: needs.setup.outputs.should-deploy == 'true' | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: build-artifacts | ||
| path: | | ||
| portal/build/ | ||
| standards/*/build/ | ||
| retention-days: 1 | ||
| - name: Stop all running agents for this CI run | ||
| if: always() | ||
| run: npx nx-cloud stop-all-agents | ||
| agents: | ||
| name: Nx Cloud - Agent ${{ matrix.agent }} | ||
| runs-on: ubuntu-latest | ||
| needs: [setup] | ||
| if: needs.setup.outputs.has-affected-projects == 'true' || github.event.inputs.force_build_all == 'true' | ||
| timeout-minutes: 60 | ||
| strategy: | ||
| matrix: | ||
| agent: [1, 2, 3] | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| - name: Setup pnpm | ||
| uses: pnpm/action-setup@v4 | ||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '22' | ||
| cache: 'pnpm' | ||
| - name: Install dependencies | ||
| run: pnpm install --no-frozen-lockfile | ||
| - name: Start Nx Agent ${{ matrix.agent }} | ||
| run: npx nx-cloud start-agent | ||
| env: | ||
| NX_AGENT_NAME: ${{ matrix.agent }} | ||
| e2e: | ||
| name: E2E Tests | ||
| runs-on: ubuntu-latest | ||
| needs: [setup, ci] | ||
| if: needs.setup.outputs.should-run-e2e == 'true' && (success() || failure()) | ||
| timeout-minutes: 30 | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| - name: Setup pnpm | ||
| uses: pnpm/action-setup@v4 | ||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '22' | ||
| cache: 'pnpm' | ||
| - name: Install dependencies | ||
| run: pnpm install --no-frozen-lockfile | ||
| - name: Install Playwright Browsers | ||
| run: npx playwright install --with-deps | ||
| - name: Download build artifacts | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: build-artifacts | ||
| path: ./ | ||
| continue-on-error: true | ||
| - name: Run Playwright tests | ||
| run: npx playwright test | ||
| env: | ||
| CI: true | ||
| - name: Upload test results | ||
| uses: actions/upload-artifact@v4 | ||
| if: always() | ||
| with: | ||
| name: e2e-test-results | ||
| path: | | ||
| test-results/ | ||
| playwright-report/ | ||
| retention-days: 7 | ||
| deploy: | ||
| name: Deploy to GitHub Pages | ||
| runs-on: ubuntu-latest | ||
| needs: [setup, ci, e2e] | ||
| if: always() && needs.setup.outputs.should-deploy == 'true' && (needs.ci.result == 'success' || needs.ci.result == 'skipped') | ||
| environment: | ||
| name: github-pages | ||
| url: ${{ steps.deployment.outputs.page_url }} | ||
| steps: | ||
| - name: Download build artifacts | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: build-artifacts | ||
| path: deployment/ | ||
| continue-on-error: true | ||
| - name: Create deployment structure | ||
| run: | | ||
| # Ensure we have a deployment directory | ||
| mkdir -p deployment | ||
| # Create standards index page | ||
| cat > deployment/standards.html << 'EOF' | ||
| <!DOCTYPE html> | ||
| <html> | ||
| <head> | ||
| <title>IFLA Standards</title> | ||
| <meta charset="utf-8"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | ||
| <style> | ||
| body { | ||
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | ||
| max-width: 800px; | ||
| margin: 0 auto; | ||
| padding: 2rem; | ||
| background: #f5f5f5; | ||
| } | ||
| .container { | ||
| background: white; | ||
| padding: 2rem; | ||
| border-radius: 8px; | ||
| box-shadow: 0 2px 4px rgba(0,0,0,0.1); | ||
| } | ||
| h1 { color: #333; margin-bottom: 0.5rem; } | ||
| .subtitle { color: #666; margin-bottom: 2rem; } | ||
| ul { list-style: none; padding: 0; } | ||
| li { margin: 1rem 0; } | ||
| a { | ||
| display: block; | ||
| padding: 1rem; | ||
| background: #f8f9fa; | ||
| color: #0066cc; | ||
| text-decoration: none; | ||
| border-radius: 4px; | ||
| border: 1px solid #e9ecef; | ||
| transition: all 0.2s; | ||
| } | ||
| a:hover { | ||
| background: #e9ecef; | ||
| border-color: #dee2e6; | ||
| transform: translateX(4px); | ||
| } | ||
| .standard-name { | ||
| font-weight: 600; | ||
| display: block; | ||
| margin-bottom: 0.25rem; | ||
| } | ||
| .standard-desc { | ||
| font-size: 0.875rem; | ||
| color: #666; | ||
| } | ||
| </style> | ||
| </head> | ||
| <body> | ||
| <div class="container"> | ||
| <h1>IFLA Standards Documentation</h1> | ||
| <p class="subtitle">International Federation of Library Associations and Institutions</p> | ||
| <ul> | ||
| <li><a href="./ISBDM/"><span class="standard-name">ISBDM</span><span class="standard-desc">International Standard Bibliographic Description for Manifestations</span></a></li> | ||
| <li><a href="./LRM/"><span class="standard-name">LRM</span><span class="standard-desc">Library Reference Model</span></a></li> | ||
| <li><a href="./FRBR/"><span class="standard-name">FRBR</span><span class="standard-desc">Functional Requirements for Bibliographic Records</span></a></li> | ||
| <li><a href="./isbd/"><span class="standard-name">ISBD</span><span class="standard-desc">International Standard Bibliographic Description</span></a></li> | ||
| <li><a href="./muldicat/"><span class="standard-name">MulDiCat</span><span class="standard-desc">Multilingual Dictionary of Cataloguing Terms</span></a></li> | ||
| <li><a href="./unimarc/"><span class="standard-name">UNIMARC</span><span class="standard-desc">Universal Machine-Readable Cataloguing</span></a></li> | ||
| </ul> | ||
| </div> | ||
| </body> | ||
| </html> | ||
| EOF | ||
| - name: Setup Pages | ||
| uses: actions/configure-pages@v5 | ||
| - name: Upload to GitHub Pages | ||
| uses: actions/upload-pages-artifact@v3 | ||
| with: | ||
| path: deployment | ||
| - name: Deploy to GitHub Pages | ||
| id: deployment | ||
| uses: actions/deploy-pages@v4 | ||