[16143] Implement Convert Step Updates #4012
This file contains 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: 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 |