[DRAFT] New Perseus Preview component #6712
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: Node CI | |
on: | |
workflow_dispatch: | |
pull_request: | |
# edited is needed because that's the trigger when the base branch is | |
# changed on a PR | |
# The rest are the defaults. | |
types: [edited, opened, synchronize, reopened] | |
# When a new revision is pushed to a PR, cancel all in-progress CI runs for that | |
# PR. See https://docs.github.com/en/actions/using-jobs/using-concurrency | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
cancel-in-progress: true | |
jobs: | |
changeset: | |
name: Check for .changeset entries for all changed files | |
if: github.actor != 'dependabot[bot]' && github.actor != 'dependabot-preview[bot]' | |
runs-on: ${{ matrix.os }} | |
strategy: | |
matrix: | |
os: [ubuntu-latest] | |
node-version: [20.x] | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Force Node version | |
uses: actions/setup-node@v4 | |
with: | |
node-version: ${{ matrix.node-version }} | |
cache: yarn | |
- name: Get changed files | |
uses: Khan/actions@get-changed-files-v2 | |
id: changed | |
- name: Filter out files that don't need a changeset | |
uses: Khan/actions@filter-files-v1 | |
id: match | |
with: | |
changed-files: ${{ steps.changed.outputs.files }} | |
files: "packages/, config/build/" # Only look for changes in packages, build | |
globs: "!(**/__tests__/*), !(**/__testdata__/*), !(**/__stories__/*), !(**/dist/*), !(**/*.test.ts), !(**/*.test.tsx)" # Ignore test files | |
matchAllGlobs: true # Default is to match any of the globs, which ends up matching all files | |
conjunctive: true # Only match files that match all of the above | |
- uses: webfactory/[email protected] | |
with: | |
ssh-private-key: ${{ secrets.KHAN_ACTIONS_BOT_SSH_PRIVATE_KEY }} | |
- name: Verify changeset entries | |
uses: Khan/[email protected] | |
with: | |
changed_files: ${{ steps.match.outputs.filtered }} | |
lint: | |
name: Lint, Typecheck, Format, and Test | |
runs-on: ${{ matrix.os }} | |
strategy: | |
matrix: | |
os: [ubuntu-latest] | |
node-version: [20.x] | |
steps: | |
- name: Checking out latest commit | |
uses: actions/checkout@v4 | |
- name: Install & cache node_modules | |
uses: ./.github/actions/shared-node-cache | |
with: | |
node-version: ${{ matrix.node-version }} | |
ssh-private-key: ${{ secrets.KHAN_ACTIONS_BOT_SSH_PRIVATE_KEY }} | |
- name: Get All Changed Files | |
uses: Khan/actions@get-changed-files-v2 | |
id: changed | |
- name: Check formatting | |
run: | | |
yarn -s prettier --check . | |
- id: js-files | |
name: Find .js(x)/.ts(x) changed files | |
uses: Khan/actions@filter-files-v1 | |
with: | |
changed-files: ${{ steps.changed.outputs.files }} | |
extensions: ".js,.jsx,.ts,.tsx" | |
files: "yarn.lock" | |
- id: eslint-reset | |
uses: Khan/actions@filter-files-v1 | |
name: Files that would trigger a full eslint run | |
with: | |
changed-files: ${{ steps.changed.outputs.files }} | |
files: ".eslintrc.js,package.json,yarn.lock,.eslintignore" | |
# Linting / type checking | |
- name: Eslint | |
uses: Khan/actions@full-or-limited-v0 | |
with: | |
full-trigger: ${{ steps.eslint-reset.outputs.filtered }} | |
full: yarn lint packages | |
limited-trigger: ${{ steps.js-files.outputs.filtered }} | |
limited: yarn lint {} | |
- name: Typecheck | |
if: (success() || failure()) && steps.js-files.outputs.filtered != '[]' | |
run: yarn typecheck | |
- name: Build types | |
if: (success() || failure()) && steps.js-files.outputs.filtered != '[]' | |
run: yarn build:types | |
# Run tests for our target matrix | |
- id: jest-reset | |
uses: Khan/actions@filter-files-v1 | |
name: Files that would trigger a full jest run | |
with: | |
changed-files: ${{ steps.changed.outputs.files }} | |
files: "jest.config.js,package.json,yarn.lock,test.config.js,test.transform.js" | |
- name: Jest | |
uses: Khan/actions@full-or-limited-v0 | |
with: | |
full-trigger: ${{ steps.jest-reset.outputs.filtered }} | |
full: yarn jest | |
limited-trigger: ${{ steps.js-files.outputs.filtered }} | |
limited: yarn jest --passWithNoTests --findRelatedTests {} | |
# We use STOPSHIP internally to mark code that's not safe to go live yet. | |
# We use an if block because we want to return the exact inverse of what | |
# `git grep` returns (0 on none found, 1 on some found). | |
- name: Checks that STOPSHIP is not used in any files. | |
run: ./utils/stopship-check.sh | |
cypress: | |
name: Cypress | |
runs-on: ${{ matrix.os }} | |
strategy: | |
matrix: | |
os: [ubuntu-latest] | |
node-version: [20.x] | |
steps: | |
- name: Checking out latest commit | |
uses: actions/checkout@v4 | |
- name: Install & cache node_modules | |
uses: ./.github/actions/shared-node-cache | |
with: | |
node-version: ${{ matrix.node-version }} | |
ssh-private-key: ${{ secrets.KHAN_ACTIONS_BOT_SSH_PRIVATE_KEY }} | |
- name: Run test with coverage | |
run: yarn cypress:ci | |
# Upload coverage report as an GitHub artifact so that it can be used | |
# later in upload_coverage. | |
- name: Upload Cypress Coverage | |
uses: actions/upload-artifact@v4 | |
with: | |
name: cypress-coverage | |
path: ./.nyc_output/out.json | |
- name: Upload Cypress Screenshots | |
uses: actions/upload-artifact@v4 | |
if: failure() | |
with: | |
name: cypress-screenshots | |
path: ./cypress/screenshots | |
coverage: | |
name: Jest Coverage | |
runs-on: ${{ matrix.os }} | |
strategy: | |
matrix: | |
os: [ubuntu-latest] | |
node-version: [20.x] | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Install & cache node_modules | |
uses: ./.github/actions/shared-node-cache | |
with: | |
node-version: ${{ matrix.node-version }} | |
ssh-private-key: ${{ secrets.KHAN_ACTIONS_BOT_SSH_PRIVATE_KEY }} | |
- name: Jest with coverage | |
run: yarn coverage | |
# Upload coverage report as an GitHub artifact so that it can be used | |
# later in upload_coverage. | |
- name: Upload Jest Coverage | |
uses: actions/upload-artifact@v4 | |
with: | |
name: jest-coverage | |
path: ./coverage/coverage-final.json | |
upload_coverage: | |
name: Upload Coverage | |
runs-on: ${{ matrix.os }} | |
strategy: | |
matrix: | |
os: [ubuntu-latest] | |
node-version: [20.x] | |
needs: [cypress, coverage] | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Install & cache node_modules | |
uses: ./.github/actions/shared-node-cache | |
with: | |
node-version: ${{ matrix.node-version }} | |
ssh-private-key: ${{ secrets.KHAN_ACTIONS_BOT_SSH_PRIVATE_KEY }} | |
- name: Download Jest Coverage | |
uses: actions/download-artifact@v4 | |
with: | |
name: jest-coverage | |
# path to decompress the artifact into, decompressed file | |
# will be ./coverage-final.json | |
path: ./ | |
- name: Download Cypress Coverage | |
uses: actions/download-artifact@v4 | |
with: | |
name: cypress-coverage | |
# path to decompress the artifact into, decompressed file | |
# will be ./out.json | |
path: ./ | |
# Upload both coverage files at once. This avoids issues where it Codecov | |
# shows the results from only one of the reports which would make it appear | |
# as though coverage dropped a lot. | |
- name: Upload Coverage | |
uses: codecov/codecov-action@v4 | |
with: | |
token: ${{ secrets.CODECOV_TOKEN }} | |
files: ./coverage-final.json,./out.json | |
check_builds: | |
name: Check builds for changes in size | |
runs-on: ${{ matrix.os }} | |
strategy: | |
matrix: | |
os: [ubuntu-latest] | |
node-version: [20.x] | |
steps: | |
- name: Checking out latest commit | |
uses: actions/checkout@v4 | |
- name: Install & cache node_modules | |
uses: ./.github/actions/shared-node-cache | |
with: | |
node-version: ${{ matrix.node-version }} | |
ssh-private-key: ${{ secrets.KHAN_ACTIONS_BOT_SSH_PRIVATE_KEY }} | |
# Make sure our packages aren't growing unexpectedly | |
# This must come last as it builds the old code last and so leaves the | |
# wrong code in place for the next job; in other words, it leaves the repo on a base branch. | |
- name: Check Builds | |
uses: preactjs/compressed-size-action@v2 | |
with: | |
# We only care about the ES module size, really: | |
pattern: "**/dist/es/*.js" | |
# Always ignore SourceMaps and node_modules: | |
exclude: "{**/*.map,**/node_modules/**}" | |
# Clean up before a build | |
clean-script: "clean" | |
# Build production | |
build-script: "build:prodsizecheck" | |
# | |
# Do not place any steps after "Check Builds" | |
# | |
publish_snapshot: | |
name: Publish npm snapshot | |
# We don't publish snapshots on draft PRs or | |
# on the main Changeset "Version Packages" PR | |
if: | | |
github.event.pull_request.draft == false | |
&& !startsWith(github.head_ref, 'changeset-release/') | |
runs-on: ${{ matrix.os }} | |
strategy: | |
matrix: | |
os: [ubuntu-latest] | |
node-version: [20.x] | |
steps: | |
# We need to checkout all history, so that the changeseat tool can diff it | |
- name: Checkout current commit | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: "0" | |
- name: Ensure main branch is available | |
run: | | |
REF=$(git rev-parse HEAD) | |
git checkout main | |
git checkout $REF | |
- name: Install & cache node_modules | |
uses: ./.github/actions/shared-node-cache | |
with: | |
node-version: ${{ matrix.node-version }} | |
ssh-private-key: ${{ secrets.KHAN_ACTIONS_BOT_SSH_PRIVATE_KEY }} | |
- name: Publish Snapshot Release to npm | |
id: publish-snapshot | |
run: ./utils/publish-snapshot.sh # All config is via Github env vars | |
env: | |
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
- name: Calculate short SHA for this commit | |
id: short-sha | |
# Why not GITHUB_SHA here? Because that is the last merge-commit | |
# for the PR (ie. the ephemeral commit that Github creates for | |
# each PR merging the base branch into the pull request HEAD) for | |
# Github Action runs). We want to reference the commit that was | |
# pushed, not this ephemeral commit. | |
run: echo "short_sha=$(echo ${{ github.event.pull_request.head.sha }} | cut -c1-8)" >> $GITHUB_OUTPUT | |
# Note: these two actions are locked to the latest version that were | |
# published when I created this yml file (just for security). | |
- name: Find existing comment | |
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e | |
id: find-comment | |
with: | |
issue-number: ${{ github.event.pull_request.number }} | |
comment-author: "github-actions[bot]" | |
body-includes: "npm Snapshot:" | |
- name: Create or update npm snapshot comment - success | |
if: steps.publish-snapshot.outputs.npm_snapshot_tag != '' | |
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 | |
with: | |
issue-number: ${{ github.event.pull_request.number }} | |
comment-id: ${{ steps.find-comment.outputs.comment-id }} | |
edit-mode: replace | |
body: | | |
# npm Snapshot: Published | |
Good news!! We've packaged up the latest commit from this PR (${{ | |
steps.short-sha.outputs.short_sha }}) and published it to npm. You | |
can install it using the tag `${{ | |
steps.publish-snapshot.outputs.npm_snapshot_tag }}`. | |
Example: | |
```sh | |
yarn add @khanacademy/perseus@${{ | |
steps.publish-snapshot.outputs.npm_snapshot_tag }} | |
``` | |
If you are working in Khan Academy's webapp, you can run: | |
```sh | |
./dev/tools/bump_perseus_version.sh -t PR${{ github.event.pull_request.number }} | |
``` | |
- name: Create or update npm snapshot comment - failure | |
if: steps.publish-snapshot.outputs.npm_snapshot_tag == '' | |
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 | |
with: | |
issue-number: ${{ github.event.pull_request.number }} | |
comment-id: ${{ steps.find-comment.outputs.comment-id }} | |
edit-mode: replace | |
body: | | |
# npm Snapshot: **NOT** Published | |
Oh noes!! We couldn't find any changesets in this PR (${{ | |
steps.short-sha.outputs.short_sha }}). As a result, we did not | |
publish an npm snapshot for you. |