ci: only run what a change affects, consolidate jobs (#3674)

* ci: only run what a change affects, consolidate jobs

- detect affected plugins from changed files and Cargo.lock dependency trees
- test/lint Rust per platform in shards instead of one job per plugin
- fold check-generated-files into lint-javascript, fmt into a single job
- skip fat LTO in integration test builds, single ABI in test-android

* ci: run e2e on bumps, use published tauri CLI, PR-safe pnpm cache

- trigger e2e on Cargo/pnpm lockfile and manifest changes
- install the latest 2.x tauri-cli with cargo-binstall in integration tests
- add setup-pnpm action: restore the store everywhere, save only on v2/v3

* fix clippy, ios build

* fix bumps [skip ci]
This commit is contained in:
Lucas Fernandes Nogueira authored and GitHub committed 2026-10-09 12:57:12 -03:00
1 parent 974af951a5
commit 9a74a78c71
18 files changed
+600 -630

No files matched your search

+44
View File
@@ -0,0 +1,44 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: setup pnpm
description: Installs Node.js, pnpm and the workspace dependencies, restoring the pnpm store from the cache
# `pnpm/action-setup`'s own cache saves from every run, pull requests included. An entry saved from
# a pull request lives on its merge ref, where nothing else can restore it, and every write evicts
# an entry that other runs would have hit (10 GB repository limit, LRU eviction), so here every run
# restores the store and only `v2`/`v3` save it.
runs:
using: composite
steps:
- uses: actions/setup-node@v7
with:
node-version: 'lts/*'
- uses: pnpm/action-setup@v6
- id: store
shell: bash
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
- id: cache
uses: actions/cache/restore@v6
with:
path: ${{ steps.store.outputs.path }}
key: pnpm-store-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: pnpm-store-${{ runner.os }}-${{ runner.arch }}-
- shell: bash
run: pnpm install --frozen-lockfile
# a store restored from an older lockfile still holds the packages it no longer uses
- if: ${{ (github.ref == 'refs/heads/v2' || github.ref == 'refs/heads/v3') && steps.cache.outputs.cache-hit != 'true' }}
shell: bash
run: pnpm store prune
- if: ${{ (github.ref == 'refs/heads/v2' || github.ref == 'refs/heads/v3') && steps.cache.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v6
with:
path: ${{ steps.store.outputs.path }}
key: ${{ steps.cache.outputs.cache-primary-key }}
+1 -7
View File
@@ -38,12 +38,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 'lts/*'
- uses: pnpm/action-setup@v6
with:
run_install: true
cache: true # the pnpm store, keyed by OS and lockfile hash and shared by every workflow
- uses: ./.github/actions/setup-pnpm
- name: audit
run: pnpm audit
-175
View File
@@ -1,175 +0,0 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: check generated files
on:
pull_request:
paths:
- '.github/workflows/check-generated-files.yml'
- pnpm-lock.yaml
- '**/guest-js/**'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
changes:
runs-on: ubuntu-latest
outputs:
packages: ${{ steps.filter.outputs.changes }}
steps:
- uses: actions/checkout@v7
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
autostart:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/autostart/guest-js/**
- plugins/autostart/src/api-iife.js
cli:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/cli/guest-js/**
- plugins/cli/src/api-iife.js
clipboard-manager:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/clipboard-manager/guest-js/**
- plugins/clipboard-manager/src/api-iife.js
dialog:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/dialog/guest-js/**
- plugins/dialog/src/api-iife.js
fs:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/fs/guest-js/**
- plugins/fs/src/api-iife.js
geolocation:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/geolocation/guest-js/**
- plugins/geolocation/src/api-iife.js
global-shortcut:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/global-shortcut/guest-js/**
- plugins/global-shortcut/src/api-iife.js
opener:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/opener/guest-js/**
- plugins/opener/src/api-iife.js
haptics:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/haptics/guest-js/**
- plugins/haptics/src/api-iife.js
http:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/http/guest-js/**
- plugins/http/src/api-iife.js
log:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/log/guest-js/**
- plugins/log/src/api-iife.js
notification:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/notification/guest-js/**
- plugins/notification/src/api-iife.js
os:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/os/guest-js/**
- plugins/os/src/api-iife.js
positioner:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/positioner/guest-js/**
- plugins/positioner/src/api-iife.js
process:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/process/guest-js/**
- plugins/process/src/api-iife.js
shell:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/shell/guest-js/**
- plugins/shell/src/api-iife.js
sql:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/sql/guest-js/**
- plugins/sql/src/api-iife.js
store:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/store/guest-js/**
- plugins/store/src/api-iife.js
stronghold:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/stronghold/guest-js/**
- plugins/stronghold/src/api-iife.js
updater:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/updater/guest-js/**
- plugins/updater/src/api-iife.js
upload:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/upload/guest-js/**
- plugins/upload/src/api-iife.js
websocket:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/websocket/guest-js/**
- plugins/websocket/src/api-iife.js
window-state:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/window-state/guest-js/**
- plugins/window-state/src/api-iife.js
test:
needs: changes
if: ${{ needs.changes.outputs.packages != '[]' && needs.changes.outputs.packages != '' }}
strategy:
fail-fast: false
matrix:
package: ${{ fromJSON(needs.changes.outputs.packages) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 'lts/*'
- uses: pnpm/action-setup@v6
with:
run_install: true
cache: true # the pnpm store, keyed by OS and lockfile hash and shared by every workflow
- name: build api
working-directory: plugins/${{ matrix.package }}
run: pnpm install && pnpm build
- name: check diff
run: |
./.scripts/ci/has-diff.sh
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dorny/paths-filter@v2
- uses: dorny/paths-filter@v3
id: filter
with:
list-files: shell
+41 -26
View File
@@ -7,49 +7,64 @@ name: check formatting
on:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
rustfmt:
# A single job whose checks only run when files they cover changed: the checks themselves take
# seconds, so a runner each would mostly be spent waiting for and setting up runners.
fmt:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read # to list the changed files
steps:
- uses: actions/checkout@v7
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
rust:
- .github/workflows/fmt.yml
- '**/*.rs'
prettier:
- .github/workflows/fmt.yml
- .prettierrc
- .prettierignore
- pnpm-lock.yaml
- '**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx,json,json5,jsonc,md,mdx,yml,yaml,css,scss,less,html,vue,svelte}'
toml:
- .github/workflows/fmt.yml
- '**/*.toml'
- name: install Rust stable and rustfmt
if: steps.filter.outputs.rust == 'true'
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- name: run cargo fmt
- name: rustfmt
if: steps.filter.outputs.rust == 'true'
run: cargo fmt --all -- --check
prettier:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 'lts/*'
- uses: pnpm/action-setup@v6
with:
run_install: true
cache: true # the pnpm store, keyed by OS and lockfile hash and shared by every workflow
- run: pnpm format:check
taplo:
name: taplo (.toml files)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: install taplo-cli
if: ${{ !cancelled() && steps.filter.outputs.toml == 'true' }}
uses: taiki-e/install-action@v2
with:
tool: taplo-cli
- run: taplo fmt --check --diff
- name: taplo (.toml files)
if: ${{ !cancelled() && steps.filter.outputs.toml == 'true' }}
run: taplo fmt --check --diff
- uses: ./.github/actions/setup-pnpm
if: ${{ !cancelled() && steps.filter.outputs.prettier == 'true' }}
- name: prettier
if: ${{ !cancelled() && steps.filter.outputs.prettier == 'true' }}
run: pnpm format:check
+69 -12
View File
@@ -8,22 +8,36 @@ on:
workflow_dispatch:
# run before publishing, see covector-version-or-publish.yml
workflow_call:
inputs:
all:
description: Run even if the updater is not affected by the pushed changes
type: boolean
default: true
push:
branches:
- v1
- v2
paths:
paths: &paths
- '.github/workflows/integration-tests.yml'
- 'plugins/updater/src/**'
- 'plugins/updater/tests/**'
- '.scripts/ci/affected-rust-packages.js'
- 'plugins/updater/**'
- '!plugins/updater/guest-js/**'
- '!plugins/updater/*.md'
- '!plugins/updater/package.json'
- '!plugins/updater/api-iife.js'
- 'Cargo.toml'
- 'Cargo.lock'
pull_request:
branches:
- v1
- v2
paths:
- '.github/workflows/integration-tests.yml'
- 'plugins/updater/src/**'
- 'plugins/updater/tests/**'
paths: *paths
concurrency:
# `github.workflow` is the caller's name in a `workflow_call` run, so the suffix keeps this
# workflow from sharing (and cancelling) the group of the other workflows the caller runs.
group: ${{ github.workflow }}-integration-tests-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
@@ -32,8 +46,30 @@ env:
CARGO_PROFILE_DEV_DEBUG: 0 # no debuginfo: faster builds and a much smaller target dir to cache
jobs:
# A `Cargo.lock` change only runs the tests when it touches the updater's dependency tree; see
# .scripts/ci/affected-rust-packages.js.
changes:
runs-on: ubuntu-latest
outputs:
updater: ${{ contains(fromJSON(steps.affected.outputs.packages), 'tauri-plugin-updater') }}
steps:
- uses: actions/checkout@v7
with:
# a pull request checks out its merge commit, whose first parent is the base branch
fetch-depth: 2
- id: affected
run: node .scripts/ci/affected-rust-packages.js
env:
BASE: ${{ github.event_name == 'pull_request' && 'HEAD^1' || github.event.before }}
ALL: ${{ inputs.all == true || github.event_name == 'workflow_dispatch' }}
GLOBAL_PATHS: .github/workflows/integration-tests.yml
run-integration-tests:
needs: changes
if: needs.changes.outputs.updater == 'true'
runs-on: ${{ matrix.platform }}
# a stuck step (e.g. `apt-get` waiting on an unreachable mirror) otherwise runs for 6 hours
timeout-minutes: 90
strategy:
fail-fast: false
@@ -61,12 +97,27 @@ jobs:
# that other runs would have hit (10 GB repository limit, LRU eviction).
save-if: ${{ github.ref == 'refs/heads/v2' || github.ref == 'refs/heads/v3' }}
- uses: taiki-e/install-action@v2
with:
tool: cargo-binstall
# The latest published 2.x CLI, downloaded from its GitHub release. `--pkg-fmt` because the
# crate's binstall metadata expects a .tgz on aarch64-apple-darwin, where the release only
# ships a .zip, and the disabled strategies make a missing binary fail the step instead of
# silently compiling the CLI from source. The token authenticates the GitHub requests and the
# longer timeout and retries ride out a slow response, which binstall otherwise reports as a
# missing binary.
- name: install Tauri CLI
# `--debug --target-dir target`: a dev-profile build in the workspace target dir reuses
# the cached dependencies (shared with the test build below) instead of a from-scratch
# release build in a temporary dir. `--locked` keeps the dependency versions stable
# between runs, so the cached artifacts stay valid.
run: cargo install tauri-cli --git https://github.com/tauri-apps/tauri --branch dev --locked --debug --target-dir target
shell: bash
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
for attempt in 1 2 3; do
cargo binstall -y tauri-cli@^2 --pkg-fmt ${{ runner.os == 'Linux' && 'tgz' || 'zip' }} --disable-strategies quick-install,compile --maximum-resolution-timeout 60 && exit 0
echo "::warning::cargo binstall failed (attempt $attempt)"
sleep 10
done
exit 1
- name: grant admin rights without a prompt
if: startsWith(matrix.platform, 'macos')
@@ -80,4 +131,10 @@ jobs:
echo "TAURI_UPDATER_ADMIN_PROMPT_TEST=1" >> "$GITHUB_ENV"
- name: run integration tests
env:
# The tests bundle the app with `cargo tauri build` over and over, changing nothing but
# its version, and the workspace release profile (fat LTO, a single codegen unit) spends
# about a minute linking each of those builds. None of it matters to the updater.
CARGO_PROFILE_RELEASE_LTO: 'false'
CARGO_PROFILE_RELEASE_CODEGEN_UNITS: '16'
run: cargo test --test '*' -- --ignored
+20 -19
View File
@@ -9,26 +9,27 @@ on:
branches:
- v1
- v2
paths:
paths: &paths
- '.github/workflows/lint-javascript.yml'
- '.github/actions/setup-pnpm/**'
- 'plugins/*/guest-js/**'
# generated by `pnpm build`, checked below
- 'plugins/*/api-iife.js'
- 'plugins/*/src/init-iife.js'
- 'plugins/*/rollup.config.js'
- 'plugins/*/tsconfig.json'
- 'shared/**'
- 'packages/**'
- '.eslintignore'
- '.eslintrc.json'
- '.prettierignore'
- 'eslint.config.js'
- 'tsconfig.base.json'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
- '**/package.json'
pull_request:
branches:
- v1
- v2
paths:
- '.github/workflows/lint-javascript.yml'
- 'plugins/*/guest-js/**'
- 'packages/**'
- '.eslintignore'
- '.eslintrc.json'
- '.prettierignore'
- '**/package.json'
paths: *paths
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -42,18 +43,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 'lts/*'
- uses: pnpm/action-setup@v6
with:
run_install: true
cache: true # the pnpm store, keyed by OS and lockfile hash and shared by every workflow
- uses: ./.github/actions/setup-pnpm
# the type-checked lint rules (and packages/api-e2e) resolve the plugins'
# types from their dist-js build output
- name: build
id: build
run: pnpm build
- name: eslint
run: pnpm lint
- name: ts:check
run: pnpm ts:check
# the build above regenerates the `api-iife.js` and `init-iife.js` files the Rust crates
# embed, which must be committed along with the guest-js changes they come from
- name: check generated files are up to date
if: ${{ !cancelled() && steps.build.outcome == 'success' }}
run: ./.scripts/ci/has-diff.sh
+58 -126
View File
@@ -9,20 +9,23 @@ on:
branches:
- v1
- v2
paths:
paths: &paths
- '.github/workflows/lint-rust.yml'
- 'plugins/*/src/**'
- '!plugins/*/src/api-iife.js'
- '**/Cargo.toml'
- '.scripts/ci/affected-rust-packages.js'
- 'plugins/**'
- '!plugins/*/guest-js/**'
- '!plugins/*/android/**'
- '!plugins/*/*.md'
- '!plugins/*/package.json'
- '!plugins/*/api-iife.js'
- 'Cargo.toml'
- 'Cargo.lock'
pull_request:
branches:
- v1
- v2
paths:
- '.github/workflows/lint-rust.yml'
- 'plugins/*/src/**'
- '!plugins/*/src/api-iife.js'
- '**/Cargo.toml'
paths: *paths
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -32,128 +35,35 @@ permissions:
contents: read
jobs:
# Lists the plugins the change affects and splits them in shards, linted one after the other in
# a single job per platform; see test-rust.yml for the reasoning.
changes:
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
packages: ${{ steps.filter.outputs.changes }}
saver: ${{ steps.saver.outputs.saver }}
shards: ${{ steps.affected.outputs.shards }}
steps:
- uses: actions/checkout@v7
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
tauri-plugin-autostart:
- .github/workflows/lint-rust.yml
- plugins/autostart/**
tauri-plugin-cli:
- .github/workflows/lint-rust.yml
- plugins/cli/**
tauri-plugin-clipboard-manager:
- .github/workflows/lint-rust.yml
- plugins/clipboard-manager/**
tauri-plugin-deep-link:
- .github/workflows/lint-rust.yml
- plugins/deep-link/**
tauri-plugin-dialog:
- .github/workflows/lint-rust.yml
- plugins/dialog/**
- plugins/fs/**
tauri-plugin-fs:
- .github/workflows/lint-rust.yml
- plugins/fs/**
tauri-plugin-geolocation:
- .github/workflows/lint-rust.yml
- plugins/geolocation/**
tauri-plugin-global-shortcut:
- .github/workflows/lint-rust.yml
- plugins/global-shortcut/**
tauri-plugin-opener:
- .github/workflows/lint-rust.yml
- plugins/opener/**
tauri-plugin-haptics:
- .github/workflows/lint-rust.yml
- plugins/haptics/**
tauri-plugin-http:
- .github/workflows/lint-rust.yml
- plugins/http/**
- plugins/fs/**
tauri-plugin-localhost:
- .github/workflows/lint-rust.yml
- plugins/localhost/**
tauri-plugin-log:
- .github/workflows/lint-rust.yml
- plugins/log/**
tauri-plugin-notification:
- .github/workflows/lint-rust.yml
- plugins/notification/**
tauri-plugin-os:
- .github/workflows/lint-rust.yml
- plugins/os/**
tauri-plugin-persisted-scope:
- .github/workflows/lint-rust.yml
- plugins/persisted-scope/**
- plugins/fs/**
tauri-plugin-positioner:
- .github/workflows/lint-rust.yml
- plugins/positioner/**
tauri-plugin-process:
- .github/workflows/lint-rust.yml
- plugins/process/**
tauri-plugin-shell:
- .github/workflows/lint-rust.yml
- plugins/shell/**
tauri-plugin-single-instance:
- .github/workflows/lint-rust.yml
- plugins/single-instance/**
tauri-plugin-sql:
- .github/workflows/lint-rust.yml
- plugins/sql/**
tauri-plugin-store:
- .github/workflows/lint-rust.yml
- plugins/store/**
tauri-plugin-stronghold:
- .github/workflows/lint-rust.yml
- plugins/stronghold/**
tauri-plugin-updater:
- .github/workflows/lint-rust.yml
- plugins/updater/**
tauri-plugin-upload:
- .github/workflows/lint-rust.yml
- plugins/upload/**
tauri-plugin-websocket:
- .github/workflows/lint-rust.yml
- plugins/websocket/**
tauri-plugin-window-state:
- .github/workflows/lint-rust.yml
- plugins/window-state/**
# Every package job for a platform restores the same rust-cache entry, and exactly one
# of them saves it (see the `save-if` of the rust-cache step). Prefer the packages whose
# dependency tree covers most of the other plugins' dependencies, so the entry is as
# useful as possible for the packages that did not save it.
- name: pick the package that saves the cache
id: saver
# a pull request checks out its merge commit, whose first parent is the base branch
fetch-depth: 2
- id: affected
run: node .scripts/ci/affected-rust-packages.js
env:
PACKAGES: ${{ steps.filter.outputs.changes }}
run: |
saver="$(jq -rn --argjson packages "${PACKAGES:-[]}" '
["tauri-plugin-upload", "tauri-plugin-sql", "tauri-plugin-updater", "tauri-plugin-single-instance"]
| map(select(. as $p | $packages | index($p) != null))
| first // $packages[0] // empty
')"
echo "saver=$saver" >> "$GITHUB_OUTPUT"
BASE: ${{ github.event_name == 'pull_request' && 'HEAD^1' || github.event.before }}
ALL: ${{ github.event_name == 'workflow_dispatch' }}
GLOBAL_PATHS: .github/workflows/lint-rust.yml
clippy:
name: clippy (${{ matrix.platform.target }}, ${{ matrix.shard.name }})
needs: changes
if: ${{ needs.changes.outputs.packages != '[]' && needs.changes.outputs.packages != '' }}
if: ${{ needs.changes.outputs.shards != '[]' && needs.changes.outputs.shards != '' }}
runs-on: ${{ matrix.platform.os }}
# a stuck step (e.g. `apt-get` waiting on an unreachable mirror) otherwise runs for 6 hours
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
package: ${{ fromJSON(needs.changes.outputs.packages) }}
shard: ${{ fromJSON(needs.changes.outputs.shards) }}
platform:
- target: x86_64-pc-windows-msvc
os: windows-latest
@@ -194,14 +104,36 @@ jobs:
- uses: Swatinem/rust-cache@v2
with:
# One entry shared by every package job (the default key is per job, not per
# matrix entry), only written from `v2`/`v3` and by a single package job; see
# test-rust.yml for the reasoning.
save-if: ${{ (github.ref == 'refs/heads/v2' || github.ref == 'refs/heads/v3') && matrix.package == needs.changes.outputs.saver }}
# One entry per target shared by every shard (the default key is per job and runner
# OS, which the Linux and Android jobs, and the macOS and iOS ones, would share), only
# written from `v2`/`v3` and by a single shard; see test-rust.yml for the reasoning.
key: ${{ matrix.platform.target }}
save-if: ${{ (github.ref == 'refs/heads/v2' || github.ref == 'refs/heads/v3') && matrix.shard.save }}
- name: clippy ${{ matrix.package }}
run: ${{ matrix.platform.cargo }} clippy --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets -- -D warnings
# The shard's packages are linted one after the other, and a failing package does not stop
# the others: the step fails at the end if any did.
- name: clippy ${{ matrix.shard.name }}
shell: bash
env:
PACKAGES: ${{ matrix.shard.packages }}
CARGO: ${{ matrix.platform.cargo }}
TARGET: ${{ matrix.platform.target }}
run: |
failed=()
for package in $PACKAGES; do
echo "::group::clippy $package"
if ! $CARGO clippy --package "$package" --target "$TARGET" --all-targets -- -D warnings; then
failed+=("$package")
# the features of `dialog` cannot all be enabled at once
elif [ "$package" != tauri-plugin-dialog ] && ! $CARGO clippy --package "$package" --target "$TARGET" --all-targets --all-features -- -D warnings; then
failed+=("$package (--all-features)")
fi
echo "::endgroup::"
done
- name: clippy ${{ matrix.package }} --all-features
if: matrix.package != 'tauri-plugin-dialog'
run: ${{ matrix.platform.cargo }} clippy --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --all-features -- -D warnings
if [ ${#failed[@]} -gt 0 ]; then
for package in "${failed[@]}"; do
echo "::error title=clippy failed::$package"
done
exit 1
fi
+1 -8
View File
@@ -27,14 +27,7 @@ jobs:
- name: Fetch git tags
run: git fetch origin 'refs/tags/*:refs/tags/*'
- uses: actions/setup-node@v7
with:
node-version: 'lts/*'
- uses: pnpm/action-setup@v6
with:
run_install: true
cache: true # the pnpm store, keyed by OS and lockfile hash and shared by every workflow
- uses: ./.github/actions/setup-pnpm
- name: Build packages
run: pnpm build
+8 -11
View File
@@ -27,21 +27,16 @@ jobs:
matrix:
platform: [ubuntu-latest, macos-latest, windows-latest]
# No caches on purpose: this workflow only runs on pull requests, so anything it saved
# would live on the merge ref where no other run can restore it, while still counting
# against the repository's 10 GB cache limit and evicting entries that `v2`/`v3` saved.
# Nothing is saved to the cache on purpose: this workflow only runs on pull requests, so
# anything it saved would live on the merge ref where no other run can restore it, while
# still counting against the repository's 10 GB cache limit and evicting entries that
# `v2`/`v3` saved. Restoring is fine, as setup-pnpm does with the pnpm store.
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@1.90
- uses: actions/setup-node@v7
with:
node-version: 'lts/*'
- uses: pnpm/action-setup@v6
with:
run_install: true
- uses: ./.github/actions/setup-pnpm
- uses: actions/setup-java@v5
with:
@@ -71,8 +66,10 @@ jobs:
- name: build API
run: pnpm build
# A release build, so R8 runs with the plugins' ProGuard rules, of a single ABI: the
# other three would only repeat the (uncached) release build of the Rust code.
- name: build APK
working-directory: ./examples/api
run: pnpm tauri android build
run: pnpm tauri android build --target aarch64
env:
NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
+10 -31
View File
@@ -11,7 +11,7 @@ on:
push:
branches:
- v2
paths:
paths: &paths
- '.github/workflows/test-api-e2e-mobile.yml'
- 'packages/api-e2e/**'
- 'examples/api/**'
@@ -21,19 +21,16 @@ on:
- 'plugins/*/ios/**'
- 'plugins/*/permissions/**'
- 'plugins/*/build.rs'
# dependency bumps
- 'Cargo.toml'
- 'Cargo.lock'
- 'plugins/*/Cargo.toml'
- 'pnpm-lock.yaml'
- '**/package.json'
pull_request:
branches:
- v2
paths:
- '.github/workflows/test-api-e2e-mobile.yml'
- 'packages/api-e2e/**'
- 'examples/api/**'
- 'plugins/*/guest-js/**'
- 'plugins/*/src/**'
- 'plugins/*/android/**'
- 'plugins/*/ios/**'
- 'plugins/*/permissions/**'
- 'plugins/*/build.rs'
paths: *paths
env:
RUST_BACKTRACE: 1
@@ -63,13 +60,7 @@ jobs:
with:
targets: x86_64-linux-android
- name: setup node
uses: actions/setup-node@v7
with:
node-version: 'lts/*'
- uses: pnpm/action-setup@v6
with:
cache: true # the pnpm store, keyed by OS and lockfile hash and shared by every workflow
- uses: ./.github/actions/setup-pnpm
- uses: actions/setup-java@v5
with:
@@ -122,9 +113,6 @@ jobs:
# that other runs would have hit (10 GB repository limit, LRU eviction).
save-if: ${{ github.ref == 'refs/heads/v2' || github.ref == 'refs/heads/v3' }}
- name: install dependencies
run: pnpm i --frozen-lockfile
- name: build plugins
run: pnpm build
@@ -186,13 +174,7 @@ jobs:
with:
targets: aarch64-apple-ios-sim
- name: setup node
uses: actions/setup-node@v7
with:
node-version: 'lts/*'
- uses: pnpm/action-setup@v6
with:
cache: true # the pnpm store, keyed by OS and lockfile hash and shared by every workflow
- uses: ./.github/actions/setup-pnpm
- uses: Swatinem/rust-cache@v2
with:
@@ -202,9 +184,6 @@ jobs:
# that other runs would have hit (10 GB repository limit, LRU eviction).
save-if: ${{ github.ref == 'refs/heads/v2' || github.ref == 'refs/heads/v3' }}
- name: install dependencies
run: pnpm i --frozen-lockfile
- name: build plugins
run: pnpm build
+9 -19
View File
@@ -11,7 +11,7 @@ on:
push:
branches:
- v2
paths:
paths: &paths
- '.github/workflows/test-api-e2e.yml'
- 'packages/api-e2e/**'
- 'examples/api/**'
@@ -19,17 +19,16 @@ on:
- 'plugins/*/src/**'
- 'plugins/*/permissions/**'
- 'plugins/*/build.rs'
# dependency bumps
- 'Cargo.toml'
- 'Cargo.lock'
- 'plugins/*/Cargo.toml'
- 'pnpm-lock.yaml'
- '**/package.json'
pull_request:
branches:
- v2
paths:
- '.github/workflows/test-api-e2e.yml'
- 'packages/api-e2e/**'
- 'examples/api/**'
- 'plugins/*/guest-js/**'
- 'plugins/*/src/**'
- 'plugins/*/permissions/**'
- 'plugins/*/build.rs'
paths: *paths
env:
RUST_BACKTRACE: 1
@@ -63,13 +62,7 @@ jobs:
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: setup node
uses: actions/setup-node@v7
with:
node-version: 'lts/*'
- uses: pnpm/action-setup@v6
with:
cache: true # the pnpm store, keyed by OS and lockfile hash and shared by every workflow
- uses: ./.github/actions/setup-pnpm
- name: install Linux dependencies
if: runner.os == 'Linux'
@@ -117,9 +110,6 @@ jobs:
# that other runs would have hit (10 GB repository limit, LRU eviction).
save-if: ${{ github.ref == 'refs/heads/v2' || github.ref == 'refs/heads/v3' }}
- name: install dependencies
run: pnpm i --frozen-lockfile
- name: build plugins
run: pnpm build
+69 -194
View File
@@ -9,22 +9,23 @@ on:
branches:
- v1
- v2
paths:
paths: &paths
- '.github/workflows/test-rust.yml'
- 'plugins/*/src/**'
- '!plugins/*/src/api-iife.js'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '.scripts/ci/affected-rust-packages.js'
- 'plugins/**'
- '!plugins/*/guest-js/**'
- '!plugins/*/android/**'
- '!plugins/*/*.md'
- '!plugins/*/package.json'
- '!plugins/*/api-iife.js'
- 'Cargo.toml'
- 'Cargo.lock'
pull_request:
branches:
- v1
- v2
paths:
- '.github/workflows/test-rust.yml'
- 'plugins/*/src/**'
- '!plugins/*/src/api-iife.js'
- '**/Cargo.toml'
- '**/Cargo.lock'
paths: *paths
workflow_dispatch:
env:
CARGO_PROFILE_DEV_DEBUG: 0 # no debuginfo: faster builds and a much smaller target dir to cache
@@ -38,182 +39,35 @@ permissions:
contents: read
jobs:
# Lists the plugins the change affects (see .scripts/ci/affected-rust-packages.js) and splits
# them in shards. Each shard is tested in a single job per platform, one package after the other
# in the same target dir, so the dependencies the plugins share (tauri, wry, tao...) are built
# (or restored) once per job instead of once per package, and a change that affects every plugin
# needs a few jobs per platform instead of one per plugin.
changes:
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
packages: ${{ steps.filter.outputs.changes }}
saver: ${{ steps.saver.outputs.saver }}
shards: ${{ steps.affected.outputs.shards }}
steps:
- uses: actions/checkout@v7
- uses: dorny/paths-filter@v2
id: filter
with:
base: v2
filters: |
tauri-plugin-autostart:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/autostart/**
tauri-plugin-cli:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/cli/**
tauri-plugin-clipboard-manager:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/clipboard-manager/**
tauri-plugin-deep-link:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/deep-link/**
tauri-plugin-dialog:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/dialog/**
- plugins/fs/**
tauri-plugin-fs:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/fs/**
tauri-plugin-geolocation:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/geolocation/**
tauri-plugin-global-shortcut:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/global-shortcut/**
tauri-plugin-opener:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/opener/**
tauri-plugin-haptics:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/haptics/**
tauri-plugin-http:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/http/**
- plugins/fs/**
tauri-plugin-localhost:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/localhost/**
tauri-plugin-log:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/log/**
tauri-plugin-notification:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/notification/**
tauri-plugin-os:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/os/**
tauri-plugin-persisted-scope:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/persisted-scope/**
- plugins/fs/**
tauri-plugin-positioner:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/positioner/**
tauri-plugin-process:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/process/**
tauri-plugin-shell:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/shell/**
tauri-plugin-single-instance:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/single-instance/**
tauri-plugin-sql:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/sql/**
tauri-plugin-store:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/store/**
tauri-plugin-stronghold:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/stronghold/**
tauri-plugin-updater:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/updater/**
tauri-plugin-upload:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/upload/**
tauri-plugin-websocket:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/websocket/**
tauri-plugin-window-state:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/window-state/**
# Every package job for a platform restores the same rust-cache entry, and exactly one
# of them saves it (see the `save-if` of the rust-cache step). Prefer the packages whose
# dependency tree covers most of the other plugins' dependencies, so the entry is as
# useful as possible for the packages that did not save it.
- name: pick the package that saves the cache
id: saver
# a pull request checks out its merge commit, whose first parent is the base branch
fetch-depth: 2
- id: affected
run: node .scripts/ci/affected-rust-packages.js
env:
PACKAGES: ${{ steps.filter.outputs.changes }}
run: |
saver="$(jq -rn --argjson packages "${PACKAGES:-[]}" '
["tauri-plugin-upload", "tauri-plugin-sql", "tauri-plugin-updater", "tauri-plugin-single-instance"]
| map(select(. as $p | $packages | index($p) != null))
| first // $packages[0] // empty
')"
echo "saver=$saver" >> "$GITHUB_OUTPUT"
BASE: ${{ github.event_name == 'pull_request' && 'HEAD^1' || github.event.before }}
ALL: ${{ github.event_name == 'workflow_dispatch' }}
GLOBAL_PATHS: .github/workflows/test-rust.yml
test:
name: test (${{ matrix.platform.target }}, ${{ matrix.shard.name }})
needs: changes
if: ${{ needs.changes.outputs.packages != '[]' && needs.changes.outputs.packages != '' }}
if: ${{ needs.changes.outputs.shards != '[]' && needs.changes.outputs.shards != '' }}
strategy:
fail-fast: false
matrix:
package: ${{ fromJSON(needs.changes.outputs.packages) }}
shard: ${{ fromJSON(needs.changes.outputs.shards) }}
platform:
- {
target: x86_64-pc-windows-msvc,
@@ -247,6 +101,8 @@ jobs:
}
runs-on: ${{ matrix.platform.os }}
# a stuck step (e.g. `apt-get` waiting on an unreachable mirror) otherwise runs for 6 hours
timeout-minutes: 90
steps:
- uses: actions/checkout@v7
@@ -263,15 +119,16 @@ jobs:
- uses: Swatinem/rust-cache@v2
with:
# One entry per platform, shared by every package job: the plugins share most of
# their dependency tree (tauri, wry, tao...), and an entry per package and platform
# (26 × 5 entries of 500-800 MB each) never fits the repository's 10 GB cache limit.
# One entry per platform, shared by every shard: the plugins share most of their
# dependency tree (tauri, wry, tao...), and an entry per package or shard and platform
# never fits the repository's 10 GB cache limit.
key: ${{ matrix.platform.target }}
# Only `v2`/`v3` write to the cache: an entry saved from a pull request lives on its
# merge ref, where nothing else can restore it, and every write evicts an entry
# that other runs would have hit (10 GB repository limit, LRU eviction).
# A single package job saves the shared entry, so the jobs don't race for the key.
save-if: ${{ (github.ref == 'refs/heads/v2' || github.ref == 'refs/heads/v3') && matrix.package == needs.changes.outputs.saver }}
# A single shard saves the shared entry, so the jobs don't race for the key; it is the
# one holding the plugins with the widest dependency trees.
save-if: ${{ (github.ref == 'refs/heads/v2' || github.ref == 'refs/heads/v3') && matrix.shard.save }}
# `cross` is built from a pinned git revision (its latest release predates the Android
# targets we need). Keep the binary in its own small cache entry (accessed by every run,
@@ -292,20 +149,38 @@ jobs:
if: ${{ matrix.platform.runner == 'cross' }}
run: echo "${{ runner.tool_cache }}/cross/bin" >> $GITHUB_PATH
- name: test ${{ matrix.package }}
if: ${{ matrix.package != 'tauri-plugin-http' && matrix.package != 'tauri-plugin-dialog' }}
run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --all-features
# The shard's packages run one after the other, and a failing package does not stop the
# others (like `fail-fast: false` across jobs): the step fails at the end if any did.
- name: ${{ matrix.platform.command }} ${{ matrix.shard.name }}
shell: bash
env:
PACKAGES: ${{ matrix.shard.packages }}
RUNNER: ${{ matrix.platform.runner }}
COMMAND: ${{ matrix.platform.command }}
TARGET: ${{ matrix.platform.target }}
run: |
failed=()
for package in $PACKAGES; do
# the features of `http` and `dialog` cannot all be enabled at once
case "$package" in
tauri-plugin-http|tauri-plugin-dialog) features=() ;;
*) features=(--all-features) ;;
esac
- name: test ${{ matrix.package }}
if: ${{ matrix.package == 'tauri-plugin-http' || matrix.package == 'tauri-plugin-dialog' }}
run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets
echo "::group::$COMMAND $package"
if ! $RUNNER $COMMAND --package "$package" --target "$TARGET" --all-targets "${features[@]}"; then
failed+=("$package")
# `--all-targets` above does not include doc tests, so they are run separately.
# Only on the platforms we actually test on, since cargo skips doc tests when cross compiling.
elif [ "$COMMAND" = test ] && ! $RUNNER test --doc --package "$package" --target "$TARGET" "${features[@]}"; then
failed+=("$package (doc tests)")
fi
echo "::endgroup::"
done
# `--all-targets` above does not include doc tests, so they are run separately.
# Only on the platforms we actually test on, since cargo skips doc tests when cross compiling.
- name: doc test ${{ matrix.package }}
if: ${{ matrix.platform.command == 'test' && matrix.package != 'tauri-plugin-http' && matrix.package != 'tauri-plugin-dialog' }}
run: ${{ matrix.platform.runner }} test --doc --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-features
- name: doc test ${{ matrix.package }}
if: ${{ matrix.platform.command == 'test' && (matrix.package == 'tauri-plugin-http' || matrix.package == 'tauri-plugin-dialog') }}
run: ${{ matrix.platform.runner }} test --doc --package ${{ matrix.package }} --target ${{ matrix.platform.target }}
if [ ${#failed[@]} -gt 0 ]; then
for package in "${failed[@]}"; do
echo "::error title=$COMMAND failed::$package"
done
exit 1
fi