diff --git a/.github/actions/apt-packages/action.yml b/.github/actions/apt-packages/action.yml new file mode 100644 index 000000000..2fcf5c042 --- /dev/null +++ b/.github/actions/apt-packages/action.yml @@ -0,0 +1,45 @@ +name: Apt packages +description: >- + Installs Ubuntu packages from the Actions cache, asking Ubuntu's mirror only the first time a runner + image needs them: the mirror has stalled at 30 kB/s long enough to cancel jobs. Keyed on the runner + image, which fixes what's already installed, so nothing else has to resolve at install time. + +inputs: + packages: + description: The packages, separated by spaces. + required: true + +runs: + using: composite + steps: + - id: key + shell: bash + env: + PACKAGES: ${{ inputs.packages }} + run: echo "key=apt-$ImageVersion-${PACKAGES// /-}" >> "$GITHUB_OUTPUT" + - id: cached + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/apt-packages + key: ${{ steps.key.outputs.key }} + - if: steps.cached.outputs.cache-hit != 'true' + shell: bash + env: + PACKAGES: ${{ inputs.packages }} + run: | + mkdir -p ~/apt-packages/partial + sudo apt-get update + sudo apt-get install -y --download-only -o Dir::Cache::archives="$HOME/apt-packages" $PACKAGES + sudo rm -rf ~/apt-packages/partial ~/apt-packages/lock + - if: steps.cached.outputs.cache-hit != 'true' + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/apt-packages + key: ${{ steps.key.outputs.key }} + # What a package needs is in the folder or on the image, so this asks no one. An empty folder + # means the image has them all. + - shell: bash + run: | + shopt -s nullglob + debs=(~/apt-packages/*.deb) + (( ${#debs[@]} == 0 )) || sudo dpkg -i "${debs[@]}" diff --git a/.github/actions/release-budgets/action.yml b/.github/actions/release-budgets/action.yml index e29ee53c3..9b91517e2 100644 --- a/.github/actions/release-budgets/action.yml +++ b/.github/actions/release-budgets/action.yml @@ -8,8 +8,9 @@ description: >- runs: using: composite steps: - - shell: bash - run: sudo apt-get update && sudo apt-get install -y libasound2-dev valgrind + - uses: ./.github/actions/apt-packages + with: + packages: libasound2-dev valgrind - shell: bash run: cargo build --profile dist -p locallibrary-cli --locked - shell: bash diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f731cd63a..78159af79 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -129,6 +129,7 @@ jobs: - 'benchmarks/**' - '.github/workflows/locallibrary-ci.yml' - '.github/actions/pr-comment/**' + - '.github/actions/apt-packages/**' - '.github/actions/release-budgets/**' - '!**/*.md' - '!apps/locallibrary/bombadil/**' diff --git a/.github/workflows/locallibrary-bench.yml b/.github/workflows/locallibrary-bench.yml index 1922af4e5..cbcb44528 100644 --- a/.github/workflows/locallibrary-bench.yml +++ b/.github/workflows/locallibrary-bench.yml @@ -93,7 +93,9 @@ jobs: with: save-if: ${{ github.ref == 'refs/heads/main' }} # The CLI's default `playback` feature builds ALSA's bindings, which need its headers. - - run: sudo apt-get update && sudo apt-get install -y libasound2-dev + - uses: ./.github/actions/apt-packages + with: + packages: libasound2-dev # Keep in step with codspeed-criterion-compat's version in Cargo.toml. It has no # install-action manifest, so this falls back to cargo-binstall, which fetches CodSpeed's # release binary. diff --git a/.github/workflows/locallibrary-ci.yml b/.github/workflows/locallibrary-ci.yml index 1b4855f26..d5013fef3 100644 --- a/.github/workflows/locallibrary-ci.yml +++ b/.github/workflows/locallibrary-ci.yml @@ -97,7 +97,9 @@ jobs: run: cargo nextest run -p locallibrary-cli --no-default-features --locked -E 'test(commands_come_with_the_features_built_in)' # The TUI's audio output goes through ALSA on Linux. - if: inputs.linux || inputs.docs || inputs.cache - run: sudo apt-get update && sudo apt-get install -y libasound2-dev + uses: ./.github/actions/apt-packages + with: + packages: libasound2-dev - if: inputs.linux || inputs.cache run: cargo clippy --workspace --all-targets --locked -- -D warnings # nextest doesn't run doctests. @@ -140,7 +142,9 @@ jobs: - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 with: save-if: ${{ github.ref == 'refs/heads/main' }} - - run: sudo apt-get update && sudo apt-get install -y libasound2-dev + - uses: ./.github/actions/apt-packages + with: + packages: libasound2-dev - uses: taiki-e/install-action@8cca0918f8471c33515202b73f56ab27f2bed283 # v2.87.29 with: tool: cargo-nextest,cargo-llvm-cov @@ -175,7 +179,9 @@ jobs: with: persist-credentials: false - run: rustup toolchain install - - run: sudo apt-get update && sudo apt-get install -y libasound2-dev sqlcipher + - uses: ./.github/actions/apt-packages + with: + packages: libasound2-dev sqlcipher - uses: taiki-e/install-action@8cca0918f8471c33515202b73f56ab27f2bed283 # v2.87.29 with: tool: cargo-nextest,cargo-llvm-cov @@ -221,7 +227,9 @@ jobs: - run: rustup toolchain install # nextest lists what's in every binary of the archive, and the CLI's links ALSA. Valgrind is # for a frame's instructions. - - run: sudo apt-get update && sudo apt-get install -y libasound2-dev valgrind + - uses: ./.github/actions/apt-packages + with: + packages: libasound2-dev valgrind - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version-file: .node-version @@ -312,7 +320,9 @@ jobs: persist-credentials: false - run: rustup toolchain install # As the shards have them, and rg, which the script picks the tests with. - - run: sudo apt-get update && sudo apt-get install -y libasound2-dev sqlcipher ripgrep + - uses: ./.github/actions/apt-packages + with: + packages: libasound2-dev sqlcipher ripgrep - uses: taiki-e/install-action@8cca0918f8471c33515202b73f56ab27f2bed283 # v2.87.29 with: tool: cargo-nextest,cargo-llvm-cov @@ -350,7 +360,9 @@ jobs: persist-credentials: false - run: rustup toolchain install # nextest lists the tests by running each binary, which links ALSA. - - run: sudo apt-get update && sudo apt-get install -y libasound2-dev + - uses: ./.github/actions/apt-packages + with: + packages: libasound2-dev - uses: taiki-e/install-action@8cca0918f8471c33515202b73f56ab27f2bed283 # v2.87.29 with: tool: cargo-nextest,cargo-llvm-cov @@ -515,7 +527,9 @@ jobs: - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 with: save-if: ${{ github.ref == 'refs/heads/main' }} - - run: sudo apt-get update && sudo apt-get install -y libasound2-dev + - uses: ./.github/actions/apt-packages + with: + packages: libasound2-dev - run: cargo +1.91 check --workspace --locked # RustSec advisories, banned crates and where crates come from (see deny.toml), when what it reads diff --git a/.github/workflows/locallibrary-scheduled.yml b/.github/workflows/locallibrary-scheduled.yml index 543a665ca..3503d0c41 100644 --- a/.github/workflows/locallibrary-scheduled.yml +++ b/.github/workflows/locallibrary-scheduled.yml @@ -139,7 +139,9 @@ jobs: - uses: taiki-e/install-action@8cca0918f8471c33515202b73f56ab27f2bed283 # v2.87.29 with: tool: cargo-hack - - run: sudo apt-get update && sudo apt-get install -y libasound2-dev + - uses: ./.github/actions/apt-packages + with: + packages: libasound2-dev - run: cargo hack clippy --workspace --feature-powerset --all-targets --locked -- -D warnings # Bombadil explores the TUI and the mix report (property-based UI testing; see @@ -162,7 +164,9 @@ jobs: - run: rustup toolchain install - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 - if: runner.os == 'Linux' - run: sudo apt-get update && sudo apt-get install -y libasound2-dev + uses: ./.github/actions/apt-packages + with: + packages: libasound2-dev - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version-file: .node-version @@ -201,7 +205,9 @@ jobs: with: tool: cargo-nextest - if: ${{ !cancelled() && needs.changes.outputs.format == 'true' && runner.os == 'Linux' }} - run: sudo apt-get update && sudo apt-get install -y dosfstools exfatprogs + uses: ./.github/actions/apt-packages + with: + packages: dosfstools exfatprogs - if: ${{ !cancelled() && needs.changes.outputs.format == 'true' }} run: cargo nextest run -p locallibrary --lib --locked --no-fail-fast -E 'test(/^format::disk_image::/)' env: @@ -399,7 +405,9 @@ jobs: - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 # As locallibrary-ci-os.yml's Linux shards have them, and rg, which tools/hegel-coverage.sh # picks the tests with. - - run: sudo apt-get update && sudo apt-get install -y libasound2-dev sqlcipher ripgrep + - uses: ./.github/actions/apt-packages + with: + packages: libasound2-dev sqlcipher ripgrep - run: echo LOCALLIBRARY_REQUIRE_SQLCIPHER=1 >> "$GITHUB_ENV" - uses: taiki-e/install-action@8cca0918f8471c33515202b73f56ab27f2bed283 # v2.87.29 with: diff --git a/.github/workflows/mix-report.yml b/.github/workflows/mix-report.yml index 9641fae71..f13748695 100644 --- a/.github/workflows/mix-report.yml +++ b/.github/workflows/mix-report.yml @@ -24,7 +24,9 @@ jobs: with: save-if: ${{ github.ref == 'refs/heads/main' }} # The CLI's default features include the player's audio output, which needs ALSA. - - run: sudo apt-get update && sudo apt-get install -y libasound2-dev + - uses: ./.github/actions/apt-packages + with: + packages: libasound2-dev - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: