diff --git a/crates/radicle-httpd/CHANGELOG.md b/CHANGELOG.md similarity index 100% rename from crates/radicle-httpd/CHANGELOG.md rename to CHANGELOG.md diff --git a/Cargo.lock b/Cargo.lock index 8e9ee5e3b..1ba364e6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -225,29 +225,6 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" -[[package]] -name = "aws-lc-rs" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00" -dependencies = [ - "aws-lc-sys", - "untrusted 0.7.1", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4" -dependencies = [ - "cc", - "cmake", - "dunce", - "fs_extra", -] - [[package]] name = "axum" version = "0.8.9" @@ -560,15 +537,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" -[[package]] -name = "cmake" -version = "0.1.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" -dependencies = [ - "cc", -] - [[package]] name = "colorchoice" version = "1.0.5" @@ -753,6 +721,7 @@ dependencies = [ "fiat-crypto", "rustc_version", "subtle", + "zeroize", ] [[package]] @@ -836,6 +805,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", + "pem-rfc7468", "zeroize", ] @@ -961,6 +931,7 @@ version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ + "pkcs8", "signature 2.2.0", ] @@ -972,8 +943,10 @@ checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ "curve25519-dalek", "ed25519 2.2.3", + "serde", "sha2", "subtle", + "zeroize", ] [[package]] @@ -997,6 +970,8 @@ dependencies = [ "ff", "generic-array", "group", + "hkdf", + "pem-rfc7468", "pkcs8", "rand_core 0.6.4", "sec1", @@ -1118,12 +1093,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[package]] name = "futures" version = "0.3.32" @@ -1380,6 +1349,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + [[package]] name = "hmac" version = "0.12.1" @@ -1741,12 +1719,18 @@ version = "10.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eba32bfb4ffdeaca3e34431072faf01745c9b26d25504aa7a6cf5684334fc4fc" dependencies = [ - "aws-lc-rs", "base64 0.22.1", + "ed25519-dalek", "getrandom 0.2.17", + "hmac", "js-sys", + "p256", + "p384", + "rand 0.8.6", + "rsa", "serde", "serde_json", + "sha2", "signature 2.2.0", "zeroize", ] @@ -2880,7 +2864,7 @@ dependencies = [ "cfg-if", "getrandom 0.2.17", "libc", - "untrusted 0.9.0", + "untrusted", "windows-sys 0.52.0", ] @@ -2965,7 +2949,7 @@ checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ "ring", "rustls-pki-types", - "untrusted 0.9.0", + "untrusted", ] [[package]] @@ -3871,12 +3855,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index e5dd47a57..a7356bd72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,11 @@ homepage = "https://radicle.dev" anyhow = "1" chrono = { version = "0.4.41", default-features = false, features = ["clock"] } lexopt = "0.3.1" -meilisearch-sdk = "0.33.0" +# Use the pure-Rust JWT backend (`jwt_rust_crypto`) instead of the default +# `jwt_aws_lc_rs`. The latter pulls in `aws-lc-sys`, whose C/asm does not +# cross-compile to the Apple release targets under cargo-zigbuild. TLS still +# uses `reqwest/rustls-tls`, which is backed by `ring` and cross-compiles fine. +meilisearch-sdk = { version = "0.33.0", default-features = false, features = ["reqwest", "tls", "jwt_rust_crypto"] } radicle = "0.24.0" radicle-surf = { version = "0.27.1", default-features = false } serde = { version = "1", features = ["derive"] } diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 000000000..9f3d19aac --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,168 @@ +# Release Process + +`radicle-httpd` and `radicle-search` are released **together** from this +workspace: a single tag, a single changelog, and one build run that produces +artifacts for both binaries. They share the same version number, bumped in +lockstep. On [files.radicle.dev][files] each binary gets its own release +folder — `releases/radicle-httpd//` and, as a sibling, +`releases/radicle-search//` — so existing `radicle-httpd` download +URLs are unaffected and `radicle-search` is downloaded independently. + +The release tooling lives in [`crates/radicle-httpd/build/`][build]. + +## Scope + +Releases cover **only** the `radicle-httpd` and `radicle-search` binaries. The +web front-end (`radicle-explorer`) is not released this way: it is deployed +continuously (rolling release) and must always remain compatible with the +latest `radicle-httpd`/`radicle-search` release. + +## Prerequisites + +- Git signing configured via SSH: + ```sh + git config set gpg.format ssh + git config set user.signingKey "key::$(rad self --ssh-key)" + ``` +- Working `podman` setup (see [Podman Setup](#podman-setup) below) +- Required tools: `podman`, `rad`, `sha256sum` + +## Prepare Release + +1. Create release branch: + ```sh + git checkout -b releases/ + ``` + +2. Bump the version in **both** crates to the same value, so the two binaries + stay coupled: + - `crates/radicle-httpd/Cargo.toml` + - `crates/radicle-search/Cargo.toml` + +3. Update lockfiles: + ```sh + cargo build + ``` + +4. Generate changelog (the version is read from + `crates/radicle-httpd/Cargo.toml`): + ```sh + crates/radicle-httpd/build/changelog >> CHANGELOG.md + ``` + +5. Edit changelog and remove irrelevant entries. Note in each entry whether a + change belongs to `radicle-httpd` or `radicle-search`. + +6. Commit release: + ```sh + git commit -m "Release " + ``` + +7. Push for review: + ```sh + git push rad HEAD:refs/patches + ``` + +## Review & Merge + +1. Wait for delegate approvals +2. Merge patch into `master` + +## Tag Release + +Create and sign the release tag (one tag covers both binaries): +```sh +crates/radicle-httpd/build/tag +``` + +Publish the tag to Radicle: +```sh +git push rad --tags +``` + +Request delegate approval to make the tag canonical: +```sh +rad sync +git push -f self /tags/releases/:refs/tags/releases/ +``` + +## Build Artifacts + +Run the reproducible build (Linux x86_64 or macOS). A single run compiles the +workspace and packages **both** binaries — one archive per binary per target: +```sh +crates/radicle-httpd/build/build +``` + +This writes to `crates/radicle-httpd/build/artifacts/`: +- `radicle-httpd--.tar.xz` (binary + man page) +- `radicle-search--.tar.xz` (binary) + +each with a `.sig` and `.sha256` alongside. + +> **Note:** A tagged commit is required; versioning uses `git describe`. + +## Upload Artifacts + +The upload publishes each binary into its own sibling folder on +[files.radicle.dev][files] and creates the version-less and `latest` symlinks +for both: +```sh +SSH_LOGIN= crates/radicle-httpd/build/upload +``` + +> **Warning:** Uploading immediately publishes the release. + +## Announce Release + +1. Mark the previous release as resolved in Zulip `#Announcements` + +2. Create a new announcement with the following template: + + **Topic:** `radicle-httpd + radicle-search ` + + **Message:** + ````markdown + # 👾 radicle-httpd + radicle-search + + `radicle-httpd` and `radicle-search` () are released. + + ## Installation + + Download binaries from: + - https://files.radicle.dev/releases/radicle-httpd/ + - https://files.radicle.dev/releases/radicle-search/ + - https://radicle.dev/download + + ## Changelog + + + + ## Checksums + + ``` + + ``` + + :info: This release was built on . Build reproducibility across platforms is unsupported; checksums may differ if rebuilt elsewhere. + ```` + +## Notes + +> **Important:** +> - macOS binaries are unsigned and not notarized; download via CLI only +> - Build reproducibility across platforms is not guaranteed + +## Podman Setup + +We use `podman` for reproducible builds across machines. It's preferred over Docker because it runs without a daemon and doesn't require root access. + +On first run, you may need to configure UID/GID ranges: + +```sh +sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER +podman system migrate +``` + +[files]: https://files.radicle.dev +[build]: crates/radicle-httpd/build/ diff --git a/crates/radicle-httpd/RELEASE.md b/crates/radicle-httpd/RELEASE.md deleted file mode 100644 index 734648a7d..000000000 --- a/crates/radicle-httpd/RELEASE.md +++ /dev/null @@ -1,132 +0,0 @@ -# Release Process - -## Prerequisites - -- Git signing configured via SSH: - ```sh - git config set gpg.format ssh - git config set user.signingKey "key::$(rad self --ssh-key)" - ``` -- Working `podman` setup (see [Podman Setup](#podman-setup) below) -- Required tools: `podman`, `rad`, `sha256sum` - -## Prepare Release - -1. Create release branch: - ```sh - git checkout -b releases/ - ``` - -2. Bump version in `radicle-httpd/Cargo.toml` - -3. Update lockfiles: - ```sh - cargo build - ``` - -4. Generate changelog: - ```sh - radicle-httpd/build/changelog >> radicle-httpd/CHANGELOG.md - ``` - -5. Edit changelog and remove irrelevant entries - -6. Commit release: - ```sh - git commit -m "httpd: Release " - ``` - -7. Push for review: - ```sh - git push rad HEAD:refs/patches - ``` - -## Review & Merge - -1. Wait for delegate approvals -2. Merge patch into `master` - -## Tag Release - -Create and sign the release tag: -```sh -build/tag -``` - -Publish the tag to Radicle: -```sh -git push rad --tags -``` - -Request delegate approval to make the tag canonical: -```sh -rad sync -git push -f self /tags/releases/:refs/tags/releases/ -``` - -## Build Artifacts - -Run the reproducible build (Linux x86_64 or macOS): -```sh -build/build -``` - -> **Note:** Artifacts are written to `build/artifacts/`. A tagged commit is required; versioning uses `git describe`. - -## Upload Artifacts - -```sh -SSH_LOGIN= build/upload -``` - -> **Warning:** Uploading immediately publishes the release. - -## Announce Release - -1. Mark the previous release as resolved in Zulip `#Announcements` - -2. Create a new announcement with the following template: - - **Topic:** `radicle-httpd ` - - **Message:** - ````markdown - # 👾 radicle-httpd - - `radicle-httpd` () is released. - - ## Installation - - Download binaries from: - - https://files.radicle.dev/releases/radicle-httpd/ - - https://radicle.dev/download - - ## Changelog - - - - ## Checksums - - ``` - - ``` - - :info: This release was built on . Build reproducibility across platforms is unsupported; checksums may differ if rebuilt elsewhere. - ```` - -## Notes - -> **Important:** -> - macOS binaries are unsigned and not notarized; download via CLI only -> - Build reproducibility across platforms is not guaranteed - -## Podman Setup - -We use `podman` for reproducible builds across machines. It's preferred over Docker because it runs without a daemon and doesn't require root access. - -On first run, you may need to configure UID/GID ranges: - -```sh -sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER -podman system migrate -``` diff --git a/crates/radicle-httpd/build/Dockerfile b/crates/radicle-httpd/build/Dockerfile index 243502ff3..b34b324a2 100644 --- a/crates/radicle-httpd/build/Dockerfile +++ b/crates/radicle-httpd/build/Dockerfile @@ -1,6 +1,6 @@ # Builds release binaries for Radicle. ARG RUST_VERSION="1.87" -ARG ALPINE_VERSION="3.20" +ARG ALPINE_VERSION="3.21" FROM rust:${RUST_VERSION}-alpine${ALPINE_VERSION} as builder LABEL maintainer="Radicle Team " WORKDIR /src @@ -13,14 +13,16 @@ ARG RADICLE_VERSION ARG GIT_HEAD # Copy cargo configuration we're going to use to specify compiler options. -RUN mkdir -p .cargo && cp build/config.toml .cargo/config.toml +RUN mkdir -p .cargo && cp crates/radicle-httpd/build/config.toml .cargo/config.toml # Install dependencies. RUN apk update && apk add --no-cache git musl-dev xz asciidoctor zig # Build man pages and strip metadata. Removes all comments, since they include # non-reproducible information, such as version numbers. -RUN asciidoctor --doctype manpage --backend manpage --destination-dir . *.1.adoc && \ +RUN asciidoctor --doctype manpage --backend manpage --destination-dir . \ + --source-dir crates/radicle-httpd crates/radicle-httpd/*.1.adoc && \ find . -maxdepth 1 -type f -name '*.1' -exec sed -i '/^.\\\"/d' '{}' \; RUN echo "{ \"name\": \"radicle-httpd\", \"version\": \"${RADICLE_VERSION}\", \"commit\": \"${GIT_HEAD}\", \"timestamp\": \"${SOURCE_DATE_EPOCH}\" }" > /src/radicle-httpd.json +RUN echo "{ \"name\": \"radicle-search\", \"version\": \"${RADICLE_VERSION}\", \"commit\": \"${GIT_HEAD}\", \"timestamp\": \"${SOURCE_DATE_EPOCH}\" }" > /src/radicle-search.json # Add cargo targets. RUN rustup target add \ x86_64-unknown-linux-musl \ @@ -36,7 +38,7 @@ RUN cargo install cargo-zigbuild@0.20.0 --locked # Parts of the macOS SDK are required to build Radicle, we make these available # here. So far only `CoreFoundation` and `Security` frameworks are needed. -RUN xz -d -c build/macos-sdk-11.3.tar.xz | tar -x +RUN xz -d -c crates/radicle-httpd/build/macos-sdk-11.3.tar.xz | tar -x # This env var is used by `cargo-zigbuild` to find the SDK. ENV SDKROOT /src/macos-sdk-11.3 @@ -46,7 +48,8 @@ RUN cargo zigbuild --locked --release \ --target=aarch64-apple-darwin \ --target=aarch64-unknown-linux-musl \ --target=x86_64-unknown-linux-musl \ - -p radicle-httpd + -p radicle-httpd \ + -p radicle-search # Now copy the files to a new image without all the intermediary artifacts to # save some space. @@ -57,29 +60,47 @@ ARG SOURCE_DATE_EPOCH COPY --from=builder \ /src/radicle-httpd.json \ + /src/radicle-search.json \ /builds/ + +# radicle-httpd: binary plus man page, one directory per target. COPY --from=builder \ /src/target/x86_64-unknown-linux-musl/release/radicle-httpd \ - /builds/x86_64-unknown-linux-musl/bin/ + /builds/radicle-httpd-${RADICLE_VERSION}-x86_64-unknown-linux-musl/bin/ COPY --from=builder \ /src/target/aarch64-unknown-linux-musl/release/radicle-httpd \ - /builds/aarch64-unknown-linux-musl/bin/ + /builds/radicle-httpd-${RADICLE_VERSION}-aarch64-unknown-linux-musl/bin/ COPY --from=builder \ /src/target/aarch64-apple-darwin/release/radicle-httpd \ - /builds/aarch64-apple-darwin/bin/ + /builds/radicle-httpd-${RADICLE_VERSION}-aarch64-apple-darwin/bin/ COPY --from=builder \ /src/target/x86_64-apple-darwin/release/radicle-httpd \ - /builds/x86_64-apple-darwin/bin/ -COPY --from=builder /src/*.1 /builds/x86_64-unknown-linux-musl/man/man1/ -COPY --from=builder /src/*.1 /builds/aarch64-unknown-linux-musl/man/man1/ -COPY --from=builder /src/*.1 /builds/aarch64-apple-darwin/man/man1/ -COPY --from=builder /src/*.1 /builds/x86_64-apple-darwin/man/man1/ + /builds/radicle-httpd-${RADICLE_VERSION}-x86_64-apple-darwin/bin/ +COPY --from=builder /src/*.1 /builds/radicle-httpd-${RADICLE_VERSION}-x86_64-unknown-linux-musl/man/man1/ +COPY --from=builder /src/*.1 /builds/radicle-httpd-${RADICLE_VERSION}-aarch64-unknown-linux-musl/man/man1/ +COPY --from=builder /src/*.1 /builds/radicle-httpd-${RADICLE_VERSION}-aarch64-apple-darwin/man/man1/ +COPY --from=builder /src/*.1 /builds/radicle-httpd-${RADICLE_VERSION}-x86_64-apple-darwin/man/man1/ -# Create and compress reproducible archive. +# radicle-search: binary only, one directory per target, as a sibling archive. +COPY --from=builder \ + /src/target/x86_64-unknown-linux-musl/release/radicle-search \ + /builds/radicle-search-${RADICLE_VERSION}-x86_64-unknown-linux-musl/bin/ +COPY --from=builder \ + /src/target/aarch64-unknown-linux-musl/release/radicle-search \ + /builds/radicle-search-${RADICLE_VERSION}-aarch64-unknown-linux-musl/bin/ +COPY --from=builder \ + /src/target/aarch64-apple-darwin/release/radicle-search \ + /builds/radicle-search-${RADICLE_VERSION}-aarch64-apple-darwin/bin/ +COPY --from=builder \ + /src/target/x86_64-apple-darwin/release/radicle-search \ + /builds/radicle-search-${RADICLE_VERSION}-x86_64-apple-darwin/bin/ + +# Create and compress reproducible archives. Every top-level release directory +# (radicle-httpd-* and radicle-search-*) becomes its own `.tar.xz`; the loose +# `.json` manifests are left in place and uploaded separately. WORKDIR /builds RUN apk update && apk add --no-cache tar xz -RUN find * -maxdepth 0 -type d -exec mv '{}' "radicle-httpd-$RADICLE_VERSION-{}" \; && \ - find * -maxdepth 0 -type d -exec tar \ +RUN find * -maxdepth 0 -type d -exec tar \ --sort=name \ --verbose \ --mtime="@$SOURCE_DATE_EPOCH" \ diff --git a/crates/radicle-httpd/build/build b/crates/radicle-httpd/build/build index af04cd7d3..ecaa0e2f4 100755 --- a/crates/radicle-httpd/build/build +++ b/crates/radicle-httpd/build/build @@ -34,7 +34,7 @@ main() { keypath="$(rad path)/keys/radicle.pub" version="$("$(dirname "$0")/version")" image=radicle-build-$version - rust_version="$(cat "$(dirname "$0")/../rust-toolchain")" + rust_version="$(cat "$(git rev-parse --show-toplevel)/rust-toolchain")" if [ ! -f "$keypath" ]; then echo "fatal: no key found at $keypath" >&2 @@ -84,20 +84,24 @@ main() { podman cp --overwrite radicle-build-container:/builds/. $outdir/ for target in $(cat "$(dirname "$0")/TARGETS"); do - echo "Signing artifacts for $target.." + # `radicle-httpd` and `radicle-search` are released together: each ships as + # its own per-target archive. + for bin in radicle-httpd radicle-search; do + echo "Signing $bin artifacts for $target.." - filename="radicle-httpd-$version-$target.tar.xz" - filepath="$outdir/$filename" + filename="$bin-$version-$target.tar.xz" + filepath="$outdir/$filename" - # Output SHA256 digest of archive. - checksum="$(cd $outdir && sha256sum $filename)" - echo "Checksum of $filepath is $(echo "$checksum" | cut -d' ' -f1)" - echo "$checksum" >$filepath.sha256 + # Output SHA256 digest of archive. + checksum="$(cd $outdir && sha256sum $filename)" + echo "Checksum of $filepath is $(echo "$checksum" | cut -d' ' -f1)" + echo "$checksum" >$filepath.sha256 - # Sign archive and verify archive. - rm -f $filepath.sig # Delete existing signature - ssh-keygen -Y sign -n file -f $keypath $filepath - ssh-keygen -Y check-novalidate -n file -s $filepath.sig <$filepath + # Sign archive and verify archive. + rm -f $filepath.sig # Delete existing signature + ssh-keygen -Y sign -n file -f $keypath $filepath + ssh-keygen -Y check-novalidate -n file -s $filepath.sig <$filepath + done done # Remove build artifacts that aren't needed anymore. diff --git a/crates/radicle-httpd/build/changelog b/crates/radicle-httpd/build/changelog index 06c1f78e4..bb867046b 100755 --- a/crates/radicle-httpd/build/changelog +++ b/crates/radicle-httpd/build/changelog @@ -60,9 +60,9 @@ if [ -n "$from" ] && ! git rev-parse --verify "$previous^{tag}" >/dev/null 2>&1; exit 1 fi -echo "# radicle-httpd $version" +echo "# radicle-httpd + radicle-search $version" echo -echo "radicle-httpd $version ($(git rev-parse --short HEAD)) is released." +echo "radicle-httpd and radicle-search $version ($(git rev-parse --short HEAD)) are released." echo echo "## Changelog" diff --git a/crates/radicle-httpd/build/upload b/crates/radicle-httpd/build/upload index 15a273870..adeb328dd 100755 --- a/crates/radicle-httpd/build/upload +++ b/crates/radicle-httpd/build/upload @@ -15,30 +15,45 @@ main() { exit 1 fi - # Create remote folder. - ssh -i $SSH_KEY $SSH_ADDRESS mkdir -p /var/www/files.radicle.dev/releases/radicle-httpd/$version - # Copy files over. - scp -i $SSH_KEY "$(dirname "$0")/artifacts/radicle-httpd-$version"* $SSH_ADDRESS:/var/www/files.radicle.dev/releases/radicle-httpd/$version - scp -i $SSH_KEY "$(dirname "$0")/artifacts/radicle-httpd.json" $SSH_ADDRESS:/var/www/files.radicle.dev/releases/radicle-httpd/$version - - for target in $(cat "$(dirname "$0")/TARGETS"); do - archive=/var/www/files.radicle.dev/releases/radicle-httpd/$version/radicle-httpd-$version-$target.tar.xz - symlink=/var/www/files.radicle.dev/releases/radicle-httpd/$version/radicle-httpd-$target.tar.xz - - echo "Creating symlinks for $target.." - - ssh -i $SSH_KEY $SSH_ADDRESS ln -snf $archive $symlink - ssh -i $SSH_KEY $SSH_ADDRESS ln -snf $archive.sig $symlink.sig - ssh -i $SSH_KEY $SSH_ADDRESS ln -snf $archive.sha256 $symlink.sha256 - done - - if git describe --exact-match --match='releases/*' 2>/dev/null; then - echo "Creating 'latest' symlink.." - ssh -i $SSH_KEY $SSH_ADDRESS ln -snf /var/www/files.radicle.dev/releases/radicle-httpd/$version /var/www/files.radicle.dev/releases/radicle-httpd/latest - else - echo "Skipping 'latest' symlink creation for development build." + # Whether this is a tagged (non-development) build; controls the `latest` + # symlink. + tagged=false + if git describe --exact-match --match='releases/*' >/dev/null 2>&1; then + tagged=true fi + # radicle-httpd and radicle-search are released together, each into its own + # sibling release folder so their download URLs stay independent. + for bin in radicle-httpd radicle-search; do + base=/var/www/files.radicle.dev/releases/$bin + + echo "Uploading $bin..." + + # Create remote folder. + ssh -i $SSH_KEY $SSH_ADDRESS mkdir -p $base/$version + # Copy files over. + scp -i $SSH_KEY "$(dirname "$0")/artifacts/$bin-$version"* $SSH_ADDRESS:$base/$version + scp -i $SSH_KEY "$(dirname "$0")/artifacts/$bin.json" $SSH_ADDRESS:$base/$version + + for target in $(cat "$(dirname "$0")/TARGETS"); do + archive=$base/$version/$bin-$version-$target.tar.xz + symlink=$base/$version/$bin-$target.tar.xz + + echo "Creating symlinks for $bin $target.." + + ssh -i $SSH_KEY $SSH_ADDRESS ln -snf $archive $symlink + ssh -i $SSH_KEY $SSH_ADDRESS ln -snf $archive.sig $symlink.sig + ssh -i $SSH_KEY $SSH_ADDRESS ln -snf $archive.sha256 $symlink.sha256 + done + + if [ "$tagged" = true ]; then + echo "Creating 'latest' symlink for $bin.." + ssh -i $SSH_KEY $SSH_ADDRESS ln -snf $base/$version $base/latest + else + echo "Skipping 'latest' symlink creation for development build." + fi + done + echo "Pushing tags.." git push rad --tags