{"id":29721240,"url":"https://github.com/francisrussell/ferrous-actions","last_synced_at":"2026-05-06T01:05:36.169Z","repository":{"id":65370559,"uuid":"580972729","full_name":"FrancisRussell/ferrous-actions","owner":"FrancisRussell","description":"GitHub actions for Rust written in Rust (Release Repository)","archived":false,"fork":false,"pushed_at":"2023-07-03T14:47:02.000Z","size":2900,"stargazers_count":21,"open_issues_count":10,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-10T16:56:27.036Z","etag":null,"topics":["cargo","rust","webassembly"],"latest_commit_sha":null,"homepage":"https://github.com/FrancisRussell/ferrous-actions-dev","language":"Rust","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FrancisRussell.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-12-21T23:41:20.000Z","updated_at":"2024-07-31T21:55:40.000Z","dependencies_parsed_at":"2023-02-19T08:45:36.604Z","dependency_job_id":null,"html_url":"https://github.com/FrancisRussell/ferrous-actions","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/FrancisRussell/ferrous-actions","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FrancisRussell%2Fferrous-actions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FrancisRussell%2Fferrous-actions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FrancisRussell%2Fferrous-actions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FrancisRussell%2Fferrous-actions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FrancisRussell","download_url":"https://codeload.github.com/FrancisRussell/ferrous-actions/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FrancisRussell%2Fferrous-actions/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266857161,"owners_count":23995804,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-24T02:00:09.469Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cargo","rust","webassembly"],"created_at":"2025-07-24T14:39:51.704Z","updated_at":"2026-05-06T01:05:36.123Z","avatar_url":"https://github.com/FrancisRussell.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ferrous Actions\n[![CI](https://github.com/FrancisRussell/ferrous-actions-dev/workflows/CI/badge.svg)](https://github.com/FrancisRussell/ferrous-actions-dev/actions?query=workflow%3ACI)\n\nGitHub action for easing Rust development, written in Rust and compiled to\nWebAssembly.\n\n## About\n\n[actions-rs](https://github.com/actions-rs), the de-facto default for\nRust-related GitHub actions appears to be all but abandoned. This repository is\nan experiment in replacing those actions with ones written in Rust, but\ncompiled down to WebAssembly. This should make them both portable across\nplatforms and more easily maintainable by developers who only know Rust.\n\nPlease note the the development repository for this action is located\n[here](https://github.com/FrancisRussell/ferrous-actions-dev/) whereas the\nrelease repository is located\n[here](https://github.com/FrancisRussell/ferrous-actions/). Issues should be\nfiled against the former.\n\n## Features at a glance\n\n* Installs Rust toolchains via [Rustup](https://rustup.rs/).\n* Intelligent caching of Cargo home (crates, registry indices and Git\n  repositories):\n  * Separate caching of registry indices, Git repositories and crate files.\n  * Only uploads new versions of cache entries when they have changed.\n  * Parameterizable minimum update interval (for fast changing items like\n    registry indices).\n  * Capable of detecting and dropping unused crate files, Git repositories and\n    registry indices on Unix-like platforms (on Windows this is not possible so\n    cache entries are keyed with the hash of all present `Cargo.lock` files).\n  * Detects races between concurrent CI jobs (since a workflow may contains\n    multiple jobs) to update the same cache entry and avoids uploading multiple\n    versions.\n  * Separates caching of content from dependency tracking of each CI job to\n    permit sharing and avoid CI jobs with differing dependencies fighting over\n    what needs to be cached.\n  * Caches can be shared across platforms (Linux, Darwin and Windows).\n* Caching of build artifacts from `cargo install` operations to accelerate\n  installation.\n* Supports the usage of [cross](https://github.com/cross-rs/cross) for\n  cross-compilation.\n* Generates GitHub annotations from output of `cargo clippy`, `cargo build` and\n  `cargo check` operations.\n\n## Usage\n\nLike all GitHub actions, this action is used via directives in a [GitHub\nActions YAML\nfile](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions).\nFor practicality and implementation reasons, Ferrous Actions is structured as\na ‘mono-action’, meaning that all operations are implemented as sub-commands of\na single action rather than being separated. The `command` parameter is always compulsory.\n\nIn all following examples, `FrancisRussell/ferrous-actions@v0.1.0-beta.2`\nshould be replaced by the version of the action that this README is for. An\nexample of the usage of Ferrous actions in a real project can be found\n[here](https://github.com/FrancisRussell/zoog/blob/develop/.github/workflows/ci.yml).\n\nNote that by default, GitHub will use the name of action as the name of a build\nstep in its user interface. This can be confusing since with a mono-action\nthese are always the same.  Liberal use of the `name` attribute is recommended\nand is used in the examples below.\n\n### Caching Cargo home\n\nRegistry indices (e.g. the list of packages on `crates.io`), crate files and\nGit repositories downloaded by Cargo can all be cached between CI jobs.\n\nFile modification timestamps are used to detect if no changes to the cached items\nhave occurred and avoid needlessly uploading them back to the cache.\n\nExample invocation:\n```yml\n- uses: FrancisRussell/ferrous-actions@v0.1.0-beta.2\n  name: Cargo cache\n  with:\n    command: cache\n    cache-only: indices\n    min-recache-crates: 1m\n    min-recache-git-repos: 12h\n    min-recache-indices: 7d\n```\n\nThe following options are also available:\n\n* `cache-only` (optional): a whitespace separated list of the token\n  `git-repos`, `crates` and `indices`. If provided, only these items will be\n  cached. The default is to cache all items.\n* `min-recache-crates` (optional): minimum time before recaching crates. \n* `min-recache-git-repos` (optional): minimum time before recaching Git\n  repositories.\n* `min-recache-indices` (optional): minimum time before recaching registry\n  indices.\n* `cross-platform-sharing` (optional): Attempt to share Cargo\n  home caches across all platforms (`all`), only Unix-like platforms\n  (`unix-like`), or make all caches platform-specific (`none`). The default is\n  `all`.\n\nAll recaching intervals are specified in [human\ntime](https://docs.rs/humantime/latest/humantime/). Specifying the recaching\ninterval makes it possible to avoid uploading a new version of a cached item\neach time it changes. This is useful for registry indices which (in the case of\n`crates.io`) can be large (hundreds of MiBs), often modified, but only with\nsmall changes. At writing, the index minimum recache interval is 2 days and\nnone is specified for crate files or Git repositories.\n\n### Installing a Rust toolchain with Rustup\n\nFerrous actions can download Rustup and install a specified Rust toolchain.\n\nExample invocation:\n```yml\n- uses: FrancisRussell/ferrous-actions@v0.1.0-beta.2\n  name: Install Rustup\n  with:\n    command: install-rustup\n    toolchain: nightly\n    target: wasm32-unknown-unknown\n    profile: minimal\n    default: true\n```\n\nThe following options are also available:\n\n* `toolchain` (required): The toolchain to install\n* `target` (optional): A whitespace separated list of target architectures.\n* `profile` (optional): The Rustup profile (e.g. `minimal`, `default` or\n  `complete`). The default is `default`.\n* `default` (optional): Whether this toolchain should be set as the Rustup\n  default compiler. This defaults to `true`. _This is different to actions-rs's\n  behaviour_.\n* `override` (optional): Whether a Rustup ‘override’ should be set for the\n  current directory. Defaults to `false`.\n\n### Cargo commands\n\nCargo commands can be invoked via Ferrous actions. The value for `command` in\nthis case is `cargo SUBCOMMAND` where `SUBCOMMAND` is a single token.\n\nExample invocation:\n```yml\n- uses: FrancisRussell/ferrous-actions@v0.1.0-beta.2\n  name: Cargo build\n  with:\n    command: cargo build\n    toolchain: stable\n    args: --release\n```\n\nThe following options are available whenever a Cargo subcommand is invoked:\n* `toolchain` (optional): A toolchain identifier that will be passed to `cargo`\n  using the `+toolchain` syntax (only supported by Rustup-installed\n  toolchains).\n* `args` (optional): Command line flags passed to `cargo`. These will be parsed\n  using Unix-style shell quoting rules regardless of platform.\n\n### Installing a package with Cargo install\n\nFerrous actions will use GitHub's caching mechanism to improve the performance\nof installing binaries compared to compiling them from scratch each time. Note\nthat Ferrous actions currently aims towards transparent tool caching - the\ncache should not result in you using a version of a binary you would not\notherwise had you not used the cache.\n\n![grcov install](doc/images/cargo-install-grcov.webp)\n\nThis means that Ferrous actions caches the build artifacts folder rather than\nthe built binaries themselves. The only way to only cache the latter would be\nto be completely certain of all dependencies prior to the build,\n[Nix-style](https://nixos.org/).\n\nFrom the user-perspective this means:\n* Tools will be recompiled from scratch when they are compiled with a\n  previously unseen version of a Rust toolchain. If you track nightly, this\n  might happen relatively frequently.\n* Any changes to a tool (because it or its dependencies have been updated in a\n  registry) will be immediately reflected in the result of an install action.\n  The updated build artifacts will be pushed back to the GitHub cache when this\n  happens.\n\nExample invocation:\n```yml\n- uses: FrancisRussell/ferrous-actions@v0.1.0-beta.2\n  name: Install grcov\n  with:\n    command: cargo install\n    args: grcov\n```\n\nThe following options have additional constraints:\n\n* `args` (required): As above, but at least the binary name is required. Note\n  that the command line is hashed to produce the cache key so changes will\n  cause a tool to be rebuilt from scratch.\n\nWhen invoked via Ferrous actions, `cargo install` will execute in a different\ndirectory to the current one. The aim here is to avoid either a\n`rust-toolchain.toml` or a Rustup override changing the compiler used to\ncompile the binary.\n\n### Getting annotations from cargo build, check or clippy\n\nWhen the `build`, `check` or `clippy` Cargo subcommands are run via Ferrous actions,\nannotations are output which can be viewed via the GitHub UI.\n\n![Unused function annotation](doc/images/annotation.webp)\n\nExample invocation:\n```yml\n- uses: FrancisRussell/ferrous-actions@v0.1.0-beta.2\n  name: Cargo clippy\n  with:\n    command: cargo clippy\n    annotations: true\n```\n\nThe following options are also available:\n\n* `annotations` (optional): Can be set to `true` or `false` depending on\n  whether annotations are desired. Default is `true`.\n\n### Cross support\n\nInvocation of `cargo build` via Ferrous actions can also be done in such a way\nthat the [cross](https://github.com/cross-rs/cross) tool is used.\n\nExample invocation:\n```yml\n- uses: FrancisRussell/ferrous-actions@v0.1.0-beta.2\n  name: Cargo build\n  with:\n    command: cargo build\n    args: --target=x86_64-apple-darwin\n    use-cross: true\n```\n\nIf `use-cross` is specified as `true` then `cross` will be used for\ncompilation. If is supplied as `false` or not at all then `cargo` will be\ninvoked as normal. If an existing `cross` binary is not available, then one\nwill be built and installed.\n\n## Implementation Notes\n\n### The monotonically increasing cache problem\n\nOne major issue with caching is how to ensure that a cache does not\nmonotonically increase in size. There are two places where this can occur: the\ncached cargo home artifacts, and cached binary intermediate build artifacts.\nThis problem is only partially solved.\n\nOn Linux and Apple systems, file access times are used to determine what\nentries in cached cargo home items were accessed and to prune items that\nweren't. This has been implemented such that it still works in the presence of\n‘relatime’ semantics - when the file access timestamp is only updated if it is\nbehind the modification timestamp. \n\nFile access times are typically disabled under Windows - Microsoft never\nimplemented an equivalent of relatime, meaning that they remain a significant\nperformance hit. On filesystems that do not update file access time-stamps,\nFerrous actions will incorporate the hash of all `Cargo.lock` files under the\ncurrent folder into the cache key. This means that caches will be rebuilt from\nscratch whenever a `Cargo.lock` file changes.\n\nThis solution is far from ideal since it causes recaching more than necessary\nand won't work if no `Cargo.lock` files are committed to Git, or items are\nadded to the cache via other means (e.g. due to `cargo install`).\n\nNo solution exists for the issue of the build artifact folder increasing in\nsize. Rust is a fast moving language so it's expected that compiler bumps will\ncause the folder to be rebuilt from scratch anyway before this becomes an\nissue. The file access timestamp technique is unlikely to work here, since it's\nlikely that necessary files are only having timestamps examined rather than\ntheir content read, which won't be reflected in the access time.\n\n### Concurrent CI jobs\n\nLarger projects will be split into multiple CI jobs which have different\ndependencies. It's important that these jobs don't compete against each other.\nThis can happen because they have different opinions on what dependencies are\nneeded or not (causing cache items to be repeatedly evicted and restored), and\nalso because they may all decide a cached item needs to be updated and each\npushes out a new copy at the same time.\n\nEach CI job is assigned a unique identifier (derived from the workflow, job ID\nand any matrix properties) for which a list of dependencies is recorded. Each\none of these dependencies is called a ‘cache group‘ and has a name which\nincorporates a hash of its expected contents.\n\nA cache group represents one or more dependencies (e.g. crates, git\nrepositories) which are bundled together. The individual dependencies may be\nupdated, but none are ever added or removed. This means any CI job is free to\nupdate any cache group it uses. Jobs which have differing dependencies will\ninteract with different cache groups.\n\nMaking a cache group the finest granularity of caching possible might seem like\na good idea. This is currently the case for cached indices and Git\nrepositories, but not for crates. Many crates are quite small (tens of KiB) and\nprojects typically depend on a large number of crates. It seems suboptimal and\npotentially irritating to users to construct a separate cache entry for each\ncached crate. Therefore crates are cached at the level of all crates used from\na particular index.\n\nTo avoid concurrent CI jobs all pushing out similar updated cache groups, we\nuse an API internal to the [cache\naction](https://github.com/actions/toolkit/tree/main/packages/cache) to\ndetermine if any cache group we intend to update has had a new version pushed\nout since we downloaded it, just before we upload a new version. This reduces\nthe window for a race from minutes down to a few seconds.\n\n## `crates.io`\n\nThis code is pushed to `crates.io` primarily as a proactive measure against\nname-squatting and for maintaining a historical record. Consequently it may be\nout of date, and the homepage should be consulted for the latest information.\n\n## Notes / Disclaimer\n\nFerrous actions is very much experimental and should not be relied upon in\nproduction environments or for business critical purposes. See LICENSE for\nadditional details. \n\nFerrous actions is primarily intended for use for hobbyish-sized Rust projects.\nIf you need a complex caching framework then it's time to look at setting up\n[sccache](https://github.com/mozilla/sccache) backed by cloud storage and/or\n[Nix](https://nixos.org/).\n\n## Acknowledgements\n\nThis repository is based off the template created by Peter Evans\n([@peter-evans](https://github.com/peter-evans))\n[here](https://github.com/peter-evans/rust-wasm-action).\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrancisrussell%2Fferrous-actions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffrancisrussell%2Fferrous-actions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrancisrussell%2Fferrous-actions/lists"}