-
-
Notifications
You must be signed in to change notification settings - Fork 0
278 lines (244 loc) · 11.6 KB
/
Copy pathbuild.yaml
File metadata and controls
278 lines (244 loc) · 11.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
---
name: Build and Test
permissions:
contents: read
on:
push:
branches:
- main
pull_request:
merge_group:
# Supersede in-flight runs on the same ref. Never cancel in a merge queue: a
# cancelled merge_group run reports failure and evicts the PR from the queue.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
CARGO_TERM_COLOR: always
RUST_TOOLCHAIN_VERSION: "1.97.1"
# Every job below names a runner image rather than a `-latest` alias, so an
# image roll cannot change what a merge is gated on. The label cannot be lifted
# into a variable: `runs-on` accepts no `env` context, and the one context that
# would work, `vars`, holds its value in repository settings rather than here.
jobs:
# The whole gate: `cargo test`, formatting, clippy (which is what enforces the
# unwrap_used / unwrap_in_result / panic denies from Cargo.toml), rustdoc,
# cargo-deny, cargo-sort and shellcheck.
#
# This lives here rather than in its own workflow because `needs:` cannot
# cross workflows, and a lint gate the required check does not observe is not
# a gate. It runs the hooks rather than the underlying commands so that CI and
# `pre-commit run --all-files` cannot drift apart -- CLAUDE.md points
# contributors at that command as the single source of truth for what must
# pass, which is only true if CI runs the same thing.
pre-commit:
name: pre-commit
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
# The cargo-test pre-commit hook links libodbc via odbc-sys.
- name: Install host dependencies
uses: awalsh128/cache-apt-pkgs-action@553a35bb8ebd9fcabcb1c9451aa4c98e1b4ca8a9 # v1.6.3
with:
packages: unixodbc-dev
# A cache key, not a runner label, but it tracks the runner image so
# that bumping the image invalidates the cached .deb files.
version: ubuntu-24.04
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install Rust ${{ env.RUST_TOOLCHAIN_VERSION }} toolchain
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # 1.95.0
with:
toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
components: rustfmt, clippy
- name: Setup Rust Cache
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- name: Install cargo-deny and cargo-sort
uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2.85.8
with:
tool: cargo-deny,cargo-sort
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
- uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
# This suite needs only unixODBC and the sqlite3 CLI, no server and no
# container, so it runs on a standard runner in seconds and is worth
# gating every pull request on. The Trino driver cannot do this, which is
# part of why this driver exists.
sqlite-integration:
name: SQLite Integration Tests
runs-on: ubuntu-24.04
timeout-minutes: 20
needs: [pre-commit]
steps:
- name: Install host dependencies
uses: awalsh128/cache-apt-pkgs-action@553a35bb8ebd9fcabcb1c9451aa4c98e1b4ca8a9 # v1.6.3
with:
packages: unixodbc-dev unixodbc sqlite3
version: ubuntu-24.04
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install Rust ${{ env.RUST_TOOLCHAIN_VERSION }} toolchain
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b
with:
toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
- name: Setup Rust Cache
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- name: Install uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
- name: Run SQLite integration tests
run: |
./integration-tests/setup.sh
# --skip-cargo-test: the pre-commit job above already ran it.
./integration-tests/run-tests.sh --skip-cargo-test
unit-tests-windows:
name: Unit Tests (Windows)
runs-on: windows-2022
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install Rust ${{ env.RUST_TOOLCHAIN_VERSION }} toolchain
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b
with:
toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
targets: x86_64-pc-windows-gnu
# A separate cache key: the Linux job's artefacts are a different target
# triple and sharing the key would thrash both.
- name: Setup Rust Cache
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
key: windows-gnu-test
# The GNU target's linker, and the C compiler libsqlite3-sys needs to
# build the bundled SQLite amalgamation. The runner image ships MSYS2,
# but its mingw64 bin directory is not on PATH by default.
- name: Add MinGW to PATH
run: echo "C:\msys64\mingw64\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
# `--target x86_64-pc-windows-gnu`, not the runner's default MSVC triple.
# That is the target release.yaml builds and packaging/build-archives.sh
# ships, and a suite passing against a toolchain nobody receives is only
# evidence about that toolchain. odbc-sys links odbc32, which comes with
# the Windows SDK already on the runner, so there is no equivalent of the
# unixodbc-dev install the Linux jobs need.
#
# This is also the only job that compiles `backend::setup`'s
# `#[cfg(windows)]` module, which is the half of the setup dialog that
# calls into kernel32.
- name: Run unit tests
run: cargo test --locked --target x86_64-pc-windows-gnu
# Builds both shipping artifacts the way release.yaml does, and checks the two
# properties that are invisible in a unit test run: that the DLL exports the
# ODBC entry points, and that what each artifact links at load time still
# matches packaging/sbom-native.json. The SBOM declares native dependencies by
# hand, since no cargo metadata describes them, so nothing but this check keeps
# the declaration true.
release-artifacts:
name: Release Artifacts
runs-on: ubuntu-24.04
timeout-minutes: 20
needs: [pre-commit]
steps:
- name: Install MinGW cross-compiler
run: sudo apt-get update && sudo apt-get install -y gcc-mingw-w64-x86-64 unixodbc-dev
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install Rust ${{ env.RUST_TOOLCHAIN_VERSION }} toolchain
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b
with:
toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
targets: x86_64-pc-windows-gnu
- name: Setup Rust Cache
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
key: windows-gnu
- name: Build Linux shared library
run: cargo build --locked --release
- name: Build Windows DLL
run: cargo build --locked --target x86_64-pc-windows-gnu --release
# Graded on what the DLL actually exports, not on the last command in a
# pipeline. The previous form piped a symbol count into `xargs echo`, and
# the step's exit status was `xargs`'s, which is 0 whatever it echoes: a
# DLL exporting nothing at all printed "0 ODBC symbols exported" and
# passed. The named set catches the entry points an application reaches
# the driver through, and the floor catches a wholesale regression in
# core's `forward_ffi!` even if these particular names survive.
- name: Verify DLL exports
run: |
DLL=target/x86_64-pc-windows-gnu/release/stackable_odbc_sqlite.dll
EXPORTS=$(x86_64-w64-mingw32-objdump -p "$DLL" \
| awk '/Export Address Table/,/Ordinal base/' \
| grep -oE '\b(SQL|Config)[A-Za-z]+\b' | sort -u)
echo "$EXPORTS" | tr '\n' ' '; echo
missing=""
for sym in SQLAllocHandle SQLFreeHandle SQLDriverConnectW SQLConnectW \
SQLBrowseConnectW SQLDisconnect SQLPrepareW SQLExecute \
SQLExecDirectW SQLBindParameter SQLDescribeParam SQLFetch \
SQLGetData SQLNumResultCols SQLDescribeColW SQLGetInfoW \
SQLGetTypeInfoW SQLGetDiagRecW SQLTablesW SQLColumnsW \
SQLEndTran SQLCancel ConfigDSNW; do
grep -qx "$sym" <<< "$EXPORTS" || missing="$missing $sym"
done
if [ -n "$missing" ]; then
echo "::error::the DLL does not export:$missing"
exit 1
fi
# The DLL exports 61 and the Linux .so 60, the difference being
# ConfigDSNW, which is `#[cfg(windows)]`.
count=$(echo "$EXPORTS" | grep -c .)
if [ "$count" -lt 55 ]; then
echo "::error::only $count ODBC symbols exported; expected at least 55"
exit 1
fi
echo "SQLite DLL: $count ODBC symbols exported, all required names present"
# build.rs embeds this, and it is what stops the ODBC Data Source
# Administrator listing the driver as "Not marked". A cross-build with no
# windres on PATH fails loudly, but a change to build.rs that silently
# stops emitting the resource would not, so the section is asserted here.
- name: Verify the DLL carries a version resource
run: |
x86_64-w64-mingw32-objdump -h target/x86_64-pc-windows-gnu/release/stackable_odbc_sqlite.dll \
| grep -q '\.rsrc' || { echo "::error::the DLL carries no .rsrc section"; exit 1; }
echo "Version resource present."
# Two different assertions behind one flag. For the .so it compares
# DT_NEEDED against the sonames sbom-native.json declares, in both
# directions. For the .dll it asserts the mingw runtime is still linked
# statically: the release archive ships no runtime DLL, so an artifact
# that imported one would fail to load on a user's machine.
#
# Only the release binaries are checked, and only here rather than in
# release.yaml, because a pull request is where a dependency change can
# still be reverted cheaply.
- name: Verify declared native dependencies
run: |
./packaging/sbom.sh --check-native target/release/libstackable_odbc_sqlite.so
./packaging/sbom.sh --check-native target/x86_64-pc-windows-gnu/release/stackable_odbc_sqlite.dll
# Single required check for branch protection rules.
finished:
name: Finished Build and Test
if: always()
needs:
- pre-commit
- sqlite-integration
- unit-tests-windows
- release-artifacts
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
# Derived from needs.* rather than a hand-written list of job names: a job
# added to `needs` above but forgotten here would otherwise be silently
# non-blocking.
- name: Check job results
env:
RESULTS: ${{ join(needs.*.result, ' ') }}
run: |
for result in $RESULTS; do
if [[ "$result" != "success" ]]; then
echo "One or more jobs did not succeed: $RESULTS"
exit 1
fi
done
echo "All jobs passed: $RESULTS"