add to docs #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: NPM Tests | ||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| env_vars: | ||
| required: false | ||
| type: string | ||
| default: "{}" | ||
| npm_build_command: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| pre_test_command: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| pull_ghcr: | ||
| required: false | ||
| type: boolean | ||
| default: false | ||
| docker_compose_file: | ||
| required: false | ||
| type: string | ||
| default: docker-compose.yml | ||
| node_version: | ||
| required: false | ||
| type: string | ||
| default: 24.x | ||
| tests: | ||
| required: false | ||
| type: string | ||
| default: '["test:unit", "test:integration"]' | ||
| coverage: | ||
| required: false | ||
| type: boolean | ||
| default: true | ||
| coverage_config_json: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| jobs: | ||
| setup: | ||
| permissions: | ||
| contents: read | ||
| name: Setup branch matrix | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| branches: ${{ steps.set-branches.outputs.branches }} | ||
| is-main: ${{ steps.check-branch.outputs.is-main }} | ||
| artifact-prefix: ${{ steps.set-prefix.outputs.prefix }} | ||
| steps: | ||
| - name: Check if running on main | ||
| id: check-branch | ||
| run: | | ||
| CURRENT_BRANCH="${{ github.head_ref || github.ref_name }}" | ||
| if [ "$CURRENT_BRANCH" = "main" ]; then | ||
| echo "is-main=true" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "is-main=false" >> $GITHUB_OUTPUT | ||
| fi | ||
| - name: Set branch matrix | ||
| id: set-branches | ||
| run: | | ||
| CURRENT_BRANCH="${{ github.head_ref || github.ref_name }}" | ||
| if [ "${{ inputs.coverage }}" = "false" ] || [ "$CURRENT_BRANCH" = "main" ]; then | ||
| BRANCHES="[\"$CURRENT_BRANCH\"]" | ||
| else | ||
| BRANCHES="[\"$CURRENT_BRANCH\", \"main\"]" | ||
| fi | ||
| echo "branches=$BRANCHES" >> "$GITHUB_OUTPUT" | ||
| - name: Generate artifact prefix | ||
| id: set-prefix | ||
| run: echo "prefix=$(uuidgen)" >> $GITHUB_OUTPUT | ||
| tests: | ||
| permissions: | ||
| contents: read | ||
| packages: read | ||
| name: Run tests - ${{ matrix.command }} - ${{ matrix.branch }} | ||
| needs: setup | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| command: ${{ fromJson(inputs.tests) }} | ||
| branch: ${{ fromJson(needs.setup.outputs.branches) }} | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| with: | ||
| ref: ${{ matrix.branch }} | ||
| - name: Set environment variables from JSON | ||
| env: | ||
| ENV_VARS_JSON: "${{ inputs.env_vars }}" | ||
| run: | | ||
| echo "Parsing JSON environment variables..." | ||
| echo "$ENV_VARS_JSON" | jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]' >> $GITHUB_ENV | ||
| - uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: ${{ inputs.node_version }} | ||
| - name: Cache Node.js modules | ||
| uses: actions/cache@v5 | ||
| with: | ||
| path: ~/.npm | ||
| key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} | ||
| restore-keys: | | ||
| ${{ runner.OS }}-node- | ||
| ${{ runner.OS }}- | ||
| - name: Install Packages | ||
| run: npm ci | ||
| - name: Build | ||
| run: ${{ inputs.npm_build_command }} | ||
| if: inputs.npm_build_command != '' | ||
| - name: Create environment file | ||
| run: touch .env | ||
| - name: Login to GitHub Container Registry | ||
| if: ${{ inputs.pull_ghcr == true }} | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Setup dependencies | ||
| run: docker compose -f ${{ inputs.docker_compose_file }} up -d --quiet-pull | ||
| if: inputs.docker_compose_file != '' | ||
| - name: Sleep | ||
| uses: kibertoad/wait-action@1.0.1 | ||
| with: | ||
| time: "30s" | ||
| if: inputs.docker_compose_file != '' | ||
| - name: Run pre-test command | ||
| run: ${{ inputs.pre_test_command }} | ||
| if: inputs.pre_test_command != '' | ||
| - name: Run tests with coverage | ||
| run: npx c8 --temp-directory coverage/tmp npm run ${{ matrix.command }} | ||
| if: inputs.coverage | ||
| - name: Run tests without coverage | ||
| run: npm run ${{ matrix.command }} | ||
| if: ${{ !inputs.coverage }} | ||
| - name: Set artifact name | ||
| id: artifact-name | ||
| run: | | ||
| COMMAND_SAFE=$(echo "${{ matrix.command }}" | sed 's/[:\";<>|*?\/\\ \r\n]/-/g') | ||
| if [ "${{ needs.setup.outputs.is-main }}" = "true" ]; then | ||
| echo "name=${{ needs.setup.outputs.artifact-prefix }}-coverage-current-$COMMAND_SAFE" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "name=${{ needs.setup.outputs.artifact-prefix }}-coverage-${{ matrix.branch == 'main' && 'main' || 'current' }}-$COMMAND_SAFE" >> $GITHUB_OUTPUT | ||
| fi | ||
| if: inputs.coverage | ||
| - name: Upload coverage JSON summary | ||
| uses: actions/upload-artifact@v6 | ||
| with: | ||
| name: ${{ steps.artifact-name.outputs.name }} | ||
| path: coverage/tmp | ||
| if: inputs.coverage | ||
| coverage: | ||
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
| name: Coverage | ||
| runs-on: ubuntu-latest | ||
| needs: [tests, setup] | ||
| if: inputs.coverage | ||
| env: | ||
| COVERAGE_CURRENT_DIR: coverage | ||
| COVERAGE_MAIN_DIR: coverage-main | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| - uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: ${{ inputs.node_version }} | ||
| - name: Setup c8 config | ||
| run: | | ||
| if [ -n "${{ inputs.coverage_config_json }}" ]; then | ||
| echo "Copying repo config '${{ inputs.coverage_config_json }}' to .c8rc.workflow.json" | ||
| cp ${{ inputs.coverage_config_json }} .c8rc.workflow.json | ||
| else | ||
| echo "Using default .c8rc.workflow.json" | ||
| cat > .c8rc.workflow.json << 'EOF' | ||
| { | ||
| "lines": 50, | ||
| "branches": 0, | ||
| "functions": 0, | ||
| "statements": 0, | ||
| "exclude": [ | ||
| "coverage/**", | ||
| "packages/*/test{,s}/**", | ||
| "**/*.d.ts", | ||
| "test{,s}/**", | ||
| "test{,-*}.js", | ||
| "**/*{.,-}test.js", | ||
| "**/__tests__/**", | ||
| "**/node_modules/**", | ||
| "**/babel.config.js", | ||
| "**/*.tsx" | ||
| ] | ||
| } | ||
| EOF | ||
| fi | ||
| - name: Download current branch coverage summaries | ||
| uses: actions/download-artifact@v7 | ||
| with: | ||
| path: ${{ env.COVERAGE_CURRENT_DIR }}/tmp | ||
| pattern: ${{ needs.setup.outputs.artifact-prefix }}-coverage-current-* | ||
| merge-multiple: true | ||
| - name: Download main branch coverage summaries | ||
| uses: actions/download-artifact@v7 | ||
| with: | ||
| path: ${{ env.COVERAGE_MAIN_DIR }}/tmp | ||
| pattern: ${{ needs.setup.outputs.artifact-prefix }}-coverage-main-* | ||
| merge-multiple: true | ||
| if: needs.setup.outputs.is-main == 'false' | ||
| - name: Generate reports | ||
| run: npx c8 --config .c8rc.workflow.json --temp-directory ${{ env.COVERAGE_CURRENT_DIR }}/tmp --reports-dir ${{ env.COVERAGE_CURRENT_DIR }} report --reporter=html --reporter=json-summary --reporter=json | ||
| - name: Generate main branch reports | ||
| if: needs.setup.outputs.is-main == 'false' | ||
| run: npx c8 --config .c8rc.workflow.json --temp-directory ${{ env.COVERAGE_MAIN_DIR }}/tmp --reports-dir ${{ env.COVERAGE_MAIN_DIR }} report --reporter=json-summary --reporter=json | ||
| - name: Setup vite config if none exists | ||
| run: | | ||
| if ! compgen -G "{vite,vitest}.config.{ts,mts,cts,js,mjs,cjs}" > /dev/null; then | ||
| echo "No vite config found, creating minimal vite.config.js" | ||
| echo "export default {}" > vite.config.js | ||
| else | ||
| echo "Vite config found" | ||
| fi | ||
| - name: Pretty coverage summary | ||
| uses: davelosert/vitest-coverage-report-action@v2 | ||
| with: | ||
| file-coverage-mode: all | ||
| json-summary-compare-path: ${{ needs.setup.outputs.is-main == 'false' && format('{0}/coverage-summary.json', env.COVERAGE_MAIN_DIR) || '' }} | ||
| - name: Upload reports for current branch | ||
| uses: actions/upload-artifact@v6 | ||
| with: | ||
| name: ${{ needs.setup.outputs.artifact-prefix }}-coverage-current-all | ||
| path: | | ||
| ${{ env.COVERAGE_CURRENT_DIR }}/** | ||
| !${{ env.COVERAGE_CURRENT_DIR }}/tmp/** | ||
| - name: Fail if under thresholds | ||
| run: npx c8 --config .c8rc.workflow.json --temp-directory ${{ env.COVERAGE_CURRENT_DIR }}/tmp check-coverage | ||