-
-
Notifications
You must be signed in to change notification settings - Fork 16
283 lines (258 loc) · 12.6 KB
/
Copy pathengine-release-check.yml
File metadata and controls
283 lines (258 loc) · 12.6 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
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
name: Engine release check
# chdb-core publishes an engine and dispatches here; this runs the suite against
# that engine and records the verdict in an issue. It gates nothing — the engine
# has already shipped by the time this starts.
#
# bindgen regenerates the FFI declarations from the header that ships with the
# engine, so a changed signature usually becomes a compile error here rather
# than a runtime surprise. That is worth having early anyway: the regular CI job
# only ever sees the engine pinned in update_libchdb.sh, so it stays green until
# someone bumps it. The cases bindgen cannot catch are the ones that matter
# most — a struct that changes meaning without changing its declaration, or
# behaviour that moves behind an unchanged signature.
on:
repository_dispatch:
types: [chdb-core-release]
workflow_dispatch:
inputs:
engine_version:
description: "chdb-core release tag, e.g. v26.5.0"
required: true
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
jobs:
# Linux only, matching the regular CI job. Adding macOS here would make the
# first failure a question about this repository's macOS support rather than
# about the engine, which is the opposite of what this is for.
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Resolve the engine version
env:
ENGINE_VERSION: ${{ github.event.client_payload.tag || github.event.inputs.engine_version }}
run: |
if [ -z "$ENGINE_VERSION" ]; then
echo "::error::no engine version in the dispatch payload or the manual input"
exit 1
fi
# The version arrives from a dispatch payload or a typed input, then flows
# into a URL, a branch name, a commit message and a sed replacement. Any
# character outside this set belongs to no chdb-core release tag, and an
# & or | reaching sed would quietly rewrite the wrong thing.
case "$ENGINE_VERSION" in
*[!A-Za-z0-9._+-]*)
echo "::error::refusing engine version '$ENGINE_VERSION': letters, digits and . _ + - only"
exit 1 ;;
esac
echo "CHDB_ENGINE_VERSION=$ENGINE_VERSION" >> "$GITHUB_ENV"
echo "Testing against chdb-core $ENGINE_VERSION"
- name: Fetch the published engine
# Copy rather than move, unlike the regular CI job. build.rs prefers a
# libchdb.so sitting next to chdb.h in the repository root and otherwise
# downloads its own; leaving the pair in place means one download and no
# chance of linking against a different engine than the tests load.
run: |
bash update_libchdb.sh --local
sudo cp libchdb.so /usr/lib/libchdb.so
sudo ldconfig
- name: Build
run: cargo build --verbose
env:
RUST_BACKTRACE: full
- name: Run tests
run: cargo test -- --test-threads=1
env:
RUST_BACKTRACE: full
# Green means the engine can be adopted, not that it has been. Adoption is a
# one-line change to a pinned version and goes through review like any other
# dependency bump; this only writes the line — in both places, since build.rs
# picks the engine when update_libchdb.sh has not already left one behind.
propose_bump:
needs: test
if: needs.test.result == 'success'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
outputs:
pr: ${{ steps.bump.outputs.pr }}
unproposed: ${{ steps.bump.outputs.unproposed }}
steps:
# The commit the suite actually ran against, not whatever the default branch
# has become since. github.sha is fixed for the whole run, so this is the
# same tree the test job exercised; a default branch that moved during a
# long matrix would otherwise put the new pin on untested code while the
# pull request claims the suite passed.
- uses: actions/checkout@v4
with:
ref: ${{ github.sha }}
- id: bump
name: Open a PR moving the pin to this engine
env:
GH_TOKEN: ${{ github.token }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
ENGINE_VERSION: ${{ github.event.client_payload.tag || github.event.inputs.engine_version }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
# test rejects these too, but this is the step that interpolates the
# version into sed replacements and a branch name.
case "$ENGINE_VERSION" in
*[!A-Za-z0-9._+-]*)
echo "::error::refusing engine version '$ENGINE_VERSION'"
exit 1 ;;
esac
# Only when the tested commit is still the tip of the default branch.
# Anything else means merging the bump would adopt commits no run
# exercised against this engine, and the bump carries no CI to catch it.
# Declining and saying why beats a pull request claiming more than the
# run established.
rel=$(gh api "repos/$GITHUB_REPOSITORY/compare/$DEFAULT_BRANCH...$GITHUB_SHA" --jq .status)
if [ "$rel" != identical ]; then
echo "unproposed=The tested commit $GITHUB_SHA is $rel relative to $DEFAULT_BRANCH, so nothing was proposed" >> "$GITHUB_OUTPUT"
echo "declining to propose a bump: $rel"
exit 0
fi
current=$(grep -E '^CHDB_ENGINE_PIN=' update_libchdb.sh | cut -d= -f2)
if [ "$current" = "$ENGINE_VERSION" ]; then
echo "already pinned to $ENGINE_VERSION, nothing to propose"
exit 0
fi
branch="engine-pin-$ENGINE_VERSION"
if [ "$(gh pr list --head "$branch" --state open --json number --jq 'length')" != 0 ]; then
echo "a PR for $ENGINE_VERSION is already open"
exit 0
fi
git switch -c "$branch"
sed -i "s|^CHDB_ENGINE_PIN=.*|CHDB_ENGINE_PIN=$ENGINE_VERSION|" update_libchdb.sh
sed -i "s|^const CHDB_ENGINE_PIN: &str = .*|const CHDB_ENGINE_PIN: \&str = \"$ENGINE_VERSION\";|" build.rs
# Only the engine key under [package.metadata.chdb], so the neighbouring
# docs.rs table is left alone.
sed -i "/^\[package\.metadata\.chdb\]/,/^\[package\.metadata\.docs\.rs\]/ \
s|^engine = \".*\"$|engine = \"$ENGINE_VERSION\"|" Cargo.toml
# Three files carry the pin. A bump that moves some of them puts the
# linked engine, the installed engine and what the crate tells a user on
# different footings — and leaves a pull request that cannot pass its own
# checks, so the automation would be proposing work it had blocked.
.github/scripts/check-engine-pin.sh
git -c user.name="github-actions[bot]" \
-c user.email="41898282+github-actions[bot]@users.noreply.github.com" \
commit -am "Move the engine pin from $current to $ENGINE_VERSION"
# The branch can already exist on the remote: a bump PR closed without
# merging leaves it behind, and a plain push is then rejected as a
# non-fast-forward, silently costing the adoption PR. No open PR uses it
# — that was checked above — and its only content is one generated line,
# so replacing it is safe.
if git ls-remote --exit-code --heads origin "$branch" >/dev/null 2>&1; then
echo "$branch is left over from an earlier attempt, replacing it"
git push --force -u origin "$branch"
else
git push -u origin "$branch"
fi
{
echo "The release check built and ran the tests against \`$ENGINE_VERSION\` and"
echo "they passed, so the engine can be adopted. This moves the pin"
echo "$current → \`$ENGINE_VERSION\` in all three places that carry it:"
echo "\`update_libchdb.sh\`, \`build.rs\`, and \`engine\` under"
echo "\`[package.metadata.chdb]\` in \`Cargo.toml\`, which is what tells a user"
echo "of the published crate which engine is inside it."
echo
echo "$RUN_URL"
echo
echo "Based on $GITHUB_SHA, the commit that run tested."
echo
echo "No checks will appear here. GitHub does not start workflow runs for"
echo "commits a workflow pushed with \`GITHUB_TOKEN\`, and running CI on this"
echo "branch would exercise the same tests against the same engine the check"
echo "just used."
} > pr-body.md
url=$(gh pr create --base "$DEFAULT_BRANCH" --head "$branch" \
--title "Move the engine pin to $ENGINE_VERSION" \
--body-file pr-body.md)
echo "pr=$url" >> "$GITHUB_OUTPUT"
echo "$url"
report:
needs: [test, propose_bump]
if: always()
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Open an issue with the verdict
env:
GH_TOKEN: ${{ github.token }}
# This job has nothing checked out, and gh does not read
# GITHUB_REPOSITORY. Without this it cannot tell which repository to
# open the issue in and every run reports nothing.
GH_REPO: ${{ github.repository }}
RESULT: ${{ needs.test.result }}
BUMP_PR: ${{ needs.propose_bump.outputs.pr }}
BUMP_RESULT: ${{ needs.propose_bump.result }}
BUMP_UNPROPOSED: ${{ needs.propose_bump.outputs.unproposed }}
ENGINE_VERSION: ${{ github.event.client_payload.tag || github.event.inputs.engine_version }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
# A green suite whose bump could not be opened is not a green run. Closing
# on needs.test.result alone would file it as "nothing to adopt" and leave
# the broken automation with no signal at all.
bump_broke=0
if [ "$RESULT" != success ]; then
verdict="FAILS"
keep=1
elif [ "$BUMP_RESULT" = failure ] || [ "$BUMP_RESULT" = cancelled ]; then
verdict="passes, bump PR did not open"
keep=1
bump_broke=1
elif [ -n "$BUMP_UNPROPOSED" ]; then
verdict="passes, no bump proposed"
keep=1
else
verdict="passes"
keep=0
fi
{
if [ "$bump_broke" = 1 ]; then
echo "chdb-rust passes against chdb-core \`$ENGINE_VERSION\`, but the bump PR did not open."
elif [ -n "$BUMP_UNPROPOSED" ]; then
echo "chdb-rust passes against chdb-core \`$ENGINE_VERSION\`, but no bump was proposed."
else
echo "chdb-rust $verdict against chdb-core \`$ENGINE_VERSION\`."
fi
echo
echo "$RUN_URL"
if [ -n "$BUMP_PR" ]; then
echo
echo "Adopting it: $BUMP_PR"
elif [ -n "$BUMP_UNPROPOSED" ]; then
echo
echo "$BUMP_UNPROPOSED. The engine is fine and the pin is unchanged; rerun"
echo "the check once the default branch stops moving, or move the pin by hand."
elif [ "$bump_broke" = 1 ]; then
echo
echo "The engine is fine; the automation is not. The pull request moving the"
echo "pin could not be opened, so this issue stays open. The usual cause is"
echo "this repository having \"Allow GitHub Actions to create and approve pull"
echo "requests\" turned off; the other is the branch push being rejected. The"
echo "pin is unchanged either way, and moving it by hand is one line."
fi
if [ "$RESULT" != success ]; then
echo
echo "This does not mean the pinned engine is broken — update_libchdb.sh is"
echo "untouched. It means adopting \`$ENGINE_VERSION\` needs work first. A"
echo "bindgen compile error names the changed declaration directly; a test"
echo "failure with a clean build points at semantics behind an unchanged one."
fi
echo
echo "cc @auxten @wudidapaopao @ShawnChen-Sirius"
} > body.md
url=$(gh issue create \
--title "Engine check: chdb-core $ENGINE_VERSION — $verdict" \
--body-file body.md)
echo "$url"
if [ "$keep" = 0 ]; then
gh issue close "$url" --comment "Green, closing. The run is linked above."
fi