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
name: Devcontainer CI
on:
push:
branches:
pull_request:
merge_group:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# The heavy devcontainer build/smoke only validates the dev *image*, so it is
# pointless on the vast majority of changes that don't touch it. We still let the
# workflow trigger on every PR/push (so the required check always reports), but gate
# the expensive job behind a fast paths check: when nothing devcontainer-related
# changed, `devcontainer-ci` is skipped — and a skipped job counts as a passing
# required check, whereas filtering the whole workflow via `on.*.paths` would leave
# the check stuck "pending" and block merges.
changes:
name: Detect devcontainer changes
runs-on: ubuntu-latest
outputs:
devcontainer: ${{ steps.filter.outputs.devcontainer }}
steps:
- uses: actions/checkout@v3
# Not on `merge_group`: that event gives `paths-filter` no base to diff against, and a throw
# here would fail this job, which would *skip* `devcontainer-ci` rather than run it -- green
# having built nothing. The queue therefore builds unconditionally, which is also the right
# answer on its own terms: it validates a combination no single pull request tested.
- uses: dorny/paths-filter@v3
id: filter
if: github.event_name != 'merge_group'
with:
filters: |
devcontainer:
- '.devcontainer/**'
- '.github/workflows/devcontainer.yml'
devcontainer-ci:
name: Build & Test in Devcontainer
needs: changes
if: github.event_name == 'merge_group' || needs.changes.outputs.devcontainer == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Cache devcontainer build layers
uses: actions/cache@v3
with:
path: /tmp/.devcontainer-cache
key: ${{ runner.os }}-devcontainer-${{ hashFiles('.devcontainer/Dockerfile.dev') }}
restore-keys: |
${{ runner.os }}-devcontainer-
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
with:
driver: docker-container
- name: Setup Node.js (for Devcontainer CLI)
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install Devcontainer CLI
run: |
npm config set prefix ~/.npm-global
npm install -g @devcontainers/cli
- name: Add npm-global bin to PATH
run: echo "$HOME/.npm-global/bin" >> $GITHUB_PATH
- name: Build devcontainer image
run: |
devcontainer build \
--workspace-folder . \
--cache-from type=local,src=/tmp/.devcontainer-cache \
--cache-to type=local,dest=/tmp/.devcontainer-cache,mode=max \
--log-level info
- name: Start devcontainer
run: |
devcontainer up \
--workspace-folder . \
--skip-post-create \
--log-level info \
--cache-from type=local,src=/tmp/.devcontainer-cache
# The point of this job is to verify the devcontainer image itself builds and
# works, not to re-run the full suite — fmt, clippy and the complete test matrix
# already run (faster) in the `main` workflow's lint-and-test job. So we only
# smoke the dev image: compile every target and run the fast lib unit tests.
- name: Smoke-build inside devcontainer
run: |
devcontainer exec --workspace-folder . -- bash -lc "\
export CARGO_HOME=\$HOME/.cargo && \
mkdir -p \$CARGO_HOME && \
cargo build --all-targets --all-features && \
cargo test --lib --all-features \
"