imbajin commented on code in PR #464:
URL: https://github.com/apache/hugegraph-doc/pull/464#discussion_r3731211342
##########
.github/workflows/validate-release-new.yml:
##########
@@ -0,0 +1,805 @@
+name: "Validate Apache Release (New)"
Review Comment:
⚠️ important — This PR is scoped as a SeaTunnel documentation change, but it
adds an 805-line release-validation workflow with active `release-*`
push/pull_request triggers. Please remove it from this PR and review it
separately; otherwise unrelated CI behavior is merged without focused
validation.
##########
.github/workflows/validate-release-new.yml:
##########
@@ -0,0 +1,805 @@
+name: "Validate Apache Release (New)"
+
+on:
+ workflow_dispatch:
+ inputs:
+ release_version:
+ required: true
+ description: svn release version
+ default: '1.7.0'
+ gpg_user:
+ required: true
+ description: current release manager (gpg username)
+ default: 'pengjunzhi'
+ java_version:
+ required: false
+ description: Java version to validate
+ default: '11'
+ type: choice
+ options:
+ - '11'
+ - '17'
+
+ push:
+ branches:
+ - 'release-*'
+ pull_request:
+ branches:
+ - 'release-*'
+
+jobs:
+ validate:
+ name: "Validate Release On ${{ matrix.os }} (java-${{ matrix.java_version
}})"
+ runs-on: ${{ matrix.os }}
+ env:
+ RELEASE_VERSION: ${{ inputs.release_version || '1.7.0' }}
+ GPG_USER: ${{ inputs.gpg_user || 'pengjunzhi' }}
+ JAVA_VERSION: ${{ inputs.java_version || matrix.java_version || '11' }}
+ SVN_URL_PREFIX:
https://dist.apache.org/repos/dist/dev/incubator/hugegraph
Review Comment:
‼️ critical — Both Apache endpoints still use the retired incubator layout
(`dist/dev/incubator/hugegraph` and
`downloads.apache.org/incubator/hugegraph/KEYS`). The parent workflow uses the
post-graduation `/hugegraph/` paths, so this workflow cannot fetch current
release material. Replace both URLs with the TLP paths.
##########
.github/workflows/validate-release-new.yml:
##########
@@ -0,0 +1,805 @@
+name: "Validate Apache Release (New)"
+
+on:
+ workflow_dispatch:
+ inputs:
+ release_version:
+ required: true
+ description: svn release version
+ default: '1.7.0'
+ gpg_user:
+ required: true
+ description: current release manager (gpg username)
+ default: 'pengjunzhi'
+ java_version:
+ required: false
+ description: Java version to validate
+ default: '11'
+ type: choice
+ options:
+ - '11'
+ - '17'
+
+ push:
+ branches:
+ - 'release-*'
+ pull_request:
+ branches:
+ - 'release-*'
+
+jobs:
+ validate:
Review Comment:
⚠️ important — This job downloads, extracts, compiles, and executes
release-candidate code, but declares no job permissions and leaves checkout
credentials enabled by default. Add `permissions: contents: read` and
`persist-credentials: false` so candidate code cannot inherit broader
repository access.
##########
.github/workflows/validate-release-new.yml:
##########
@@ -0,0 +1,805 @@
+name: "Validate Apache Release (New)"
+
+on:
+ workflow_dispatch:
+ inputs:
+ release_version:
+ required: true
+ description: svn release version
+ default: '1.7.0'
+ gpg_user:
+ required: true
+ description: current release manager (gpg username)
+ default: 'pengjunzhi'
+ java_version:
+ required: false
+ description: Java version to validate
+ default: '11'
+ type: choice
+ options:
+ - '11'
+ - '17'
+
+ push:
+ branches:
+ - 'release-*'
+ pull_request:
+ branches:
+ - 'release-*'
+
+jobs:
+ validate:
+ name: "Validate Release On ${{ matrix.os }} (java-${{ matrix.java_version
}})"
+ runs-on: ${{ matrix.os }}
+ env:
+ RELEASE_VERSION: ${{ inputs.release_version || '1.7.0' }}
+ GPG_USER: ${{ inputs.gpg_user || 'pengjunzhi' }}
+ JAVA_VERSION: ${{ inputs.java_version || matrix.java_version || '11' }}
+ SVN_URL_PREFIX:
https://dist.apache.org/repos/dist/dev/incubator/hugegraph
+ KEYS_URL: https://downloads.apache.org/incubator/hugegraph/KEYS
+ MAX_FILE_SIZE: 800k
+ SERVER_START_DELAY: 3
+ # License Patterns (ASF Category X - Prohibited)
+ CATEGORY_X: '\bGPL|\bLGPL|Sleepycat
License|BSD-4-Clause|\bBCL\b|JSR-275|Amazon Software
License|\bRSAL\b|\bQPL\b|\bSSPL|\bCPOL|\bNPL1|Creative Commons
Non-Commercial|JSON\.org'
+ # License Patterns (ASF Category B - Must be documented)
+ CATEGORY_B: '\bCDDL1|\bCPL|\bEPL|\bIPL|\bMPL|\bSPL|OSL-3.0|UnRAR
License|Erlang Public License|\bOFL\b|Ubuntu Font License Version 1.0|IPA Font
License Agreement v1.0|EPL2.0|CC-BY'
+ steps:
+ - name: Checkout source
+ uses: actions/checkout@v4
+
+ - name: Install JDK ${{ env.JAVA_VERSION }}
+ uses: actions/setup-java@v3
+ with:
+ java-version: ${{ env.JAVA_VERSION }}
+ distribution: 'adopt'
+
+ - name: Install dependencies
+ run: |
+ if [[ "${{ runner.os }}" == "macOS" ]]; then
+ brew install svn wget perl
+ elif [[ "${{ runner.os }}" == "Linux" ]]; then
+ sudo apt-get update
+ sudo apt-get install -y subversion wget perl
+ fi
+ # Verify all required commands
+ for cmd in svn gpg shasum mvn java wget tar curl awk grep find perl;
do
+ if ! command -v "$cmd" &> /dev/null; then
+ echo "Error: Missing required dependency: $cmd"
+ exit 1
+ fi
+ echo "✓ $cmd: $(command -v $cmd)"
+ done
+
+ - name: Cache Maven packages
+ uses: actions/cache@v3
+ with:
+ path: ~/.m2
+ key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: ${{ runner.os }}-m2
+
+ - name: Step 1 - Check Dependencies
+ run: |
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [1/9]: Check Dependencies"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ # Check Java version
+ CURRENT_JAVA=$(java -version 2>&1 | head -n 1 | awk -F '"' '{print
$2}' | awk -F '.' '{print $1}')
+ echo "Current Java version: $CURRENT_JAVA (Required: ${{
env.JAVA_VERSION }})"
+ if [[ "$CURRENT_JAVA" != "${{ env.JAVA_VERSION }}" ]]; then
+ echo "Error: Java version mismatch! Current: Java $CURRENT_JAVA,
Required: Java ${{ env.JAVA_VERSION }}"
+ exit 1
+ fi
+ echo "✓ Java version check passed: Java $CURRENT_JAVA"
+
+ - name: Step 2 - Prepare Release Files
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [2/9]: Prepare Release Files"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ DIST_DIR="dist/${{ env.RELEASE_VERSION }}"
Review Comment:
⚠️ important — Workflow inputs are interpolated directly into generated
shell text (`${{ env.RELEASE_VERSION }}` and `GPG_USER` usages below). A value
containing shell syntax can execute before the script's quoted variables are
applied. Pass values through the process environment, quote
`"$RELEASE_VERSION"`/`"$GPG_USER"`, and validate them against strict allowlists.
##########
.github/workflows/validate-release-new.yml:
##########
@@ -0,0 +1,805 @@
+name: "Validate Apache Release (New)"
+
+on:
+ workflow_dispatch:
+ inputs:
+ release_version:
+ required: true
+ description: svn release version
+ default: '1.7.0'
+ gpg_user:
+ required: true
+ description: current release manager (gpg username)
+ default: 'pengjunzhi'
+ java_version:
+ required: false
+ description: Java version to validate
+ default: '11'
+ type: choice
+ options:
+ - '11'
+ - '17'
+
+ push:
+ branches:
+ - 'release-*'
+ pull_request:
+ branches:
+ - 'release-*'
+
+jobs:
+ validate:
+ name: "Validate Release On ${{ matrix.os }} (java-${{ matrix.java_version
}})"
+ runs-on: ${{ matrix.os }}
+ env:
+ RELEASE_VERSION: ${{ inputs.release_version || '1.7.0' }}
+ GPG_USER: ${{ inputs.gpg_user || 'pengjunzhi' }}
+ JAVA_VERSION: ${{ inputs.java_version || matrix.java_version || '11' }}
+ SVN_URL_PREFIX:
https://dist.apache.org/repos/dist/dev/incubator/hugegraph
+ KEYS_URL: https://downloads.apache.org/incubator/hugegraph/KEYS
+ MAX_FILE_SIZE: 800k
+ SERVER_START_DELAY: 3
+ # License Patterns (ASF Category X - Prohibited)
+ CATEGORY_X: '\bGPL|\bLGPL|Sleepycat
License|BSD-4-Clause|\bBCL\b|JSR-275|Amazon Software
License|\bRSAL\b|\bQPL\b|\bSSPL|\bCPOL|\bNPL1|Creative Commons
Non-Commercial|JSON\.org'
+ # License Patterns (ASF Category B - Must be documented)
+ CATEGORY_B: '\bCDDL1|\bCPL|\bEPL|\bIPL|\bMPL|\bSPL|OSL-3.0|UnRAR
License|Erlang Public License|\bOFL\b|Ubuntu Font License Version 1.0|IPA Font
License Agreement v1.0|EPL2.0|CC-BY'
+ steps:
+ - name: Checkout source
+ uses: actions/checkout@v4
+
+ - name: Install JDK ${{ env.JAVA_VERSION }}
+ uses: actions/setup-java@v3
+ with:
+ java-version: ${{ env.JAVA_VERSION }}
+ distribution: 'adopt'
+
+ - name: Install dependencies
+ run: |
+ if [[ "${{ runner.os }}" == "macOS" ]]; then
+ brew install svn wget perl
+ elif [[ "${{ runner.os }}" == "Linux" ]]; then
+ sudo apt-get update
+ sudo apt-get install -y subversion wget perl
+ fi
+ # Verify all required commands
+ for cmd in svn gpg shasum mvn java wget tar curl awk grep find perl;
do
+ if ! command -v "$cmd" &> /dev/null; then
+ echo "Error: Missing required dependency: $cmd"
+ exit 1
+ fi
+ echo "✓ $cmd: $(command -v $cmd)"
+ done
+
+ - name: Cache Maven packages
+ uses: actions/cache@v3
+ with:
+ path: ~/.m2
+ key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: ${{ runner.os }}-m2
+
+ - name: Step 1 - Check Dependencies
+ run: |
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [1/9]: Check Dependencies"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ # Check Java version
+ CURRENT_JAVA=$(java -version 2>&1 | head -n 1 | awk -F '"' '{print
$2}' | awk -F '.' '{print $1}')
+ echo "Current Java version: $CURRENT_JAVA (Required: ${{
env.JAVA_VERSION }})"
+ if [[ "$CURRENT_JAVA" != "${{ env.JAVA_VERSION }}" ]]; then
+ echo "Error: Java version mismatch! Current: Java $CURRENT_JAVA,
Required: Java ${{ env.JAVA_VERSION }}"
+ exit 1
+ fi
+ echo "✓ Java version check passed: Java $CURRENT_JAVA"
+
+ - name: Step 2 - Prepare Release Files
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [2/9]: Prepare Release Files"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ DIST_DIR="dist/${{ env.RELEASE_VERSION }}"
+ echo "Downloading from SVN to: ${DIST_DIR}"
+
+ rm -rf "${DIST_DIR}"
+ mkdir -p "${DIST_DIR}"
+
+ if ! svn co "${SVN_URL_PREFIX}/${{ env.RELEASE_VERSION }}"
"${DIST_DIR}"; then
+ echo "Error: Failed to download from SVN: ${SVN_URL_PREFIX}/${{
env.RELEASE_VERSION }}"
+ exit 1
+ fi
+
+ echo "✓ Downloaded release files from SVN"
+ cd "${DIST_DIR}"
+ ls -lh
+
+ - name: Step 3 - Import & Trust GPG Keys
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [3/9]: Import & Trust GPG Keys"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ cd dist/${{ env.RELEASE_VERSION }}
+
+ echo "Downloading KEYS file from ${KEYS_URL}..."
+ if ! wget -q "${KEYS_URL}" -O KEYS; then
+ echo "Error: Failed to download KEYS file from ${KEYS_URL}"
+ exit 1
+ fi
+ echo "✓ KEYS file downloaded"
+
+ echo "Importing GPG keys..."
+ IMPORT_OUTPUT=$(gpg --import KEYS 2>&1)
+ IMPORTED_COUNT=$(echo "$IMPORT_OUTPUT" | grep -c "imported" || echo
"0")
+
+ if [[ "$IMPORTED_COUNT" == "0" ]]; then
+ echo "⚠ No new keys imported (may already exist in keyring)"
+ else
+ echo "✓ Imported GPG keys"
+ fi
+
+ # Trust specific user key
+ if ! gpg --list-keys "${{ env.GPG_USER }}" &>/dev/null; then
+ echo "Error: User '${{ env.GPG_USER }}' key not found in imported
keys. Please verify the username."
+ exit 1
+ fi
+
+ echo "Trusting GPG key for user: ${{ env.GPG_USER }}"
+ echo -e "5\ny\n" | gpg --batch --command-fd 0 --edit-key "${{
env.GPG_USER }}" trust 2>/dev/null
+ echo "✓ Trusted key for ${{ env.GPG_USER }}"
+
+ # Trust all imported keys
+ echo "Trusting all imported public keys..."
+ TRUSTED=0
+ for key in $(gpg --no-tty --list-keys --with-colons | awk -F:
'/^pub/ {print $5}'); do
+ echo -e "5\ny\n" | gpg --batch --command-fd 0 --edit-key "$key"
trust 2>/dev/null
+ TRUSTED=$((TRUSTED + 1))
+ done
+ echo "✓ Trusted $TRUSTED GPG keys"
+
+ - name: Step 4 - Verify SHA512 & GPG Signatures
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [4/9]: Verify SHA512 & GPG Signatures"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ cd dist/${{ env.RELEASE_VERSION }}
+
+ PACKAGE_COUNT=0
+ for pkg in *.tar.gz; do
+ if [[ -f "$pkg" ]]; then
+ PACKAGE_COUNT=$((PACKAGE_COUNT + 1))
+ fi
+ done
+
+ CURRENT=0
+ for pkg in *.tar.gz; do
+ if [[ ! -f "$pkg" ]]; then
+ continue
+ fi
+ CURRENT=$((CURRENT + 1))
+ echo " [${CURRENT}/${PACKAGE_COUNT}] $pkg"
+
+ # Check SHA512
+ if shasum -a 512 --check "${pkg}.sha512"; then
+ echo " ✓ SHA512 verified: $pkg"
+ else
+ echo " ✗ SHA512 verification failed: $pkg"
+ exit 1
+ fi
+
+ # Check GPG signature
+ if gpg --verify "${pkg}.asc" "$pkg" 2>&1 | grep -q "Good
signature"; then
+ echo " ✓ GPG signature verified: $pkg"
+ else
+ echo " ✗ GPG signature verification failed: $pkg"
+ exit 1
+ fi
+ done
+
+ - name: Step 5 - Validate Source Packages
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [5/9]: Validate Source Packages"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ cd dist/${{ env.RELEASE_VERSION }}
+
+ SRC_PACKAGES=()
+ for pkg in *-src.tar.gz; do
+ if [[ -f "$pkg" ]]; then
+ SRC_PACKAGES+=("$pkg")
+ fi
+ done
+
+ echo "Found ${#SRC_PACKAGES[@]} source package(s)"
+
+ for src_pkg in "${SRC_PACKAGES[@]}"; do
+ echo ""
+ echo "Validating source package: $src_pkg"
+
+ # Extract package
+ PACKAGE_DIR=$(basename "$src_pkg" .tar.gz)
+ rm -rf "$PACKAGE_DIR"
+ tar -xzf "$src_pkg"
+
+ if [[ ! -d "$PACKAGE_DIR" ]]; then
+ echo "Error: Failed to extract package: $src_pkg"
+ exit 1
+ fi
+
+ pushd "$PACKAGE_DIR"
+
+ # 5.1: Check incubating name
+ if [[ ! "$src_pkg" =~ "incubating" ]]; then
Review Comment:
‼️ critical — The workflow requires `incubating` in source and binary names
and checks incubator-shaped directories (also at line 631), while the parent
workflow rejects that naming for current TLP artifacts. Valid packages will
therefore be rejected or not found. Port the post-graduation naming/glob rules
and remove the mandatory `DISCLAIMER` checks.
##########
content/cn/docs/quickstart/toolchain/hugegraph-seatunnel-connector.md:
##########
@@ -0,0 +1,79 @@
+---
+title: "HugeGraph-SeaTunnel Connector Quick Start"
+linkTitle: "使用 SeaTunnel Connector 同步数据"
+weight: 5
+---
+
+### 1 HugeGraph-SeaTunnel Connector 概述
+
+[Apache SeaTunnel](https://seatunnel.apache.org/)
是一个高性能、分布式的数据集成平台,支持海量数据的实时同步与批处理。
+HugeGraph 为 Apache SeaTunnel 提供了 Connector-V2 支持,用户可以通过 SeaTunnel 方便地在
HugeGraph
+与外部数据系统之间进行数据同步。
+
+> **注意**:SeaTunnel Connector 由 HugeGraph 社区贡献至 Apache SeaTunnel 项目,具体使用方式请参考
+> [Apache SeaTunnel 官方文档](https://seatunnel.apache.org/docs/)。
+
+### 2 功能特性
+
+HugeGraph-SeaTunnel Connector 提供以下能力:
+
+- **HugeGraph Source Connector**:从 HugeGraph 读取图数据,支持顶点和边的批量读取
+- **HugeGraph Sink Connector**:将外部数据写入 HugeGraph,支持顶点和边的批量写入
+- **顶点同步**:支持全量或增量同步顶点数据
+- **边同步**:支持全量或增量同步边数据
+- **Schema 映射**:自动映射 HugeGraph Schema(PropertyKey、VertexLabel、EdgeLabel)与外部数据字段
+- **数据迁移**:支持在不同 HugeGraph 实例之间进行数据迁移,或从其他数据源导入图数据
+
+### 3 环境要求
+
+- Java 8+
+- Apache SeaTunnel 2.3.x+
+- HugeGraph Server 1.0.0+
+
+### 4 快速开始
+
+#### 4.1 安装 SeaTunnel
+
+请参考 [Apache SeaTunnel 安装指南](https://seatunnel.apache.org/docs/start-v2/) 完成
SeaTunnel 的部署。
+
+#### 4.2 使用 HugeGraph Connector
+
+HugeGraph Connector 已包含在 SeaTunnel 的 Connector-V2 生态中。在 SeaTunnel 配置文件中直接引用即可:
+
+**从 HugeGraph 读取数据(Source)示例:**
+
+```hocon
+source {
+ HugeGraph {
+ url = "http://127.0.0.1:8080"
+ graph = "hugegraph"
+ label = "person"
+ # 更多配置请参考 SeaTunnel 官方文档
+ }
+}
+```
+
+**向 HugeGraph 写入数据(Sink)示例:**
+
+```hocon
+sink {
+ HugeGraph {
+ url = "http://127.0.0.1:8080"
Review Comment:
⚠️ important — The Sink example uses unsupported `url`/`graph` fields and
omits required `host`, `port`, `graph_name`, and `schema_config`, so it cannot
run. Replace it with a complete versioned example using the [official HugeGraph
Sink options](https://seatunnel.apache.org/docs/connectors/sink/HugeGraph/) and
state that the HugeGraph schema must already exist.
##########
.github/workflows/validate-release-new.yml:
##########
@@ -0,0 +1,805 @@
+name: "Validate Apache Release (New)"
+
+on:
+ workflow_dispatch:
+ inputs:
+ release_version:
+ required: true
+ description: svn release version
+ default: '1.7.0'
+ gpg_user:
+ required: true
+ description: current release manager (gpg username)
+ default: 'pengjunzhi'
+ java_version:
+ required: false
+ description: Java version to validate
+ default: '11'
+ type: choice
+ options:
+ - '11'
+ - '17'
+
+ push:
+ branches:
+ - 'release-*'
+ pull_request:
+ branches:
+ - 'release-*'
+
+jobs:
+ validate:
+ name: "Validate Release On ${{ matrix.os }} (java-${{ matrix.java_version
}})"
+ runs-on: ${{ matrix.os }}
+ env:
+ RELEASE_VERSION: ${{ inputs.release_version || '1.7.0' }}
+ GPG_USER: ${{ inputs.gpg_user || 'pengjunzhi' }}
+ JAVA_VERSION: ${{ inputs.java_version || matrix.java_version || '11' }}
+ SVN_URL_PREFIX:
https://dist.apache.org/repos/dist/dev/incubator/hugegraph
+ KEYS_URL: https://downloads.apache.org/incubator/hugegraph/KEYS
+ MAX_FILE_SIZE: 800k
+ SERVER_START_DELAY: 3
+ # License Patterns (ASF Category X - Prohibited)
+ CATEGORY_X: '\bGPL|\bLGPL|Sleepycat
License|BSD-4-Clause|\bBCL\b|JSR-275|Amazon Software
License|\bRSAL\b|\bQPL\b|\bSSPL|\bCPOL|\bNPL1|Creative Commons
Non-Commercial|JSON\.org'
+ # License Patterns (ASF Category B - Must be documented)
+ CATEGORY_B: '\bCDDL1|\bCPL|\bEPL|\bIPL|\bMPL|\bSPL|OSL-3.0|UnRAR
License|Erlang Public License|\bOFL\b|Ubuntu Font License Version 1.0|IPA Font
License Agreement v1.0|EPL2.0|CC-BY'
+ steps:
+ - name: Checkout source
+ uses: actions/checkout@v4
+
+ - name: Install JDK ${{ env.JAVA_VERSION }}
+ uses: actions/setup-java@v3
+ with:
+ java-version: ${{ env.JAVA_VERSION }}
+ distribution: 'adopt'
+
+ - name: Install dependencies
+ run: |
+ if [[ "${{ runner.os }}" == "macOS" ]]; then
+ brew install svn wget perl
+ elif [[ "${{ runner.os }}" == "Linux" ]]; then
+ sudo apt-get update
+ sudo apt-get install -y subversion wget perl
+ fi
+ # Verify all required commands
+ for cmd in svn gpg shasum mvn java wget tar curl awk grep find perl;
do
+ if ! command -v "$cmd" &> /dev/null; then
+ echo "Error: Missing required dependency: $cmd"
+ exit 1
+ fi
+ echo "✓ $cmd: $(command -v $cmd)"
+ done
+
+ - name: Cache Maven packages
+ uses: actions/cache@v3
+ with:
+ path: ~/.m2
+ key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: ${{ runner.os }}-m2
+
+ - name: Step 1 - Check Dependencies
+ run: |
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [1/9]: Check Dependencies"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ # Check Java version
+ CURRENT_JAVA=$(java -version 2>&1 | head -n 1 | awk -F '"' '{print
$2}' | awk -F '.' '{print $1}')
+ echo "Current Java version: $CURRENT_JAVA (Required: ${{
env.JAVA_VERSION }})"
+ if [[ "$CURRENT_JAVA" != "${{ env.JAVA_VERSION }}" ]]; then
+ echo "Error: Java version mismatch! Current: Java $CURRENT_JAVA,
Required: Java ${{ env.JAVA_VERSION }}"
+ exit 1
+ fi
+ echo "✓ Java version check passed: Java $CURRENT_JAVA"
+
+ - name: Step 2 - Prepare Release Files
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [2/9]: Prepare Release Files"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ DIST_DIR="dist/${{ env.RELEASE_VERSION }}"
+ echo "Downloading from SVN to: ${DIST_DIR}"
+
+ rm -rf "${DIST_DIR}"
+ mkdir -p "${DIST_DIR}"
+
+ if ! svn co "${SVN_URL_PREFIX}/${{ env.RELEASE_VERSION }}"
"${DIST_DIR}"; then
+ echo "Error: Failed to download from SVN: ${SVN_URL_PREFIX}/${{
env.RELEASE_VERSION }}"
+ exit 1
+ fi
+
+ echo "✓ Downloaded release files from SVN"
+ cd "${DIST_DIR}"
+ ls -lh
+
+ - name: Step 3 - Import & Trust GPG Keys
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [3/9]: Import & Trust GPG Keys"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ cd dist/${{ env.RELEASE_VERSION }}
+
+ echo "Downloading KEYS file from ${KEYS_URL}..."
+ if ! wget -q "${KEYS_URL}" -O KEYS; then
+ echo "Error: Failed to download KEYS file from ${KEYS_URL}"
+ exit 1
+ fi
+ echo "✓ KEYS file downloaded"
+
+ echo "Importing GPG keys..."
+ IMPORT_OUTPUT=$(gpg --import KEYS 2>&1)
+ IMPORTED_COUNT=$(echo "$IMPORT_OUTPUT" | grep -c "imported" || echo
"0")
+
+ if [[ "$IMPORTED_COUNT" == "0" ]]; then
+ echo "⚠ No new keys imported (may already exist in keyring)"
+ else
+ echo "✓ Imported GPG keys"
+ fi
+
+ # Trust specific user key
+ if ! gpg --list-keys "${{ env.GPG_USER }}" &>/dev/null; then
+ echo "Error: User '${{ env.GPG_USER }}' key not found in imported
keys. Please verify the username."
+ exit 1
+ fi
+
+ echo "Trusting GPG key for user: ${{ env.GPG_USER }}"
+ echo -e "5\ny\n" | gpg --batch --command-fd 0 --edit-key "${{
env.GPG_USER }}" trust 2>/dev/null
+ echo "✓ Trusted key for ${{ env.GPG_USER }}"
+
+ # Trust all imported keys
+ echo "Trusting all imported public keys..."
+ TRUSTED=0
+ for key in $(gpg --no-tty --list-keys --with-colons | awk -F:
'/^pub/ {print $5}'); do
+ echo -e "5\ny\n" | gpg --batch --command-fd 0 --edit-key "$key"
trust 2>/dev/null
+ TRUSTED=$((TRUSTED + 1))
+ done
+ echo "✓ Trusted $TRUSTED GPG keys"
+
+ - name: Step 4 - Verify SHA512 & GPG Signatures
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [4/9]: Verify SHA512 & GPG Signatures"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ cd dist/${{ env.RELEASE_VERSION }}
+
+ PACKAGE_COUNT=0
+ for pkg in *.tar.gz; do
+ if [[ -f "$pkg" ]]; then
+ PACKAGE_COUNT=$((PACKAGE_COUNT + 1))
+ fi
+ done
+
+ CURRENT=0
+ for pkg in *.tar.gz; do
+ if [[ ! -f "$pkg" ]]; then
+ continue
+ fi
+ CURRENT=$((CURRENT + 1))
+ echo " [${CURRENT}/${PACKAGE_COUNT}] $pkg"
+
+ # Check SHA512
+ if shasum -a 512 --check "${pkg}.sha512"; then
+ echo " ✓ SHA512 verified: $pkg"
+ else
+ echo " ✗ SHA512 verification failed: $pkg"
+ exit 1
+ fi
+
+ # Check GPG signature
+ if gpg --verify "${pkg}.asc" "$pkg" 2>&1 | grep -q "Good
signature"; then
+ echo " ✓ GPG signature verified: $pkg"
+ else
+ echo " ✗ GPG signature verification failed: $pkg"
+ exit 1
+ fi
+ done
+
+ - name: Step 5 - Validate Source Packages
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [5/9]: Validate Source Packages"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ cd dist/${{ env.RELEASE_VERSION }}
+
+ SRC_PACKAGES=()
+ for pkg in *-src.tar.gz; do
+ if [[ -f "$pkg" ]]; then
+ SRC_PACKAGES+=("$pkg")
+ fi
+ done
+
+ echo "Found ${#SRC_PACKAGES[@]} source package(s)"
+
+ for src_pkg in "${SRC_PACKAGES[@]}"; do
+ echo ""
+ echo "Validating source package: $src_pkg"
+
+ # Extract package
+ PACKAGE_DIR=$(basename "$src_pkg" .tar.gz)
+ rm -rf "$PACKAGE_DIR"
+ tar -xzf "$src_pkg"
+
+ if [[ ! -d "$PACKAGE_DIR" ]]; then
+ echo "Error: Failed to extract package: $src_pkg"
+ exit 1
+ fi
+
+ pushd "$PACKAGE_DIR"
+
+ # 5.1: Check incubating name
+ if [[ ! "$src_pkg" =~ "incubating" ]]; then
+ echo "Error: Package name '$src_pkg' should include 'incubating'"
+ exit 1
+ fi
+ echo " ✓ Package name includes 'incubating'"
+
+ # 5.2: Check required files
+ if [[ ! -f "LICENSE" ]]; then
+ echo "Error: Package '$src_pkg' missing LICENSE file"
+ exit 1
+ fi
+ echo " ✓ LICENSE file exists"
+
+ if [[ ! -f "NOTICE" ]]; then
+ echo "Error: Package '$src_pkg' missing NOTICE file"
+ exit 1
+ fi
+ echo " ✓ NOTICE file exists"
+
+ if [[ ! -f "DISCLAIMER" ]]; then
+ echo "Error: Package '$src_pkg' missing DISCLAIMER file"
+ exit 1
+ fi
+ echo " ✓ DISCLAIMER file exists"
+
+ # 5.3: Check license categories (Category X - Prohibited)
+ CAT_X_MATCHES=$(grep -r -E "${{ env.CATEGORY_X }}" LICENSE NOTICE
2>/dev/null || true)
+ CAT_X_COUNT=$(echo "$CAT_X_MATCHES" | grep -v '^$' | wc -l | tr -d
' ')
+
+ if [[ $CAT_X_COUNT -ne 0 ]]; then
+ echo "Error: Package '$src_pkg' contains $CAT_X_COUNT prohibited
ASF Category X license(s):"
+ echo "$CAT_X_MATCHES"
+ exit 1
+ fi
+ echo " ✓ No Category X licenses found"
+
+ # 5.4: Check license categories (Category B - Warning)
+ CAT_B_COUNT=$(grep -r -E "${{ env.CATEGORY_B }}" LICENSE NOTICE
2>/dev/null | wc -l | tr -d ' ' || echo "0")
+ if [[ $CAT_B_COUNT -ne 0 ]]; then
+ echo " ⚠ Warning: Package '$src_pkg' contains $CAT_B_COUNT ASF
Category B license(s) - please verify documentation"
+ else
+ echo " ✓ No Category B licenses found"
+ fi
+
+ # 5.5: Check empty files and directories
+ EMPTY_DIRS=$(find . -type d -empty 2>/dev/null || true)
+ EMPTY_FILES=$(find . -type f -empty 2>/dev/null || true)
+
+ if [[ -n "$EMPTY_DIRS" ]]; then
+ echo "Error: Package '$src_pkg' contains empty director(y/ies):"
+ echo "$EMPTY_DIRS"
+ exit 1
+ fi
+
+ if [[ -n "$EMPTY_FILES" ]]; then
+ echo "Error: Package '$src_pkg' contains empty file(s):"
+ echo "$EMPTY_FILES"
+ exit 1
+ fi
+ echo " ✓ No empty files or directories"
+
+ # 5.6: Check file sizes
+ LARGE_FILES=$(find . -type f -size "+${{ env.MAX_FILE_SIZE }}"
2>/dev/null || true)
+ if [[ -n "$LARGE_FILES" ]]; then
+ echo "Error: Package '$src_pkg' contains file(s) larger than ${{
env.MAX_FILE_SIZE }}:"
+ echo "$LARGE_FILES"
+ exit 1
+ fi
+ echo " ✓ All files are within size limit"
+
+ # 5.7: Check binary files
+ BINARY_COUNT=0
+ UNDOCUMENTED_COUNT=0
+ while IFS= read -r binary_file; do
+ BINARY_COUNT=$((BINARY_COUNT + 1))
+ FILE_NAME=$(basename "$binary_file")
+ if ! grep -q "$FILE_NAME" LICENSE 2>/dev/null; then
+ echo "Error: Undocumented binary file: $binary_file"
+ UNDOCUMENTED_COUNT=$((UNDOCUMENTED_COUNT + 1))
+ fi
+ done < <(find . -type f 2>/dev/null | perl -lne 'print if -B $_'
|| true)
+
+ if [[ $BINARY_COUNT -eq 0 ]]; then
+ echo " ✓ No binary files found"
+ elif [[ $UNDOCUMENTED_COUNT -eq 0 ]]; then
+ echo " ✓ All $BINARY_COUNT binary file(s) are documented"
+ else
+ echo "Error: Found $UNDOCUMENTED_COUNT undocumented binary
file(s)"
+ exit 1
+ fi
+
+ # 5.8: Check license headers in source files
+ echo " Checking for ASF license headers in source files..."
+
+ # Define file patterns to check
+ FILE_PATTERNS=("*.java" "*.sh" "*.py" "*.go" "*.js" "*.ts" "*.jsx"
"*.tsx" "*.c" "*.h" "*.cpp" "*.cc" "*.cxx" "*.hpp" "*.scala" "*.groovy"
"*.gradle" "*.rs" "*.kt" "*.proto")
+
+ # Files to exclude
+ EXCLUDE_PATTERNS=("*.min.js" "*.min.css" "*node_modules*"
"*target*" "*build*" "*.pb.go" "*generated*" "*third_party*" "*vendor*")
+
+ FILES_WITHOUT_LICENSE=()
+ TOTAL_CHECKED=0
+ EXCLUDED_COUNT=0
+ DOCUMENTED_COUNT=0
+
+ # Build find command
+ FIND_CMD="find . -type f \\("
+ FIRST=1
+ for pattern in "${FILE_PATTERNS[@]}"; do
+ if [[ $FIRST -eq 1 ]]; then
+ FIND_CMD="$FIND_CMD -name \"$pattern\""
+ FIRST=0
+ else
+ FIND_CMD="$FIND_CMD -o -name \"$pattern\""
+ fi
+ done
+ FIND_CMD="$FIND_CMD \\) 2>/dev/null"
+
+ # Check each source file
+ while IFS= read -r source_file; do
+ # Skip if file matches exclude patterns
+ SHOULD_EXCLUDE=0
+ for exclude_pattern in "${EXCLUDE_PATTERNS[@]}"; do
+ if [[ "$source_file" == $exclude_pattern ]]; then
+ SHOULD_EXCLUDE=1
+ EXCLUDED_COUNT=$((EXCLUDED_COUNT + 1))
+ break
+ fi
+ done
+
+ if [[ $SHOULD_EXCLUDE -eq 1 ]]; then
+ continue
+ fi
+
+ TOTAL_CHECKED=$((TOTAL_CHECKED + 1))
+
+ # Check first 30 lines for Apache license header
+ if ! head -n 30 "$source_file" | grep -q "Licensed to the Apache
Software Foundation"; then
+ # Check if documented in LICENSE file
+ FILE_NAME=$(basename "$source_file")
+ FILE_PATH_RELATIVE=$(echo "$source_file" | sed 's|^\./||')
+
+ if [[ -f "LICENSE" ]] && (grep -q "$FILE_NAME" LICENSE
2>/dev/null || grep -q "$FILE_PATH_RELATIVE" LICENSE 2>/dev/null); then
+ DOCUMENTED_COUNT=$((DOCUMENTED_COUNT + 1))
+ else
+ FILES_WITHOUT_LICENSE+=("$source_file")
+ fi
+ fi
+ done < <(eval "$FIND_CMD")
+
+ echo " Checked $TOTAL_CHECKED source file(s) for ASF license
headers (excluded $EXCLUDED_COUNT generated/vendored files)"
+
+ if [[ $DOCUMENTED_COUNT -gt 0 ]]; then
+ echo " Found $DOCUMENTED_COUNT source file(s) documented in
LICENSE as third-party code (allowed)"
+ fi
+
+ if [[ ${#FILES_WITHOUT_LICENSE[@]} -gt 0 ]]; then
+ echo "Error: Found ${#FILES_WITHOUT_LICENSE[@]} source file(s)
without ASF license headers:"
+ SHOW_COUNT=${#FILES_WITHOUT_LICENSE[@]}
+ if [[ $SHOW_COUNT -gt 20 ]]; then
+ SHOW_COUNT=20
+ fi
+ for ((i=0; i<SHOW_COUNT; i++)); do
+ echo " ${FILES_WITHOUT_LICENSE[$i]}"
+ done
+ if [[ ${#FILES_WITHOUT_LICENSE[@]} -gt 20 ]]; then
+ echo " ... and $((${#FILES_WITHOUT_LICENSE[@]} - 20)) more
files"
+ fi
+ echo "All source files must include the Apache License header or
be documented in LICENSE file"
+ exit 1
+ else
+ echo " ✓ All $TOTAL_CHECKED source file(s) have ASF license
headers or are documented in LICENSE"
+ fi
+
+ # 5.9: Check version consistency (skip for Python projects)
+ if [[ ! "$src_pkg" =~ 'hugegraph-ai' ]]; then
+ echo " Checking version consistency (revision property)..."
+
+ ROOT_POM=""
+ REVISION_VALUE=""
+
+ while IFS= read -r pom_file; do
+ if grep -q "<revision>" "$pom_file" 2>/dev/null; then
+ REVISION_VALUE=$(grep "<revision>" "$pom_file" | head -1 |
sed 's/.*<revision>\(.*\)<\/revision>.*/\1/')
+ ROOT_POM="$pom_file"
+ break
+ fi
+ done < <(find . -name "pom.xml" -type f 2>/dev/null)
+
+ if [[ -n "$ROOT_POM" ]]; then
+ echo " Found revision property in $ROOT_POM:
<revision>$REVISION_VALUE</revision>"
+ if [[ "$REVISION_VALUE" != "${{ env.RELEASE_VERSION }}" ]];
then
+ echo "Error: Version mismatch:
<revision>$REVISION_VALUE</revision> in $ROOT_POM (expected: ${{
env.RELEASE_VERSION }})"
+ exit 1
+ fi
+ echo " ✓ Version consistency check passed:
revision=$REVISION_VALUE"
+ else
+ echo " ⚠ Warning: No <revision> property found in pom.xml
files - skipping version check"
+ fi
+ else
+ echo " Skipping version check for Python project: $src_pkg"
+ fi
+
+ # 5.10: Check NOTICE year
+ if [[ -f "NOTICE" ]]; then
+ CURRENT_YEAR=$(date +%Y)
+ if ! grep -q "$CURRENT_YEAR" NOTICE; then
+ echo " ⚠ Warning: NOTICE file may not contain current year
($CURRENT_YEAR). Please verify copyright dates."
+ else
+ echo " ✓ NOTICE file contains current year"
+ fi
+ fi
+
+ # 5.11: Compile source package
+ echo " Compiling source package: $src_pkg"
+
+ if [[ "$src_pkg" =~ 'hugegraph-ai' ]]; then
+ echo " ⚠ Skipping compilation for AI module (not required)"
+ elif [[ "$src_pkg" =~ "hugegraph-computer" ]]; then
+ if cd computer 2>/dev/null && mvn clean package -DskipTests
-Dcheckstyle.skip=true -ntp -e; then
+ echo " ✓ Compilation successful: $src_pkg"
+ else
+ echo "Error: Compilation failed: $src_pkg"
+ exit 1
+ fi
+ cd ..
+ else
+ if mvn clean package -DskipTests -Dcheckstyle.skip=true -ntp -e;
then
+ echo " ✓ Compilation successful: $src_pkg"
+ else
+ echo "Error: Compilation failed: $src_pkg"
+ exit 1
+ fi
+ fi
+
+ popd
+ echo "✓ Finished validating source package: $src_pkg"
+ done
+
+ - name: Step 6 - Test Compiled Server Package
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [6/9]: Test Compiled Server Package"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ cd dist/${{ env.RELEASE_VERSION }}
+
+ # Find server directory
+ SERVER_DIR=$(find . -maxdepth 3 -type d -path
"*hugegraph-incubating*src/hugegraph-server/*hugegraph*${{ env.RELEASE_VERSION
}}" 2>/dev/null | head -n1)
+
+ if [[ -z "$SERVER_DIR" ]]; then
+ echo "Error: Could not find compiled server directory"
+ exit 1
+ fi
+
+ echo "Starting HugeGraph server from: $SERVER_DIR"
+ pushd "$SERVER_DIR"
+
+ if bin/init-store.sh; then
+ echo " ✓ Store initialized"
+ else
+ echo "Error: Failed to initialize store"
+ exit 1
+ fi
+
+ sleep ${{ env.SERVER_START_DELAY }}
+
+ if bin/start-hugegraph.sh; then
+ echo " ✓ Server started"
+ else
+ echo "Error: Failed to start server"
+ exit 1
+ fi
+
+ popd
+
+ - name: Step 7 - Test Compiled Toolchain Packages
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [7/9]: Test Compiled Toolchain Packages"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ cd dist/${{ env.RELEASE_VERSION }}
+
+ TOOLCHAIN_SRC=$(find . -maxdepth 3 -type d -path "*toolchain*src"
2>/dev/null | head -n1)
+
+ if [[ -n "$TOOLCHAIN_SRC" ]]; then
+ pushd "$TOOLCHAIN_SRC"
+
+ TOOLCHAIN_DIR=$(find . -maxdepth 1 -type d -name "*toolchain*${{
env.RELEASE_VERSION }}" | head -n1)
+ if [[ -n "$TOOLCHAIN_DIR" ]]; then
+ pushd "$TOOLCHAIN_DIR"
+
+ # Test Loader
+ echo "Testing HugeGraph Loader..."
+ LOADER_DIR=$(find . -maxdepth 1 -type d -name "*loader*${{
env.RELEASE_VERSION }}" | head -n1)
+ if [[ -n "$LOADER_DIR" ]]; then
+ pushd "$LOADER_DIR"
+ if bin/hugegraph-loader.sh -f ./example/file/struct.json -s
./example/file/schema.groovy -g hugegraph; then
+ echo " ✓ Loader test passed"
+ else
+ echo "Error: Loader test failed"
+ exit 1
+ fi
+ popd
+ fi
+
+ # Test Tool
+ echo "Testing HugeGraph Tool..."
+ TOOL_DIR=$(find . -maxdepth 1 -type d -name "*tool*${{
env.RELEASE_VERSION }}" | head -n1)
+ if [[ -n "$TOOL_DIR" ]]; then
+ pushd "$TOOL_DIR"
+ if bin/hugegraph gremlin-execute --script 'g.V().count()' && \
+ bin/hugegraph task-list && \
+ bin/hugegraph backup -t all --directory ./backup-test; then
+ echo " ✓ Tool test passed"
+ else
+ echo "Error: Tool test failed"
+ exit 1
+ fi
+ popd
+ fi
+
+ # Test Hubble
+ echo "Testing HugeGraph Hubble..."
+ HUBBLE_DIR=$(find . -maxdepth 1 -type d -name "*hubble*${{
env.RELEASE_VERSION }}" | head -n1)
+ if [[ -n "$HUBBLE_DIR" ]]; then
+ pushd "$HUBBLE_DIR"
+ if bin/start-hubble.sh; then
+ echo " ✓ Hubble started"
+ sleep 2
+ bin/stop-hubble.sh
+ echo " ✓ Hubble stopped"
+ else
+ echo "Error: Hubble test failed"
+ exit 1
+ fi
+ popd
+ fi
+
+ popd
+ fi
+
+ popd
+ fi
+
+ # Stop server after toolchain tests
+ SERVER_DIR=$(find . -maxdepth 3 -type d -path
"*hugegraph-incubating*src/hugegraph-server/*hugegraph*${{ env.RELEASE_VERSION
}}" 2>/dev/null | head -n1)
+ if [[ -n "$SERVER_DIR" ]]; then
+ echo "Stopping server..."
+ pushd "$SERVER_DIR"
+ bin/stop-hugegraph.sh
+ echo " ✓ Server stopped"
+ popd
+ fi
+
+ - name: Step 8 - Validate Binary Packages
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [8/9]: Validate Binary Packages"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ cd dist/${{ env.RELEASE_VERSION }}
+
+ BIN_PACKAGES=()
+ for pkg in *.tar.gz; do
+ if [[ "$pkg" != *-src.tar.gz ]] && [[ -f "$pkg" ]]; then
+ BIN_PACKAGES+=("$pkg")
+ fi
+ done
+
+ echo "Found ${#BIN_PACKAGES[@]} binary package(s)"
+
+ for bin_pkg in "${BIN_PACKAGES[@]}"; do
+ echo ""
+ echo "Validating binary package: $bin_pkg"
+
+ # Extract package
+ PACKAGE_DIR=$(basename "$bin_pkg" .tar.gz)
+ rm -rf "$PACKAGE_DIR"
+ tar -xzf "$bin_pkg"
+
+ if [[ ! -d "$PACKAGE_DIR" ]]; then
+ echo "Error: Failed to extract package: $bin_pkg"
+ exit 1
+ fi
+
+ pushd "$PACKAGE_DIR"
+
+ # 8.1: Check incubating name
+ if [[ ! "$bin_pkg" =~ "incubating" ]]; then
+ echo "Error: Package name '$bin_pkg' should include 'incubating'"
+ exit 1
+ fi
+ echo " ✓ Package name includes 'incubating'"
+
+ # 8.2: Check required files
+ if [[ ! -f "LICENSE" ]]; then
+ echo "Error: Package '$bin_pkg' missing LICENSE file"
+ exit 1
+ fi
+ echo " ✓ LICENSE file exists"
+
+ if [[ ! -f "NOTICE" ]]; then
+ echo "Error: Package '$bin_pkg' missing NOTICE file"
+ exit 1
+ fi
+ echo " ✓ NOTICE file exists"
+
+ if [[ ! -f "DISCLAIMER" ]]; then
+ echo "Error: Package '$bin_pkg' missing DISCLAIMER file"
+ exit 1
+ fi
+ echo " ✓ DISCLAIMER file exists"
+
+ # 8.3: Check licenses directory
+ if [[ ! -d "licenses" ]]; then
+ echo "Error: Package '$bin_pkg' missing licenses directory"
+ exit 1
+ fi
+ echo " ✓ licenses directory exists"
+
+ # 8.4: Check license categories (Category X - Prohibited)
+ CAT_X_MATCHES=$(grep -r -E "${{ env.CATEGORY_X }}" LICENSE NOTICE
licenses 2>/dev/null || true)
+ CAT_X_COUNT=$(echo "$CAT_X_MATCHES" | grep -v '^$' | wc -l | tr -d
' ')
+
+ if [[ $CAT_X_COUNT -ne 0 ]]; then
+ echo "Error: Package '$bin_pkg' contains $CAT_X_COUNT prohibited
ASF Category X license(s):"
+ echo "$CAT_X_MATCHES"
+ exit 1
+ fi
+ echo " ✓ No Category X licenses found"
+
+ # 8.5: Check license categories (Category B - Warning)
+ CAT_B_COUNT=$(grep -r -E "${{ env.CATEGORY_B }}" LICENSE NOTICE
licenses 2>/dev/null | wc -l | tr -d ' ' || echo "0")
+ if [[ $CAT_B_COUNT -ne 0 ]]; then
+ echo " ⚠ Warning: Package '$bin_pkg' contains $CAT_B_COUNT ASF
Category B license(s) - please verify documentation"
+ else
+ echo " ✓ No Category B licenses found"
+ fi
+
+ # 8.6: Check empty files and directories
+ EMPTY_DIRS=$(find . -type d -empty 2>/dev/null || true)
+ EMPTY_FILES=$(find . -type f -empty 2>/dev/null || true)
+
+ if [[ -n "$EMPTY_DIRS" ]]; then
+ echo "Error: Package '$bin_pkg' contains empty director(y/ies):"
+ echo "$EMPTY_DIRS"
+ exit 1
+ fi
+
+ if [[ -n "$EMPTY_FILES" ]]; then
+ echo "Error: Package '$bin_pkg' contains empty file(s):"
+ echo "$EMPTY_FILES"
+ exit 1
+ fi
+ echo " ✓ No empty files or directories"
+
+ popd
+ echo "✓ Finished validating binary package: $bin_pkg"
+ done
+
+ - name: Step 9 - Test Binary Server & Toolchain
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [9/9]: Test Binary Server & Toolchain"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ cd dist/${{ env.RELEASE_VERSION }}
+
+ # Test binary server
+ BIN_SERVER_DIR=$(find . -maxdepth 3 -type d -path
"*hugegraph-incubating*${{ env.RELEASE_VERSION
}}/*hugegraph-server-incubating*${{ env.RELEASE_VERSION }}" 2>/dev/null | head
-n1)
+
+ if [[ -n "$BIN_SERVER_DIR" ]]; then
+ echo "Testing binary server package..."
+ pushd "$BIN_SERVER_DIR"
+
+ if bin/init-store.sh && sleep ${{ env.SERVER_START_DELAY }} &&
bin/start-hugegraph.sh; then
+ echo " ✓ Binary server started"
+ else
+ echo "Error: Failed to start binary server"
+ exit 1
+ fi
+
+ popd
+ fi
+
+ # Test binary toolchain
+ BIN_TOOLCHAIN=$(find . -maxdepth 3 -type d -path "*toolchain*${{
env.RELEASE_VERSION }}" 2>/dev/null | head -n1)
+
+ if [[ -n "$BIN_TOOLCHAIN" ]]; then
+ pushd "$BIN_TOOLCHAIN"
+
+ # Test binary loader
+ BIN_LOADER=$(find . -maxdepth 1 -type d -name "*loader*${{
env.RELEASE_VERSION }}" | head -n1)
+ if [[ -n "$BIN_LOADER" ]]; then
+ pushd "$BIN_LOADER"
+ if bin/hugegraph-loader.sh -f ./example/file/struct.json -s
./example/file/schema.groovy -g hugegraph; then
+ echo " ✓ Binary loader test passed"
+ else
+ echo "Error: Binary loader test failed"
+ exit 1
+ fi
+ popd
+ fi
+
+ # Test binary tool
+ BIN_TOOL=$(find . -maxdepth 1 -type d -name "*tool*${{
env.RELEASE_VERSION }}" | head -n1)
+ if [[ -n "$BIN_TOOL" ]]; then
+ pushd "$BIN_TOOL"
+ if bin/hugegraph gremlin-execute --script 'g.V().count()' && \
+ bin/hugegraph task-list && \
+ bin/hugegraph backup -t all --directory ./backup-test; then
+ echo " ✓ Binary tool test passed"
+ else
+ echo "Error: Binary tool test failed"
+ exit 1
+ fi
+ popd
+ fi
+
+ # Test binary hubble
+ BIN_HUBBLE=$(find . -maxdepth 1 -type d -name "*hubble*${{
env.RELEASE_VERSION }}" | head -n1)
+ if [[ -n "$BIN_HUBBLE" ]]; then
+ pushd "$BIN_HUBBLE"
+ if bin/start-hubble.sh; then
+ echo " ✓ Binary hubble started"
+ sleep 2
+ bin/stop-hubble.sh
+ echo " ✓ Binary hubble stopped"
+ else
+ echo "Error: Binary hubble test failed"
+ exit 1
+ fi
+ popd
+ fi
+
+ popd
+ fi
+
+ # Stop binary server
+ if [[ -n "$BIN_SERVER_DIR" ]]; then
+ pushd "$BIN_SERVER_DIR"
+ bin/stop-hugegraph.sh
+ echo " ✓ Binary server stopped"
+ popd
+ fi
+
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo " VALIDATION SUMMARY "
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo ""
+ echo "✓ VALIDATION PASSED"
Review Comment:
⚠️ important — The workflow always prints `VALIDATION PASSED` even when
`BIN_PACKAGES` is empty and the binary server/toolchain discovery skips all
smoke tests. Assert non-zero expected artifact counts and fail when required
server, loader, tool, or Hubble components are absent before reporting success.
##########
.github/workflows/validate-release-new.yml:
##########
@@ -0,0 +1,805 @@
+name: "Validate Apache Release (New)"
+
+on:
+ workflow_dispatch:
+ inputs:
+ release_version:
+ required: true
+ description: svn release version
+ default: '1.7.0'
+ gpg_user:
+ required: true
+ description: current release manager (gpg username)
+ default: 'pengjunzhi'
+ java_version:
+ required: false
+ description: Java version to validate
+ default: '11'
+ type: choice
+ options:
+ - '11'
+ - '17'
+
+ push:
+ branches:
+ - 'release-*'
+ pull_request:
+ branches:
+ - 'release-*'
+
+jobs:
+ validate:
+ name: "Validate Release On ${{ matrix.os }} (java-${{ matrix.java_version
}})"
+ runs-on: ${{ matrix.os }}
+ env:
+ RELEASE_VERSION: ${{ inputs.release_version || '1.7.0' }}
Review Comment:
⚠️ important — `push` and `pull_request` triggers provide no release input,
so these runs silently validate the hard-coded default `1.7.0` regardless of
the `release-*` branch. Restrict this workflow to `workflow_dispatch`, or
derive and strictly validate the release version from the ref.
##########
.github/workflows/validate-release-new.yml:
##########
@@ -0,0 +1,805 @@
+name: "Validate Apache Release (New)"
+
+on:
+ workflow_dispatch:
+ inputs:
+ release_version:
+ required: true
+ description: svn release version
+ default: '1.7.0'
+ gpg_user:
+ required: true
+ description: current release manager (gpg username)
+ default: 'pengjunzhi'
+ java_version:
+ required: false
+ description: Java version to validate
+ default: '11'
+ type: choice
+ options:
+ - '11'
+ - '17'
+
+ push:
+ branches:
+ - 'release-*'
+ pull_request:
+ branches:
+ - 'release-*'
+
+jobs:
+ validate:
+ name: "Validate Release On ${{ matrix.os }} (java-${{ matrix.java_version
}})"
+ runs-on: ${{ matrix.os }}
+ env:
+ RELEASE_VERSION: ${{ inputs.release_version || '1.7.0' }}
+ GPG_USER: ${{ inputs.gpg_user || 'pengjunzhi' }}
+ JAVA_VERSION: ${{ inputs.java_version || matrix.java_version || '11' }}
+ SVN_URL_PREFIX:
https://dist.apache.org/repos/dist/dev/incubator/hugegraph
+ KEYS_URL: https://downloads.apache.org/incubator/hugegraph/KEYS
+ MAX_FILE_SIZE: 800k
+ SERVER_START_DELAY: 3
+ # License Patterns (ASF Category X - Prohibited)
+ CATEGORY_X: '\bGPL|\bLGPL|Sleepycat
License|BSD-4-Clause|\bBCL\b|JSR-275|Amazon Software
License|\bRSAL\b|\bQPL\b|\bSSPL|\bCPOL|\bNPL1|Creative Commons
Non-Commercial|JSON\.org'
+ # License Patterns (ASF Category B - Must be documented)
+ CATEGORY_B: '\bCDDL1|\bCPL|\bEPL|\bIPL|\bMPL|\bSPL|OSL-3.0|UnRAR
License|Erlang Public License|\bOFL\b|Ubuntu Font License Version 1.0|IPA Font
License Agreement v1.0|EPL2.0|CC-BY'
+ steps:
+ - name: Checkout source
+ uses: actions/checkout@v4
+
+ - name: Install JDK ${{ env.JAVA_VERSION }}
+ uses: actions/setup-java@v3
Review Comment:
⚠️ important — `actions/setup-java@v3` and `actions/cache@v3` (line 74) use
obsolete action runtimes; a fresh `actionlint` run reports both. Upgrade them
to supported versions, at least `@v4`, and pin reviewed commit SHAs.
##########
content/cn/docs/quickstart/toolchain/hugegraph-seatunnel-connector.md:
##########
@@ -0,0 +1,79 @@
+---
+title: "HugeGraph-SeaTunnel Connector Quick Start"
+linkTitle: "使用 SeaTunnel Connector 同步数据"
+weight: 5
+---
+
+### 1 HugeGraph-SeaTunnel Connector 概述
+
+[Apache SeaTunnel](https://seatunnel.apache.org/)
是一个高性能、分布式的数据集成平台,支持海量数据的实时同步与批处理。
+HugeGraph 为 Apache SeaTunnel 提供了 Connector-V2 支持,用户可以通过 SeaTunnel 方便地在
HugeGraph
+与外部数据系统之间进行数据同步。
+
+> **注意**:SeaTunnel Connector 由 HugeGraph 社区贡献至 Apache SeaTunnel 项目,具体使用方式请参考
+> [Apache SeaTunnel 官方文档](https://seatunnel.apache.org/docs/)。
+
+### 2 功能特性
+
+HugeGraph-SeaTunnel Connector 提供以下能力:
+
+- **HugeGraph Source Connector**:从 HugeGraph 读取图数据,支持顶点和边的批量读取
Review Comment:
⚠️ important — This page presents Source and incremental synchronization as
available under the broad `2.3.x+` range, but the current released [HugeGraph
connector
documentation](https://seatunnel.apache.org/docs/connectors/sink/HugeGraph/)
documents the Sink and does not establish a released Source/CDC version. Narrow
this page to released Sink support, or label Source as unreleased and publish
an exact version matrix; remove or qualify the incremental claims.
##########
content/cn/docs/quickstart/toolchain/hugegraph-seatunnel-connector.md:
##########
@@ -0,0 +1,79 @@
+---
+title: "HugeGraph-SeaTunnel Connector Quick Start"
+linkTitle: "使用 SeaTunnel Connector 同步数据"
+weight: 5
+---
+
+### 1 HugeGraph-SeaTunnel Connector 概述
+
+[Apache SeaTunnel](https://seatunnel.apache.org/)
是一个高性能、分布式的数据集成平台,支持海量数据的实时同步与批处理。
+HugeGraph 为 Apache SeaTunnel 提供了 Connector-V2 支持,用户可以通过 SeaTunnel 方便地在
HugeGraph
+与外部数据系统之间进行数据同步。
+
+> **注意**:SeaTunnel Connector 由 HugeGraph 社区贡献至 Apache SeaTunnel 项目,具体使用方式请参考
+> [Apache SeaTunnel 官方文档](https://seatunnel.apache.org/docs/)。
+
+### 2 功能特性
+
+HugeGraph-SeaTunnel Connector 提供以下能力:
+
+- **HugeGraph Source Connector**:从 HugeGraph 读取图数据,支持顶点和边的批量读取
+- **HugeGraph Sink Connector**:将外部数据写入 HugeGraph,支持顶点和边的批量写入
+- **顶点同步**:支持全量或增量同步顶点数据
+- **边同步**:支持全量或增量同步边数据
+- **Schema 映射**:自动映射 HugeGraph Schema(PropertyKey、VertexLabel、EdgeLabel)与外部数据字段
+- **数据迁移**:支持在不同 HugeGraph 实例之间进行数据迁移,或从其他数据源导入图数据
+
+### 3 环境要求
+
+- Java 8+
+- Apache SeaTunnel 2.3.x+
+- HugeGraph Server 1.0.0+
+
+### 4 快速开始
+
+#### 4.1 安装 SeaTunnel
+
+请参考 [Apache SeaTunnel 安装指南](https://seatunnel.apache.org/docs/start-v2/) 完成
SeaTunnel 的部署。
Review Comment:
⚠️ important — The installation link points to `/docs/start-v2/`, which is
not the current deployment guide, and the page says the connector can be
referenced directly although current SeaTunnel deployments require
connector-plugin installation. Link the [current deployment
guide](https://seatunnel.apache.org/docs/getting-started/locally/deployment/)
and document the required plugin installation step.
##########
content/cn/docs/introduction/_index.md:
##########
@@ -94,6 +94,7 @@ HugeGraph 独立的 AI 组件,连接图与大语言模型(LLM):
| [Loader](/cn/docs/quickstart/toolchain/hugegraph-loader) |
数据导入工具:支持本地文件、HDFS、MySQL 等多数据源,TXT/CSV/JSON 等格式 |
| [Client](/cn/docs/quickstart/client/hugegraph-client) | 多语言 SDK:Java /
Python / Go |
| [Spark-connector](/cn/docs/quickstart/toolchain/hugegraph-spark-connector) |
Spark 集成:支持通过 Spark 批量读写图数据,适合大数据离线处理场景 |
+|
[SeaTunnel-connector](/cn/docs/quickstart/toolchain/hugegraph-seatunnel-connector)
| SeaTunnel 集成:支持通过 SeaTunnel 在 HugeGraph 与外部数据系统之间同步数据 |
Review Comment:
⚠️ important — The patch adds only the Chinese quick-start and introduction
entry, while the repository maintains parallel `content/cn` and `content/en`
documentation. Add the corresponding English page and
`content/en/docs/introduction/_index.md` entry so the integration is
discoverable on both sites.
##########
content/cn/docs/quickstart/toolchain/hugegraph-seatunnel-connector.md:
##########
@@ -0,0 +1,79 @@
+---
+title: "HugeGraph-SeaTunnel Connector Quick Start"
+linkTitle: "使用 SeaTunnel Connector 同步数据"
+weight: 5
+---
+
+### 1 HugeGraph-SeaTunnel Connector 概述
+
+[Apache SeaTunnel](https://seatunnel.apache.org/)
是一个高性能、分布式的数据集成平台,支持海量数据的实时同步与批处理。
+HugeGraph 为 Apache SeaTunnel 提供了 Connector-V2 支持,用户可以通过 SeaTunnel 方便地在
HugeGraph
+与外部数据系统之间进行数据同步。
+
+> **注意**:SeaTunnel Connector 由 HugeGraph 社区贡献至 Apache SeaTunnel 项目,具体使用方式请参考
+> [Apache SeaTunnel 官方文档](https://seatunnel.apache.org/docs/)。
+
+### 2 功能特性
+
+HugeGraph-SeaTunnel Connector 提供以下能力:
+
+- **HugeGraph Source Connector**:从 HugeGraph 读取图数据,支持顶点和边的批量读取
+- **HugeGraph Sink Connector**:将外部数据写入 HugeGraph,支持顶点和边的批量写入
+- **顶点同步**:支持全量或增量同步顶点数据
+- **边同步**:支持全量或增量同步边数据
+- **Schema 映射**:自动映射 HugeGraph Schema(PropertyKey、VertexLabel、EdgeLabel)与外部数据字段
+- **数据迁移**:支持在不同 HugeGraph 实例之间进行数据迁移,或从其他数据源导入图数据
+
+### 3 环境要求
+
+- Java 8+
+- Apache SeaTunnel 2.3.x+
+- HugeGraph Server 1.0.0+
+
+### 4 快速开始
+
+#### 4.1 安装 SeaTunnel
+
+请参考 [Apache SeaTunnel 安装指南](https://seatunnel.apache.org/docs/start-v2/) 完成
SeaTunnel 的部署。
+
+#### 4.2 使用 HugeGraph Connector
+
+HugeGraph Connector 已包含在 SeaTunnel 的 Connector-V2 生态中。在 SeaTunnel 配置文件中直接引用即可:
+
+**从 HugeGraph 读取数据(Source)示例:**
+
+```hocon
+source {
+ HugeGraph {
+ url = "http://127.0.0.1:8080"
Review Comment:
⚠️ important — The Source example uses `url` and `graph`, which are not the
documented connection fields, and omits required connection parameters such as
`host`, `port`, and `graph_name`. Provide a versioned, runnable Source example
only if that Source implementation is released; otherwise remove it.
##########
.github/workflows/validate-release-new.yml:
##########
@@ -0,0 +1,805 @@
+name: "Validate Apache Release (New)"
+
+on:
+ workflow_dispatch:
+ inputs:
+ release_version:
+ required: true
+ description: svn release version
+ default: '1.7.0'
+ gpg_user:
+ required: true
+ description: current release manager (gpg username)
+ default: 'pengjunzhi'
+ java_version:
+ required: false
+ description: Java version to validate
+ default: '11'
+ type: choice
+ options:
+ - '11'
+ - '17'
+
+ push:
+ branches:
+ - 'release-*'
+ pull_request:
+ branches:
+ - 'release-*'
+
+jobs:
+ validate:
+ name: "Validate Release On ${{ matrix.os }} (java-${{ matrix.java_version
}})"
+ runs-on: ${{ matrix.os }}
+ env:
+ RELEASE_VERSION: ${{ inputs.release_version || '1.7.0' }}
+ GPG_USER: ${{ inputs.gpg_user || 'pengjunzhi' }}
+ JAVA_VERSION: ${{ inputs.java_version || matrix.java_version || '11' }}
+ SVN_URL_PREFIX:
https://dist.apache.org/repos/dist/dev/incubator/hugegraph
+ KEYS_URL: https://downloads.apache.org/incubator/hugegraph/KEYS
+ MAX_FILE_SIZE: 800k
+ SERVER_START_DELAY: 3
+ # License Patterns (ASF Category X - Prohibited)
+ CATEGORY_X: '\bGPL|\bLGPL|Sleepycat
License|BSD-4-Clause|\bBCL\b|JSR-275|Amazon Software
License|\bRSAL\b|\bQPL\b|\bSSPL|\bCPOL|\bNPL1|Creative Commons
Non-Commercial|JSON\.org'
+ # License Patterns (ASF Category B - Must be documented)
+ CATEGORY_B: '\bCDDL1|\bCPL|\bEPL|\bIPL|\bMPL|\bSPL|OSL-3.0|UnRAR
License|Erlang Public License|\bOFL\b|Ubuntu Font License Version 1.0|IPA Font
License Agreement v1.0|EPL2.0|CC-BY'
+ steps:
+ - name: Checkout source
+ uses: actions/checkout@v4
+
+ - name: Install JDK ${{ env.JAVA_VERSION }}
+ uses: actions/setup-java@v3
+ with:
+ java-version: ${{ env.JAVA_VERSION }}
+ distribution: 'adopt'
+
+ - name: Install dependencies
+ run: |
+ if [[ "${{ runner.os }}" == "macOS" ]]; then
+ brew install svn wget perl
+ elif [[ "${{ runner.os }}" == "Linux" ]]; then
+ sudo apt-get update
+ sudo apt-get install -y subversion wget perl
+ fi
+ # Verify all required commands
+ for cmd in svn gpg shasum mvn java wget tar curl awk grep find perl;
do
+ if ! command -v "$cmd" &> /dev/null; then
+ echo "Error: Missing required dependency: $cmd"
+ exit 1
+ fi
+ echo "✓ $cmd: $(command -v $cmd)"
+ done
+
+ - name: Cache Maven packages
+ uses: actions/cache@v3
+ with:
+ path: ~/.m2
+ key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: ${{ runner.os }}-m2
+
+ - name: Step 1 - Check Dependencies
+ run: |
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [1/9]: Check Dependencies"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ # Check Java version
+ CURRENT_JAVA=$(java -version 2>&1 | head -n 1 | awk -F '"' '{print
$2}' | awk -F '.' '{print $1}')
+ echo "Current Java version: $CURRENT_JAVA (Required: ${{
env.JAVA_VERSION }})"
+ if [[ "$CURRENT_JAVA" != "${{ env.JAVA_VERSION }}" ]]; then
+ echo "Error: Java version mismatch! Current: Java $CURRENT_JAVA,
Required: Java ${{ env.JAVA_VERSION }}"
+ exit 1
+ fi
+ echo "✓ Java version check passed: Java $CURRENT_JAVA"
+
+ - name: Step 2 - Prepare Release Files
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [2/9]: Prepare Release Files"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ DIST_DIR="dist/${{ env.RELEASE_VERSION }}"
+ echo "Downloading from SVN to: ${DIST_DIR}"
+
+ rm -rf "${DIST_DIR}"
+ mkdir -p "${DIST_DIR}"
+
+ if ! svn co "${SVN_URL_PREFIX}/${{ env.RELEASE_VERSION }}"
"${DIST_DIR}"; then
+ echo "Error: Failed to download from SVN: ${SVN_URL_PREFIX}/${{
env.RELEASE_VERSION }}"
+ exit 1
+ fi
+
+ echo "✓ Downloaded release files from SVN"
+ cd "${DIST_DIR}"
+ ls -lh
+
+ - name: Step 3 - Import & Trust GPG Keys
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [3/9]: Import & Trust GPG Keys"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ cd dist/${{ env.RELEASE_VERSION }}
+
+ echo "Downloading KEYS file from ${KEYS_URL}..."
+ if ! wget -q "${KEYS_URL}" -O KEYS; then
+ echo "Error: Failed to download KEYS file from ${KEYS_URL}"
+ exit 1
+ fi
+ echo "✓ KEYS file downloaded"
+
+ echo "Importing GPG keys..."
+ IMPORT_OUTPUT=$(gpg --import KEYS 2>&1)
+ IMPORTED_COUNT=$(echo "$IMPORT_OUTPUT" | grep -c "imported" || echo
"0")
+
+ if [[ "$IMPORTED_COUNT" == "0" ]]; then
+ echo "⚠ No new keys imported (may already exist in keyring)"
+ else
+ echo "✓ Imported GPG keys"
+ fi
+
+ # Trust specific user key
+ if ! gpg --list-keys "${{ env.GPG_USER }}" &>/dev/null; then
+ echo "Error: User '${{ env.GPG_USER }}' key not found in imported
keys. Please verify the username."
+ exit 1
+ fi
+
+ echo "Trusting GPG key for user: ${{ env.GPG_USER }}"
+ echo -e "5\ny\n" | gpg --batch --command-fd 0 --edit-key "${{
env.GPG_USER }}" trust 2>/dev/null
+ echo "✓ Trusted key for ${{ env.GPG_USER }}"
+
+ # Trust all imported keys
+ echo "Trusting all imported public keys..."
+ TRUSTED=0
+ for key in $(gpg --no-tty --list-keys --with-colons | awk -F:
'/^pub/ {print $5}'); do
+ echo -e "5\ny\n" | gpg --batch --command-fd 0 --edit-key "$key"
trust 2>/dev/null
+ TRUSTED=$((TRUSTED + 1))
+ done
+ echo "✓ Trusted $TRUSTED GPG keys"
+
+ - name: Step 4 - Verify SHA512 & GPG Signatures
+ run: |
+ echo ""
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+ echo "Step [4/9]: Verify SHA512 & GPG Signatures"
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+
+ cd dist/${{ env.RELEASE_VERSION }}
+
+ PACKAGE_COUNT=0
+ for pkg in *.tar.gz; do
+ if [[ -f "$pkg" ]]; then
+ PACKAGE_COUNT=$((PACKAGE_COUNT + 1))
+ fi
+ done
+
+ CURRENT=0
+ for pkg in *.tar.gz; do
+ if [[ ! -f "$pkg" ]]; then
+ continue
+ fi
+ CURRENT=$((CURRENT + 1))
+ echo " [${CURRENT}/${PACKAGE_COUNT}] $pkg"
+
+ # Check SHA512
+ if shasum -a 512 --check "${pkg}.sha512"; then
+ echo " ✓ SHA512 verified: $pkg"
+ else
+ echo " ✗ SHA512 verification failed: $pkg"
+ exit 1
+ fi
+
+ # Check GPG signature
+ if gpg --verify "${pkg}.asc" "$pkg" 2>&1 | grep -q "Good
signature"; then
Review Comment:
⚠️ important — `gpg --verify | grep -q "Good signature"` accepts any
imported key; `GPG_USER` is never tied to the signer. Resolve the selected
release manager's fingerprint and compare GPG's machine-readable `VALIDSIG`
status for every artifact.
##########
content/cn/docs/introduction/_index.md:
##########
@@ -32,7 +32,7 @@ HugeGraph 支持百亿以上的顶点和边的快速存储与查询,具备出
│ Server │ Computer (Dist.) │ GraphRAG/GNN/Py │
├──────────────────┴────────────────────┴──────────────────────┤
│ HugeGraph Toolchain │
-│ Hubble | Loader | Client(Java/Go/Py) | Spark | Tools │
+│ Hubble | Loader | Client(Java/Go/Py) | Spark | SeaTunnel | Tools │
Review Comment:
🧹 minor — The new SeaTunnel row is wider than the ASCII diagram's top and
bottom borders, so the right edge no longer aligns. Extend the frame or shorten
the row and adjust the padding.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]