Implement delivering client assets for custom elements in shared questions #36021
Workflow file for this run
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: CI | |
on: | |
push: | |
branches: | |
- master | |
pull_request: | |
merge_group: | |
concurrency: | |
# Ensure that we only run one concurrent job for Pull Requests. This ensures | |
# that someone can't kill our throughput by pushing a bunch of commits to a | |
# single branch in rapid succession. | |
# | |
# However, for master builds, we allow maximum concurrency. This is achieved | |
# because `github.head_ref` isn't defined there, and `github.run_id` is | |
# globally unique in this repo. | |
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | |
cancel-in-progress: true | |
env: | |
COMMIT_SHA: ${{ github.event.pull_request.head.sha || github.sha }} | |
jobs: | |
build-workspace-images: | |
runs-on: ubuntu-latest | |
env: | |
# Secrets aren't accessible for PRs coming from forks, and we also can't | |
# check secrets in an `if` conditional, so we check for the presence of | |
# the secret here and use this value in conditionals below. | |
CAN_PUSH_IMAGE: ${{ secrets.DOCKERHUB_USERNAME != '' }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
# We need the whole history so we can diff against `master` to determine | |
# what images need to be built. | |
fetch-depth: 0 | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v3 # https://github.com/marketplace/actions/docker-setup-qemu | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 # https://github.com/marketplace/actions/docker-setup-buildx | |
- name: Login to DockerHub | |
if: ${{ env.CAN_PUSH_IMAGE == 'true' }} | |
uses: docker/login-action@v3 # https://github.com/marketplace/actions/docker-login | |
with: | |
username: ${{ secrets.DOCKERHUB_USERNAME }} | |
password: ${{ secrets.DOCKERHUB_TOKEN }} | |
###################################################################################################### | |
# prairielearn/workspace-desktop | |
- name: Check whether workspaces/desktop was modified | |
run: tools/check_path_modified.sh workspaces/desktop workspaces_desktop_modified | |
- name: Build and push prairielearn/workspace-desktop | |
if: ${{ env.workspaces_desktop_modified }} | |
uses: docker/build-push-action@v5 # https://github.com/marketplace/actions/build-and-push-docker-images | |
with: | |
context: workspaces/desktop | |
platforms: linux/amd64,linux/arm64 | |
push: ${{ env.CAN_PUSH_IMAGE == 'true' }} | |
no-cache: true | |
tags: prairielearn/workspace-desktop:${{ env.COMMIT_SHA }} | |
###################################################################################################### | |
# prairielearn/workspace-jupyterlab | |
- name: Check whether workspaces/jupyterlab was modified | |
run: tools/check_path_modified.sh workspaces/jupyterlab workspaces_jupyterlab_modified | |
- name: Build and push prairielearn/workspace-jupyterlab | |
if: ${{ env.workspaces_jupyterlab_modified }} | |
uses: docker/build-push-action@v5 # https://github.com/marketplace/actions/build-and-push-docker-images | |
with: | |
context: workspaces/jupyterlab | |
platforms: linux/amd64,linux/arm64 | |
push: ${{ env.CAN_PUSH_IMAGE == 'true' }} | |
no-cache: true | |
tags: prairielearn/workspace-jupyterlab:${{ env.COMMIT_SHA }} | |
###################################################################################################### | |
# prairielearn/workspace-jupyterlab-python | |
- name: Check whether workspaces/jupyterlab-python was modified | |
run: tools/check_path_modified.sh workspaces/jupyterlab-python workspaces_jupyterlab_python_modified | |
- name: Build and push prairielearn/workspace-jupyterlab-python | |
if: ${{ env.workspaces_jupyterlab_python_modified }} | |
uses: docker/build-push-action@v5 # https://github.com/marketplace/actions/build-and-push-docker-images | |
with: | |
context: workspaces/jupyterlab-python | |
platforms: linux/amd64,linux/arm64 | |
push: ${{ env.CAN_PUSH_IMAGE == 'true' }} | |
no-cache: true | |
tags: prairielearn/workspace-jupyterlab-python:${{ env.COMMIT_SHA }} | |
###################################################################################################### | |
# prairielearn/workspace-rstudio | |
- name: Check whether workspaces/rstudio was modified | |
run: tools/check_path_modified.sh workspaces/rstudio workspaces_rstudio_modified | |
- name: Build and push prairielearn/workspace-rstudio | |
if: ${{ env.workspaces_rstudio_modified }} | |
uses: docker/build-push-action@v5 # https://github.com/marketplace/actions/build-and-push-docker-images | |
with: | |
context: workspaces/rstudio | |
platforms: linux/amd64,linux/arm64 | |
push: ${{ env.CAN_PUSH_IMAGE == 'true' }} | |
no-cache: true | |
tags: prairielearn/workspace-rstudio:${{ env.COMMIT_SHA }} | |
###################################################################################################### | |
# prairielearn/workspace-xtermjs | |
- name: Check whether workspaces/xtermjs was modified | |
run: tools/check_path_modified.sh workspaces/xtermjs workspaces_xtermjs_modified | |
- name: Build and push prairielearn/workspace-xtermjs | |
if: ${{ env.workspaces_xtermjs_modified }} | |
uses: docker/build-push-action@v5 # https://github.com/marketplace/actions/build-and-push-docker-images | |
with: | |
context: workspaces/xtermjs | |
platforms: linux/amd64,linux/arm64 | |
push: ${{ env.CAN_PUSH_IMAGE == 'true' }} | |
no-cache: true | |
tags: prairielearn/workspace-xtermjs:${{ env.COMMIT_SHA }} | |
build-grader-images: | |
runs-on: ubuntu-latest | |
env: | |
# Secrets aren't accessible for PRs coming from forks, and we also can't | |
# check secrets in an `if` conditional, so we check for the presence of | |
# the secret here and use this value in conditionals below. | |
CAN_PUSH_IMAGE: ${{ secrets.DOCKERHUB_USERNAME != '' }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
# We need the whole history so we can diff against `master` to determine | |
# what images need to be built. | |
fetch-depth: 0 | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v3 # https://github.com/marketplace/actions/docker-setup-qemu | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 # https://github.com/marketplace/actions/docker-setup-buildx | |
- name: Login to DockerHub | |
if: ${{ env.CAN_PUSH_IMAGE == 'true' }} | |
uses: docker/login-action@v3 # https://github.com/marketplace/actions/docker-login | |
with: | |
username: ${{ secrets.DOCKERHUB_USERNAME }} | |
password: ${{ secrets.DOCKERHUB_TOKEN }} | |
###################################################################################################### | |
# grader-c | |
- name: Check whether graders/c was modified | |
run: tools/check_path_modified.sh graders/c graders_c_modified | |
- name: Build and push prairielearn/grader-c | |
if: ${{ env.graders_c_modified }} | |
uses: docker/build-push-action@v5 # https://github.com/marketplace/actions/build-and-push-docker-images | |
with: | |
context: graders/c | |
platforms: linux/amd64,linux/arm64 | |
push: ${{ env.CAN_PUSH_IMAGE == 'true' }} | |
no-cache: true | |
tags: prairielearn/grader-c:${{ env.COMMIT_SHA }} | |
###################################################################################################### | |
# grader-java | |
- name: Check whether graders/java was modified | |
run: tools/check_path_modified.sh graders/java graders_java_modified | |
- name: Build and push prairielearn/grader-java | |
if: ${{ env.graders_java_modified }} | |
uses: docker/build-push-action@v5 # https://github.com/marketplace/actions/build-and-push-docker-images | |
with: | |
context: graders/java | |
platforms: linux/amd64,linux/arm64 | |
push: ${{ env.CAN_PUSH_IMAGE == 'true' }} | |
no-cache: true | |
tags: prairielearn/grader-java:${{ env.COMMIT_SHA }} | |
###################################################################################################### | |
# grader-python | |
- name: Check whether graders/python was modified | |
run: tools/check_path_modified.sh graders/python graders_python_modified | |
- name: Build and push prairielearn/grader-python | |
if: ${{ env.graders_python_modified }} | |
uses: docker/build-push-action@v5 # https://github.com/marketplace/actions/build-and-push-docker-images | |
with: | |
context: graders/python | |
platforms: linux/amd64,linux/arm64 | |
push: ${{ env.CAN_PUSH_IMAGE == 'true' }} | |
no-cache: true | |
tags: prairielearn/grader-python:${{ env.COMMIT_SHA }} | |
###################################################################################################### | |
# grader-r | |
- name: Check whether graders/r was modified | |
run: tools/check_path_modified.sh graders/r graders_r_modified | |
- name: Build and push prairielearn/grader-r | |
if: ${{ env.graders_r_modified }} | |
uses: docker/build-push-action@v5 # https://github.com/marketplace/actions/build-and-push-docker-images | |
with: | |
context: graders/r | |
platforms: linux/amd64,linux/arm64 | |
push: ${{ env.CAN_PUSH_IMAGE == 'true' }} | |
no-cache: true | |
tags: prairielearn/grader-r:${{ env.COMMIT_SHA }} | |
build-core-images: | |
runs-on: ubuntu-latest | |
env: | |
# Secrets aren't accessible for PRs coming from forks, and we also can't | |
# check secrets in an `if` conditional, so we check for the presence of | |
# the secret here and use this value in conditionals below. | |
CAN_PUSH_IMAGE: ${{ secrets.DOCKERHUB_USERNAME != '' }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
# We need the whole history so we can diff against `master` to determine | |
# what images need to be built. | |
fetch-depth: 0 | |
- name: Login to DockerHub | |
if: ${{ env.CAN_PUSH_IMAGE == 'true'}} | |
uses: docker/login-action@v3 | |
with: | |
username: ${{ secrets.DOCKERHUB_USERNAME }} | |
password: ${{ secrets.DOCKERHUB_TOKEN }} | |
- name: Check whether images/plbase was modified | |
run: tools/check_path_modified.sh images/plbase images_plbase_modified | |
- name: Build and push prairielearn/plbase | |
if: ${{ env.images_plbase_modified }} | |
uses: docker/build-push-action@v5 # https://github.com/marketplace/actions/build-and-push-docker-images | |
with: | |
context: images/plbase | |
platforms: linux/amd64 | |
push: ${{ env.CAN_PUSH_IMAGE == 'true' }} | |
no-cache: true | |
tags: prairielearn/plbase:${{ env.COMMIT_SHA }} | |
# This ensures that the `prairielearn/prairielearn` image is built with the | |
# correct version of `prairielearn/plbase`. We'll only tag this as `latest` | |
# if we actually built it; if it wasn't built, we don't tag it, so Docker will | |
# correctly fall back to pulling the `latest` version from the registry. | |
- name: Tag plbase image as latest | |
if: ${{ env.images_plbase_modified }} | |
run: docker tag prairielearn/plbase:${{ env.COMMIT_SHA }} prairielearn/plbase:latest | |
- name: Build the prairielearn docker image | |
run: docker build -t prairielearn/prairielearn:${{ env.COMMIT_SHA }} . | |
# This ensures that the `prairielearn/executor` image is built with the | |
# correct version of `prairielearn/prairielearn`. | |
- name: Tag prairielearn image as latest | |
run: docker tag prairielearn/prairielearn:${{ env.COMMIT_SHA }} prairielearn/prairielearn:latest | |
- name: Build executor image | |
run: docker build ./images/executor --tag prairielearn/executor:${{ env.COMMIT_SHA }} | |
- name: Tag executor image as latest | |
run: docker tag prairielearn/executor:${{ env.COMMIT_SHA }} prairielearn/executor:latest | |
- name: Push prairielearn image to Docker registry | |
if: ${{ env.CAN_PUSH_IMAGE == 'true' }} | |
run: docker push prairielearn/prairielearn:${{ env.COMMIT_SHA }} | |
- name: Push executor image to Docker registry | |
if: ${{ env.CAN_PUSH_IMAGE == 'true' }} | |
run: docker push prairielearn/executor:${{ env.COMMIT_SHA }} | |
# Only push the `:latest` image if we're on the `master` branch. | |
- name: Push latest executor image to Docker registry | |
if: ${{ env.CAN_PUSH_IMAGE == 'true' && github.ref == 'refs/heads/master' }} | |
run: docker push prairielearn/executor:latest | |
# We run the following steps in this job instead of separately to avoid the | |
# overhead of pulling the image another time. | |
- name: Create a temporary directory for host files | |
run: mkdir -p /tmp/prairielearn | |
- name: Start the container | |
# We have tests for external grading code, which relies on the Docker | |
# socket being available, as well as a specific volume mount and | |
# environment variable. See the docs for more details: | |
# https://prairielearn.readthedocs.io/en/latest/externalGrading/#running-locally-for-development | |
# | |
# We put the Postgres data on a tmpfs volume, which should be much faster. | |
run: docker run -td -v /var/run/docker.sock:/var/run/docker.sock -v /tmp/prairielearn:/jobs --tmpfs=/var/postgres -e HOST_JOBS_DIR=/tmp/prairielearn --name=test_container prairielearn/prairielearn /bin/bash | |
- name: Run the JavaScript tests | |
run: docker exec test_container /PrairieLearn/docker/test_js.sh | |
# The JS tests hang relatively often when someone makes a mistake in a PR, | |
# and the GitHub Actions default timeout is 6 hours, so the CI run keeps | |
# spinning until it eventually times out. This shorter timeout helps | |
# ensure that the tests fail more quickly so that people can fix them. | |
timeout-minutes: 30 | |
native-checks: | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Install OS packages | |
run: sudo apt-get install -y graphviz graphviz-dev | |
- name: Set up Python | |
uses: actions/setup-python@v5 | |
with: | |
python-version: '3.10' | |
cache: pip | |
cache-dependency-path: images/plbase/python-requirements.txt | |
- name: Install Python dependencies | |
run: pip install -r images/plbase/python-requirements.txt | |
- name: Set up Node | |
uses: actions/setup-node@v4 | |
with: | |
node-version: '20' | |
cache: 'yarn' | |
- name: Install Node dependencies | |
run: yarn install --immutable | |
- name: Set up Turborepo cache | |
uses: actions/cache@v4 | |
with: | |
path: ./node_modules/.cache/turbo | |
key: ${{ runner.os }}-turbo-${{ github.sha }} | |
restore-keys: | | |
${{ runner.os }}-turbo- | |
- name: Build all code | |
run: make build | |
- name: Run the JavaScript linter | |
run: make lint-js | |
- name: Run the HTML linter | |
run: make lint-html | |
- name: Run the links linter | |
run: make lint-links | |
- name: Run the Python typechecker | |
run: make typecheck-python | |
- name: Run the Python linter | |
run: make lint-python | |
- name: Run the Python tests | |
run: make test-python | |
timeout-minutes: 5 | |
- name: Check dependency structure | |
run: make check-dependencies | |
# The rest of our code is typechecked in the `build` Makefile target, which | |
# is run above. | |
- name: Run the TypeScript typechecker for tools | |
run: make typecheck-tools | |
# This step runs at the end, since it is common for it to fail in | |
# dependabot PRs, but we still want all other tests above to run | |
# in those cases. | |
- name: Check for duplicate Node dependencies | |
run: yarn dedupe --check | |
- name: Check for CJS requires which could be ESM imports | |
run: node ./tools/cjs-to-esm-candidates.mjs --check | |
report-image-sizes: | |
runs-on: ubuntu-latest | |
needs: | |
- build-workspace-images | |
- build-grader-images | |
- build-core-images | |
if: ${{ always() }} | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up Node | |
uses: actions/setup-node@v4 | |
with: | |
node-version: '20' | |
- name: Install Node dependencies | |
run: yarn workspaces focus @prairielearn/actions-report-image-sizes | |
- name: Build | |
run: yarn build | |
working-directory: packages/actions-report-image-sizes | |
- name: Report image sizes | |
uses: ./packages/actions-report-image-sizes | |
with: | |
title: All images | |
sha: ${{ env.COMMIT_SHA }} | |
token: ${{ secrets.GITHUB_TOKEN }} | |
images: | | |
prairielearn/workspace-desktop | |
prairielearn/workspace-jupyterlab | |
prairielearn/workspace-jupyterlab-python | |
prairielearn/workspace-rstudio | |
prairielearn/workspace-xtermjs | |
prairielearn/grader-c | |
prairielearn/grader-java | |
prairielearn/grader-python | |
prairielearn/grader-r | |
prairielearn/plbase | |
prairielearn/prairielearn | |
prairielearn/executor |