neiam
/neiam-portal
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
Publish to the forge's cargo registry
f1c3bee · Gabriel Morell · 2026-09-16 18:41
Message
{commit_body(@commit)}
Files changed
added
.forgejo/workflows/publish.yml
+111
−0
@@ -0,0 +1,111 @@
| 1 | +name: publish | |
| 2 | + | |
| 3 | +# A tag publishes; master only checks that a publish *would* work. | |
| 4 | +# | |
| 5 | +# Cargo refuses to overwrite a published version, and rightly — so a workflow | |
| 6 | +# that published on every push would fail on its second run and stay failed | |
| 7 | +# until someone bumped the version. The dry run on master is the useful half of | |
| 8 | +# that anyway: it catches a manifest that cannot be packaged at the commit that | |
| 9 | +# broke it, rather than at the tag three weeks later. | |
| 10 | +on: | |
| 11 | + push: | |
| 12 | + branches: [master] | |
| 13 | + tags: ['v*'] | |
| 14 | + | |
| 15 | +jobs: | |
| 16 | + publish: | |
| 17 | + runs-on: self-hosted | |
| 18 | + | |
| 19 | + env: | |
| 20 | + # `cargo publish` needs a host toolchain and nothing else — no ESP | |
| 21 | + # anything, since esp-idf-svc is target-scoped in Cargo.toml and a host | |
| 22 | + # build compiles only the pure modules. | |
| 23 | + # | |
| 24 | + # Installed here rather than taken from a `container:` image, because the | |
| 25 | + # runner executes JavaScript actions with node inside the job container | |
| 26 | + # and `rust:1.90-bookworm` has no node: `actions/checkout@v4` would die | |
| 27 | + # before this workflow started. (lambent-flex-c6 hits the same wall from | |
| 28 | + # the other side; see its firmware.yml.) | |
| 29 | + RUST_VERSION: "1.90.0" | |
| 30 | + REGISTRY_NAME: neiam-portal | |
| 31 | + | |
| 32 | + steps: | |
| 33 | + - uses: actions/checkout@v4 | |
| 34 | + | |
| 35 | + - name: Resolve the forge URL | |
| 36 | + env: | |
| 37 | + CI_FORGE_URL: ${{ vars.CI_FORGE_URL }} | |
| 38 | + run: | | |
| 39 | + set -euo pipefail | |
| 40 | + forge_url=${CI_FORGE_URL:-${GITHUB_SERVER_URL:-}} | |
| 41 | + | |
| 42 | + if [ -z "$forge_url" ]; then | |
| 43 | + echo "No forge URL available." >&2 | |
| 44 | + echo "Set a CI_FORGE_URL variable on this repository or its org." >&2 | |
| 45 | + exit 1 | |
| 46 | + fi | |
| 47 | + | |
| 48 | + echo "FORGE_URL=$forge_url" >> "$GITHUB_ENV" | |
| 49 | + | |
| 50 | + - name: Cache the toolchain and the registry | |
| 51 | + uses: actions/cache@v4 | |
| 52 | + with: | |
| 53 | + path: | | |
| 54 | + .home | |
| 55 | + target | |
| 56 | + key: rust-${{ env.RUST_VERSION }}-${{ hashFiles('Cargo.toml') }} | |
| 57 | + restore-keys: rust-${{ env.RUST_VERSION }}- | |
| 58 | + | |
| 59 | + - name: Rust | |
| 60 | + run: | | |
| 61 | + set -euo pipefail | |
| 62 | + export RUSTUP_HOME="$PWD/.home/.rustup" CARGO_HOME="$PWD/.home/.cargo" | |
| 63 | + echo "RUSTUP_HOME=$RUSTUP_HOME" >> "$GITHUB_ENV" | |
| 64 | + echo "CARGO_HOME=$CARGO_HOME" >> "$GITHUB_ENV" | |
| 65 | + echo "$CARGO_HOME/bin" >> "$GITHUB_PATH" | |
| 66 | + | |
| 67 | + if [ ! -x "$CARGO_HOME/bin/cargo" ]; then | |
| 68 | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ | |
| 69 | + | sh -s -- -y --profile minimal --default-toolchain "$RUST_VERSION" | |
| 70 | + fi | |
| 71 | + | |
| 72 | + "$CARGO_HOME/bin/cargo" --version | |
| 73 | + | |
| 74 | + # The registry is per repository: its index lives under this repository's | |
| 75 | + # own path, and the name a consumer registers it under is the repository | |
| 76 | + # name. Cargo takes an index from configuration only, never a flag — and | |
| 77 | + # this goes in CARGO_HOME rather than ./.cargo/config.toml on purpose, | |
| 78 | + # because `cargo publish` refuses a dirty working tree and writing into | |
| 79 | + # the checkout would make it one. | |
| 80 | + - name: Point cargo at the forge | |
| 81 | + run: | | |
| 82 | + set -euo pipefail | |
| 83 | + mkdir -p "$CARGO_HOME" | |
| 84 | + cat >> "$CARGO_HOME/config.toml" <<TOML | |
| 85 | + | |
| 86 | + [registries.$REGISTRY_NAME] | |
| 87 | + index = "sparse+$FORGE_URL/pkg/cargo/${{ github.repository }}/" | |
| 88 | + TOML | |
| 89 | + cat "$CARGO_HOME/config.toml" | |
| 90 | + | |
| 91 | + # `${{ github.token }}` is minted for this job and may write this | |
| 92 | + # repository's packages and nothing else, so there is no secret to create | |
| 93 | + # first. Cargo reads it from CARGO_REGISTRIES_<NAME>_TOKEN, uppercased | |
| 94 | + # with every non-alphanumeric run folded to `_`. | |
| 95 | + - name: Publish | |
| 96 | + env: | |
| 97 | + CARGO_REGISTRIES_NEIAM_PORTAL_TOKEN: ${{ github.token }} | |
| 98 | + run: | | |
| 99 | + set -euo pipefail | |
| 100 | + | |
| 101 | + if [ "${GITHUB_REF_TYPE:-branch}" = "tag" ]; then | |
| 102 | + cargo publish --registry "$REGISTRY_NAME" | |
| 103 | + echo | |
| 104 | + echo "Published. Consumers add:" | |
| 105 | + echo " [registries.$REGISTRY_NAME]" | |
| 106 | + echo " index = \"sparse+$FORGE_URL/pkg/cargo/${{ github.repository }}/\"" | |
| 107 | + else | |
| 108 | + # --dry-run still packages and verify-builds; it just does not | |
| 109 | + # upload. That is the whole value of running this on master. | |
| 110 | + cargo publish --registry "$REGISTRY_NAME" --dry-run | |
| 111 | + fi |
modified
.gitignore
+4
−0
@@ -3,3 +3,7 @@
| 3 | 3 | /web/node_modules |
| 4 | 4 | /web/dist |
| 5 | 5 | /.embuild |
| 6 | +# CI keeps the toolchain and cargo registry here so actions/cache can see | |
| 7 | +# them. Must be ignored: `cargo publish` refuses a dirty working tree, and | |
| 8 | +# ignoring it also keeps it out of the packaged .crate. | |
| 9 | +/.home |
Parents: b85db9e