forked from PrairieLearn/PrairieLearn
-
Notifications
You must be signed in to change notification settings - Fork 0
406 lines (358 loc) · 17.3 KB
/
main.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
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
# Since tests run in the context of the container, we need to copy all
# the coverage reports out of the container and into the host filesystem.
- name: Copy coverage reports to the host
run: ./tools/copy_docker_coverage_reports.sh test_container
- name: Upload coverage reports to Codecov
uses: codecov/[email protected]
with:
token: ${{ secrets.CODECOV_TOKEN }}
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
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