Skip to content

[16143] Implement Convert Step Updates #4012

[16143] Implement Convert Step Updates

[16143] Implement Convert Step Updates #4012

Workflow file for this run

name: Frontend CI
on: pull_request
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
defaults:
run:
working-directory: frontend-react
shell: bash
env:
TEST_ADMIN_USERNAME: ${{ secrets.TEST_ADMIN_USERNAME }}
TEST_ADMIN_PASSWORD: ${{ secrets.TEST_ADMIN_PASSWORD }}
TEST_SENDER_USERNAME: ${{ secrets.TEST_SENDER_USERNAME }}
TEST_SENDER_PASSWORD: ${{ secrets.TEST_SENDER_PASSWORD }}
TEST_RECEIVER_USERNAME: ${{ secrets.TEST_RECEIVER_USERNAME }}
TEST_RECEIVER_PASSWORD: ${{ secrets.TEST_RECEIVER_PASSWORD }}
LOCAL_SITEMAP_URL: "http://localhost:3000/sitemap.xml"
jobs:
pre-job:
name: Pre Job
runs-on: ubuntu-latest
outputs:
# Should not run for deployment PRs
is_permitted: ${{ github.event_name == 'pull_request' && steps.build_vars.outputs.has_frontend_change == 'true' && steps.build_vars.outputs.is_deployment_pr == 'false' }}
steps:
- name: "Check out changes"
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
- name: Build vars
id: build_vars
uses: ./.github/actions/build-vars
lint:
name: Lint
needs: pre-job
if: needs.pre-job.outputs.is_permitted == 'true'
runs-on: ubuntu-latest
steps:
- name: Check out changes
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
- name: Use Node.js with yarn
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6
with:
node-version-file: frontend-react/.nvmrc
cache: yarn
cache-dependency-path: frontend-react/yarn.lock
- name: Yarn install
run: yarn install --immutable
- name: Run linting
run: yarn run lint
pa11y:
name: Run Pa11y 508 Compliance Check
needs: lint
runs-on: ubuntu-20.04 # pinned to this version due to: https://github.com/pa11y/pa11y-ci/issues/198
steps:
- name: Check out changes
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
- name: Use Node.js with yarn
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6
with:
node-version-file: frontend-react/.nvmrc
cache: yarn
cache-dependency-path: frontend-react/yarn.lock
- name: Yarn install
run: yarn install --immutable
- name: Run Frontend Server
run: |
yarn run dev --host 0.0.0.0 --port 3000 &
echo $! > server.pid
sleep 5 # Wait for the server to start up
echo
echo "Checking for sitemap on localhost:3000"
if ! curl -s ${{ env.LOCAL_SITEMAP_URL }}; then
echo "❌ Server failed to start or sitemap not present"
exit 1
else
echo "✅ Server started successfully"
fi
- name: Install Pa11y
run: |
echo "Installing google-chrome-stable"
sudo apt-get update && sudo apt-get install -y google-chrome-stable jq
which google-chrome-stable || echo "google-chrome-stable not found"
echo "Installing Pa11y"
npm install -g \
[email protected] \
[email protected] \
--no-save
- name: Run Pa11y Check # Pa11y is configured in frontend-react/.pa11yci
run: |
SITEMAP_URL="${{ env.LOCAL_SITEMAP_URL }}"
echo "Local Sitemap URL: $SITEMAP_URL"
echo "Checking Pa11y is installed and accessible"
pa11y --version
if [ $? -ne 0 ]; then
echo "❌ Pa11y installation failed"
exit 1
else
echo "Running sitemap check - curl on localhost:3000"
if ! curl -s "$SITEMAP_URL"; then
echo "❌ Server failed to start or sitemap not accessible"
exit 1
else
echo "✅ Server appears to be running"
echo "Extracting URLs from sitemap"
# Download the sitemap.xml content
curl -s "$SITEMAP_URL" -o sitemap.xml
# Check if download was successful
if [ ! -s sitemap.xml ]; then
echo "❌ Failed to download sitemap or file is empty."
exit 1
fi
# Extract URLs and save them to sitemap_urls.txt
#Linux grep flags: -P for Perl-compatible regex, -o for only matching part, -P for non-greedy matching
grep -oP '(?<=<loc>).*?(?=</loc>)' sitemap.xml | sed "s|https://reportstream.cdc.gov|http://localhost:3000|g" > sitemap_urls.txt
# OSX
# grep "<loc>" sitemap.xml | sed -E 's/.*<loc>(.*)<\/loc>.*/\1/'| sed "s|https://reportstream.cdc.gov|http://localhost:3000|g" > sitemap_urls.txt
# Check if URLs were extracted successfully
if [ -s sitemap_urls.txt ]; then
echo "✅ URLs extracted successfully:"
cat sitemap_urls.txt
echo "Running Pa11y WCAG2AA checks on sitemap URLs"
for f in `cat sitemap_urls.txt`;do pa11y -c ./pa11y.json -e htmlcs -e axe -d -s WCAG2AA $f ;done
echo "Pa11y WCAG2AA checks complete"
else
echo "❌ No URLs found in sitemap.xml."
exit 1
fi
# Clean up
rm sitemap.xml sitemap_urls.txt
fi
fi
- name: Stop Frontend Server
run: |
echo "Stopping Frontend Server"
kill $(cat server.pid)
unit_tests:
name: Unit tests
needs: lint
runs-on: ubuntu-latest
steps:
- name: Check out changes
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
- name: Use Node.js with yarn
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6
with:
node-version-file: "frontend-react/.nvmrc"
cache: yarn
cache-dependency-path: frontend-react/yarn.lock
- name: Yarn install
run: yarn install --immutable
- name: Unit tests
run: yarn run test:ci
e2e_tests:
name: E2E tests
needs: lint
runs-on: ubuntu-latest
# Keep shards under 10 minutes
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4, 5, 6]
shardTotal: [6]
steps:
- name: Add swapfile
working-directory: /
run: |
sudo swapoff -a
sudo fallocate -l 15G /mnt/swapfile
sudo chmod 600 /mnt/swapfile
sudo mkswap /mnt/swapfile
sudo swapon /mnt/swapfile
sudo swapon --show
- name: Check out changes
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
- name: Use Node.js with yarn
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6
with:
node-version-file: "frontend-react/.nvmrc"
cache: yarn
cache-dependency-path: frontend-react/yarn.lock
- name: Yarn install
run: yarn install --immutable
- name: Install Playwright
run: npx playwright install --with-deps
- name: Run E2E tests
run: yarn run test:e2e --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- name: Upload blob report to GitHub Actions Artifacts
if: ${{ !cancelled() }}
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874
with:
name: frontend-e2e-data--shard-${{ matrix.shardIndex }}
path: frontend-react/e2e-data
retention-days: 1
# the e2e_tests job doesn't properly reflect being skipped when set as required on the repo.
# this step will always run and provide a status
e2e_tests_result:
if: ${{ always() }}
runs-on: ubuntu-latest
name: E2E Tests Result
needs: [e2e_tests]
steps:
- run: |
result="${{ needs.e2e_tests.result }}"
if [[ $result == "success" || $result == "skipped" ]]; then
exit 0
else
exit 1
fi
working-directory: /
# Merge reports after e2e-tests, even if some shards have failed
merge_e2e_data:
name: Merge E2E Data
needs: [pre-job, e2e_tests]
if: ${{ !cancelled() && needs.pre-job.outputs.is_permitted == 'true' && needs.e2e_tests.result == 'success' }}
runs-on: ubuntu-latest
env:
COMMENT:
WARNING_LOG_FILE: e2e-data/frontend-warnings.json
steps:
- name: Check out changes
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
- name: Use Node.js with yarn
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6
with:
node-version-file: "frontend-react/.nvmrc"
cache: yarn
cache-dependency-path: frontend-react/yarn.lock
- name: Download blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16
with:
path: frontend-react/e2e-data
pattern: frontend-e2e-data--shard-*
merge-multiple: true
- name: Merge reports
run: npx playwright merge-reports --reporter html,github ./e2e-data/report
# merge-reports command has no cli option to change default output dir (playwright-report),
# so merge it into the e2e-data/report manually and do clean up before uploading
- name: Merge folders
run: mv ./playwright-report/* ./e2e-data/report && rmdir ./playwright-report && rm ./e2e-data/report/*.zip && rm -rf ./e2e-data/report/resources
- name: Upload final e2e-data
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874
with:
name: frontend-e2e-data--attempt-${{ github.run_attempt }}
path: frontend-react/e2e-data
retention-days: 7
- name: Find Previous Warnings Comment
id: comment_find
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: "github-actions[bot]"
body-regex: '⚠️ Broken Links ⚠️'
- name: Delete Previous Warnings Comment
if: ${{ steps.comment_find.outputs.comment-id != '' }}
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: ${{ steps.comment_find.outputs.comment-id }},
})
- name: Set Broken Links Comment
if: github.event.sender.login != 'dependabot[bot]'
id: set-comment
run: |
if [ -f "$WARNING_LOG_FILE" ]; then
COMMENT="## ⚠️ Broken Links ⚠️\n\n"
while IFS= read -r row; do
URL=$(echo $row | jq -r '.url')
ERROR=$(echo $row | jq -r '.message')
COMMENT="${COMMENT}❌ $URL\n\n**Error:** \`$ERROR\`\n\n---\n\n"
done < <(jq -c '.[]' "$WARNING_LOG_FILE")
fi
echo "COMMENT<<EOF" >> $GITHUB_ENV
echo -e "$COMMENT" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
shell: bash
- name: Create New Comment
if: ${{ env.COMMENT != '' }}
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043
with:
issue-number: ${{ github.event.pull_request.number }}
body: ${{ env.COMMENT }}
chromatic:
name: Chromatic Analysis
# remove this if statement whenever dependabot has access to secrets
if: github.event.sender.login != 'dependabot[bot]'
needs: lint
runs-on: ubuntu-latest
steps:
- name: Checkout - On Pull Request
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
with:
fetch-depth: 0
# By default the pull_request event will run on a ephermeral merge commit which simulates a merge between the pull request
# and the target branch. This can cause issues with Chromatic https://www.chromatic.com/docs/turbosnap#github-pullrequest-triggers
# Hopefully by checking out the HEAD commit of a PR instead of the merge commit we can avoid some of those issues.
ref: ${{ github.event.pull_request.head.sha }}
- name: Use Node.js with yarn
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6
with:
node-version-file: "frontend-react/.nvmrc"
cache: yarn
cache-dependency-path: frontend-react/yarn.lock
- name: Yarn install
run: yarn install --immutable
- name: Run Chromatic
id: chromatic
uses: chromaui/action@f4e60a7072abcac4203f4ca50613f28e199a52ba
with:
workingDir: frontend-react
token: ${{ secrets.GITHUB_TOKEN }}
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
ignoreLastBuildOnBranch: true
onlyChanged: true
exitZeroOnChanges: true
exitOnceUploaded: true
- name: Find Previous Comment
id: comment_find
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: "github-actions[bot]"
body-regex: '\.*deployed to Chromatic.*\gi'
- name: Delete Previous Comment
if: ${{ steps.comment_find.outputs.comment-id }}
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
github.rest.issues.deleteComment({
comment_id: ${{ steps.comment_find.outputs.comment-id }},
owner: context.repo.owner,
repo: context.repo.repo,
})
- name: Create New Comment
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043
with:
issue-number: ${{ github.event.pull_request.number }}
body: |
Branch deployed to Chromatic 🚀.
- ${{ steps.chromatic.outputs.changeCount && format('⚠️ Detected {0} tests with visual changes.', steps.chromatic.outputs.changeCount) }}
- ${{ steps.chromatic.outputs.errorCount > 0 && format('❌ {0} tests failed!', steps.chromatic.outputs.errorCount) || '✅ All tests passed.' }}
View via:
- Chromatic: ${{ steps.chromatic.outputs.url }}
- Storybook: ${{ steps.chromatic.outputs.storybookUrl }}
# codeql:
# name: CodeQL Analysis
# needs: lint
# if: github.actor != 'dependabot[bot]'
# runs-on: ubuntu-latest
# permissions:
# actions: read
# contents: read
# security-events: write
# steps:
# - name: Check out changes
# uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
# - name: Initialize CodeQL
# uses: github/codeql-action/init@65c74964a9ed8c44ed9f19d4bbc5757a6a8e9ab9
# with:
# languages: javascript
# source-root: frontend-react
# - name: Perform CodeQL Analysis
# uses: github/codeql-action/analyze@65c74964a9ed8c44ed9f19d4bbc5757a6a8e9ab9
# with:
# category: /language:javascript,typescript
# sonarcloud:
# name: SonarCloud Analysis
# needs: lint
# if: github.actor != 'dependabot[bot]'
# runs-on: ubuntu-latest
# steps:
# - name: Check out changes
# uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
# with:
# fetch-depth: 0
# - name: Use Node.js with yarn
# uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6
# with:
# node-version-file: "frontend-react/.nvmrc"
# cache: yarn
# cache-dependency-path: frontend-react/yarn.lock
# - name: Yarn install
# run: yarn install --immutable
# - name: Collect coverage
# run: yarn run test:ci
# - name: Run SonarCloud Scan
# run: >
# npx sonarqube-scanner
# -Dsonar.host.url=https://sonarcloud.io
# -Dsonar.projectBaseDir=../
# -Dsonar.token="${{ secrets.SONAR_TOKEN }}"
# -Dsonar.coverage.exclusions=prime-router/**,frontend-react/**/__mocks__/**,frontend-react/**/mocks/**,frontend-react/**/*.test.*,frontend-react/**/*.stories.*
# -Dsonar.cpd.exclusions=prime-router/**,frontend-react/**/*.test.*,frontend-react/**/*.stories.*
# -Dsonar.sources=frontend-react/src,prime-router/src
# -Dsonar.exclusions=prime-router/src/**/*
# -Dsonar.projectKey=CDCgov_prime-data-hub
# -Dsonar.organization=cdcgov
# -Dsonar.javascript.lcov.reportPaths=frontend-react/coverage/lcov.info
# snyk:
# name: Snyk Analysis
# needs: lint
# runs-on: ubuntu-latest
# steps:
# - name: Check out changes
# uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
# - name: Use Node.js with yarn
# uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6
# with:
# node-version-file: "frontend-react/.nvmrc"
# cache: yarn
# cache-dependency-path: frontend-react/yarn.lock
# - name: Yarn install
# run: yarn install --immutable
# - name: Check for dependency vulnerabilities
# uses: snyk/actions/node@b98d498629f1c368650224d6d212bf7dfa89e4bf
# continue-on-error: true # To make sure that SARIF upload gets called
# env:
# SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
# with:
# args: ./frontend-react --sarif-file-output=frontend-react/sarif/snyk-dependencies.sarif --org=prime-reportstream
# - name: Check for code vulnerabilities
# uses: snyk/actions/node@b98d498629f1c368650224d6d212bf7dfa89e4bf
# continue-on-error: true # To make sure that SARIF upload gets called
# env:
# SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
# with:
# command: code test
# args: ./frontend-react --sarif-file-output=frontend-react/sarif/snyk-code.sarif --org=prime-reportstream
# - name: Upload result to GitHub Code Scanning
# uses: github/codeql-action/upload-sarif@65c74964a9ed8c44ed9f19d4bbc5757a6a8e9ab9
# with:
# sarif_file: frontend-react/sarif