DC-153 - Implement “Request replacement card” flow in self-service portal #707
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
| # State-based CI Workflow | |
| # Automatically discovers and builds for all configured states | |
| # Each state can specify Docker or native builds via config files | |
| name: State CI | |
| on: | |
| push: | |
| branches: ["main", "deploy/*"] | |
| pull_request: | |
| branches: ["main"] | |
| workflow_dispatch: | |
| inputs: | |
| state: | |
| description: "Specific state to build (leave empty for all)" | |
| required: false | |
| type: string | |
| jobs: | |
| discover-states: | |
| name: Discover States | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.set-matrix.outputs.matrix }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Discover state configurations | |
| id: set-matrix | |
| run: | | |
| BRANCH="${{ github.ref_name }}" | |
| # Priority 1: Manual workflow_dispatch with specific state | |
| if [ -n "${{ github.event.inputs.state }}" ]; then | |
| echo "Manual trigger for state: ${{ github.event.inputs.state }}" | |
| echo "matrix={\"state\":[\"${{ github.event.inputs.state }}\"]}" >> $GITHUB_OUTPUT | |
| # Priority 2: Branch name pattern (deploy/STATE or deploy/STATE-feature) | |
| elif [[ "$BRANCH" =~ ^deploy/([a-z]{2})(-.*)?$ ]]; then | |
| STATE="${BASH_REMATCH[1]}" | |
| echo "Branch-based trigger for state: $STATE" | |
| echo "matrix={\"state\":[\"$STATE\"]}" >> $GITHUB_OUTPUT | |
| # Priority 3: Default (main branch, feature branches, PRs) = all states | |
| else | |
| echo "Building all states (branch: $BRANCH)" | |
| STATES=$(find .github/config/states -name "*.yaml" ! -name "_template.yaml" -exec basename {} .yaml \; | jq -R -s -c 'split("\n")[:-1]') | |
| echo "matrix={\"state\":$STATES}" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Show discovered states | |
| run: | | |
| echo "Building for states: ${{ steps.set-matrix.outputs.matrix }}" | |
| build-and-test: | |
| name: ${{ matrix.state }} - Build & Test | |
| needs: discover-states | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: ${{ fromJson(needs.discover-states.outputs.matrix) }} | |
| fail-fast: false # Continue other states even if one fails | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install yq (YAML parser) | |
| run: | | |
| sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 | |
| sudo chmod +x /usr/local/bin/yq | |
| - name: Load state configuration | |
| id: config | |
| run: | | |
| CONFIG_FILE=".github/config/states/${{ matrix.state }}.yaml" | |
| if [ ! -f "$CONFIG_FILE" ]; then | |
| echo "Error: Configuration file not found: $CONFIG_FILE" | |
| exit 1 | |
| fi | |
| # Extract configuration values | |
| echo "use_docker=$(yq eval '.infrastructure.use_docker' $CONFIG_FILE)" >> $GITHUB_OUTPUT | |
| echo "node_version=$(yq eval '.versions.node' $CONFIG_FILE)" >> $GITHUB_OUTPUT | |
| echo "pnpm_version=$(yq eval '.versions.pnpm' $CONFIG_FILE)" >> $GITHUB_OUTPUT | |
| echo "dotnet_version=$(yq eval '.versions.dotnet' $CONFIG_FILE)" >> $GITHUB_OUTPUT | |
| echo "build_config=$(yq eval '.build.configuration' $CONFIG_FILE)" >> $GITHUB_OUTPUT | |
| echo "frontend_flags=$(yq eval '.build.frontend_flags' $CONFIG_FILE)" >> $GITHUB_OUTPUT | |
| echo "backend_flags=$(yq eval '.build.backend_flags' $CONFIG_FILE)" >> $GITHUB_OUTPUT | |
| echo "skip_tests=$(yq eval '.build.skip_tests' $CONFIG_FILE)" >> $GITHUB_OUTPUT | |
| - name: Show configuration | |
| run: | | |
| echo "State: ${{ matrix.state }}" | |
| echo "Use Docker: ${{ steps.config.outputs.use_docker }}" | |
| echo "Node: ${{ steps.config.outputs.node_version }}" | |
| echo "pnpm: ${{ steps.config.outputs.pnpm_version }}" | |
| echo ".NET: ${{ steps.config.outputs.dotnet_version }}" | |
| echo "Build Config: ${{ steps.config.outputs.build_config }}" | |
| - name: Determine state connector ref | |
| id: connector-ref | |
| run: | | |
| # Same-named branch as this run (PR head branch or push branch) | |
| BRANCH="${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }}" | |
| # Fallback when that branch does not exist in the state connector repo | |
| FALLBACK="${{ github.event_name == 'pull_request' && github.base_ref || 'main' }}" | |
| REPO_URL="https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository_owner }}/sebt-self-service-portal-state-connector.git" | |
| if git ls-remote --exit-code --heads "$REPO_URL" "refs/heads/${BRANCH}" 1>/dev/null 2>&1; then | |
| echo "ref=${BRANCH}" >> "$GITHUB_OUTPUT" | |
| echo "Using state connector branch: ${BRANCH}" | |
| else | |
| echo "ref=${FALLBACK}" >> "$GITHUB_OUTPUT" | |
| echo "Branch '${BRANCH}' not in state connector, using: ${FALLBACK}" | |
| fi | |
| - name: Checkout interfaces repo | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: codeforamerica/sebt-self-service-portal-state-connector | |
| ref: ${{ steps.connector-ref.outputs.ref }} | |
| path: state-connector | |
| # Docker Build Path | |
| - name: Build Backend (Docker) | |
| if: steps.config.outputs.use_docker == 'true' | |
| run: | | |
| docker run --rm \ | |
| -v ${{ github.workspace }}:/workspace \ | |
| -w /workspace \ | |
| mcr.microsoft.com/dotnet/sdk:${{ steps.config.outputs.dotnet_version }} \ | |
| bash -c "./.github/workflows/scripts/build-backend.sh --configuration ${{ steps.config.outputs.build_config }} ${{ steps.config.outputs.backend_flags }}" | |
| - name: Test Backend (Docker) | |
| if: steps.config.outputs.use_docker == 'true' && steps.config.outputs.skip_tests != 'true' | |
| timeout-minutes: 5 | |
| run: | | |
| docker run --rm \ | |
| -v ${{ github.workspace }}:/workspace \ | |
| -w /workspace \ | |
| -e SKIP_SQLSERVER_TESTS=1 \ | |
| mcr.microsoft.com/dotnet/sdk:${{ steps.config.outputs.dotnet_version }} \ | |
| bash -c "./.github/workflows/scripts/test-backend.sh --skip-build --configuration ${{ steps.config.outputs.build_config }}" | |
| - name: Build Frontend (Docker) | |
| if: steps.config.outputs.use_docker == 'true' | |
| run: | | |
| docker run --rm \ | |
| -v ${{ github.workspace }}:/workspace \ | |
| -w /workspace \ | |
| node:${{ steps.config.outputs.node_version }}-alpine \ | |
| sh -c "corepack enable && corepack prepare pnpm@${{ steps.config.outputs.pnpm_version }} --activate && sh .github/workflows/scripts/build-frontend.sh --production ${{ steps.config.outputs.frontend_flags }}" | |
| - name: Test Frontend (Docker) | |
| if: steps.config.outputs.use_docker == 'true' && steps.config.outputs.skip_tests != 'true' | |
| run: | | |
| docker run --rm \ | |
| -v ${{ github.workspace }}:/workspace \ | |
| -w /workspace \ | |
| node:${{ steps.config.outputs.node_version }}-alpine \ | |
| sh -c "corepack enable && corepack prepare pnpm@${{ steps.config.outputs.pnpm_version }} --activate && sh .github/workflows/scripts/test-frontend.sh --skip-install" | |
| # Native Build Path | |
| - name: Setup .NET (Native) | |
| if: steps.config.outputs.use_docker != 'true' | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ steps.config.outputs.dotnet_version }} | |
| - name: Setup pnpm (Native) | |
| if: steps.config.outputs.use_docker != 'true' | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: ${{ steps.config.outputs.pnpm_version }} | |
| - name: Setup Node.js (Native) | |
| if: steps.config.outputs.use_docker != 'true' | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ steps.config.outputs.node_version }} | |
| cache: "pnpm" | |
| - name: Build Backend (Native) | |
| if: steps.config.outputs.use_docker != 'true' | |
| run: ./.github/workflows/scripts/build-backend.sh --configuration ${{ steps.config.outputs.build_config }} ${{ steps.config.outputs.backend_flags }} | |
| - name: Test Backend (Native) | |
| if: steps.config.outputs.use_docker != 'true' && steps.config.outputs.skip_tests != 'true' | |
| timeout-minutes: 5 | |
| run: ./.github/workflows/scripts/test-backend.sh --skip-build --configuration ${{ steps.config.outputs.build_config }} | |
| - name: Generate Backend Dependencies CSV | |
| id: generate-backend-dependencies-csv | |
| if: steps.config.outputs.use_docker != 'true' | |
| run: ./.github/workflows/scripts/license-audit.sh | |
| - name: Build Frontend (Native) | |
| if: steps.config.outputs.use_docker != 'true' | |
| run: ./.github/workflows/scripts/build-frontend.sh --production ${{ steps.config.outputs.frontend_flags }} | |
| - name: Test Frontend (Native) | |
| if: steps.config.outputs.use_docker != 'true' && steps.config.outputs.skip_tests != 'true' | |
| run: ./.github/workflows/scripts/test-frontend.sh --skip-install | |
| # Upload artifacts | |
| - name: Upload build artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.state }}-build-artifacts | |
| path: | | |
| src/SEBT.Portal.Web/.next/standalone | |
| src/**/bin/${{ steps.config.outputs.build_config }} | |
| output/backend-dependencies.csv | |
| retention-days: 7 |