Skip to content

Commit 0909d11

Browse files
committed
Simplify CI episode
1 parent f030098 commit 0909d11

File tree

3 files changed

+84
-88
lines changed

3 files changed

+84
-88
lines changed

episodes/10-CI.Rmd

Lines changed: 84 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ of running tests on every code change to ensure that the code is working as
2626
expected. GitHub provides a feature called GitHub Actions that allows you to
2727
integrate this into your projects.
2828

29-
In this lesson we will go over the very basics of how to set up a GitHub Action
29+
In this lesson we will go over the basics of how to set up a GitHub Action
3030
to run tests on your code.
3131

3232
:::::: prereq
@@ -95,10 +95,11 @@ on:
9595
push:
9696

9797
# This is a list of jobs that the action will run. In this case, we have only
98-
# one job called build.
98+
# one job called test.
9999
jobs:
100100

101-
build:
101+
# This is the name of the job
102+
test:
102103

103104
# This is the environment that the job will run on. In this case, we are
104105
# using the latest version of Ubuntu, however you can use other operating
@@ -166,77 +167,6 @@ individual stages of the workflow and inspect the terminal output.
166167
![Detailed view of a GitHub workflow run](fig/github_action.png){alt="Detailed view of a GitHub workflow run"}
167168

168169

169-
## Enable running the tests on a Pull Request
170-
171-
The typical use-case for a CI system is to run the tests when a pull request is
172-
made to the `main` branch to add a feature or fix a bug. However, there is a
173-
subtlety to consider: what if the tests pass on your feature branch, but would
174-
fail after merging into `main` due to a divergence between the two branches?
175-
176-
To verify this, we can set our workflow to run on both `push` and
177-
`pull_request` by modifying the `tests.yaml` file so that the `on:` sections
178-
reads:
179-
180-
```yaml
181-
on:
182-
push:
183-
pull_request:
184-
```
185-
186-
Let's test it out.
187-
188-
- From within your `main` branch, add a new file `sandwich.py` containing the
189-
following function:
190-
191-
```python
192-
def sandwich():
193-
bread = "======"
194-
filling = "jam"
195-
return "\n".join([bread, filling, bread])
196-
```
197-
198-
- Create a new branch in your repository called `sanwich_test` using `git switch -c sandwich_test`
199-
- Add a new file `test_sandwich.py` with the function:
200-
201-
```python
202-
from sandwich import sandwich
203-
204-
def test_sandwich():
205-
assert sandwich() == "======\njam\n======"
206-
```
207-
208-
- Push this to your repo with `git push -u origin sandwich_test`, but don't
209-
raise a pull request just yet.
210-
- Imagine that somebody else modifies the `main` branch before your branch can
211-
be merged -- something that happens all too often in open source projets!
212-
Return to the `main` branch using `git switch main`, and modify
213-
`sandwich.py`:
214-
215-
```python
216-
def sandwich():
217-
bread = "======"
218-
filling = "cheese"
219-
return "\n".join([bread, filling, bread])
220-
```
221-
222-
- Push this change to `main` with `git push`.
223-
- Now raise a pull request on your respository to merge `sandwich_test` into
224-
`main`.
225-
226-
After raising the pull request, you should see that the GitHub Action runs twice:
227-
once for a push, which will pass, and once for a pull request, which will fail:
228-
229-
![Example of tests failing on pull requests.](fig/pull_request_test_failed.png){alt="Example of tests failing on pull requests."}
230-
231-
To fix this:
232-
233-
- Switch to the `sandwich_test` branch, and call `git merge main`.
234-
- Fix the test on the `sandwich_test` branch, ensure the tests pass locally,
235-
and commit/push the changes.
236-
237-
The tests should now pass for both `push` and `pull_request`.
238-
239-
240170
## Testing across multiple platforms
241171

242172
A very useful feature of GitHub Actions is the ability to test over a wider
@@ -250,7 +180,7 @@ We can achieve this by setting `jobs.<job_id>.strategy.matrix` in our workflow:
250180

251181
```yaml
252182
jobs:
253-
build:
183+
test:
254184
strategy:
255185
matrix:
256186
python_version: ["3.12", "3.13", "3.14"]
@@ -272,13 +202,24 @@ Later in the file, the `setup-python` step should be changed to:
272202
By default, all combinations in the matrix will be run in separate jobs. The
273203
syntax `${{ matrix.x }}` inserts the text from the `x` list for the given matrix job.
274204

275-
- Switch to a new branch `matrix_test` using `git switch -c matrix_test`
276-
- Make the changes above to `.github/workflows/tests.yaml`
277-
- Commit, push, and raise a pull request to `main`.
205+
::::::::::::::::::::::::::::::::::::: challenge
206+
207+
## Upgrade the workflow to run across multiple platforms
208+
209+
- Make the changes above to your workflow file, being careful to get the indentation right!
210+
- Commit the changes and push to GitHub.
211+
- Check the latest jobs in the Actions panel.
212+
213+
:::::::::::::::::::::::: solution
214+
215+
You should see that a total of 6 jobs have run, and hopefully all will have passed!
278216

279-
You should now see that _12_ separate jobs run!
217+
![Image showing completed matrix jobs.](fig/matrix_tests.png){alt="Completed matrix tests."}
218+
219+
:::::::::::::::::::::::::::::::::
220+
221+
::::::::::::::::::::::::::::::::::::::::::::::::
280222

281-
![Completed matrix jobs.](fig/matrix_tests.png){alt="Completed matrix tests."}
282223

283224
This ensures that code that runs on your machine should, in theory, run on many
284225
other peoples' machines too. However, it's best to restrict the matrix to the
@@ -298,11 +239,11 @@ can do so with a list of exclusions:
298239
python_version: "3.13"
299240
````
300241
242+
## Running on other events
301243
302-
## Other tips
303-
304-
You may have wondered why there is a trailing colon when we specify `push:` or `pull_request:`.
305-
The reason is that we can optionally set additional conditions on when they'll run. For example:
244+
You may have wondered why there is a trailing colon when we specify `push:` at
245+
the top of the file. The reason is that we can optionally set additional
246+
conditions on when CI jobs will run. For example:
306247

307248
```yaml
308249
on:
@@ -312,17 +253,72 @@ on:
312253
paths:
313254
- '**.py'
314255
- 'pyproject.toml'
256+
# Only check when somebody raises a push to main.
257+
# (not recommended in general!)
258+
branches: [main]
259+
```
260+
261+
Doing this can prevent pointless CI jobs from running and save resources.
262+
263+
You can also run on events other than a push. For example:
264+
265+
```yaml
266+
on:
267+
push:
268+
paths:
269+
- '**.py'
270+
- 'pyproject.toml'
271+
# Run on code in pull requests.
315272
pull_request:
316273
paths:
317274
- '**.py'
318275
- 'pyproject.toml'
319-
# Only check when somebody raises a pull_request to main.
320-
branches: [main]
321-
# This allows you to run the tests manually if you choose
276+
# This allows you to launch the job manually
322277
workflow_dispatch:
323278
```
324279

325-
Doing this can prevent pointless CI jobs from running and save resources.
280+
There is an important subtlety to running on `pull_request` versus
281+
`push`:
282+
283+
- `push` runs directly on the commits you push to GitHub.
284+
- `pull_request` runs on the code that would result _after_ the pull request
285+
has been merged into its target branch.
286+
287+
In collaborative coding projects, it is entirely possible that `main` will have
288+
diverged from your branch while you were working on it, and tests that pass on
289+
your branch will fail after the merge. For this reason, it's recommended to
290+
always include both `push` and `pull_request` in your testing workflows.
291+
292+
::::::::::::::::::::::::::::::::::::: challenge
293+
294+
## Running on pull requests (advanced)
295+
296+
Can you engineer a situation where a CI job passes on `push` but
297+
fails on `pull_request`?
298+
299+
- Write a new function, commit the changes, and push it to your `main`
300+
branch.
301+
- Switch to a new branch `my_branch` with `git switch -c my_branch`,
302+
and write a test for that function.
303+
- Check that the test passes, and commit it.
304+
- Push `my_branch` to GitHub with `git push -u origin my_branch`,
305+
but don't raise a pull request yet.
306+
- Return to your `main` branch, and modify the function being tested.
307+
- Push the changes to `main`.
308+
- Now raise a pull request from `my_branch` into `main`.
309+
310+
:::::::::::::::::::::::: solution
311+
312+
The code on the new branch will be testing the old implementation,
313+
and should pass. However, following the merge, the test would fail.
314+
This results in the `push` test passing, and the `pull_request` test
315+
failing.
316+
317+
![Example of tests failing on pull requests.](fig/pull_request_test_failed.png){alt="Example of tests failing on pull requests."}
318+
319+
:::::::::::::::::::::::::::::::::
320+
321+
::::::::::::::::::::::::::::::::::::::::::::::::
326322

327323
## Keypoints
328324

episodes/fig/github_action.png

-2.87 KB
Loading

episodes/fig/matrix_tests.png

-71.7 KB
Loading

0 commit comments

Comments
 (0)