├── .gitignore ├── .github ├── FUNDING.yml └── workflows │ ├── buckle.yml │ ├── dircnt.yml │ ├── faketty.yml │ ├── sha1dir.yml │ ├── cbindgen.yml │ ├── dotslash.yml │ ├── cargo-afl.yml │ ├── cargo-web.yml │ ├── cargo-bloat.yml │ ├── cargo-fuzz.yml │ ├── cargo-tally.yml │ ├── cargo-expand.yml │ ├── cargo-unlock.yml │ ├── star-history.yml │ ├── cargo-docs-rs.yml │ ├── cargo-outdated.yml │ ├── bindgen.yml │ ├── cargo-llvm-lines.yml │ ├── honggfuzz.yml │ ├── wasmtime.yml │ ├── cxxbridge-cmd.yml │ ├── taplo-cli.yml │ ├── reindeer.yml │ ├── mdbook.yml │ ├── ci.yml │ ├── rustup-toolchain-install-master.yml │ └── build.yml ├── scripts └── rebase.sh ├── LICENSE ├── README.md └── action.yml /.gitignore: -------------------------------------------------------------------------------- 1 | *.gpg 2 | *.sig 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: dtolnay 2 | -------------------------------------------------------------------------------- /.github/workflows/buckle.yml: -------------------------------------------------------------------------------- 1 | name: buckle 2 | 3 | on: 4 | push: 5 | branches: 6 | - buckle 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: buckle 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/dircnt.yml: -------------------------------------------------------------------------------- 1 | name: dircnt 2 | 3 | on: 4 | push: 5 | branches: 6 | - dircnt 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: dircnt 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/faketty.yml: -------------------------------------------------------------------------------- 1 | name: faketty 2 | 3 | on: 4 | push: 5 | branches: 6 | - faketty 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: faketty 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/sha1dir.yml: -------------------------------------------------------------------------------- 1 | name: sha1dir 2 | 3 | on: 4 | push: 5 | branches: 6 | - sha1dir 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: sha1dir 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/cbindgen.yml: -------------------------------------------------------------------------------- 1 | name: cbindgen 2 | 3 | on: 4 | push: 5 | branches: 6 | - cbindgen 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: cbindgen 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/dotslash.yml: -------------------------------------------------------------------------------- 1 | name: dotslash 2 | 3 | on: 4 | push: 5 | branches: 6 | - dotslash 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: dotslash 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/cargo-afl.yml: -------------------------------------------------------------------------------- 1 | name: cargo-afl 2 | 3 | on: 4 | push: 5 | branches: 6 | - cargo-afl 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: cargo-afl 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/cargo-web.yml: -------------------------------------------------------------------------------- 1 | name: cargo-web 2 | 3 | on: 4 | push: 5 | branches: 6 | - cargo-web 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: cargo-web 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/cargo-bloat.yml: -------------------------------------------------------------------------------- 1 | name: cargo-bloat 2 | 3 | on: 4 | push: 5 | branches: 6 | - cargo-bloat 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: cargo-bloat 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/cargo-fuzz.yml: -------------------------------------------------------------------------------- 1 | name: cargo-fuzz 2 | 3 | on: 4 | push: 5 | branches: 6 | - cargo-fuzz 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: cargo-fuzz 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/cargo-tally.yml: -------------------------------------------------------------------------------- 1 | name: cargo-tally 2 | 3 | on: 4 | push: 5 | branches: 6 | - cargo-tally 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: cargo-tally 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/cargo-expand.yml: -------------------------------------------------------------------------------- 1 | name: cargo-expand 2 | 3 | on: 4 | push: 5 | branches: 6 | - cargo-expand 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: cargo-expand 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/cargo-unlock.yml: -------------------------------------------------------------------------------- 1 | name: cargo-unlock 2 | 3 | on: 4 | push: 5 | branches: 6 | - cargo-unlock 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: cargo-unlock 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/star-history.yml: -------------------------------------------------------------------------------- 1 | name: star-history 2 | 3 | on: 4 | push: 5 | branches: 6 | - star-history 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: star-history 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/cargo-docs-rs.yml: -------------------------------------------------------------------------------- 1 | name: cargo-docs-rs 2 | 3 | on: 4 | push: 5 | branches: 6 | - cargo-docs-rs 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: cargo-docs-rs 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/cargo-outdated.yml: -------------------------------------------------------------------------------- 1 | name: cargo-outdated 2 | 3 | on: 4 | push: 5 | branches: 6 | - cargo-outdated 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: cargo-outdated 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/bindgen.yml: -------------------------------------------------------------------------------- 1 | name: bindgen-cli 2 | 3 | on: 4 | push: 5 | branches: 6 | - bindgen-cli 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: bindgen-cli 14 | bin: bindgen 15 | permissions: 16 | attestations: write 17 | contents: write 18 | id-token: write 19 | -------------------------------------------------------------------------------- /.github/workflows/cargo-llvm-lines.yml: -------------------------------------------------------------------------------- 1 | name: cargo-llvm-lines 2 | 3 | on: 4 | push: 5 | branches: 6 | - cargo-llvm-lines 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: cargo-llvm-lines 14 | permissions: 15 | attestations: write 16 | contents: write 17 | id-token: write 18 | -------------------------------------------------------------------------------- /.github/workflows/honggfuzz.yml: -------------------------------------------------------------------------------- 1 | name: honggfuzz 2 | 3 | on: 4 | push: 5 | branches: 6 | - honggfuzz 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: honggfuzz 14 | bin: cargo-hfuzz 15 | permissions: 16 | attestations: write 17 | contents: write 18 | id-token: write 19 | -------------------------------------------------------------------------------- /.github/workflows/wasmtime.yml: -------------------------------------------------------------------------------- 1 | name: wasmtime-cli 2 | 3 | on: 4 | push: 5 | branches: 6 | - wasmtime-cli 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: wasmtime-cli 14 | bin: wasmtime 15 | permissions: 16 | attestations: write 17 | contents: write 18 | id-token: write 19 | -------------------------------------------------------------------------------- /.github/workflows/cxxbridge-cmd.yml: -------------------------------------------------------------------------------- 1 | name: cxxbridge-cmd 2 | 3 | on: 4 | push: 5 | branches: 6 | - cxxbridge-cmd 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: cxxbridge-cmd 14 | bin: cxxbridge 15 | permissions: 16 | attestations: write 17 | contents: write 18 | id-token: write 19 | -------------------------------------------------------------------------------- /.github/workflows/taplo-cli.yml: -------------------------------------------------------------------------------- 1 | name: taplo-cli 2 | 3 | on: 4 | push: 5 | branches: 6 | - taplo-cli 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: taplo-cli 14 | bin: taplo 15 | locked: true 16 | permissions: 17 | attestations: write 18 | contents: write 19 | id-token: write 20 | -------------------------------------------------------------------------------- /.github/workflows/reindeer.yml: -------------------------------------------------------------------------------- 1 | name: reindeer 2 | 3 | on: 4 | push: 5 | branches: 6 | - reindeer 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: reindeer 14 | git: facebookincubator/reindeer 15 | locked: true 16 | permissions: 17 | attestations: write 18 | contents: write 19 | id-token: write 20 | -------------------------------------------------------------------------------- /.github/workflows/mdbook.yml: -------------------------------------------------------------------------------- 1 | name: mdbook 2 | 3 | on: 4 | push: 5 | branches: 6 | - mdbook 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: mdbook 14 | version: 0.4.47 # https://github.com/rust-lang/mdBook/issues/2634 15 | permissions: 16 | attestations: write 17 | contents: write 18 | id-token: write 19 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | workflow_dispatch: 8 | schedule: [cron: "40 1 * * *"] 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | install: 15 | name: Install 16 | runs-on: ubuntu-latest 17 | timeout-minutes: 45 18 | steps: 19 | - uses: actions/checkout@v6 20 | - uses: ./ 21 | with: 22 | crate: cargo-outdated 23 | - run: cargo outdated --version 24 | -------------------------------------------------------------------------------- /.github/workflows/rustup-toolchain-install-master.yml: -------------------------------------------------------------------------------- 1 | name: rustup-toolchain-install-master 2 | 3 | on: 4 | push: 5 | branches: 6 | - rustup-toolchain-install-master 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | uses: ./.github/workflows/build.yml 12 | with: 13 | crate: rustup-toolchain-install-master 14 | git: dtolnay-contrib/rustup-toolchain-install-master 15 | ref: nodefault 16 | permissions: 17 | attestations: write 18 | contents: write 19 | id-token: write 20 | -------------------------------------------------------------------------------- /scripts/rebase.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." 6 | 7 | if ! git diff-index --quiet HEAD; then 8 | echo "Not running rebase.sh because git working directory is dirty" >&2 9 | exit 1 10 | fi 11 | 12 | if [ -z "$1" ]; then 13 | echo "Usage: scripts/rebase.sh [crate]..." >&2 14 | exit 1 15 | fi 16 | 17 | base=$(git rev-parse HEAD) 18 | push=() 19 | 20 | ( 21 | set -x 22 | git fetch origin --quiet --tags --force 23 | ) 24 | 25 | for crate in "$@"; do 26 | ( 27 | set -x 28 | git tag --delete "$crate" &>/dev/null || true 29 | git checkout --quiet origin/"$crate" 30 | git commit --quiet --amend --no-edit 31 | git rebase --quiet "$base" 32 | ) 33 | push+=("$(git rev-parse HEAD):refs/heads/$crate") 34 | done 35 | 36 | ( 37 | set -x 38 | git checkout --quiet "$base" 39 | ) 40 | 41 | git push origin --force-with-lease "${push[@]}" 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fast `cargo install` action 2 | 3 | This GitHub Action installs a Rust crate using precompiled signed binaries built 4 | on GitHub and hosted as GitHub release artifacts. 5 | 6 | ## Example workflow 7 | 8 | ```yaml 9 | name: test suite 10 | on: [push, pull_request] 11 | 12 | jobs: 13 | doc: 14 | name: Documentation 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v6 18 | - uses: dtolnay/install@cargo-docs-rs 19 | - run: cargo docs-rs 20 | ``` 21 | 22 | 23 | 24 | ## Security 25 | 26 | Binaries are cryptographically signed and verified using [GitHub artifact 27 | attestation] to establish the build's provenance, including the specific 28 | workflow file and workflow run that produced the artifact. 29 | 30 | [GitHub artifact attestation]: https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds 31 | 32 | ## License 33 | 34 | The scripts and documentation in this project are released under the [MIT 35 | License]. 36 | 37 | [MIT License]: LICENSE 38 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: cargo install 2 | author: David Tolnay 3 | description: Fast `cargo install` action using a GitHub-based binary cache 4 | inputs: 5 | crate: 6 | description: Name of crate as published to crates.io 7 | required: true 8 | bin: 9 | description: Name of binary; default = same as crate name 10 | required: false 11 | github_token: 12 | description: Access token for connecting to GitHub API for artifact attestation; normally the ephemeral {{github.token}} when used in a GitHub workflow, or a personal access token {{secrets.GH_TOKEN}} in Gitea's act runner 13 | default: ${{github.token}} 14 | runs: 15 | using: composite 16 | steps: 17 | - name: Check inputs 18 | run: | 19 | echo "crate=${{inputs.crate}}" >> $GITHUB_OUTPUT 20 | echo "bin=${{inputs.bin || inputs.crate}}" >> $GITHUB_OUTPUT 21 | shell: bash 22 | id: inputs 23 | - name: Determine cargo bin directory 24 | run: echo "dir=$(dirname $(which cargo))" >> $GITHUB_OUTPUT 25 | shell: bash 26 | id: cargo 27 | - name: Download ${{steps.inputs.outputs.bin}} 28 | run: curl --output ${{steps.cargo.outputs.dir}}/${{steps.inputs.outputs.bin}} https://github.com/dtolnay/install/releases/download/${{steps.inputs.outputs.crate}}/${{steps.inputs.outputs.bin}} --location --silent --show-error --fail --retry 5 29 | shell: bash 30 | - name: Verify artifact attestation 31 | run: gh attestation verify --owner dtolnay ${{steps.cargo.outputs.dir}}/${{steps.inputs.outputs.bin}} 32 | env: 33 | GH_TOKEN: ${{inputs.github_token}} 34 | shell: bash 35 | - name: Set executable bit 36 | run: chmod +x ${{steps.cargo.outputs.dir}}/${{steps.inputs.outputs.bin}} 37 | shell: bash 38 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | crate: 7 | required: true 8 | type: string 9 | version: 10 | required: false 11 | type: string 12 | bin: 13 | required: false 14 | type: string 15 | git: 16 | required: false 17 | type: string 18 | ref: 19 | required: false 20 | type: string 21 | path: 22 | required: false 23 | type: string 24 | toolchain: 25 | required: false 26 | type: string 27 | default: stable 28 | locked: 29 | required: false 30 | type: boolean 31 | default: false 32 | 33 | jobs: 34 | build: 35 | name: ${{inputs.crate}} 36 | runs-on: ubuntu-latest 37 | permissions: 38 | attestations: write 39 | contents: write 40 | id-token: write 41 | timeout-minutes: 45 42 | steps: 43 | - uses: actions/checkout@v6 44 | - uses: actions/checkout@v6 45 | with: 46 | repository: ${{inputs.git}} 47 | ref: ${{inputs.ref}} 48 | path: ${{inputs.crate}} 49 | if: inputs.git 50 | - uses: dtolnay/rust-toolchain@master 51 | with: 52 | toolchain: ${{inputs.toolchain}} 53 | - run: cargo install --force ${{inputs.git && format('--path={0}', inputs.path || '.') || inputs.crate}} ${{inputs.version && format('--version={0}', inputs.version) || ''}} --bin ${{inputs.bin || inputs.crate}} ${{inputs.locked && '--locked' || ''}} 54 | working-directory: ${{inputs.git && inputs.crate || '.'}} 55 | - id: which 56 | run: echo "which=$(which ${{inputs.bin || inputs.crate}})" >> $GITHUB_OUTPUT 57 | - id: version 58 | run: echo "version=$(cargo install --list | grep -o '^${{inputs.crate}} \([^ :]\)\+')" >> $GITHUB_OUTPUT 59 | - uses: actions/attest-build-provenance@v2 60 | with: 61 | subject-path: ${{steps.which.outputs.which}} 62 | - run: git tag -d ${{inputs.crate}} || true 63 | - run: git tag ${{inputs.crate}} 64 | - run: git push origin tag ${{inputs.crate}} --force 65 | - uses: softprops/action-gh-release@v2 66 | with: 67 | tag_name: ${{inputs.crate}} 68 | target_commitish: ${{github.ref}} 69 | files: ${{steps.which.outputs.which}} 70 | fail_on_unmatched_files: true 71 | body: ${{steps.version.outputs.version}} 72 | --------------------------------------------------------------------------------