Repository navigation
186 lines (173 loc) · 7.31 KB
/
Copy pathci.yml
File metadata and controls
186 lines (173 loc) · 7.31 KB
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
name: CI
# Three operating systems, and none of them on a push.
#
# A push to main starts NOTHING here: the owner commits and pushes freely, and CI is a
# thing that runs at the boundaries instead - a pull request, a manual dispatch, and -
# through `workflow_call` - the gate a release passes before it
# publishes anything. The check that must never be skipped is the one at the cut, and the
# cut is what pays for it. (Before this, every push to main ran one job, on the platform a
# Windows development machine cannot check for itself; that job now waits for the release.)
#
# This workflow builds the RUST app only. The node/JS half needs no build: it is the same
# files on every platform, it is packaged by release.yml as its own archive, and
# `scripts/run-web.*` works without this app at all.
#
# NO THIRD-PARTY ACTIONS, and that is a constraint rather than a taste: this repository's
# Actions policy is `local_only`, so `actions/checkout` is refused at STARTUP (measured: a
# pull request produced a `startup_failure` in 0 s). Every step below is a shell command
# against a tool the runner image already carries - git, rustc, cargo, node, gh - so the
# workflow runs under the policy instead of asking for the policy to be relaxed.
on:
# NO `push` TRIGGER, on purpose. Adding one back brings the per-commit CI bill back with
# it; a release reaches this workflow through `workflow_call` from release.yml.
pull_request:
paths-ignore:
- '**.md'
- 'docs/**'
- 'assets/**'
workflow_dispatch:
workflow_call:
# A superseded push has nothing to say. Cancel it and let the cache serve the next one.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: '0'
jobs:
# The matrix is chosen by the event rather than written twice, so the caller and the
# push cannot disagree about what "checked" means.
plan:
name: Choose the matrix
runs-on: ubuntu-latest
timeout-minutes: 2
outputs:
os: ${{ steps.pick.outputs.os }}
steps:
- id: pick
run: |
if [ "${{ github.event_name }}" = "push" ]; then
echo 'os=["ubuntu-latest"]' >> "$GITHUB_OUTPUT"
else
echo 'os=["ubuntu-latest","windows-latest","macos-latest"]' >> "$GITHUB_OUTPUT"
fi
check:
name: ${{ matrix.os }}
needs: plan
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
os: ${{ fromJSON(needs.plan.outputs.os) }}
steps:
# The checkout step, without an action. `pull_request` checks the merge commit GitHub
# already built (refs/pull/N/merge); everything else checks the sha.
- name: Checkout
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
ref="$GITHUB_SHA"
if [ -n "$PR_NUMBER" ]; then ref="refs/pull/$PR_NUMBER/merge"; fi
git init -q .
git remote add origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
git fetch -q --depth 1 origin "$ref"
git checkout -q FETCH_HEAD
# The runner image carries the Rust toolchain and the clippy component. `rust-version`
# in app/Cargo.toml is the floor the code is written to; a toolchain below it fails
# here by name rather than somewhere inside a build.
- name: Toolchain
shell: bash
run: |
rustc --version
cargo --version
cargo clippy --version
# Warnings denied, so a dependency that arrives with a warning is a failure rather
# than a line nobody reads. The workspace has no GUI toolkit and no web engine to
# link, so this needs no `apt-get install` on the Linux runner - which is one of the
# things the cut bought.
- name: Clippy
working-directory: app
run: cargo clippy --workspace --all-targets --locked -- -D warnings
# `VNCODE_TEST_DIR` keeps the tests' scratch files inside the checkout. They are
# writable in a CI temp directory, but a test that writes where a confined host
# denies it is how this suite reported failures about the HOST rather than the code.
- name: Test
working-directory: app
shell: bash
env:
VNCODE_TEST_DIR: ${{ github.workspace }}/.test-tmp
run: |
mkdir -p "$VNCODE_TEST_DIR"
cargo test --workspace --locked
- name: Build (release)
working-directory: app
shell: bash
run: |
if [ "$RUNNER_OS" = "Windows" ]; then
export RUSTFLAGS='-C target-feature=+crt-static'
fi
cargo build --release --locked -p vn-shell
# The budget is a test, not a hope. A dependency that quietly pulls a GUI stack or a
# web engine changes this number, and that is the change this project exists to
# prevent - so it fails here by name.
- name: Size budget
working-directory: app
shell: bash
run: |
BIN="target/release/vncode"
[ "$RUNNER_OS" = "Windows" ] && BIN="$BIN.exe"
BYTES=$(wc -c < "$BIN")
MB=$((BYTES / 1048576))
echo "vncode: $BYTES bytes (${MB} MB)"
if [ "$BYTES" -gt $((6 * 1048576)) ]; then
echo "::error::$BIN is ${MB} MB, over the 6 MB budget - a dependency that draws a window or a web view is the usual cause"
exit 1
fi
- name: Smoke
working-directory: app
shell: bash
run: |
BIN="target/release/vncode"
[ "$RUNNER_OS" = "Windows" ] && BIN="$BIN.exe"
"$BIN" --version
"$BIN" -Help > /dev/null
# `-Mode embed` is the flag the deleted web view used to answer. It must fail by
# name, not be silently ignored - that is what "no web view" means.
#
# Captured first, then matched. These steps run with `-o pipefail`, where
# `vncode ... | grep -q` reports the BINARY's exit 1 and turns a correct refusal
# into a failed pipeline - measured on the first run of this workflow.
OUT=$("$BIN" -Mode embed 2>&1 || true)
case "$OUT" in
*"unknown flag"*) echo "the deleted mode is refused by name" ;;
*)
echo "::error::-Mode embed was accepted, or refused without naming it"
exit 1
;;
esac
secrets:
name: No secrets
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout (full history - the check reads what a push would stage)
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
ref="$GITHUB_SHA"
if [ -n "$PR_NUMBER" ]; then ref="refs/pull/$PR_NUMBER/merge"; fi
git init -q .
git remote add origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
git fetch -q origin "$ref"
git checkout -q FETCH_HEAD
# The one check that is about the repository rather than a platform, and the one
# whose failure can never be undone by a later commit. `node` is on the runner image.
- name: check-no-secrets
run: node scripts/checks/check-no-secrets.mjs