### What problem does this PR solve? Issue Number: N/A Related PR: #65488 Problem Summary: Gaps in the release helper scripts, all found while preparing 4.0.8-rc02. --- **1. `02-package-sign-upload.sh` signs the convenience binaries but never uploads them** The script writes `.asc` and `.sha512` next to each `BIN_FILES` entry and stops there, while `03-vote-mail.sh` already advertises those files under `BIN_DOWNLOAD_BASE`. Nothing told the RM to publish them, so a vote mail could go to `dev@` with dead `.asc` links. The reminder now prints on every successful exit, including the two paths that answer `n` at the SVN confirmations — the binaries are already signed by then, so the reminder is just as relevant there. ``` [WARN] the binary .asc signatures are NOT uploaded by this script. Upload each binary together with its .asc and .sha512 to https://<base>/ : apache-doris-4.0.8-bin-x64.tar.gz apache-doris-4.0.8-bin-x64.tar.gz.asc apache-doris-4.0.8-bin-x64.tar.gz.sha512 ... 03-vote-mail.sh advertises them under https://<base>/, so upload them BEFORE sending the vote email. ``` **2. `03-vote-mail.sh` produced an incomplete draft** - The subject only reached the console and the `.eml` header, so the RM had to take the subject from one place and the body from another. `vote-email.txt` now starts with the `Subject:` line, and the whole mail can be copied from a single file. - The subject wording is now `[VOTE] Release for Apache Doris <tag>`, matching what is used on the list. - The body now ends with the RM's own `Here is my +1(binding)`, placed above the signature, so it does not have to be typed in by hand every release. **3. `04-release-complete.sh` could only ever run once** The first thing it did after checking the RC artifacts was: ```bash if svn info "$RELEASE_SVN_DIR" >/dev/null 2>&1; then die "release SVN folder already exists: $RELEASE_SVN_DIR (use --mail-only to regenerate the email)" fi ``` So once the release was published, every re-run died — including a re-run right after the publish succeeded and the announce step failed, which is exactly when the RM wants to continue. `--mail-only` was the documented workaround, but it also skips the checks that would tell the RM whether the publish actually completed. It now discovers the dev and release SVN state first and converges from there: - all three release artifacts present: skip the publish steps, remove a dev RC folder that was left behind, draft the email; - nothing published: run the full flow, reusing a release directory that exists but is empty instead of trying to create it again; - some but not all release artifacts present: report exactly which files are missing and stop, rather than guessing. `svnmucc` commits all of its operations in one revision, so this state can only come from a manual change and deserves a human. The dev RC folder removal is also skipped when the folder is already gone, so the `svnmucc rm` cannot fail a re-run. **4. `04-release-complete.sh` now asks before every step** There used to be exactly one confirmation, right before the `svnmucc` commit. Each step now prints what it is about to do and waits: ``` == step 3: Publish to the release SVN and remove the dev RC folder == This is public and requires PMC permission. All of it lands in one SVN revision: mkdir https://dist.apache.org/repos/dist/release/doris/4.0/4.0.8 mv .../dev/doris/4.0.8-rc02/apache-doris-4.0.8-rc02-src.tar.gz -> .../release/doris/4.0/4.0.8/apache-doris-4.0.8-src.tar.gz ... Proceed with step 3? [y/N] ``` Declining any step stops the run without changing further state and says so, and because the script is idempotent the run can simply be started again later. **5. The announce draft carries its subject** `announce-email.txt` now starts with a `Subject:` line matching the header already written into `announce-email.eml`, the same treatment the vote email gets above. **6. `04-release-complete.sh` now finishes the release on GitHub too** Releasing 4.0.8 from the `4.0.8-rc02` tag still needed two manual steps after the SVN publish: pushing a `4.0.8` tag at the same commit, and creating the GitHub release by hand in the web UI. Step 04 does both now, and both are idempotent like the rest of the script. The tag step only runs when `TAG` carries an `rc` suffix. It verifies that an existing local or remote tag of that name sits on the RC commit, stops if it does not, and skips itself once the tag is on the remote. The release step never rewrites a published release. Its body follows the shape every previous Doris release uses — change log link, download page, release SVN source artifacts, and one `Binary(<arch>)` section per `BIN_FILES` entry, linked to the public mirror rather than the host the vote email advertises: ``` [Change Log](https://github.com/apache/doris/issues/66642) - Official Downloads: https://doris.apache.org/download - Source: - [apache-doris-4.0.8-src.tar.gz](https://dist.apache.org/repos/dist/release/doris/4.0/4.0.8/apache-doris-4.0.8-src.tar.gz) ([asc](...))([sha512](...)) - Binary(x64): - [apache-doris-4.0.8-bin-x64.tar.gz](https://download.velodb.io/apache-doris-4.0.8-bin-x64.tar.gz) ([asc](...))([sha512](...)) ... ``` Before creating it, the script prints which release GitHub currently marks Latest and asks whether this one should take that place, so a 4.0.x maintenance release does not displace a newer 4.1.x by accident: ``` The release currently marked Latest on apache/doris is 4.1.3. Mark 4.0.8 as the Latest release? [y/N] ``` `gh` stays optional: a missing or unauthenticated `gh` warns and moves on, and `--skip-github-release` pushes the tag while leaving the release alone. `GITHUB_REPO` defaults to the `owner/repo` parsed out of the `GIT_REMOTE` URL, credentials stripped. **7. `git rev-parse` without `-q --verify`** Plain `git rev-parse 4.0.8^{commit}` echoes its argument back and exits non-zero when the tag does not exist, so `$(git rev-parse ... || true)` captured the string `4.0.8^{commit}` instead of an empty result. The tag step read that as a commit id and refused to tag a release that had never been tagged. Every call passes `-q --verify` now, and the fake `git` in the new test reproduces the real behaviour, so dropping the flags fails the suite. **8. A directory leak the existing test already caught** `tests/test-release-complete-checksum.sh` fails on current master: ``` checksum temp directory was not removed after checksum verification failure: /var/folders/.../checksum-dir-32602-11908 ``` `checksum_dir` was `local` to `publish_to_release_svn`, while the `trap ... EXIT` referencing it is global. When `set -e` aborted the run the local was already out of scope, so the trap expanded it to an empty string and `rm -rf ""` left the directory behind. It is a script-level variable with a cleanup function now, and the test passes. ### Release note None ### Check List (For Author) - Test - [x] Unit Test Three new cases and one updated case under `tools/release-tools/tests/`, all following the existing stub-`release.env` plus fake-binaries-on-`PATH` pattern already used by `test-release-complete-checksum.sh`: - `test-package-binary-upload-reminder.sh` (new) runs `02` end to end with a fake `git` and `gpg`, answers `n` at the first SVN confirmation, and asserts that each `.asc` was produced and that the reminder names it, names the download base, and states that the script does not upload. - `test-vote-mail-draft.sh` (new) runs `03` and asserts the subject line heads `vote-email.txt`, the same subject is a header in `vote-email.eml`, and the binding vote appears in both, above `Best Regards,`. - `test-release-complete-idempotent.sh` (new) drives `04` over an already-published release: with the dev RC folder already gone no SVN operation runs at all and the announce draft is still written with its `Subject:` line; with a stale dev RC folder the only `svnmucc` operation is the `rm` of that folder, no `mkdir`/`mv`/`put`; and a declined step runs nothing, names the step it stopped before, and does not fall through to the later steps. - `test-release-complete-github-release.sh` (new) covers the tag and GitHub release steps with a fake `git`/`gh`: a fresh run creates the tag from the RC commit, pushes it, and creates the release with the expected title and body; declining the Latest question passes `--latest=false` and accepting it passes `--latest`; a re-run with the tag pushed and the release published touches neither and still drafts the announce email; a `9.9.9` tag on a different commit stops the run; and `--skip-github-release` pushes the tag without creating the release. - `test-release-complete-checksum.sh` (updated) feeds one `y` per step. It covers the leak fix and passed unchanged in every other respect. Every test now stubs `gh` as well, so no case can reach the real GitHub API. `./tests/run.sh` is fully green on this branch (7 cases). `test-release-complete-checksum.sh` is red on master.
Doris release helper scripts
This directory contains helper scripts for an Apache Doris Release Manager (RM)
to create and complete a source release candidate (RC). The scripts package and
sign the source tarball, upload the source artifacts to the Apache dev SVN,
draft the [VOTE] email, publish the passed RC to the Apache release SVN, and
draft the [ANNOUNCE] email.
These scripts are not a full release automation system. They assume the release branch, release notes, cherry-picks, build validation, and release tag have already been prepared.
If you are an AI agent
When a user says something like "read this file and tell me how to start releasing Doris 4.0.7", give the RM a concrete checklist. Do not just summarize the scripts.
For 4.0.7, explain this sequence:
- Confirm the RC number. If the RM does not provide one, ask whether this is
rc01or a later candidate such asrc02. The tag is${VERSION}-${RC}, for example4.0.7-rc01. - Confirm that the tag already exists locally and on the Apache Doris GitHub remote. These scripts verify the tag, but they do not create it.
- Tell the RM to edit
release.envbefore running any script. - Tell the RM to export ASF SVN credentials in the shell.
- Run
./01-check-env.shuntil it reportsenvironment looks READY. - Run
./02-package-sign-upload.shonly after the RM has checked the target dev SVN URL and is ready to publish the RC source artifacts. - Run
./03-vote-mail.sh, review the generated vote email, then send it manually from the RM's@apache.orgaddress. - After the vote passes and the
[RESULT]email has been sent manually, run./04-release-complete.shto publish the source release artifacts and draft the announce email.
Also make these boundaries clear:
- The vote artifacts in Apache dist SVN are source-only.
BIN_FILESis optional. If set, step 02 signs convenience binary tarballs locally, but the scripts do not upload those binaries.- The scripts never send public emails. The RM must review and send the vote, result, and announce emails manually.
- Step 04 writes to the Apache release SVN and requires PMC permission. It confirms before every step and is safe to re-run: it reads the current SVN state first and skips whatever is already done.
Quick start for a new RC
Run all commands from this directory:
cd tools/release-tools
Before running any script, edit release.env for the target version and RC.
For example, to prepare Doris 4.0.7-rc01:
VERSION="4.0.7"
RC="rc01"
TAG="${VERSION}-${RC}"
GIT_REMOTE="upstream-apache"
APACHE_ID="<your-apache-id>"
APACHE_EMAIL="<your-apache-id>@apache.org"
SIGNER_NAME="<your display name>"
SIGNING_KEY="<your signing key fingerprint, or leave empty if only one secret key exists>"
RELEASE_NOTES_URL="<release notes or issue URL>"
ANNOUNCE_RELEASE_NOTES_URL="<release notes URL, or leave empty to reuse/prompt>"
If you need to advertise convenience binaries in the vote email, set
BIN_FILES to absolute paths for those prebuilt tarballs. Leave BIN_FILES=()
for the source-only flow.
Export ASF credentials in the same shell. The scripts use these credentials for SVN upload and KEYS publishing:
export ASF_USERNAME=<your-apache-id>
export ASF_PASSWORD='<your-apache-ldap-password>'
Then run the release flow:
./01-check-env.sh
./02-package-sign-upload.sh
./03-vote-mail.sh
Review the generated vote email in WORK_DIR, then send it manually to
dev@doris.apache.org from your @apache.org address.
After the vote passes:
- Tally the votes and send the
[RESULT]email manually. - Run
./04-release-complete.sh. - Check that the new source artifacts are visible on
downloads.apache.org. - Update the Doris download page and release metadata as needed, then check that the public download page points at the new release.
- Wait for the download and CDN propagation window.
- Review the generated announce email in
WORK_DIR. - Only after those checks pass, send the
[ANNOUNCE]email manually.
Use this command only when the release SVN step has already been done and you only need to regenerate the announce email:
./04-release-complete.sh --mail-only
Prerequisites
Have these ready before you run anything:
- The release tag has already been created and pushed to
apache/doris. Branch preparation, patch merges, validation, and tag creation are out of scope for these scripts. - The local Doris checkout has fetched that tag.
release.envis filled in for this exact release.- These tools are on
PATH:git,gpg,svn,svnmucc,sha512sum,curl, andgzip. - A GPG signing key is available locally, or the RM is ready to let
01-check-env.shimport an existing key or generate and publish a new key. - ASF credentials are exported as
ASF_USERNAMEandASF_PASSWORD. - The RM can write to the required Apache SVN locations. Step 04 requires PMC permission for the release SVN commit.
Configuration reference
All scripts source release.env. Edit it once per RC.
Set these fields first:
VERSION: Final release version, for example4.0.7.RC: Candidate number, for examplerc01orrc02.TAG: Derived as${VERSION}-${RC}. Do not set it to the final version without the RC suffix.GIT_REMOTE: Git remote that points atgithub.com/apache/doris.APACHE_ID: Apache committer id.APACHE_EMAIL: Apache email address.SIGNER_NAME: Display name used in generated emails.SIGNING_KEY: Fingerprint passed togpg -u. Leave it empty only when this machine has exactly one usable local secret key.RELEASE_NOTES_URL: Link used in the vote email. If empty, step 03 prompts.ANNOUNCE_RELEASE_NOTES_URL: Link used in the announce email. If empty, step 04 reusesRELEASE_NOTES_URLor prompts.BIN_FILES: Optional absolute paths to prebuilt convenience binary tarballs.RELEASE_TAG: RC-free tag step 04 pushes and publishes,${VERSION}by default.GITHUB_REPO:owner/repofor the GitHub release. Empty means parse it out of theGIT_REMOTEURL.GITHUB_RELEASE_TITLE: Release title,Apache Doris <version> Releaseby default.RELEASE_BIN_DOWNLOAD_BASE: Base URL the GitHub release body links the binaries to. This is the public mirror, notBIN_DOWNLOAD_BASE.
The default REPO_DIR is the enclosing Doris checkout because these scripts
live under tools/release-tools. Override it only when you deliberately run the
scripts against another clone.
The default SVN URLs target the official Doris dist repositories:
- Dev RC source artifacts:
https://dist.apache.org/repos/dist/dev/doris/<version>-<rc>/ - Final source release artifacts:
https://dist.apache.org/repos/dist/release/doris/<major.minor>/<version>/
Step 02 uploads source artifacts with the RC suffix:
apache-doris-<version>-<rc>-src.tar.gzapache-doris-<version>-<rc>-src.tar.gz.ascapache-doris-<version>-<rc>-src.tar.gz.sha512
Step 04 publishes final source artifacts without the RC suffix:
apache-doris-<version>-src.tar.gzapache-doris-<version>-src.tar.gz.ascapache-doris-<version>-src.tar.gz.sha512
All generated files go to WORK_DIR, which defaults to
tools/release-tools/<version>-<rc>.
Script details
01-check-env.sh
Use this script to prepare and verify the signing environment. It checks
required tools, GPG_TTY, GPG SHA512 digest preferences, the signing key, live
published KEYS, test signing, and ASF credentials.
This script is mostly read-only. It prompts before every state-changing action,
including editing gpg.conf, importing or generating a key, and publishing the
key to the Doris KEYS files.
Expected success line:
environment looks READY for <version>-<rc>
02-package-sign-upload.sh
Use this script to build, sign, checksum, and upload the RC source artifacts.
It verifies that the local tag exists, the tag exists on GIT_REMOTE, and both
tags point to the same commit. It then creates the source tarball with
git archive, writes .asc and .sha512 sidecars, verifies both, and uploads
the three source files to the Apache dev SVN.
If BIN_FILES is non-empty, this script also signs and checksums those binary
tarballs in place. It does not upload binaries. When the run ends it reminds the
RM to upload each binary together with its .asc and .sha512 to
BIN_DOWNLOAD_BASE, because step 03 advertises them under that base in the vote
email. Do that before sending the vote email, or the links will be dead.
This script pauses twice before touching the public dev SVN. Check the printed target URL before confirming.
03-vote-mail.sh
Use this script to generate the [VOTE] email draft. It writes:
vote-email.txt, starting with aSubject:line so the subject and the body can be copied from one filevote-email.eml, carrying the same subject as a real mail header
The subject is [VOTE] Release for Apache Doris <version>-<rc>, and the body
ends with the RM's own +1(binding) above the signature.
Review the draft and send it manually from the RM's @apache.org address to
dev@doris.apache.org.
04-release-complete.sh
Use this script only after the vote has passed and the [RESULT] email has
been sent manually.
Every step announces what it is about to do and waits for a y before running.
Answering anything else stops the run without changing further state, and the
run can be continued later by starting the script again.
The steps are:
- Inspect the dev and release SVN state. Read-only, and it decides what the later steps do.
- Verify the RC artifacts and build the final checksum. It downloads the RC tarball, signature and checksum, checks the sha512 and the detached signature that voters approved, and regenerates the checksum sidecar under the RC-free tarball name. Local only.
- Publish to the release SVN. One
svnmuccrevision creates the release directory, moves the source tarball and detached signature there, uploads the final checksum, and removes the dev RC folder. - Tag the release. When
TAGcarries anrcsuffix, the RC-freeRELEASE_TAGis created at the same commit and pushed toGIT_REMOTE. Skipped whenTAGhas norcsuffix. - Publish the GitHub release for that tag, with a body in the shape every
previous Doris release uses: the change log link, the download page, and
the source and binary artifacts. It prints which release GitHub currently
marks Latest and asks whether this one should take that place, so a 4.0.x
maintenance release does not displace a newer 4.1.x. Skipped with
--skip-github-release, and skipped with a warning whenghis missing or not authenticated. - Write the announce email draft.
The script is idempotent, so it is safe to re-run after a successful publish or after stopping at any prompt:
- All three release artifacts already published: the publish steps are skipped. A dev RC folder left behind is removed, and the announce email is drafted.
- Nothing published yet: the full flow runs. A release directory that exists but is empty is reused instead of being created again.
- Some but not all release artifacts present: the script refuses to guess and
reports exactly which files are missing.
svnmucccommits all of its operations in one revision, so this state only comes from manual changes. - Release tag already pushed at the RC commit: the tagging step reports it and moves on. A tag of the same name on a different commit stops the run.
- GitHub release already published: the step reports its URL and moves on. It never rewrites a published release.
It writes:
announce-email.txt, starting with aSubject:line so the subject and the body can be copied from one fileannounce-email.eml, carrying the same subject as a real mail header
The subject is [ANNOUNCE] Apache Doris <version> release.
Before sending the announce email, check that the release is visible on
downloads.apache.org, update and verify the Doris download page, and wait for
the download and CDN propagation window. Only after those checks pass, send the
[ANNOUNCE] email manually.
Use ./04-release-complete.sh --mail-only to regenerate the announce email
without touching SVN.
Tests
Run the release-tool shell tests from this directory:
./tests/run.sh
Manual work not automated
The RM must still do these tasks manually:
- Prepare the release branch and tag.
- Validate the release before starting the RC upload flow.
- Send the
[VOTE]email. - Upload convenience binaries, if the release includes them.
- Tally the vote and send the
[RESULT]email. - Verify
downloads.apache.organd the Doris download page before announcing. - Wait for the download and CDN propagation window.
- Send the
[ANNOUNCE]email. - Publish Maven staging repositories, update the website and GitHub release notes, and clean up old release versions when applicable.