| 1 | --- |
| 2 | title: Cargo |
| 3 | description: Publish and add a workspace's Rust crates with Cargo, from a sparse registry of its own on g1t.sh, from your machine and from workflows. |
| 4 | --- |
| 5 | |
| 6 | Every workspace has a Cargo registry of its own: a sparse index, with the |
| 7 | web API that `cargo publish`, `cargo yank` and `cargo search` use. It |
| 8 | works with Cargo 1.74 or later, private crates included. |
| 9 | |
| 10 | ```text |
| 11 | sparse+https://g1t.sh/-/cargo/<workspace>/index/ |
| 12 | ``` |
| 13 | |
| 14 | Crates from crates.io still come from crates.io; only the crates you name |
| 15 | with the workspace's registry come from g1t. |
| 16 | |
| 17 | ## Set up `.cargo/config.toml` |
| 18 | |
| 19 | Name the registry in the project's `.cargo/config.toml`, or in |
| 20 | `~/.cargo/config.toml` for every project. The name you give it is the one |
| 21 | you pass to `--registry`; these pages use the workspace's slug: |
| 22 | |
| 23 | ```toml |
| 24 | [registries.acme] |
| 25 | index = "sparse+https://g1t.sh/-/cargo/acme/index/" |
| 26 | credential-provider = "cargo:token" |
| 27 | ``` |
| 28 | |
| 29 | Cargo sends a token to a registry that asks for one only through a |
| 30 | credential provider named for it. `cargo:token` keeps the token in |
| 31 | `~/.cargo/credentials.toml`, which stays out of the project. To keep it in |
| 32 | your system's keychain instead, name `cargo:wincred` (Windows), |
| 33 | `cargo:macos-keychain` (macOS) or `cargo:libsecret` (Linux). |
| 34 | |
| 35 | Then give Cargo an [access token](https://g1t.sh/settings/tokens): |
| 36 | |
| 37 | ```sh |
| 38 | cargo login --registry acme |
| 39 | ``` |
| 40 | |
| 41 | Cargo asks for the token and hands it to the provider. A token with full |
| 42 | access works; one with scopes needs `packages:read` to add private crates |
| 43 | and `packages:write` to publish and yank them. |
| 44 | |
| 45 | The token can also come from the environment, as |
| 46 | `CARGO_REGISTRIES_ACME_TOKEN` for a registry named `acme`, which is how |
| 47 | [workflows](#in-workflows) give it. |
| 48 | |
| 49 | ## Publish |
| 50 | |
| 51 | Say in `Cargo.toml` where the crate is published and which repository it |
| 52 | comes from: |
| 53 | |
| 54 | ```toml |
| 55 | [package] |
| 56 | name = "http-client" |
| 57 | version = "0.3.1" |
| 58 | edition = "2021" |
| 59 | description = "Our HTTP client" |
| 60 | license = "MIT" |
| 61 | readme = "README.md" |
| 62 | repository = "https://g1t.sh/acme/http-client" |
| 63 | publish = ["acme"] |
| 64 | ``` |
| 65 | |
| 66 | ```sh |
| 67 | cargo publish --registry acme |
| 68 | ``` |
| 69 | |
| 70 | The first publish makes the crate. When its `repository` is a g1t.sh |
| 71 | repository of the same workspace, or a repository is named like the crate |
| 72 | (a crate `http_client` is also matched to a repository `http-client`), it |
| 73 | is linked to that repository and has its visibility and roles: publishing needs Write on it. |
| 74 | Otherwise it is the workspace's, private, and needs the workspace's Write |
| 75 | base permission. See |
| 76 | [who can see and publish a package](/guides/packages/#who-can-see-and-publish-a-package). |
| 77 | |
| 78 | `publish = ["acme"]` keeps the crate from being published to crates.io by |
| 79 | mistake, and lets `cargo publish` leave out `--registry` when it is the |
| 80 | only registry named. |
| 81 | |
| 82 | A crate may depend on crates.io crates and on other crates of the |
| 83 | workspace's registry. The crate's page on g1t.sh shows the README and |
| 84 | description of its highest stable version. |
| 85 | |
| 86 | ## Add a crate |
| 87 | |
| 88 | ```sh |
| 89 | cargo add http-client --registry acme |
| 90 | ``` |
| 91 | |
| 92 | That writes the dependency with its registry into `Cargo.toml`: |
| 93 | |
| 94 | ```toml |
| 95 | [dependencies] |
| 96 | http-client = { version = "0.3.1", registry = "acme" } |
| 97 | ``` |
| 98 | |
| 99 | `Cargo.lock` records each crate's registry and the SHA-256 of its |
| 100 | `.crate` file, which g1t computes when the version is published. |
| 101 | |
| 102 | `cargo search --registry acme http` lists the workspace's crates you can |
| 103 | see whose names match. |
| 104 | |
| 105 | ## Names and versions |
| 106 | |
| 107 | A crate's name follows the crates.io rules: ASCII letters, digits, `-` and |
| 108 | `_`, starting with a letter, at most 64 characters. In a workspace, names |
| 109 | that differ only in case or in `-` against `_` are one name: once |
| 110 | `http-client` is published, `HTTP_Client` is refused. |
| 111 | |
| 112 | A version is published once. Publishing a version that is already there is |
| 113 | refused, as is one that differs from it only in build metadata (`1.0.0+a` |
| 114 | and `1.0.0+b`), so bump `version` first. |
| 115 | |
| 116 | ## Yank |
| 117 | |
| 118 | ```sh |
| 119 | cargo yank --registry acme http-client@0.3.1 |
| 120 | cargo yank --registry acme http-client@0.3.1 --undo |
| 121 | ``` |
| 122 | |
| 123 | A yanked version stays in the registry: projects whose `Cargo.lock` |
| 124 | names it still build, but Cargo no longer picks it for new lockfiles or |
| 125 | `cargo update`. Yanking needs what publishing does. The crate's page marks |
| 126 | yanked versions, and someone with Admin on the linked repository (an |
| 127 | owner, for the workspace's own crates) can delete a version there for |
| 128 | good. |
| 129 | |
| 130 | Crate owners are not kept: who may publish a crate is decided by its |
| 131 | repository's roles, or the workspace's, so `cargo owner` answers with an |
| 132 | error that says so. |
| 133 | |
| 134 | ## Private and public crates |
| 135 | |
| 136 | A crate linked to a repository has the repository's visibility; one of |
| 137 | the workspace's own is private until an owner makes it public on its page. |
| 138 | |
| 139 | | The workspace's crates | Without a token | With a token | |
| 140 | | --- | --- | --- | |
| 141 | | All public | Cargo reads the index and downloads them. | The same; the token is sent to publish and yank. | |
| 142 | | Some private | The registry answers `401`: Cargo needs a token for every crate in it, public ones too. | Cargo sends the token with every request, and sees the crates the token's owner may see. | |
| 143 | |
| 144 | Cargo first asks for the registry's `config.json` without a token. When |
| 145 | the registry answers `401`, Cargo asks again with its token, and the |
| 146 | answer says `"auth-required": true`, so Cargo sends the token from then on. |
| 147 | A private crate you cannot see looks exactly like one that does not exist. |
| 148 | |
| 149 | ## In workflows |
| 150 | |
| 151 | A workflow's `G1T_TOKEN` is the workspace's own token for the run, and can |
| 152 | add and publish the workspace's crates. Give it to Cargo for the registry: |
| 153 | |
| 154 | ```yaml |
| 155 | jobs: |
| 156 | publish: |
| 157 | runs-on: ubuntu-latest |
| 158 | env: |
| 159 | CARGO_REGISTRIES_ACME_INDEX: sparse+https://g1t.sh/-/cargo/acme/index/ |
| 160 | CARGO_REGISTRIES_ACME_CREDENTIAL_PROVIDER: cargo:token |
| 161 | CARGO_REGISTRIES_ACME_TOKEN: ${{ secrets.G1T_TOKEN }} |
| 162 | steps: |
| 163 | - uses: actions/checkout@v4 |
| 164 | - run: cargo test |
| 165 | - run: cargo publish --registry acme |
| 166 | ``` |
| 167 | |
| 168 | `CARGO_REGISTRIES_ACME_INDEX` and `CARGO_REGISTRIES_ACME_CREDENTIAL_PROVIDER` |
| 169 | are needed only when the project has no `.cargo/config.toml` naming the |
| 170 | registry. |
| 171 | |
| 172 | ## Size |
| 173 | |
| 174 | A publish is one request with the `.crate` file inside it, and may hold at |
| 175 | most 100 MB. Without the [g1t plan](/guides/usage-and-billing/#the-g1t-plan), |
| 176 | a workspace's private packages may hold 500 MB and its public ones 10 GB, |
| 177 | as for [container images](/guides/containers/#storage-and-pull-limits). |
| 178 | A `.crate` file is stored once, by its content. |
| 179 | |
| 180 | ## Errors |
| 181 | |
| 182 | | Error | Means | |
| 183 | | --- | --- | |
| 184 | | `401` | No token, or a wrong or expired one. Run `cargo login --registry acme` with a g1t access token. | |
| 185 | | `authenticated registries require a credential-provider to be configured` | The workspace has private crates, and Cargo has no provider for its token. Add `credential-provider = "cargo:token"` to the registry in `.cargo/config.toml`. | |
| 186 | | `403` | Signed in, but your role or your token's scopes do not allow it, or the workspace is out of free package storage. The message says which. | |
| 187 | | `404` | No such crate or version, or a private one you cannot see. | |
| 188 | | `400` | The publish was refused: a name that is not valid or is taken, a version already published, or metadata Cargo did not send in full. The message says which. | |
| 189 | | `413` | The publish is over 100 MB. Leave large files out with `exclude` or `include` in `Cargo.toml`, and check with `cargo package --list`. | |