Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 14 additions & 17 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,29 +197,26 @@ jobs:

- name: Install Linux dependencies
if: matrix.os == 'linux'
# One list, one apt call. This was two `apt-get install` invocations
# naming 21 packages between them, five of them in both --
# libappindicator3-dev, librsvg2-dev, patchelf, rpm and
# libwebkit2gtk-4.1-dev. Same 16 packages, said once.
# The same list test_build.yml installs, which is what makes it a
# check: a pull request now compiles and bundles against exactly the
# packages a release does. An assertion holds the two together.
#
# It was sixteen. Six of those apt installs anyway --
# libwebkit2gtk-4.1-dev depends on libwebkit2gtk-4.1-0,
# libjavascriptcoregtk-4.1-dev, gir1.2-webkit2-4.1 and libgtk-3-dev,
# and those pull the remaining two -- and four libxcb *-dev packages
# and xdg-utils appear in no Tauri v2 prerequisite list. Run
# 31487547674 built the .deb, the .rpm and the AppImage on
# ubuntu-24.04 with the six below and nothing else.
run: |
sudo apt-get update
sudo apt-get install -y \
gir1.2-javascriptcoregtk-4.1 \
gir1.2-webkit2-4.1 \
libappindicator3-dev \
libgtk-3-dev \
libjavascriptcoregtk-4.1-0 \
libjavascriptcoregtk-4.1-dev \
librsvg2-dev \
libwebkit2gtk-4.1-0 \
libwebkit2gtk-4.1-dev \
libxcb1-dev \
libxcb-render0-dev \
libxcb-shape0-dev \
libxcb-xfixes0-dev \
libappindicator3-dev \
librsvg2-dev \
patchelf \
rpm \
xdg-utils
rpm

- name: Install Frontend Dependencies
run: npm ci
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,17 @@ jobs:
# against a 10 GB per-repository limit shared with ~110 npm caches, and
# GitHub evicts least-recently-used -- so unbounded per-branch copies
# would push out the very entries they are meant to reuse.
- name: name the runner image for the cache key
run: echo "IMAGE_OS=$ImageOS" >> "$GITHUB_ENV"

- name: cache rust dependencies
uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri
# See the note in test_build.yml: rust-cache keys on `runner.os`, so
# ubuntu-22.04 and ubuntu-24.04 share a cache and a build script's
# probe of the wrong distribution's headers gets reused.
key: ${{ env.IMAGE_OS }}
save-if: ${{ github.ref == 'refs/heads/master' }}

- name: install dependencies (ubuntu only)
Expand Down
16 changes: 15 additions & 1 deletion .github/workflows/test_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,25 @@ jobs:
# Writing only on master pins the total at one set. Pull requests restore
# from master and save nothing, which is also what makes the push trigger
# above worth its runner time: it is the only writer.
# rust-cache's key ends `-Linux-x64`: `runner.os`, not the image. A cache
# written on ubuntu-22.04 restores onto ubuntu-24.04 as a full match --
# measured, `v0-rust-linux-build-test-Linux-x64-e8b3ee54-a2c94f3a` on both
# -- and cargo fingerprints do not track system libraries, so the
# webkit2gtk-sys build script's probe of jammy's headers would be reused
# against noble's without anything noticing.
#
# `$ImageOS` is `ubuntu22`/`ubuntu24`/`macos15`, so this invalidates the
# next runner move too, including the ones `-latest` makes without a
# commit. Named once, from the runner itself, rather than written down.
- name: name the runner image for the cache key
run: echo "IMAGE_OS=$ImageOS" >> "$GITHUB_ENV"
shell: bash

- name: cache rust dependencies
uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri
key: ${{ matrix.os-name }}
key: ${{ matrix.os-name }}-${{ env.IMAGE_OS }}
save-if: ${{ github.ref == 'refs/heads/master' }}

# Keyed on which entry this is, not on which Ubuntu it happens to be.
Expand Down
63 changes: 63 additions & 0 deletions scripts/releaseWorkflow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,69 @@ test('a step asks which matrix entry it is, not which runner it landed on', () =
}
});

/** The packages an `apt-get install -y` line asks for, sorted. */
function aptPackages(source: string): string[] {
const line = /apt-get install -y((?:[^\n]*\\\n)*[^\n]*)/.exec(source)?.[1] ?? '';
return line
.split(/[\s\\]+/)
.filter(Boolean)
.sort();
}

test('a release installs the dependencies a pull request proved it can build with', () => {
// build.yml only runs on workflow_dispatch, so its apt list is the one part
// of the Linux build no pull request exercises -- it asked for sixteen
// packages against test_build.yml's six, and nothing said which was right.
// Six of the ten extras apt installs anyway as dependencies of
// libwebkit2gtk-4.1-dev; the four libxcb *-dev packages and xdg-utils are in
// no Tauri v2 prerequisite list. Run 31487547674 built the .deb, the .rpm and
// the AppImage on ubuntu-24.04 with six.
//
// One list rather than a shorter one is the point. Both workflows compile and
// bundle, so a difference between them is a release depending on something
// nothing tested — which is what this was.
assert.deepEqual(
aptPackages(sliceFrom(workflow, 'Install Linux dependencies')),
aptPackages(sliceFrom(testBuildWorkflow, 'install dependencies (ubuntu only)')),
'the release build and the pull request build install different Linux packages',
);

// test.yml compiles but never bundles, so it needs everything above except
// the bundlers. Asserted as a subset rather than as its own list, so adding a
// dependency in one place cannot leave it behind.
const bundlers = new Set(['rpm']);
assert.deepEqual(
aptPackages(sliceFrom(testWorkflow, 'install dependencies (ubuntu only)')),
aptPackages(sliceFrom(testBuildWorkflow, 'install dependencies (ubuntu only)')).filter(
(p) => !bundlers.has(p),
),
'test.yml has drifted from the list the builds use',
);
});

test('a cargo cache cannot outlive the runner image that filled it', () => {
// rust-cache's key ends `-Linux-x64`: `runner.os`, not the image. Measured on
// two runs of the same job, one per Ubuntu, the key was identical --
// `v0-rust-linux-build-test-Linux-x64-e8b3ee54-a2c94f3a` -- so moving the
// runner would have restored a jammy-built target/ into a noble build as a
// full match. Cargo fingerprints do not track system libraries: the
// webkit2gtk-sys build script's probe of the wrong distribution's headers
// would have been reused with nothing to notice.
//
// `$ImageOS` comes from the runner, so this also covers the image changing
// under `macos-latest` and `windows-latest`, which happens without a commit.
for (const [name, source] of [
['test.yml', testWorkflow],
['test_build.yml', testBuildWorkflow],
] as const) {
const cacheStep = sliceFrom(source, 'uses: Swatinem/rust-cache@v2');
const key = /^\s*key:\s*(.+)$/m.exec(cacheStep)?.[1];
assert.ok(key, `${name} caches cargo without a key naming the runner image`);
assert.match(key, /env\.IMAGE_OS/, `${name}'s cache key does not change when the runner image does`);
assert.match(source, /IMAGE_OS=\$ImageOS/, `${name} never reads $ImageOS into the environment`);
}
});

test('the updater feed publishes the keys an installed Markpad can ask for', () => {
// tauri-plugin-updater tries `{os}-{arch}-{installer}` and then `{os}-{arch}`,
// and only tries the first when the binary knows its own bundle type. Ours
Expand Down