This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch release-improvements
in repository https://gitbox.apache.org/repos/asf/skywalking-java.git

commit a06a84adc6f6c0892e9f3aa631c925214911ad06
Author: Wu Sheng <[email protected]>
AuthorDate: Fri Apr 10 22:33:56 2026 +0800

    Only publish toolkit to Maven Central, add unified release script
    
    - Set maven.deploy.skip=true by default, override to false only in
      apm-application-toolkit. Agent and plugins are distributed via
      download package and Docker images, not Maven Central.
    - Add tools/releasing/release.sh with two-step release flow:
      prepare-vote (preflight + prepare + stage + upload + vote email)
      and vote-passed (promote + docker + announce email + cleanup).
    - Remove create_release.sh (logic merged into release.sh stage).
    - Update release-java-agent.md documentation.
---
 CHANGES.md                                 |   4 +-
 apm-application-toolkit/pom.xml            |   5 +
 docs/en/contribution/release-java-agent.md | 254 ++---------
 pom.xml                                    |   2 +
 tools/releasing/create_release.sh          |  84 ----
 tools/releasing/release.sh                 | 648 +++++++++++++++++++++++++++++
 6 files changed, 692 insertions(+), 305 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 237ce9ff0c..ef6a81a3e4 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -21,7 +21,9 @@ Release Notes.
 * Enhance test/plugin/run.sh to support extra Maven properties per version in 
support-version.list (format: version,key=value).
 * Add MariaDB 3.x plugin (all classes renamed in 3.x).
 * Extend Jedis 4.x plugin to support Jedis 5.x (fix witness method for 5.x 
compatibility).
-* Add Elasticsearch Java client (co.elastic.clients:elasticsearch-java) plugin 
for 7.x-9.x.
+* Add Elasticsearch Java client (co.elastic.clients:elasticsearch-java) plugin 
for 7.16.x-9.x.
+* Only publish `apm-application-toolkit` modules to Maven Central. Agent and 
plugins are distributed via download package and Docker images.
+* Add unified release script (`tools/releasing/release.sh`) with two-step 
flow: `prepare-vote` and `vote-passed`.
 
 All issues and pull requests are 
[here](https://github.com/apache/skywalking/milestone/249?closed=1)
 
diff --git a/apm-application-toolkit/pom.xml b/apm-application-toolkit/pom.xml
index cc173543d0..b018a7ef16 100644
--- a/apm-application-toolkit/pom.xml
+++ b/apm-application-toolkit/pom.xml
@@ -26,6 +26,11 @@
     <artifactId>apm-application-toolkit</artifactId>
     <packaging>pom</packaging>
 
+    <properties>
+        <!-- Toolkit modules are the only artifacts published to Maven Central 
-->
+        <maven.deploy.skip>false</maven.deploy.skip>
+    </properties>
+
     <modules>
         <module>apm-toolkit-log4j-1.x</module>
         <module>apm-toolkit-log4j-2.x</module>
diff --git a/docs/en/contribution/release-java-agent.md 
b/docs/en/contribution/release-java-agent.md
index 567cf81615..5b941a822c 100644
--- a/docs/en/contribution/release-java-agent.md
+++ b/docs/en/contribution/release-java-agent.md
@@ -36,151 +36,47 @@ If you are a committer, use your Apache ID and password to 
log in this svn, and
 1. Upload your GPG public key to the public GPG site, such as [MIT's 
site](http://pgp.mit.edu:11371/). This site should be in the
 Apache maven staging repository checklist.
 
-## Test your settings
-This step is only for testing purpose. If your env is correctly set, you don't 
need to check every time.
-```
-./mvnw clean install(this will build artifacts, sources and sign)
-```
-
-## Prepare for the release
-```
-./mvnw release:clean
-./mvnw release:prepare -DautoVersionSubmodules=true -Pall
-```
-
-- Set version number as x.y.z, and tag as **v**x.y.z (The version tag must 
start with **v**. You will find out why this is necessary in the next step.)
-
-_You could do a GPG signature before preparing for the release. If you need to 
input the password to sign, and the maven doesn't provide you with the 
opportunity to do so, this may lead to failure of the release. To resolve this, 
you may run `gpg --sign xxx` in any file. This will allow it to remember the 
password for long enough to prepare for the release._
-
-## Stage the release
-```
-./mvnw release:perform -DskipTests -Pall
-```
+## Release using the release script
 
-- The release will be automatically inserted into a temporary staging 
repository.
+The release script `tools/releasing/release.sh` automates the full release 
workflow. The release is a **two-step process** with a vote in between.
 
-## Build and sign the source code and binary package
+### Quick start
 ```shell
-export RELEASE_VERSION=x.y.z (example: RELEASE_VERSION=5.0.0-alpha)
-cd tools/releasing
-bash create_release.sh
-```
-
-This script takes care of the following things:
-1. Use `v` + `RELEASE_VERSION` as tag to clone the codes.
-2. Complete `git submodule init/update`.
-3. Exclude all unnecessary files in the target source tar, such as `.git`, 
`.github`, and `.gitmodules`. See the script for more details.
-4. Execute `gpg` and `shasum 512` for source code tar.
-5. Use maven package to build the agent tar.
-6. Execute `gpg` and `shasum 512` for binary tar.
-
-`apache-skywalking-java-agent-x.y.z-src.tgz` and files ending with `.asc` and 
`.sha512` may be found in the `tools/releasing` folder.
-`apache-skywalking-java-agent-x.y.z.tgz` and files ending with `.asc` and 
`.sha512` may be found in the 
`tools/releasing/apache-skywalking-java-agent-x.y.z` folder.
-
-
-## Upload to Apache svn
-1. Use your Apache ID to log in to 
`https://dist.apache.org/repos/dist/dev/skywalking/java-agent/`.
-1. Create a folder and name it by the release version and round, such as: 
`x.y.z`
-1. Upload the source code package to the folder with files ending with `.asc` 
and `.sha512`.
-1. Upload the distribution package to the folder with files ending with `.asc` 
and `.sha512`.
+# Step 1: Build, stage, upload, and generate vote email
+./tools/releasing/release.sh prepare-vote x.y.z
 
-## Make the internal announcements
-Send an announcement mail in dev mail list.
+# (send vote email to [email protected], wait 72h for vote to pass)
 
+# Step 2: Promote, push Docker images, generate announce email, and clean up
+./tools/releasing/release.sh vote-passed [old_version_to_remove]
 ```
-Mail title: [ANNOUNCE] SkyWalking Java Agent x.y.z test build available
-
-Mail content:
-The test build of Java Agent x.y.z is available.
-
-We welcome any comments you may have, and will take all feedback into
-account if a quality vote is called for this build.
-
-Release notes:
-
- * 
https://github.com/apache/skywalking-java/blob/master/changes/changes-x.y.z.md
 
-Release Candidate:
+Run `./tools/releasing/release.sh` without arguments to see all available 
commands, including individual steps if you need to run them separately.
 
- * https://dist.apache.org/repos/dist/dev/skywalking/java-agent/xxxx
- * sha512 checksums
+### Pre-flight checks
+Before starting, the script verifies:
+- Required tools are installed (git, gpg, svn, shasum, mvn, java, tar, gh)
+- GPG signing works **without password prompt** (critical for maven release)
+- Maven settings contain Apache server credentials
+- Git working tree is clean
 
-Maven 2 staging repository:
-
- * 
https://repository.apache.org/content/repositories/xxxx/org/apache/skywalking-java/
-
-Release Tag :
-
- * (Git Tag) x.y.z
-
-Release CommitID :
-
- * https://github.com/apache/skywalking-java/tree/(Git Commit ID)
- * Git submodule
-   * apm-protocol/apm-network/src/main/proto: 
https://github.com/apache/skywalking-data-collect-protocol/tree/(Git Commit ID)
-
-Keys to verify the Release Candidate :
-
- * https://dist.apache.org/repos/dist/release/skywalking/KEYS
-
-Guide to build the release from source :
-
- > ./mvnw clean package
-
-A vote regarding the quality of this test build will be initiated
-within the next couple of days.
+If GPG signing fails, configure gpg-agent to cache the passphrase:
 ```
-
-## Wait for at least 48 hours for test responses
-Any PMC member, committer or contributor can test the release features and 
provide feedback.
-Based on that, the PMC will decide whether to start the voting process.
-
-## Call a vote in dev
-Call a vote in `[email protected]`
-
+# ~/.gnupg/gpg-agent.conf
+default-cache-ttl 86400
+max-cache-ttl 86400
 ```
-Mail title: [VOTE] Release Apache SkyWalking Java Agent version x.y.z
-
-Mail content:
-Hi All,
-This is a call for vote to release Apache SkyWalking Java Agent version x.y.z.
-
-Release notes:
-
- * 
https://github.com/apache/skywalking-java/blob/master/changes/changes-x.y.z.md
-
-Release Candidate:
-
- * https://dist.apache.org/repos/dist/dev/skywalking/java-agent/xxxx
- * sha512 checksums
-
-Maven 2 staging repository:
+Then run `gpgconf --kill gpg-agent` and `gpg --sign /dev/null` to cache it.
 
- * 
https://repository.apache.org/content/repositories/xxxx/org/apache/skywalking/
+### prepare-vote
+`prepare-vote` runs the following steps in sequence:
+1. **preflight** — verify tools and environment
+2. **prepare** — create `release/x.y.z` branch, run `mvn release:prepare` 
(creates tag `vx.y.z` with full CHANGES.md), then archive changelog and reset 
for next version, push branch and tag, create PR
+3. **stage** — run `mvn release:perform`, build source and binary tars with 
GPG signatures and sha512 checksums
+4. **upload** — upload to Apache SVN `dist/dev` (prompts for SVN credentials)
+5. **email vote** — print vote email template with pre-filled version, commit 
ID, submodule commit, and checksums
 
-Release Tag :
-
- * (Git Tag) x.y.z
-
-Release CommitID :
-
- * https://github.com/apache/skywalking-java/tree/(Git Commit ID)
- * Git submodule
-   * apm-protocol/apm-network/src/main/proto: 
https://github.com/apache/skywalking-data-collect-protocol/tree/(Git Commit ID)
-
-Keys to verify the Release Candidate :
-
- * https://dist.apache.org/repos/dist/release/skywalking/KEYS
-
-Guide to build the release from source :
-
- > ./mvnw clean package
-
-Voting will start now (xxxx date) and will remain open for at least 72 hours, 
Request all PMC members to give their vote.
-[ ] +1 Release this package.
-[ ] +0 No opinion.
-[ ] -1 Do not release this package because....
-```
+Copy the generated email and send it to `[email protected]`. Voting 
remains open for at least 72 hours. At least 3 (+1 binding) PMC votes with more 
+1 than -1 are required.
 
 ## Vote Check
 All PMC members and committers should check these before casting +1 votes.
@@ -195,91 +91,9 @@ are found in 
`https://dist.apache.org/repos/dist/dev/skywalking/java-agent/x.y.z
 1. Build a distribution package from the source code package 
(`apache-skywalking-java-agent-x.y.z-src.tar.gz`).
 1. Check the Apache License Header. Run `docker run --rm -v 
$(pwd):/github/workspace apache/skywalking-eyes header check`. (No binaries in 
source codes)
 
-
-The voting process is as follows:
-1. All PMC member votes are +1 binding, and all other votes are +1 but 
non-binding.
-1. If you obtain at least 3 (+1 binding) votes with more +1 than -1 votes 
within 72 hours, the release will be approved.
-
-
-## Publish the release
-1. Move source codes tar and distribution packages to 
`https://dist.apache.org/repos/dist/release/skywalking/java-agent/`.
-```
-> export SVN_EDITOR=vim
-> svn mv https://dist.apache.org/repos/dist/dev/skywalking/java-agent/x.y.z 
https://dist.apache.org/repos/dist/release/skywalking/java-agent
-....
-enter your apache password
-....
-
-```
-2. Release in the nexus staging repo.
-3. Public download source and distribution tar/zip are located in 
`http://www.apache.org/dyn/closer.cgi/skywalking/java-agent/x.y.z/xxx`.
-The Apache mirror path is the only release information that we publish.
-4. Public asc and sha512 are located in 
`https://www.apache.org/dist/skywalking/java-agent/x.y.z/xxx`.
-5. Public KEYS point to  `https://www.apache.org/dist/skywalking/KEYS`.
-6. Update the website download page. http://skywalking.apache.org/downloads/ . 
Add a new download source, distribution, sha512, asc, and document
-links. The links can be found following rules (3) to (6) above.
-7. Add a release event on the website homepage and event page. Announce the 
public release with changelog or key features.
-8. Send ANNOUNCE email to `[email protected]`, `[email protected]`. 
The sender should use the Apache email account.
-```
-Mail title: [ANNOUNCE] Apache SkyWalking Java Agent x.y.z released
-
-Mail content:
-Hi all,
-
-Apache SkyWalking Team is glad to announce the first release of Apache 
SkyWalking Java Agent x.y.z.
-
-SkyWalking: APM (application performance monitor) tool for distributed systems,
-especially designed for microservices, cloud native and container-based 
(Docker, Kubernetes, Mesos) architectures.
-
-The Java Agent for Apache SkyWalking, which provides the native 
tracing/metrics/logging abilities for Java projects.
-
-This release contains a number of new features, bug fixes and improvements 
compared to
-version a.b.c(last release). The notable changes since x.y.z include:
-
-(Highlight key changes)
-1. ...
-2. ...
-3. ...
-
-Please refer to the change log for the complete list of changes:
-https://github.com/apache/skywalking-java/blob/master/changes/changes-x.y.z.md
-
-Apache SkyWalking website:
-http://skywalking.apache.org/
-
-Downloads:
-http://skywalking.apache.org/downloads/
-
-Twitter:
-https://twitter.com/AsfSkyWalking
-
-SkyWalking Resources:
-- GitHub: https://github.com/apache/skywalking-java
-- Issue: https://github.com/apache/skywalking/issues
-- Mailing list: [email protected]
-
-
-- Apache SkyWalking Team
-```
-
-## Release Docker images
-
-```shell
-export SW_VERSION=x.y.z
-git clone --depth 1 --branch v$SW_VERSION 
https://github.com/apache/skywalking-java.git
-cd skywalking-java
-
-curl -O 
https://dist.apache.org/repos/dist/release/skywalking/java-agent/$SW_VERSION/apache-skywalking-java-agent-$SW_VERSION.tgz
-tar -xzvf apache-skywalking-java-agent-$SW_VERSION.tgz
-
-export NAME=skywalking-java-agent
-export HUB=apache
-export TAG=$SW_VERSION
-
-make docker.push.alpine docker.push.java8 docker.push.java11 
docker.push.java17 docker.push.java21 docker.push.java25
-```
-
-## Clean up the old releases
-Once the latest release has been published, you should clean up the old 
releases from the mirror system.
-1. Update the download links (source, dist, asc, and sha512) on the website to 
the archive repo (https://archive.apache.org/dist/skywalking).
-2. Remove previous releases from 
https://dist.apache.org/repos/dist/release/skywalking/java-agent.
+## vote-passed
+After the vote passes, run `vote-passed` which executes:
+1. **promote** — move packages from `dist/dev` to `dist/release` in Apache SVN 
(prompts for SVN credentials), then release the Nexus staging repository at 
https://repository.apache.org and update the website download page
+2. **docker** — build and push all Docker image variants (alpine, java8, 
java11, java17, java21, java25)
+3. **email announce** — print announcement email template. Copy and send to 
`[email protected]` and `[email protected]`
+4. **cleanup** (optional) — if old version is provided, remove it from 
`dist/release`. Update download page links to point to 
`https://archive.apache.org/dist/skywalking`
diff --git a/pom.xml b/pom.xml
index b675688a4a..1f3297d2d1 100755
--- a/pom.xml
+++ b/pom.xml
@@ -131,6 +131,8 @@
         <jmh.version>1.33</jmh.version>
         <gmaven-plugin.version>1.5</gmaven-plugin.version>
         <checkstyle.fails.on.error>true</checkstyle.fails.on.error>
+        <!-- Only publish toolkit modules to Maven Central; agent/plugins are 
distributed via package -->
+        <maven.deploy.skip>true</maven.deploy.skip>
                
<maven-docker-plugin.version>0.46.0</maven-docker-plugin.version>
     </properties>
 
diff --git a/tools/releasing/create_release.sh 
b/tools/releasing/create_release.sh
deleted file mode 100755
index 98cedccc01..0000000000
--- a/tools/releasing/create_release.sh
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/usr/bin/env bash
-
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# This script relies on few environment variables to determine source code 
package
-# behavior, those variables are:
-#   RELEASE_VERSION -- The version of this source package.
-# For example: RELEASE_VERSION=5.0.0-alpha
-
-
-RELEASE_VERSION=${RELEASE_VERSION}
-TAG_NAME=v${RELEASE_VERSION}
-PRODUCT_NAME="apache-skywalking-java-agent"
-
-echo "Release version "${RELEASE_VERSION}
-echo "Source tag "${TAG_NAME}
-
-if [ "$RELEASE_VERSION" == "" ]; then
-  echo "RELEASE_VERSION environment variable not found, Please setting the 
RELEASE_VERSION."
-  echo "For example: export RELEASE_VERSION=5.0.0-alpha"
-  exit 1
-fi
-
-echo "Creating source package"
-
-PRODUCT_NAME=${PRODUCT_NAME}-${RELEASE_VERSION}
-
-rm -rf ${PRODUCT_NAME}
-mkdir ${PRODUCT_NAME}
-
-git clone https://github.com/apache/skywalking-java.git ./${PRODUCT_NAME}
-cd ${PRODUCT_NAME}
-
-TAG_EXIST=`git tag -l ${TAG_NAME} | wc -l`
-
-if [ ${TAG_EXIST} -ne 1 ]; then
-    echo "Could not find the tag named" ${TAG_NAME}
-    exit 1
-fi
-
-git checkout ${TAG_NAME}
-
-# Init submodules
-git submodule init
-git submodule update
-
-# Generate a static skywalking-agent-version.properties and override the 
template when releasing source tar
-# because after that there is no Git information anymore.
-./mvnw -q -pl apm-sniffer/apm-agent-core initialize \
-       
-DgenerateGitPropertiesFilename="$(pwd)/apm-sniffer/apm-agent-core/src/main/resources/skywalking-agent-version.properties"
-
-cd ..
-# Build source code tar
-tar czf ${PRODUCT_NAME}-src.tgz \
-    --exclude .git \
-    --exclude .DS_Store \
-    --exclude .github \
-    --exclude .gitignore \
-    --exclude .gitmodules \
-    ${PRODUCT_NAME}
-
-gpg --armor --detach-sig ${PRODUCT_NAME}-src.tgz
-
-shasum -a 512 ${PRODUCT_NAME}-src.tgz > ${PRODUCT_NAME}-src.tgz.sha512
-
-# Build binary tar
-cd ${PRODUCT_NAME}
-export TAG=${RELEASE_VERSION}
-make dist
diff --git a/tools/releasing/release.sh b/tools/releasing/release.sh
new file mode 100755
index 0000000000..8338e60486
--- /dev/null
+++ b/tools/releasing/release.sh
@@ -0,0 +1,648 @@
+#!/usr/bin/env bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Apache SkyWalking Java Agent Release Script
+#
+# Usage:
+#   ./release.sh preflight                  Check tools and environment
+#   ./release.sh prepare <version>          Prepare release (branch, maven 
release:prepare, tag)
+#   ./release.sh stage                      Stage release (maven 
release:perform, build tars)
+#   ./release.sh upload                     Upload to Apache SVN dist/dev
+#   ./release.sh prepare-vote               Run prepare + stage + upload, then 
generate vote email
+#   ./release.sh email [vote|announce]      Generate email content
+#   ./release.sh promote                    Move from dist/dev to dist/release 
in SVN
+#   ./release.sh docker                     Build and push Docker images
+#   ./release.sh vote-passed                Run promote + docker, then 
generate announce email
+#   ./release.sh cleanup <old_version>      Remove old release from 
dist/release
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
+PRODUCT_NAME="apache-skywalking-java-agent"
+
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+info()  { echo -e "${GREEN}[INFO]${NC} $*"; }
+warn()  { echo -e "${YELLOW}[WARN]${NC} $*"; }
+error() { echo -e "${RED}[ERROR]${NC} $*"; exit 1; }
+
+# ============================================================
+# preflight — check tools and environment
+# ============================================================
+cmd_preflight() {
+    info "Running pre-flight checks..."
+
+    local failed=0
+
+    # Required tools
+    for tool in git gpg svn shasum mvn java tar gh; do
+        if command -v "$tool" &>/dev/null; then
+            info "  $tool: $(command -v $tool)"
+        else
+            error "  $tool: NOT FOUND"
+            failed=1
+        fi
+    done
+
+    # Java version
+    local java_version
+    java_version=$(java -version 2>&1 | head -1)
+    info "  Java: $java_version"
+
+    # GPG key
+    local gpg_keys
+    gpg_keys=$(gpg --list-secret-keys --keyid-format SHORT 2>/dev/null | grep 
-c "sec" || true)
+    if [ "$gpg_keys" -eq 0 ]; then
+        error "  GPG: No secret keys found. Import your GPG key first."
+        failed=1
+    else
+        info "  GPG: $gpg_keys secret key(s) found"
+    fi
+
+    # GPG signing without password prompt
+    info "  Testing GPG signing (should not ask for password)..."
+    local test_file
+    test_file=$(mktemp)
+    echo "test" > "$test_file"
+    if gpg --batch --yes --armor --detach-sig "$test_file" 2>/dev/null; then
+        info "  GPG signing: OK (no password prompt)"
+        rm -f "$test_file" "${test_file}.asc"
+    else
+        rm -f "$test_file" "${test_file}.asc"
+        echo ""
+        echo "  GPG signing FAILED. The agent must be configured to cache the 
passphrase."
+        echo ""
+        echo "  Options to fix:"
+        echo "    1. Configure gpg-agent with a longer cache TTL in 
~/.gnupg/gpg-agent.conf:"
+        echo "       default-cache-ttl 86400"
+        echo "       max-cache-ttl 86400"
+        echo "       Then: gpgconf --kill gpg-agent"
+        echo ""
+        echo "    2. Or run 'gpg --sign /dev/null' manually first to cache the 
passphrase."
+        echo ""
+        failed=1
+    fi
+
+    # Maven settings (Apache credentials)
+    local settings_file="${HOME}/.m2/settings.xml"
+    if [ -f "$settings_file" ]; then
+        if grep -q "apache.releases.https" "$settings_file"; then
+            info "  Maven settings: apache.releases.https server found"
+        else
+            warn "  Maven settings: apache.releases.https server NOT found in 
$settings_file"
+            failed=1
+        fi
+    else
+        warn "  Maven settings: $settings_file not found"
+        failed=1
+    fi
+
+    # Git status
+    cd "$PROJECT_ROOT"
+    if [ -n "$(git status --porcelain)" ]; then
+        warn "  Git: working tree is dirty"
+    else
+        info "  Git: working tree is clean"
+    fi
+
+    local branch
+    branch=$(git rev-parse --abbrev-ref HEAD)
+    info "  Git branch: $branch"
+
+    if [ "$failed" -ne 0 ]; then
+        echo ""
+        error "Pre-flight checks failed. Fix the issues above before 
releasing."
+    fi
+
+    echo ""
+    info "All pre-flight checks passed."
+}
+
+# ============================================================
+# prepare — prepare the release (CHANGES.md, maven)
+# ============================================================
+cmd_prepare() {
+    local version="${1:-}"
+    local next_version="${2:-}"
+    if [ -z "$version" ]; then
+        error "Usage: $0 prepare <version> [next_version]  (e.g., 9.7.0 9.8.0)"
+    fi
+
+    cd "$PROJECT_ROOT"
+
+    if [ -z "$next_version" ]; then
+        next_version=$(echo "$version" | awk -F. '{printf "%s.%s.%s", $1, 
$2+1, 0}')
+    fi
+    local branch_name="release/${version}"
+
+    info "Preparing release ${version}..."
+    echo "  Release version: ${version}"
+    echo "  Tag: v${version}"
+    echo "  Next dev version: ${next_version}-SNAPSHOT"
+    echo "  Branch: ${branch_name}"
+    echo ""
+    read -rp "Continue? [y/N] " confirm
+    if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
+        info "Aborted."
+        exit 0
+    fi
+
+    # Step 1: Create release branch from main
+    info "Creating branch ${branch_name}..."
+    git checkout -b "${branch_name}"
+
+    # Step 2: Maven release:prepare
+    # This creates two commits:
+    #   1. [maven-release-plugin] prepare release vx.y.z  (pom versions set to 
x.y.z)
+    #   2. [maven-release-plugin] prepare for next development iteration (pom 
versions set to next-SNAPSHOT)
+    # And a tag vx.y.z pointing to commit 1.
+    # CHANGES.md is kept as-is so the tag includes the full changelog.
+    info "Running maven release:prepare..."
+    ./mvnw release:clean
+    ./mvnw release:prepare -DautoVersionSubmodules=true -Pall \
+        -DreleaseVersion="${version}" \
+        -DdevelopmentVersion="${next_version}-SNAPSHOT" \
+        -Dtag="v${version}" \
+        -DpushChanges=false
+
+    # Step 3: After the tag is created, move CHANGES.md for next dev cycle
+    info "Moving changelog to changes/changes-${version}.md..."
+    local changes_file="changes/changes-${version}.md"
+
+    # Extract current version section from CHANGES.md
+    sed -n "/^${version}$/,/^------------------$/p" CHANGES.md | head -n -1 > 
"$changes_file"
+    grep "All issues and pull requests" CHANGES.md >> "$changes_file" || true
+    info "Created $changes_file"
+
+    # Reset CHANGES.md for next development version
+    cat > CHANGES.md << EOF
+Changes by Version
+==================
+Release Notes.
+
+${next_version}
+------------------
+
+
+All issues and pull requests are 
[here](https://github.com/apache/skywalking/milestone/xxx?closed=1)
+
+------------------
+Find change logs of all versions [here](changes).
+EOF
+
+    git add CHANGES.md "$changes_file"
+    git commit -m "Move ${version} changelog and reset for ${next_version} 
development"
+
+    # Step 4: Push branch and tag
+    info "Pushing branch and tag..."
+    git push -u origin "${branch_name}"
+    git push origin "v${version}"
+
+    # Step 5: Create PR
+    info "Creating pull request..."
+    if command -v gh &>/dev/null; then
+        gh pr create --base main --head "${branch_name}" \
+            --title "Release ${version}" \
+            --body "Release Apache SkyWalking Java Agent ${version}.
+
+- Maven release:prepare completed (tag \`v${version}\` created)
+- CHANGES.md archived to \`changes/changes-${version}.md\`
+- Next development version: ${next_version}-SNAPSHOT"
+        info "PR created."
+    else
+        warn "GitHub CLI (gh) not found. Create PR manually for branch 
${branch_name}."
+    fi
+
+    info "Release ${version} prepared."
+    info "  Tag v${version} is ready."
+    info "  PR created for branch ${branch_name} → main."
+    info "Next step: $0 stage"
+}
+
+# ============================================================
+# stage — stage the release (maven, build source & binary tars)
+# ============================================================
+cmd_stage() {
+    cd "$PROJECT_ROOT"
+
+    # Detect version from latest tag
+    local version
+    version=$(git describe --tags --abbrev=0 | sed 's/^v//')
+    local tag_name="v${version}"
+
+    info "Staging release ${version}..."
+
+    # Maven release:perform
+    info "Running maven release:perform..."
+    ./mvnw release:perform -DskipTests -Pall
+
+    # Build source and binary packages (inlined from create_release.sh)
+    info "Building source and binary packages..."
+
+    cd "${SCRIPT_DIR}"
+    local product_dir="${PRODUCT_NAME}-${version}"
+
+    rm -rf "${product_dir}"
+    mkdir "${product_dir}"
+
+    git clone https://github.com/apache/skywalking-java.git "./${product_dir}"
+    cd "${product_dir}"
+
+    TAG_EXIST=$(git tag -l "${tag_name}" | wc -l)
+    if [ "${TAG_EXIST}" -ne 1 ]; then
+        error "Could not find the tag named ${tag_name}"
+    fi
+
+    git checkout "${tag_name}"
+    git submodule init
+    git submodule update
+
+    # Generate static version properties (no Git info in source tar)
+    ./mvnw -q -pl apm-sniffer/apm-agent-core initialize \
+           
-DgenerateGitPropertiesFilename="$(pwd)/apm-sniffer/apm-agent-core/src/main/resources/skywalking-agent-version.properties"
+
+    cd "${SCRIPT_DIR}"
+
+    # Source tar
+    info "Creating source tar..."
+    tar czf "${product_dir}-src.tgz" \
+        --exclude .git \
+        --exclude .DS_Store \
+        --exclude .github \
+        --exclude .gitignore \
+        --exclude .gitmodules \
+        "${product_dir}"
+
+    gpg --armor --detach-sig "${product_dir}-src.tgz"
+    shasum -a 512 "${product_dir}-src.tgz" > "${product_dir}-src.tgz.sha512"
+
+    # Binary tar
+    info "Creating binary tar..."
+    cd "${product_dir}"
+    export TAG="${version}"
+    make dist
+
+    echo ""
+    info "Release ${version} staged."
+    info "Source tar: ${SCRIPT_DIR}/${product_dir}-src.tgz"
+    info "Binary tar: 
${SCRIPT_DIR}/${product_dir}/${PRODUCT_NAME}-${version}.tgz"
+    info "Next step: $0 upload"
+}
+
+# ============================================================
+# upload — upload to Apache SVN dist/dev
+# ============================================================
+cmd_upload() {
+    cd "$PROJECT_ROOT"
+
+    local version
+    version=$(git describe --tags --abbrev=0 | sed 's/^v//')
+    local 
svn_dev="https://dist.apache.org/repos/dist/dev/skywalking/java-agent";
+
+    info "Uploading release ${version} to Apache SVN (dist/dev)..."
+
+    local staging_dir="${SCRIPT_DIR}/${PRODUCT_NAME}-${version}"
+
+    # Verify files exist
+    local src_tar="${SCRIPT_DIR}/${PRODUCT_NAME}-${version}-src.tgz"
+    local bin_tar="${staging_dir}/${PRODUCT_NAME}-${version}.tgz"
+
+    for f in "$src_tar" "${src_tar}.asc" "${src_tar}.sha512" \
+             "$bin_tar" "${bin_tar}.asc" "${bin_tar}.sha512"; do
+        if [ ! -f "$f" ]; then
+            error "Missing file: $f. Run '$0 stage' first."
+        fi
+    done
+
+    # Create SVN directory and upload
+    read -rp "SVN username (Apache ID): " svn_user
+
+    local tmp_svn
+    tmp_svn=$(mktemp -d)
+    info "Checking out SVN dist/dev..."
+    svn checkout --depth empty "$svn_dev" "$tmp_svn" --username "$svn_user"
+
+    mkdir -p "${tmp_svn}/${version}"
+
+    cp "$src_tar" "${src_tar}.asc" "${src_tar}.sha512" "${tmp_svn}/${version}/"
+    cp "$bin_tar" "${bin_tar}.asc" "${bin_tar}.sha512" "${tmp_svn}/${version}/"
+
+    cd "$tmp_svn"
+    svn add "${version}"
+    svn commit -m "Stage Apache SkyWalking Java Agent ${version}" --username 
"$svn_user"
+
+    rm -rf "$tmp_svn"
+    info "Uploaded to ${svn_dev}/${version}"
+    info "Next step: $0 email vote"
+}
+
+# ============================================================
+# email — generate email templates
+# ============================================================
+cmd_email() {
+    local type="${1:-}"
+    if [[ ! "$type" =~ ^(vote|announce)$ ]]; then
+        error "Usage: $0 email [vote|announce]"
+    fi
+
+    cd "$PROJECT_ROOT"
+
+    local version
+    version=$(git describe --tags --abbrev=0 | sed 's/^v//')
+    local tag="v${version}"
+    local commit_id
+    commit_id=$(git rev-list -n1 "$tag" 2>/dev/null || echo "<GIT_COMMIT_ID>")
+    local submodule_commit
+    submodule_commit=$(git ls-tree "$tag" 
apm-protocol/apm-network/src/main/proto 2>/dev/null | awk '{print $3}' || echo 
"<SUBMODULE_COMMIT_ID>")
+
+    # Get sha512 checksums
+    local src_sha512=""
+    local bin_sha512=""
+    local 
src_sha_file="${SCRIPT_DIR}/${PRODUCT_NAME}-${version}-src.tgz.sha512"
+    local 
bin_sha_file="${SCRIPT_DIR}/${PRODUCT_NAME}-${version}/${PRODUCT_NAME}-${version}.tgz.sha512"
+    [ -f "$src_sha_file" ] && src_sha512=$(cat "$src_sha_file")
+    [ -f "$bin_sha_file" ] && bin_sha512=$(cat "$bin_sha_file")
+
+    echo ""
+    echo "============================================================"
+
+    case "$type" in
+    vote)
+        cat << EOF
+Mail to: [email protected]
+Subject: [VOTE] Release Apache SkyWalking Java Agent version ${version}
+
+Hi All,
+This is a call for vote to release Apache SkyWalking Java Agent version 
${version}.
+
+Release notes:
+
+ * 
https://github.com/apache/skywalking-java/blob/master/changes/changes-${version}.md
+
+Release Candidate:
+
+ * https://dist.apache.org/repos/dist/dev/skywalking/java-agent/${version}
+ * sha512 checksums
+   - ${src_sha512}
+   - ${bin_sha512}
+
+Maven 2 staging repository:
+
+ * 
https://repository.apache.org/content/repositories/<STAGING_REPO_ID>/org/apache/skywalking/
+
+Release Tag :
+
+ * (Git Tag) v${version}
+
+Release CommitID :
+
+ * https://github.com/apache/skywalking-java/tree/${commit_id}
+ * Git submodule
+   * apm-protocol/apm-network/src/main/proto: 
https://github.com/apache/skywalking-data-collect-protocol/tree/${submodule_commit}
+
+Keys to verify the Release Candidate :
+
+ * https://dist.apache.org/repos/dist/release/skywalking/KEYS
+
+Guide to build the release from source :
+
+ > ./mvnw clean package
+
+Voting will start now ($(date '+%B %d, %Y')) and will remain open for at least 
72 hours, Request all PMC members to give their vote.
+[ ] +1 Release this package.
+[ ] +0 No opinion.
+[ ] -1 Do not release this package because....
+EOF
+        ;;
+    announce)
+        cat << EOF
+Mail to: [email protected], [email protected]
+Subject: [ANNOUNCE] Apache SkyWalking Java Agent ${version} released
+
+Hi all,
+
+Apache SkyWalking Team is glad to announce the release of Apache SkyWalking 
Java Agent ${version}.
+
+SkyWalking: APM (application performance monitor) tool for distributed systems,
+especially designed for microservices, cloud native and container-based 
(Docker, Kubernetes, Mesos) architectures.
+
+The Java Agent for Apache SkyWalking, which provides the native 
tracing/metrics/logging abilities for Java projects.
+
+This release contains a number of new features, bug fixes and improvements 
compared to
+the previous version. The notable changes include:
+
+(Highlight key changes from changes-${version}.md)
+1. ...
+2. ...
+3. ...
+
+Please refer to the change log for the complete list of changes:
+https://github.com/apache/skywalking-java/blob/master/changes/changes-${version}.md
+
+Apache SkyWalking website:
+http://skywalking.apache.org/
+
+Downloads:
+http://skywalking.apache.org/downloads/
+
+Twitter:
+https://twitter.com/AsfSkyWalking
+
+SkyWalking Resources:
+- GitHub: https://github.com/apache/skywalking-java
+- Issue: https://github.com/apache/skywalking/issues
+- Mailing list: [email protected]
+
+
+- Apache SkyWalking Team
+EOF
+        ;;
+    esac
+
+    echo "============================================================"
+    echo ""
+    warn "Replace <STAGING_REPO_ID> with the actual Nexus staging repository 
ID."
+}
+
+# ============================================================
+# docker — build and push Docker images
+# ============================================================
+cmd_docker() {
+    cd "$PROJECT_ROOT"
+
+    local version
+    version=$(git describe --tags --abbrev=0 | sed 's/^v//')
+
+    info "Building and pushing Docker images for ${version}..."
+
+    local 
dist_tar="${SCRIPT_DIR}/${PRODUCT_NAME}-${version}/${PRODUCT_NAME}-${version}.tgz"
+
+    if [ ! -f "$dist_tar" ]; then
+        error "Binary tar not found: $dist_tar. Run '$0 stage' first."
+    fi
+
+    # Extract agent package
+    tar -xzf "$dist_tar" -C "$PROJECT_ROOT"
+
+    export NAME=skywalking-java-agent
+    export HUB=apache
+    export TAG="$version"
+
+    make docker.push.alpine docker.push.java8 docker.push.java11 
docker.push.java17 docker.push.java21 docker.push.java25
+
+    info "Docker images pushed for ${version}."
+}
+
+# ============================================================
+# promote — move from dist/dev to dist/release
+# ============================================================
+cmd_promote() {
+    cd "$PROJECT_ROOT"
+
+    local version
+    version=$(git describe --tags --abbrev=0 | sed 's/^v//')
+
+    info "Promoting release ${version} from dist/dev to dist/release..."
+
+    read -rp "SVN username (Apache ID): " svn_user
+
+    svn mv 
"https://dist.apache.org/repos/dist/dev/skywalking/java-agent/${version}"; \
+           
"https://dist.apache.org/repos/dist/release/skywalking/java-agent/${version}"; \
+           -m "Release Apache SkyWalking Java Agent ${version}" \
+           --username "$svn_user"
+
+    info "Release ${version} promoted."
+    info "Next steps:"
+    info "  1. Release the Nexus staging repository"
+    info "  2. Update website download page"
+    info "  3. Run: $0 email announce"
+    info "  4. Run: $0 docker"
+}
+
+# ============================================================
+# cleanup — remove old release from dist/release
+# ============================================================
+cmd_cleanup() {
+    local old_version="${1:-}"
+    if [ -z "$old_version" ]; then
+        error "Usage: $0 cleanup <old_version>  (e.g., 9.5.0)"
+    fi
+
+    info "Removing old release ${old_version} from dist/release..."
+
+    read -rp "SVN username (Apache ID): " svn_user
+
+    svn rm 
"https://dist.apache.org/repos/dist/release/skywalking/java-agent/${old_version}";
 \
+           -m "Remove old Apache SkyWalking Java Agent ${old_version} release" 
\
+           --username "$svn_user"
+
+    info "Removed ${old_version} from dist/release."
+    warn "Remember to update download page links to point to 
archive.apache.org."
+}
+
+# ============================================================
+# prepare-vote — run all steps before the vote
+# ============================================================
+cmd_prepare_vote() {
+    local version="${1:-}"
+    local next_version="${2:-}"
+    if [ -z "$version" ]; then
+        error "Usage: $0 prepare-vote <version> [next_version]  (e.g., 9.7.0 
9.8.0)"
+    fi
+
+    cmd_preflight
+    echo ""
+    cmd_prepare "$version" "$next_version"
+    echo ""
+    cmd_stage
+    echo ""
+    cmd_upload
+    echo ""
+    cmd_email vote
+}
+
+# ============================================================
+# vote-passed — run all steps after the vote passes
+# ============================================================
+cmd_vote_passed() {
+    local old_version="${1:-}"
+
+    cmd_promote
+    echo ""
+    cmd_docker
+    echo ""
+    cmd_email announce
+
+    if [ -n "$old_version" ]; then
+        echo ""
+        cmd_cleanup "$old_version"
+    else
+        echo ""
+        warn "To clean up an old release, run: $0 cleanup <old_version>"
+    fi
+}
+
+# ============================================================
+# Main dispatcher
+# ============================================================
+main() {
+    local cmd="${1:-}"
+    shift || true
+
+    case "$cmd" in
+        preflight)    cmd_preflight "$@" ;;
+        prepare)      cmd_prepare "$@" ;;
+        stage)        cmd_stage "$@" ;;
+        upload)       cmd_upload "$@" ;;
+        email)        cmd_email "$@" ;;
+        docker)       cmd_docker "$@" ;;
+        promote)      cmd_promote "$@" ;;
+        cleanup)      cmd_cleanup "$@" ;;
+        prepare-vote) cmd_prepare_vote "$@" ;;
+        vote-passed)  cmd_vote_passed "$@" ;;
+        *)
+            echo "Apache SkyWalking Java Agent Release Tool"
+            echo ""
+            echo "Usage: $0 <command> [args]"
+            echo ""
+            echo "Quick start (two-step release):"
+            echo "  $0 prepare-vote 9.7.0 [9.8.0]     # before vote (next 
version auto-calculated if omitted)"
+            echo "  (wait for 72h vote to pass)"
+            echo "  $0 vote-passed [old_version]       # after vote"
+            echo ""
+            echo "Individual commands:"
+            echo "  preflight                     Check tools and environment"
+            echo "  prepare <ver> [next_ver]      Prepare release (branch, 
tag, PR)"
+            echo "  stage                         Stage release (maven 
release:perform, build tars)"
+            echo "  upload                        Upload to Apache SVN 
dist/dev"
+            echo "  prepare-vote <ver> [next_ver] Run preflight + prepare + 
stage + upload + vote email"
+            echo "  email [vote|announce]  Generate email content"
+            echo "  promote                Move from dist/dev to dist/release 
in SVN"
+            echo "  docker                 Build and push Docker images"
+            echo "  vote-passed [old_ver]  Run promote + docker + announce 
email [+ cleanup]"
+            echo "  cleanup <old_version>  Remove old release from 
dist/release"
+            ;;
+    esac
+}
+
+main "$@"


Reply via email to