diff --git a/.github/workflows/validate-release-new.yml b/.github/workflows/validate-release-new.yml new file mode 100644 index 000000000..08d678d11 --- /dev/null +++ b/.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" "$pom_file" 2>/dev/null; then + REVISION_VALUE=$(grep "" "$pom_file" | head -1 | sed 's/.*\(.*\)<\/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_VALUE" + if [[ "$REVISION_VALUE" != "${{ env.RELEASE_VERSION }}" ]]; then + echo "Error: Version mismatch: $REVISION_VALUE in $ROOT_POM (expected: ${{ env.RELEASE_VERSION }})" + exit 1 + fi + echo " ✓ Version consistency check passed: revision=$REVISION_VALUE" + else + echo " ⚠ Warning: No 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" + echo "" + echo "Please review the validation results and provide feedback in the" + echo "release voting thread on the mailing list." + + strategy: + fail-fast: false + matrix: + java_version: ['11'] + os: [ubuntu-latest, macos-latest] + diff --git a/content/cn/docs/images/seatunnel/hugegraph-fullstack-ecosystem.png b/content/cn/docs/images/seatunnel/hugegraph-fullstack-ecosystem.png new file mode 100644 index 000000000..e6fe1279f Binary files /dev/null and b/content/cn/docs/images/seatunnel/hugegraph-fullstack-ecosystem.png differ diff --git a/content/cn/docs/images/seatunnel/hugegraph-seatunnel-architecture.png b/content/cn/docs/images/seatunnel/hugegraph-seatunnel-architecture.png new file mode 100644 index 000000000..c84fb41f1 Binary files /dev/null and b/content/cn/docs/images/seatunnel/hugegraph-seatunnel-architecture.png differ diff --git a/content/cn/docs/images/seatunnel/hugegraph-seatunnel-source-sink.png b/content/cn/docs/images/seatunnel/hugegraph-seatunnel-source-sink.png new file mode 100644 index 000000000..c0e658b25 Binary files /dev/null and b/content/cn/docs/images/seatunnel/hugegraph-seatunnel-source-sink.png differ diff --git a/content/cn/docs/introduction/_index.md b/content/cn/docs/introduction/_index.md index a586f1081..5eb12de20 100644 --- a/content/cn/docs/introduction/_index.md +++ b/content/cn/docs/introduction/_index.md @@ -23,18 +23,22 @@ HugeGraph 支持百亿以上的顶点和边的快速存储与查询,具备出 ### 生态系统全景 +```text +┌────────────────────────────────────────────────────────────────────┐ +│ Apache HugeGraph - Full-Stack Graph System │ +├──────────────────┬────────────────────┬────────────────────────────┤ +│ Graph DB (OLTP) │ Graph Compute │ Graph AI │ +│ HugeGraph │ Vermeer (Memory) │ HugeGraph-AI │ +│ Server │ Computer (Dist.) │ GraphRAG/GNN/Py │ +├──────────────────┴────────────────────┴────────────────────────────┤ +│ HugeGraph Toolchain │ +│ Hubble | Loader | Client(Java/Go/Py) | Spark | SeaTunnel | Tools │ +└────────────────────────────────────────────────────────────────────┘ ``` -┌──────────────────────────────────────────────────────────────┐ -│ Apache HugeGraph - Full-Stack Graph System │ -├──────────────────┬────────────────────┬──────────────────────┤ -│ Graph DB (OLTP) │ Graph Compute │ Graph AI │ -│ HugeGraph │ Vermeer (Memory) │ HugeGraph-AI │ -│ Server │ Computer (Dist.) │ GraphRAG/GNN/Py │ -├──────────────────┴────────────────────┴──────────────────────┤ -│ HugeGraph Toolchain │ -│ Hubble | Loader | Client(Java/Go/Py) | Spark | Tools │ -└──────────────────────────────────────────────────────────────┘ -``` + +![Apache HugeGraph 全栈图系统生态全景图](/cn/docs/images/seatunnel/hugegraph-fullstack-ecosystem.png) + +```text --- @@ -94,6 +98,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 与外部数据系统之间同步数据 | | [Tools](/cn/docs/quickstart/toolchain/hugegraph-tools) | 命令行运维工具:图管理、备份恢复、Gremlin 执行等 | --- diff --git a/content/cn/docs/quickstart/toolchain/hugegraph-seatunnel-connector.md b/content/cn/docs/quickstart/toolchain/hugegraph-seatunnel-connector.md new file mode 100644 index 000000000..20831e3dd --- /dev/null +++ b/content/cn/docs/quickstart/toolchain/hugegraph-seatunnel-connector.md @@ -0,0 +1,146 @@ +--- +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 与外部数据系统进行数据同步。 + +![HugeGraph + SeaTunnel 数据集成架构图](/cn/docs/images/seatunnel/hugegraph-seatunnel-architecture.png) + +### 2 功能特性 + +HugeGraph-SeaTunnel Connector 提供以下能力: + +- **HugeGraph Sink Connector**(已发布):将外部数据写入 HugeGraph,支持顶点和边的批量写入、更新与删除 +- **HugeGraph Source Connector**(开发中):从 HugeGraph 读取图数据,支持顶点和边的批量读取 +- **顶点同步**:支持全量或增量同步顶点数据,支持多种 ID 策略 +- **边同步**:支持全量或增量同步边数据,自动关联源顶点与目标顶点 +- **Schema 自动管理**:支持自动创建 PropertyKey、VertexLabel、EdgeLabel(`CREATE_SCHEMA_WHEN_NOT_EXIST`) +- **数据迁移**:支持在不同 HugeGraph 实例之间迁移数据,或从其他数据源导入图数据 + +![HugeGraph Source/Sink 双向数据流示意图](/cn/docs/images/seatunnel/hugegraph-seatunnel-source-sink.png) + +### 3 环境要求 + +| 组件 | 版本要求 | 说明 | +|------|---------|------| +| Java | 8+ | SeaTunnel 运行环境要求 | +| Apache SeaTunnel | 2.3.12+ | Sink Connector 自此版本发布 | +| HugeGraph Server | 1.0.0+ | 建议使用最新稳定版 | + +> **Source Connector 说明**:HugeGraph Source Connector 目前仅在 SeaTunnel 开发分支(Next/master)中可用, +> 尚未包含在正式 Release 中。如需使用 Source 功能,请从 SeaTunnel 源码编译或等待下一版本发布。 + +### 4 快速开始 + +#### 4.1 安装 SeaTunnel + +请参考 [Apache SeaTunnel 部署指南](https://seatunnel.apache.org/docs/getting-started/) 完成 SeaTunnel 的安装部署。 + +#### 4.2 使用 HugeGraph Sink Connector(写入数据) + +以下示例展示如何通过 SeaTunnel 将数据写入 HugeGraph: + +**写入顶点数据:** + +```hocon +env { + job.mode = "BATCH" +} + +source { + FakeSource { + plugin_output = "fake" + schema = { + fields = { + name = "string" + age = "int" + } + } + } +} + +sink { + HugeGraph { + host = "127.0.0.1" + port = 8080 + graph_name = "hugegraph" + mappings = [ + { + type = "VERTEX" + label = "person" + idStrategy = "PRIMARY_KEY" + idFields = ["name"] + properties = ["name", "age"] + } + ] + } +} +``` + +**写入边数据:** + +```hocon +sink { + HugeGraph { + host = "127.0.0.1" + port = 8080 + graph_name = "hugegraph" + mappings = [ + { + type = "EDGE" + label = "knows" + sourceConfig = { + label = "person" + idFields = ["person1_name"] + } + targetConfig = { + label = "person" + idFields = ["person2_name"] + } + properties = ["since"] + fieldMapping = { + person1_name = "name" + person2_name = "name" + } + } + ] + } +} +``` + +> **注意**:HugeGraph 的 Schema(PropertyKey、VertexLabel、EdgeLabel)需要在执行写入任务前预先创建, +> 或使用 `schema_save_mode = CREATE_SCHEMA_WHEN_NOT_EXIST`(默认行为)由 Connector 自动创建。 + +#### 4.3 核心配置参数 + +| 参数 | 类型 | 必填 | 默认值 | 说明 | +|------|------|------|--------|------| +| `host` | String | 是 | - | HugeGraph Server 地址 | +| `port` | Integer | 是 | - | HugeGraph Server 端口 | +| `graph_name` | String | 是 | - | 图名称 | +| `graph_space` | String | 否 | DEFAULT | 图空间名称 | +| `username` | String | 否 | - | 认证用户名 | +| `password` | String | 否 | - | 认证密码 | +| `protocol` | String | 否 | http | 协议,可选 `http` 或 `https` | +| `batch_size` | Integer | 否 | 500 | 每批写入的记录数 | +| `batch_interval_ms` | Integer | 否 | 5000 | 批次最大等待时间(毫秒) | +| `max_retries` | Integer | 否 | 3 | 写入失败最大重试次数 | +| `retry_backoff_ms` | Integer | 否 | 5000 | 重试间隔(毫秒) | + +> 完整参数列表和详细说明请参考 [Apache SeaTunnel HugeGraph Connector 官方文档](https://seatunnel.apache.org/docs/connector-v2/sink/HugeGraph/)。 + +### 5 文档与资源 + +- [Apache SeaTunnel 官方网站](https://seatunnel.apache.org/) +- [Apache SeaTunnel Connector-V2 文档](https://seatunnel.apache.org/docs/connector-v2/) +- [Apache SeaTunnel GitHub](https://github.com/apache/seatunnel) +- [HugeGraph GitHub](https://github.com/apache/hugegraph) + +### 6 许可证 + +与 HugeGraph 一样,HugeGraph-SeaTunnel Connector 采用 Apache 2.0 许可证。 diff --git a/content/en/docs/images/seatunnel/hugegraph-fullstack-ecosystem.png b/content/en/docs/images/seatunnel/hugegraph-fullstack-ecosystem.png new file mode 100644 index 000000000..e6fe1279f Binary files /dev/null and b/content/en/docs/images/seatunnel/hugegraph-fullstack-ecosystem.png differ diff --git a/content/en/docs/images/seatunnel/hugegraph-seatunnel-architecture.png b/content/en/docs/images/seatunnel/hugegraph-seatunnel-architecture.png new file mode 100644 index 000000000..c84fb41f1 Binary files /dev/null and b/content/en/docs/images/seatunnel/hugegraph-seatunnel-architecture.png differ diff --git a/content/en/docs/images/seatunnel/hugegraph-seatunnel-source-sink.png b/content/en/docs/images/seatunnel/hugegraph-seatunnel-source-sink.png new file mode 100644 index 000000000..c0e658b25 Binary files /dev/null and b/content/en/docs/images/seatunnel/hugegraph-seatunnel-source-sink.png differ diff --git a/content/en/docs/introduction/_index.md b/content/en/docs/introduction/_index.md index 00955a612..dec3d75c1 100644 --- a/content/en/docs/introduction/_index.md +++ b/content/en/docs/introduction/_index.md @@ -21,16 +21,16 @@ HugeGraph supports the rapid storage and querying of tens of billions of vertice ### Ecosystem Overview ```text -┌──────────────────────────────────────────────────────────────┐ -│ Apache HugeGraph - Full-Stack Graph System │ -├──────────────────┬────────────────────┬──────────────────────┤ -│ Graph DB (OLTP) │ Graph Compute │ Graph AI │ -│ HugeGraph │ Vermeer (Memory) │ HugeGraph-AI │ -│ Server │ Computer (Dist.) │ GraphRAG/GNN/Py │ -├──────────────────┴────────────────────┴──────────────────────┤ -│ HugeGraph Toolchain │ -│ Hubble | Loader | Client(Java/Go/Py) | Spark | Tools │ -└──────────────────────────────────────────────────────────────┘ +┌────────────────────────────────────────────────────────────────────┐ +│ Apache HugeGraph - Full-Stack Graph System │ +├──────────────────┬────────────────────┬────────────────────────────┤ +│ Graph DB (OLTP) │ Graph Compute │ Graph AI │ +│ HugeGraph │ Vermeer (Memory) │ HugeGraph-AI │ +│ Server │ Computer (Dist.) │ GraphRAG/GNN/Py │ +├──────────────────┴────────────────────┴────────────────────────────┤ +│ HugeGraph Toolchain │ +│ Hubble | Loader | Client(Java/Go/Py) | Spark | SeaTunnel | Tools │ +└────────────────────────────────────────────────────────────────────┘ ``` --- @@ -91,6 +91,7 @@ A complete tool ecosystem surrounding the graph system ([toolchain repository](h | [Loader](/docs/quickstart/toolchain/hugegraph-loader) | Data import tool: supports multiple data sources like local files, HDFS, MySQL, and formats like TXT/CSV/JSON. | | [Client](/docs/quickstart/client/hugegraph-client) | Multi-language SDKs: Java / Python / Go. | | [Spark-connector](/docs/quickstart/toolchain/hugegraph-spark-connector) | Spark integration: supports batch graph data read/write via Spark, suitable for big data offline processing. | +| [SeaTunnel-connector](/docs/quickstart/toolchain/hugegraph-seatunnel-connector) | SeaTunnel integration: supports data synchronization between HugeGraph and external data systems via SeaTunnel. | | [Tools](/docs/quickstart/toolchain/hugegraph-tools) | Command-line operational tools: graph management, backup/restore, Gremlin execution, etc. | --- diff --git a/content/en/docs/quickstart/toolchain/hugegraph-seatunnel-connector.md b/content/en/docs/quickstart/toolchain/hugegraph-seatunnel-connector.md new file mode 100644 index 000000000..ac612f167 --- /dev/null +++ b/content/en/docs/quickstart/toolchain/hugegraph-seatunnel-connector.md @@ -0,0 +1,149 @@ +--- +title: "HugeGraph-SeaTunnel Connector Quick Start" +linkTitle: "Sync Data with SeaTunnel Connector" +weight: 5 +--- + +### 1 HugeGraph-SeaTunnel Connector Overview + +[Apache SeaTunnel](https://seatunnel.apache.org/) is a high-performance, distributed data integration platform +that supports real-time synchronization and batch processing of massive data. The HugeGraph community has contributed +Connector-V2 support to Apache SeaTunnel, enabling users to synchronize data between HugeGraph and external data systems. + +![HugeGraph + SeaTunnel Integration Architecture](/docs/images/seatunnel/hugegraph-seatunnel-architecture.png) + +### 2 Features + +HugeGraph-SeaTunnel Connector provides the following capabilities: + +- **HugeGraph Sink Connector** (Released): Write external data to HugeGraph, supporting batch write, update, and delete of vertices and edges +- **HugeGraph Source Connector** (In Development): Read graph data from HugeGraph, supporting batch reading of vertices and edges +- **Vertex Synchronization**: Support full or incremental vertex data synchronization with multiple ID strategies +- **Edge Synchronization**: Support full or incremental edge data synchronization, auto-resolving source and target vertices +- **Automatic Schema Management**: Support auto-creating PropertyKey, VertexLabel, EdgeLabel (`CREATE_SCHEMA_WHEN_NOT_EXIST`) +- **Data Migration**: Support data migration between different HugeGraph instances, or importing graph data from other data sources + +![HugeGraph Source/Sink Bidirectional Data Flow](/docs/images/seatunnel/hugegraph-seatunnel-source-sink.png) + +### 3 Environment Requirements + +| Component | Version | Notes | +|-----------|---------|-------| +| Java | 8+ | SeaTunnel runtime requirement | +| Apache SeaTunnel | 2.3.12+ | Sink Connector released since this version | +| HugeGraph Server | 1.0.0+ | Latest stable version recommended | + +> **Source Connector Note**: The HugeGraph Source Connector is currently only available in the SeaTunnel development +> branch (Next/master) and has not been included in an official release. If you need the Source feature, please build +> SeaTunnel from source or wait for the next release. + +### 4 Quick Start + +#### 4.1 Install SeaTunnel + +Please refer to the [Apache SeaTunnel Deployment Guide](https://seatunnel.apache.org/docs/getting-started/) to install and deploy SeaTunnel. + +#### 4.2 Use HugeGraph Sink Connector (Write Data) + +The following examples demonstrate how to write data to HugeGraph via SeaTunnel: + +**Write vertices:** + +```hocon +env { + job.mode = "BATCH" +} + +source { + FakeSource { + plugin_output = "fake" + schema = { + fields = { + name = "string" + age = "int" + } + } + } +} + +sink { + HugeGraph { + host = "127.0.0.1" + port = 8080 + graph_name = "hugegraph" + mappings = [ + { + type = "VERTEX" + label = "person" + idStrategy = "PRIMARY_KEY" + idFields = ["name"] + properties = ["name", "age"] + } + ] + } +} +``` + +**Write edges:** + +```hocon +sink { + HugeGraph { + host = "127.0.0.1" + port = 8080 + graph_name = "hugegraph" + mappings = [ + { + type = "EDGE" + label = "knows" + sourceConfig = { + label = "person" + idFields = ["person1_name"] + } + targetConfig = { + label = "person" + idFields = ["person2_name"] + } + properties = ["since"] + fieldMapping = { + person1_name = "name" + person2_name = "name" + } + } + ] + } +} +``` + +> **Note**: The HugeGraph schema (PropertyKey, VertexLabel, EdgeLabel) must be created before executing write tasks, +> or you can use `schema_save_mode = CREATE_SCHEMA_WHEN_NOT_EXIST` (default behavior) for the Connector to auto-create it. + +#### 4.3 Core Configuration Parameters + +| Parameter | Type | Required | Default | Description | +|-----------|------|----------|---------|-------------| +| `host` | String | Yes | - | HugeGraph Server host | +| `port` | Integer | Yes | - | HugeGraph Server port | +| `graph_name` | String | Yes | - | Graph name | +| `graph_space` | String | No | DEFAULT | Graph space name | +| `username` | String | No | - | Authentication username | +| `password` | String | No | - | Authentication password | +| `protocol` | String | No | http | Protocol, `http` or `https` | +| `batch_size` | Integer | No | 500 | Records per batch write | +| `batch_interval_ms` | Integer | No | 5000 | Max wait time per batch (ms) | +| `max_retries` | Integer | No | 3 | Max retries on write failure | +| `retry_backoff_ms` | Integer | No | 5000 | Retry backoff interval (ms) | + +> For the complete parameter list and detailed documentation, please refer to the +> [Apache SeaTunnel HugeGraph Connector Official Docs](https://seatunnel.apache.org/docs/connector-v2/sink/HugeGraph/). + +### 5 Documentation & Resources + +- [Apache SeaTunnel Official Website](https://seatunnel.apache.org/) +- [Apache SeaTunnel Connector-V2 Documentation](https://seatunnel.apache.org/docs/connector-v2/) +- [Apache SeaTunnel GitHub](https://github.com/apache/seatunnel) +- [HugeGraph GitHub](https://github.com/apache/hugegraph) + +### 6 License + +Same as HugeGraph, HugeGraph-SeaTunnel Connector is licensed under Apache 2.0.