diff --git a/.github/workflows/nightly-gnu.yml b/.github/workflows/nightly-gnu.yml index 8f1480084..868ccbaa6 100644 --- a/.github/workflows/nightly-gnu.yml +++ b/.github/workflows/nightly-gnu.yml @@ -352,69 +352,16 @@ jobs: # engineers can download and install the nightly directly. The branch is # a single-commit orphan rewritten on every build, which keeps the repo # small while the latest files stay reachable at stable raw URLs. - - name: Publish packages to auto-testing assets + # Publish the deb/rpm pair as assets of the rolling `nightly` release on + # rustfs/auto-testing (see scripts/release/publish_nightly_assets.sh). + - name: Publish packages to auto-testing release assets env: ASSETS_TOKEN: ${{ secrets.PF_TESTING_GH_TOKEN }} DEB_FILE: ${{ steps.deb.outputs.deb_file }} RPM_FILE: ${{ steps.rpm.outputs.rpm_file }} DEB_DATE: ${{ steps.deb.outputs.deb_date }} BUILD_REF: ${{ env.NIGHTLY_BUILD_REF }} - run: | - set -euo pipefail - - if [ -z "${ASSETS_TOKEN}" ]; then - echo "PF_TESTING_GH_TOKEN is not configured; skipping assets upload" - exit 0 - fi - export GH_TOKEN="${ASSETS_TOKEN}" - - for f in "${DEB_FILE}" "${RPM_FILE}"; do - [ -f "$f" ] || { echo "missing package: $f"; exit 1; } - done - - # Plain git + token URL: the build fleet has no gh CLI. - ASSETS_URL="https://x-access-token:${ASSETS_TOKEN}@github.com/rustfs/auto-testing.git" - rm -rf assets-work && mkdir assets-work - if git clone -q --depth 1 --branch assets "${ASSETS_URL}" assets-work 2>/dev/null; then - echo "assets branch cloned" - else - echo "assets branch does not exist yet; creating an orphan" - git -C assets-work init -q -b assets - fi - cd assets-work - git remote add origin "${ASSETS_URL}" 2>/dev/null || \ - git remote set-url origin "${ASSETS_URL}" - - mkdir -p nightly - cp "../${DEB_FILE}" "nightly/${DEB_FILE}" - cp "../${RPM_FILE}" "nightly/${RPM_FILE}" - cp "nightly/${DEB_FILE}" nightly/rustfs-nightly-latest.deb - cp "nightly/${RPM_FILE}" nightly/rustfs-nightly-latest.rpm - - SOURCE_SHA="$(git -C .. rev-parse HEAD 2>/dev/null || echo "${GITHUB_SHA}")" - { - echo "# Nightly packages" - echo "" - echo "- Built: ${DEB_DATE} from \`${BUILD_REF}@${SOURCE_SHA:0:12}\`" - echo "- Run: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" - echo "" - echo '| File | Size | SHA256 |' - echo '|---|---|---|' - for f in "nightly/${DEB_FILE}" "nightly/${RPM_FILE}" nightly/rustfs-nightly-latest.deb nightly/rustfs-nightly-latest.rpm; do - printf '| %s | %s | %s |\n' "$f" "$(du -h "$f" | cut -f1)" "$(sha256sum "$f" | cut -d' ' -f1)" - done - echo "" - echo "Download: replace /blob/ with /raw/ in any file URL, e.g." - echo "\`https://raw.githubusercontent.com/rustfs/auto-testing/assets/nightly/rustfs-nightly-latest.deb\`" - } > BUILD-INFO.md - - git add -A - git -c user.name="rustfs-nightly-bot" -c user.email="support@rustfs.com" \ - commit -q -m "nightly ${DEB_DATE} (${BUILD_REF}@${SOURCE_SHA:0:12})" \ - --allow-empty - git push --force origin assets - echo "✅ Published ${DEB_FILE} and ${RPM_FILE} to rustfs/auto-testing@assets" - + run: bash scripts/release/publish_nightly_assets.sh # Live-Vault lane for the rustfs-kms suite (rustfs/backlog#1774). # # RUSTFS_KMS_VAULT_TOKEN is the single switch that adds the Vault KV2 and diff --git a/scripts/release/publish_nightly_assets.sh b/scripts/release/publish_nightly_assets.sh new file mode 100755 index 000000000..5b6d98cca --- /dev/null +++ b/scripts/release/publish_nightly_assets.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash +# Publish the nightly DEB/RPM as assets of the rolling `nightly` release on +# rustfs/auto-testing, replacing the previous build's files in place. +# +# Required environment: +# ASSETS_TOKEN token with contents:write on rustfs/auto-testing +# DEB_FILE path to the built .deb +# RPM_FILE path to the built .rpm +# DEB_DATE build date (YYYY-MM-DD) +# BUILD_REF branch/ref the nightly was built from +# Optional environment: +# GITHUB_SHA / GITHUB_RUN_ID / GITHUB_REPOSITORY / GITHUB_SERVER_URL +# +# Plain curl + python3 by design: the nightly build fleet has no gh CLI. + +set -euo pipefail + +: "${ASSETS_TOKEN:?ASSETS_TOKEN is required}" +: "${DEB_FILE:?DEB_FILE is required}" +: "${RPM_FILE:?RPM_FILE is required}" +: "${DEB_DATE:?DEB_DATE is required}" +: "${BUILD_REF:?BUILD_REF is required}" + +for f in "${DEB_FILE}" "${RPM_FILE}"; do + [ -f "$f" ] || { echo "missing package: $f" >&2; exit 1; } +done + +API="https://api.github.com/repos/rustfs/auto-testing" +UPLOADS="https://uploads.github.com/repos/rustfs/auto-testing/releases" +AUTH="Authorization: token ${ASSETS_TOKEN}" +SOURCE_SHA="$(git rev-parse HEAD 2>/dev/null || echo "${GITHUB_SHA:-unknown}")" + +release_id="$(curl -fsS --retry 3 -H "${AUTH}" "${API}/releases/tags/nightly" \ + | python3 -c 'import json,sys; print(json.load(sys.stdin).get("id", ""))' 2>/dev/null || true)" +if [ -z "${release_id}" ]; then + echo "creating the rolling nightly release" + release_id="$(curl -fsS --retry 3 -X POST -H "${AUTH}" -H "Content-Type: application/json" \ + -d '{"tag_name":"nightly","name":"Nightly builds","body":"Rolling nightly builds. Assets are replaced on every build; the release body documents the provenance of the current files."}' \ + "${API}/releases" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')" +fi +[ -n "${release_id}" ] || { echo "could not resolve the nightly release id" >&2; exit 1; } + +upload_asset() { + local name="$1" file="$2" asset_id + asset_id="$(curl -fsS --retry 3 -H "${AUTH}" "${API}/releases/tags/nightly" \ + | ASSET_NAME="${name}" python3 -c ' +import json, sys, os +d = json.load(sys.stdin) +name = os.environ["ASSET_NAME"] +print(next((a["id"] for a in d.get("assets", []) if a["name"] == name), ""))')" + if [ -n "${asset_id}" ]; then + curl -fsS --retry 3 -X DELETE -H "${AUTH}" "${API}/releases/assets/${asset_id}" >/dev/null + fi + curl -fsS --retry 3 --max-time 900 -X POST \ + -H "${AUTH}" -H "Content-Type: application/octet-stream" \ + --data-binary "@${file}" \ + "${UPLOADS}/${release_id}/assets?name=${name}" >/dev/null + echo "uploaded ${name}" +} + +upload_asset "rustfs-nightly-latest.deb" "${DEB_FILE}" +upload_asset "rustfs-nightly-latest.rpm" "${RPM_FILE}" + +DEB_SHA="$(sha256sum "${DEB_FILE}" | cut -d ' ' -f 1)" +RPM_SHA="$(sha256sum "${RPM_FILE}" | cut -d ' ' -f 1)" +RUN_URL="${GITHUB_SERVER_URL:-https://github.com}/${GITHUB_REPOSITORY:-/rustfs/rustfs}/actions/runs/${GITHUB_RUN_ID:-0}" +export BUILD_REF SOURCE_SHA DEB_DATE DEB_FILE RPM_FILE DEB_SHA RPM_SHA RUN_URL + +python3 - << 'PY' > /tmp/release-body.json +import json, os +e = os.environ +deb_mb = os.path.getsize(e["DEB_FILE"]) // 1048576 +rpm_mb = os.path.getsize(e["RPM_FILE"]) // 1048576 +body = ( + f"Nightly build from `{e['BUILD_REF']}@{e['SOURCE_SHA'][:12]}`, built {e['DEB_DATE']}.\n\n" + f"[Build run]({e['RUN_URL']}). The `latest` assets are replaced in place on every nightly.\n\n" + f"| Asset | Size | SHA256 |\n|---|---|---|\n" + f"| rustfs-nightly-latest.deb (={e['DEB_FILE']}) | {deb_mb} MB | `{e['DEB_SHA']}` |\n" + f"| rustfs-nightly-latest.rpm (={e['RPM_FILE']}) | {rpm_mb} MB | `{e['RPM_SHA']}` |\n" +) +print(json.dumps({"body": body})) +PY + +curl -fsS --retry 3 -X PATCH -H "${AUTH}" -H "Content-Type: application/json" \ + --data-binary @/tmp/release-body.json "${API}/releases/${release_id}" >/dev/null + +echo "published ${DEB_FILE} and ${RPM_FILE} to the rustfs/auto-testing 'nightly' release"