From 58d396054193c699c9294047981a452696143981 Mon Sep 17 00:00:00 2001 From: Jack Ye Date: Sat, 30 Aug 2025 17:01:29 -0700 Subject: [PATCH 01/12] feat: add automated version bump and release workflows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add auto-bump workflow for automated version management - Add release workflow for creating GitHub releases - Add Java publish workflow for Maven Central deployment - Add Python publish workflow for PyPI deployment - Add Rust publish workflow for crates.io deployment - Add CI helper scripts for version calculation and bumping - Handle auto-generated code regeneration during version updates The workflows support: - Automatic version bumping based on commit messages - Preview/beta releases - Multi-language publishing (Java, Python, Rust) - Dry run mode for testing - Automatic release note generation ๐Ÿค– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .github/workflows/auto-bump.yml | 225 +++++++++++++++++++++++++++ .github/workflows/java-release.yml | 185 ++++++++++++++++++++++ .github/workflows/python-release.yml | 133 ++++++++++++++++ .github/workflows/release.yml | 198 +++++++++++++++++++++++ .github/workflows/rust-release.yml | 142 +++++++++++++++++ ci/bump_version.py | 173 ++++++++++++++++++++ ci/calculate_version.py | 68 ++++++++ ci/generate_release_notes.py | 159 +++++++++++++++++++ 8 files changed, 1283 insertions(+) create mode 100644 .github/workflows/auto-bump.yml create mode 100644 .github/workflows/java-release.yml create mode 100644 .github/workflows/python-release.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/rust-release.yml create mode 100755 ci/bump_version.py create mode 100755 ci/calculate_version.py create mode 100755 ci/generate_release_notes.py diff --git a/.github/workflows/auto-bump.yml b/.github/workflows/auto-bump.yml new file mode 100644 index 000000000..d81ee4ced --- /dev/null +++ b/.github/workflows/auto-bump.yml @@ -0,0 +1,225 @@ +name: Auto Bump Version + +on: + workflow_dispatch: + inputs: + bump_type: + description: 'Type of version bump' + required: false + default: 'auto' + type: choice + options: + - auto + - patch + - minor + - major + +jobs: + check-for-changes: + runs-on: ubuntu-latest + outputs: + should_bump: ${{ steps.check.outputs.should_bump }} + bump_type: ${{ steps.check.outputs.bump_type }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Check for unreleased changes + id: check + run: | + # Get the last tag + LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") + + if [ -z "$LAST_TAG" ]; then + echo "No tags found, should create initial release" + echo "should_bump=true" >> $GITHUB_OUTPUT + echo "bump_type=patch" >> $GITHUB_OUTPUT + exit 0 + fi + + # Check for commits since last tag + COMMITS_SINCE_TAG=$(git rev-list --count ${LAST_TAG}..HEAD) + + if [ "$COMMITS_SINCE_TAG" -gt 0 ]; then + echo "Found $COMMITS_SINCE_TAG commits since last tag $LAST_TAG" + + # Determine bump type based on input or commit analysis + if [ "${{ inputs.bump_type }}" != "auto" ] && [ -n "${{ inputs.bump_type }}" ]; then + # Use manual input if provided and not "auto" + BUMP_TYPE="${{ inputs.bump_type }}" + else + # Analyze commit messages to determine bump type + BUMP_TYPE="patch" + + # Check for breaking changes (major bump) + if git log ${LAST_TAG}..HEAD --grep="BREAKING CHANGE" --grep="!:" | grep -q .; then + BUMP_TYPE="major" + # Check for features (minor bump) + elif git log ${LAST_TAG}..HEAD --grep="^feat" --grep="^feature" | grep -q .; then + BUMP_TYPE="minor" + fi + fi + + echo "should_bump=true" >> $GITHUB_OUTPUT + echo "bump_type=$BUMP_TYPE" >> $GITHUB_OUTPUT + else + echo "No commits since last tag $LAST_TAG" + echo "should_bump=false" >> $GITHUB_OUTPUT + fi + + - name: Summary + run: | + echo "## Auto Bump Check" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [ "${{ steps.check.outputs.should_bump }}" == "true" ]; then + echo "โœ… Version bump needed" >> $GITHUB_STEP_SUMMARY + echo "- **Bump Type:** ${{ steps.check.outputs.bump_type }}" >> $GITHUB_STEP_SUMMARY + else + echo "โญ๏ธ No version bump needed" >> $GITHUB_STEP_SUMMARY + fi + + create-bump-pr: + needs: check-for-changes + if: needs.check-for-changes.outputs.should_bump == 'true' + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install packaging lxml toml + + - name: Get current version from Java Makefile + id: current_version + run: | + CURRENT_VERSION=$(grep "^VERSION = " java/Makefile | cut -d' ' -f3) + echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT + echo "Current version: $CURRENT_VERSION" + + - name: Calculate new version + id: new_version + run: | + python ci/calculate_version.py \ + --current "${{ steps.current_version.outputs.version }}" \ + --type "${{ needs.check-for-changes.outputs.bump_type }}" \ + --channel "stable" + + - name: Create feature branch + run: | + BRANCH_NAME="auto-bump-${{ steps.new_version.outputs.version }}" + git checkout -b $BRANCH_NAME + echo "branch=$BRANCH_NAME" >> $GITHUB_ENV + + - name: Bump version + run: | + python ci/bump_version.py --version "${{ steps.new_version.outputs.version }}" + + - name: Regenerate auto-generated code + run: | + # Install uv for Python code generation + curl -LsSf https://astral.sh/uv/install.sh | sh + export PATH="$HOME/.local/bin:$PATH" + + # Install openapi-generator-cli + uv tool install openapi-generator-cli + + # Generate Java auto-generated code + cd java + make gen + cd .. + + # Generate Python auto-generated code + cd python + make gen + cd .. + + # Generate Rust auto-generated code + cd rust + make gen + cd .. + + - name: Configure git + run: | + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + + - name: Commit changes + run: | + git add -A + git commit -m "chore: bump version to ${{ steps.new_version.outputs.version }} + + Automated version bump from ${{ steps.current_version.outputs.version }} to ${{ steps.new_version.outputs.version }}. + Bump type: ${{ needs.check-for-changes.outputs.bump_type }}" + + - name: Push changes + run: | + git push origin ${{ env.branch }} + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + branch: ${{ env.branch }} + base: main + title: "chore: bump version to ${{ steps.new_version.outputs.version }}" + body: | + ## Automated Version Bump + + This PR automatically bumps the version from `${{ steps.current_version.outputs.version }}` to `${{ steps.new_version.outputs.version }}`. + + ### Details + - **Bump Type:** ${{ needs.check-for-changes.outputs.bump_type }} + - **Triggered By:** Manual trigger + + ### Updated Files + - All Makefiles (Java, Python, Rust) + - Java: pom.xml files (including auto-generated) + - Python: pyproject.toml files (including auto-generated) + - Rust: Cargo.toml files (including auto-generated) + + ### Checklist + - [ ] Review version bump changes + - [ ] Verify all version files are updated + - [ ] Confirm CI checks pass + + ### Next Steps + After merging this PR, you can create a release by: + 1. Going to Actions โ†’ Create Release workflow + 2. Selecting the release channel (stable/preview) + 3. Running the workflow + + --- + *This PR was automatically generated by the auto-bump workflow.* + labels: | + version-bump + automated + assignees: ${{ github.actor }} + + - name: Summary + run: | + echo "## Version Bump PR Created" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **Current Version:** ${{ steps.current_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "- **New Version:** ${{ steps.new_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "- **Bump Type:** ${{ needs.check-for-changes.outputs.bump_type }}" >> $GITHUB_STEP_SUMMARY + echo "- **Branch:** ${{ env.branch }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "โœ… Pull request created successfully!" >> $GITHUB_STEP_SUMMARY \ No newline at end of file diff --git a/.github/workflows/java-release.yml b/.github/workflows/java-release.yml new file mode 100644 index 000000000..fd6d3fac2 --- /dev/null +++ b/.github/workflows/java-release.yml @@ -0,0 +1,185 @@ +name: Publish Java packages +on: + release: + # Use released instead of published, since we don't publish preview/beta versions + types: [released] + pull_request: + paths: + - .github/workflows/java-release.yml + types: + - opened + - synchronize + - ready_for_review + - reopened + workflow_dispatch: + inputs: + mode: + description: 'Release mode' + required: true + type: choice + default: dry_run + options: + - dry_run + - release + ref: + description: 'The branch, tag or SHA to checkout' + required: false + type: string + +jobs: + release: + name: Release Java Packages + runs-on: ubuntu-24.04 + timeout-minutes: 60 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + # When triggered by a release, use the release tag + # When triggered manually, use the provided ref + ref: ${{ github.event.release.tag_name || inputs.ref }} + + - name: Set up Java 17 + uses: actions/setup-java@v4 + with: + distribution: corretto + java-version: 17 + cache: "maven" + server-id: ossrh + server-username: SONATYPE_USER + server-password: SONATYPE_TOKEN + gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} + gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }} + + - name: Set github + run: | + git config --global user.email "dev+gha@lancedb.com" + git config --global user.name "Lance Github Runner" + + - name: Install dependencies for code generation + run: | + # Install uv and openapi-generator-cli for auto-generated code + curl -LsSf https://astral.sh/uv/install.sh | sh + export PATH="$HOME/.local/bin:$PATH" + uv tool install openapi-generator-cli + + - name: Generate auto-generated code + run: | + export PATH="$HOME/.local/bin:$PATH" + cd java + make gen + cd .. + + - name: Dry run + if: | + github.event_name == 'pull_request' || + inputs.mode == 'dry_run' + run: | + cd java + mvn --batch-mode -DskipTests package + + - name: Publish to Maven Central + if: | + github.event_name == 'release' || + inputs.mode == 'release' + run: | + echo "use-agent" >> ~/.gnupg/gpg.conf + echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf + export GPG_TTY=$(tty) + cd java + mvn --batch-mode -DskipTests -DpushChanges=false -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }} deploy -P deploy-to-ossrh + env: + SONATYPE_USER: ${{ secrets.SONATYPE_USER }} + SONATYPE_TOKEN: ${{ secrets.SONATYPE_TOKEN }} + + - name: Get published version + if: | + github.event_name == 'release' || + inputs.mode == 'release' + id: get_version + run: | + cd java + VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Published version: $VERSION" + + - name: Wait for Maven Central availability + if: | + github.event_name == 'release' || + inputs.mode == 'release' + run: | + VERSION="${{ steps.get_version.outputs.version }}" + GROUP_ID="com.lancedb" + + # List of artifacts to check (both auto-generated and manual) + ARTIFACTS=( + "lance-namespace-core" + "lance-namespace-adapter" + "lance-namespace-apache-client" + "lance-namespace-springboot-server" + "lance-namespace-hive2" + "lance-namespace-hive3" + "lance-namespace-glue" + "lance-namespace-unity" + "lance-namespace-lancedb" + ) + + echo "Waiting for version $VERSION to be available in Maven Central..." + echo "This typically takes 10-30 minutes after publishing to OSSRH." + + # Maximum wait time: 60 minutes + MAX_WAIT=3600 + INTERVAL=60 + ELAPSED=0 + + while [ $ELAPSED -lt $MAX_WAIT ]; do + ALL_AVAILABLE=true + + for ARTIFACT_ID in "${ARTIFACTS[@]}"; do + URL="https://repo1.maven.org/maven2/com/lancedb/${ARTIFACT_ID}/${VERSION}/${ARTIFACT_ID}-${VERSION}.pom" + + if curl --head --silent --fail "$URL" > /dev/null 2>&1; then + echo "โœ“ ${ARTIFACT_ID} is available" + else + echo "โœ— ${ARTIFACT_ID} is not yet available" + ALL_AVAILABLE=false + fi + done + + if [ "$ALL_AVAILABLE" = true ]; then + echo "" + echo "๐ŸŽ‰ All artifacts are now available in Maven Central!" + echo "" + echo "Users can now add the following dependencies to their projects:" + echo "" + echo "Maven:" + echo "" + echo " com.lancedb" + echo " lance-namespace-core" + echo " ${VERSION}" + echo "" + echo "" + echo "Gradle:" + echo "implementation 'com.lancedb:lance-namespace-core:${VERSION}'" + echo "" + echo "SBT:" + echo "libraryDependencies += \"com.lancedb\" % \"lance-namespace-core\" % \"${VERSION}\"" + exit 0 + fi + + ELAPSED=$((ELAPSED + INTERVAL)) + + if [ $ELAPSED -lt $MAX_WAIT ]; then + echo "" + echo "Artifacts not yet available. Waiting ${INTERVAL} seconds... (${ELAPSED}s elapsed)" + sleep $INTERVAL + fi + done + + echo "" + echo "โš ๏ธ WARNING: Artifacts are not yet available in Maven Central after ${MAX_WAIT} seconds." + echo "This is normal - Maven Central sync can take up to 2 hours." + echo "The artifacts will appear at: https://central.sonatype.com/artifact/com.lancedb/lance-namespace-core/${VERSION}" + echo "" + echo "You can check the sync status at: https://s01.oss.sonatype.org/" + exit 0 \ No newline at end of file diff --git a/.github/workflows/python-release.yml b/.github/workflows/python-release.yml new file mode 100644 index 000000000..6ce984296 --- /dev/null +++ b/.github/workflows/python-release.yml @@ -0,0 +1,133 @@ +name: Python Release + +on: + release: + types: + - released + pull_request: + paths: + - .github/workflows/python-release.yml + workflow_dispatch: + inputs: + mode: + description: "dry_run: build & test only, release: build & publish to PyPI" + required: true + default: "dry_run" + type: choice + options: + - dry_run + - release + ref: + description: 'The branch, tag or SHA to checkout' + required: false + type: string + +jobs: + publish: + runs-on: ubuntu-latest + permissions: + id-token: write # Required for PyPI trusted publishing + contents: read + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + # When triggered by a release, use the release tag + # When triggered manually, use the provided ref + ref: ${{ github.event.release.tag_name || inputs.ref }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install uv + uses: astral-sh/setup-uv@v4 + + - name: Install openapi-generator-cli + run: | + uv tool install openapi-generator-cli + + - name: Generate auto-generated Python client + run: | + cd python + make gen-urllib3-client + cd .. + + - name: Build lance_namespace_urllib3_client + run: | + cd python/lance_namespace_urllib3_client + uv build + cd ../.. + + - name: Build lance_namespace + run: | + cd python/lance_namespace + # Copy README for package + cp ../../README.md README.md + uv build + cd ../.. + + - name: Get package versions + id: get_versions + run: | + # Get urllib3_client version + URLLIB3_VERSION=$(python -c "import tomllib; print(tomllib.load(open('python/lance_namespace_urllib3_client/pyproject.toml', 'rb'))['project']['version'])") + echo "urllib3_version=$URLLIB3_VERSION" >> $GITHUB_OUTPUT + + # Get lance_namespace version + NS_VERSION=$(python -c "import tomllib; print(tomllib.load(open('python/lance_namespace/pyproject.toml', 'rb'))['project']['version'])") + echo "ns_version=$NS_VERSION" >> $GITHUB_OUTPUT + + echo "lance_namespace_urllib3_client version: $URLLIB3_VERSION" + echo "lance_namespace version: $NS_VERSION" + + - name: Publish lance_namespace_urllib3_client to PyPI + if: | + (github.event_name == 'release' && github.event.action == 'released') || + (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') + run: | + cd python/lance_namespace_urllib3_client + uv publish --trusted-publishing always + echo "โœ… Successfully published lance_namespace_urllib3_client version ${{ steps.get_versions.outputs.urllib3_version }} to PyPI!" + cd ../.. + + - name: Publish lance_namespace to PyPI + if: | + (github.event_name == 'release' && github.event.action == 'released') || + (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') + run: | + cd python/lance_namespace + uv publish --trusted-publishing always + echo "โœ… Successfully published lance_namespace version ${{ steps.get_versions.outputs.ns_version }} to PyPI!" + cd ../.. + + - name: Verify PyPI availability + if: | + (github.event_name == 'release' && github.event.action == 'released') || + (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') + run: | + echo "Waiting for packages to be available on PyPI..." + sleep 30 + + # Check urllib3_client + URLLIB3_VERSION="${{ steps.get_versions.outputs.urllib3_version }}" + if pip index versions lance_namespace_urllib3_client | grep -q "$URLLIB3_VERSION"; then + echo "โœ“ lance_namespace_urllib3_client $URLLIB3_VERSION is available on PyPI" + else + echo "โš ๏ธ lance_namespace_urllib3_client $URLLIB3_VERSION not yet visible on PyPI (this is normal, may take a few minutes)" + fi + + # Check lance_namespace + NS_VERSION="${{ steps.get_versions.outputs.ns_version }}" + if pip index versions lance_namespace | grep -q "$NS_VERSION"; then + echo "โœ“ lance_namespace $NS_VERSION is available on PyPI" + else + echo "โš ๏ธ lance_namespace $NS_VERSION not yet visible on PyPI (this is normal, may take a few minutes)" + fi + + echo "" + echo "Users can install the packages with:" + echo "" + echo "pip install lance-namespace==$NS_VERSION" + echo "pip install lance-namespace-urllib3-client==$URLLIB3_VERSION" \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..e69b9f447 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,198 @@ +name: Create Release + +on: + workflow_dispatch: + inputs: + release_type: + description: 'Release type' + required: true + default: 'patch' + type: choice + options: + - patch + - minor + - major + release_channel: + description: 'Release channel' + required: true + default: 'preview' + type: choice + options: + - preview + - stable + dry_run: + description: 'Dry run (simulate the release without pushing)' + required: true + default: true + type: boolean + +jobs: + create-release: + runs-on: ubuntu-latest + outputs: + tag: ${{ steps.tag_name.outputs.tag }} + version: ${{ steps.new_version.outputs.version }} + steps: + - name: Output Inputs + run: echo "${{ toJSON(github.event.inputs) }}" + + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: main + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install packaging lxml toml + + - name: Get current version from Java Makefile + id: current_version + run: | + CURRENT_VERSION=$(grep "^VERSION = " java/Makefile | cut -d' ' -f3) + echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT + echo "Current version: $CURRENT_VERSION" + + - name: Calculate new version + id: new_version + run: | + python ci/calculate_version.py \ + --current "${{ steps.current_version.outputs.version }}" \ + --type "${{ inputs.release_type }}" \ + --channel "${{ inputs.release_channel }}" + + - name: Determine tag name + id: tag_name + run: | + if [ "${{ inputs.release_channel }}" == "stable" ]; then + VERSION="${{ steps.new_version.outputs.version }}" + TAG="v${VERSION}" + else + # For preview releases, use current version with beta suffix + VERSION="${{ steps.current_version.outputs.version }}" + # Find the next beta number for current version + BETA_TAGS=$(git tag -l "v${VERSION}-beta.*" | sort -V) + if [ -z "$BETA_TAGS" ]; then + BETA_NUM=1 + else + LAST_BETA=$(echo "$BETA_TAGS" | tail -n 1) + LAST_NUM=$(echo "$LAST_BETA" | sed "s/v${VERSION}-beta.//") + BETA_NUM=$((LAST_NUM + 1)) + fi + TAG="v${VERSION}-beta.${BETA_NUM}" + fi + + echo "tag=$TAG" >> $GITHUB_OUTPUT + echo "Tag will be: $TAG" + + - name: Update version (stable releases only) + if: inputs.release_channel == 'stable' + run: | + python ci/bump_version.py --version "${{ steps.new_version.outputs.version }}" + + # Regenerate auto-generated code with new version + # Install uv for Python code generation + curl -LsSf https://astral.sh/uv/install.sh | sh + export PATH="$HOME/.local/bin:$PATH" + + # Install openapi-generator-cli + uv tool install openapi-generator-cli + + # Generate Java auto-generated code + cd java + make gen + cd .. + + # Generate Python auto-generated code + cd python + make gen + cd .. + + # Generate Rust auto-generated code + cd rust + make gen + cd .. + + - name: Configure git identity + run: | + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + + - name: Create release commit (stable releases only) + if: inputs.release_channel == 'stable' + run: | + git add -A + git commit -m "chore: release version ${{ steps.new_version.outputs.version }}" || echo "No changes to commit" + + - name: Create tag + run: | + git tag -a "${{ steps.tag_name.outputs.tag }}" -m "Release ${{ steps.tag_name.outputs.tag }}" + + - name: Push changes (if not dry run) + if: ${{ !inputs.dry_run }} + run: | + if [ "${{ inputs.release_channel }}" == "stable" ]; then + # Push the commit for stable releases + git push origin main + fi + # Always push the tag + git push origin "${{ steps.tag_name.outputs.tag }}" + + - name: Generate release notes + id: release_notes + if: ${{ !inputs.dry_run }} + run: | + python ci/generate_release_notes.py \ + --tag "${{ steps.tag_name.outputs.tag }}" \ + --repo "${{ github.repository }}" \ + --token "${{ secrets.GITHUB_TOKEN }}" + + - name: Create GitHub Release Draft (if not dry run) + if: ${{ !inputs.dry_run }} + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.tag_name.outputs.tag }} + name: ${{ steps.tag_name.outputs.tag }} + body_path: release_notes.md + draft: true + prerelease: ${{ inputs.release_channel == 'preview' }} + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Summary + run: | + echo "## Release Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **Release Type:** ${{ inputs.release_type }}" >> $GITHUB_STEP_SUMMARY + echo "- **Release Channel:** ${{ inputs.release_channel }}" >> $GITHUB_STEP_SUMMARY + echo "- **Current Version:** ${{ steps.current_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY + if [ "${{ inputs.release_channel }}" == "stable" ]; then + echo "- **New Version:** ${{ steps.new_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY + fi + echo "- **Tag:** ${{ steps.tag_name.outputs.tag }}" >> $GITHUB_STEP_SUMMARY + echo "- **Dry Run:** ${{ inputs.dry_run }}" >> $GITHUB_STEP_SUMMARY + + if [ "${{ inputs.dry_run }}" == "true" ]; then + echo "" >> $GITHUB_STEP_SUMMARY + echo "โš ๏ธ This was a dry run. No changes were pushed." >> $GITHUB_STEP_SUMMARY + else + echo "" >> $GITHUB_STEP_SUMMARY + echo "๐Ÿ“ Draft release created successfully!" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Next Steps:" >> $GITHUB_STEP_SUMMARY + echo "1. Review the draft release on the [releases page](https://github.com/${{ github.repository }}/releases)" >> $GITHUB_STEP_SUMMARY + echo "2. Edit the release notes if needed" >> $GITHUB_STEP_SUMMARY + echo "3. Publish the release to:" >> $GITHUB_STEP_SUMMARY + if [ "${{ inputs.release_channel }}" == "stable" ]; then + echo " - Create the official release" >> $GITHUB_STEP_SUMMARY + echo " - Trigger automatic publishing to Maven Central and PyPI" >> $GITHUB_STEP_SUMMARY + else + echo " - Create a preview/beta release" >> $GITHUB_STEP_SUMMARY + echo " - Note: Preview releases are not published to package repositories" >> $GITHUB_STEP_SUMMARY + fi + fi \ No newline at end of file diff --git a/.github/workflows/rust-release.yml b/.github/workflows/rust-release.yml new file mode 100644 index 000000000..bb27ef9e6 --- /dev/null +++ b/.github/workflows/rust-release.yml @@ -0,0 +1,142 @@ +name: Rust Release + +on: + release: + types: + - released + pull_request: + paths: + - .github/workflows/rust-release.yml + workflow_dispatch: + inputs: + mode: + description: "dry_run: build & test only, release: build & publish to crates.io" + required: true + default: "dry_run" + type: choice + options: + - dry_run + - release + ref: + description: 'The branch, tag or SHA to checkout' + required: false + type: string + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + # When triggered by a release, use the release tag + # When triggered manually, use the provided ref + ref: ${{ github.event.release.tag_name || inputs.ref }} + + - name: Set up Rust + uses: dtolnay/rust-toolchain@stable + + - name: Set up Python for code generation + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install uv and openapi-generator-cli + run: | + curl -LsSf https://astral.sh/uv/install.sh | sh + export PATH="$HOME/.local/bin:$PATH" + uv tool install openapi-generator-cli + + - name: Generate auto-generated Rust client + run: | + export PATH="$HOME/.local/bin:$PATH" + cd rust + make gen-reqwest-client + cd .. + + - name: Build and test + run: | + cd rust + cargo build --all + cargo test --all + cd .. + + - name: Get package versions + id: get_versions + run: | + # Get reqwest-client version + REQWEST_VERSION=$(grep "^version = " rust/lance-namespace-reqwest-client/Cargo.toml | cut -d'"' -f2) + echo "reqwest_version=$REQWEST_VERSION" >> $GITHUB_OUTPUT + + # Get lance-namespace version + NS_VERSION=$(grep "^version = " rust/lance-namespace/Cargo.toml | cut -d'"' -f2) + echo "ns_version=$NS_VERSION" >> $GITHUB_OUTPUT + + echo "lance-namespace-reqwest-client version: $REQWEST_VERSION" + echo "lance-namespace version: $NS_VERSION" + + - name: Dry run - check publishability + if: | + github.event_name == 'pull_request' || + inputs.mode == 'dry_run' + run: | + cd rust + + # Check lance-namespace-reqwest-client + cd lance-namespace-reqwest-client + cargo publish --dry-run + cd .. + + # Check lance-namespace + cd lance-namespace + cargo publish --dry-run + cd .. + + echo "โœ… Dry run successful - packages are ready to publish" + + - name: Publish lance-namespace-reqwest-client to crates.io + if: | + (github.event_name == 'release' && github.event.action == 'released') || + (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') + run: | + cd rust/lance-namespace-reqwest-client + cargo publish --token ${{ secrets.CRATES_IO_TOKEN }} + echo "โœ… Successfully published lance-namespace-reqwest-client version ${{ steps.get_versions.outputs.reqwest_version }} to crates.io!" + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} + + - name: Wait for dependency availability + if: | + (github.event_name == 'release' && github.event.action == 'released') || + (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') + run: | + echo "Waiting for lance-namespace-reqwest-client to be available on crates.io..." + sleep 60 + + - name: Publish lance-namespace to crates.io + if: | + (github.event_name == 'release' && github.event.action == 'released') || + (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') + run: | + cd rust/lance-namespace + cargo publish --token ${{ secrets.CRATES_IO_TOKEN }} + echo "โœ… Successfully published lance-namespace version ${{ steps.get_versions.outputs.ns_version }} to crates.io!" + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} + + - name: Verify crates.io availability + if: | + (github.event_name == 'release' && github.event.action == 'released') || + (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') + run: | + echo "Packages published to crates.io!" + echo "" + echo "Users can add the following to their Cargo.toml:" + echo "" + echo "[dependencies]" + echo "lance-namespace = \"${{ steps.get_versions.outputs.ns_version }}\"" + echo "lance-namespace-reqwest-client = \"${{ steps.get_versions.outputs.reqwest_version }}\"" + echo "" + echo "View on crates.io:" + echo "- https://crates.io/crates/lance-namespace" + echo "- https://crates.io/crates/lance-namespace-reqwest-client" \ No newline at end of file diff --git a/ci/bump_version.py b/ci/bump_version.py new file mode 100755 index 000000000..fc54c3e59 --- /dev/null +++ b/ci/bump_version.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python3 +""" +Version management script for Lance Namespace project. +Updates version in multiple locations: +- Java: Makefiles and pom.xml files (excluding auto-generated ones) +- Python: Makefiles and pyproject.toml files (excluding auto-generated ones) +- Rust: Makefiles and Cargo.toml files (excluding auto-generated ones) +""" + +import argparse +import subprocess +import sys +import re +from pathlib import Path +import toml +from lxml import etree + +def update_makefile_version(makefile_path, new_version): + """Update VERSION variable in Makefile""" + content = makefile_path.read_text() + updated_content = re.sub( + r'^VERSION\s*=\s*.*$', + f'VERSION = {new_version}', + content, + flags=re.MULTILINE + ) + makefile_path.write_text(updated_content) + print(f"Updated {makefile_path}") + +def update_java_pom_version(pom_path, new_version): + """Update version in pom.xml""" + parser = etree.XMLParser(remove_blank_text=False, remove_comments=False) + tree = etree.parse(str(pom_path), parser) + root = tree.getroot() + + # Handle namespace + nsmap = root.nsmap + ns = nsmap[None] if None in nsmap else None + + # Create namespace prefix for XPath + if ns: + xpath_ns = {'m': ns} + version_xpath = '//m:project/m:version' + parent_version_xpath = '//m:project/m:parent/m:version' + else: + xpath_ns = None + version_xpath = '//project/version' + parent_version_xpath = '//project/parent/version' + + # Update project version + version_elements = tree.xpath(version_xpath, namespaces=xpath_ns) + for elem in version_elements: + elem.text = new_version + + # Update parent version in root pom + if 'pom.xml' in str(pom_path) and pom_path.parent.name == 'java': + parent_version_elements = tree.xpath(parent_version_xpath, namespaces=xpath_ns) + for elem in parent_version_elements: + elem.text = new_version + + # Write back with proper formatting + tree.write(str(pom_path), pretty_print=True, xml_declaration=True, encoding='UTF-8') + print(f"Updated {pom_path}") + +def update_python_pyproject_version(pyproject_path, new_version): + """Update version in pyproject.toml""" + data = toml.load(pyproject_path) + + # Update version in [project] section + if 'project' in data and 'version' in data['project']: + data['project']['version'] = new_version + + # Update version in [tool.poetry] section if exists + if 'tool' in data and 'poetry' in data['tool'] and 'version' in data['tool']['poetry']: + data['tool']['poetry']['version'] = new_version + + # Write back + with open(pyproject_path, 'w') as f: + toml.dump(data, f) + print(f"Updated {pyproject_path}") + +def update_rust_cargo_version(cargo_path, new_version): + """Update version in Cargo.toml""" + data = toml.load(cargo_path) + + # Update package version + if 'package' in data and 'version' in data['package']: + data['package']['version'] = new_version + + # Write back + with open(cargo_path, 'w') as f: + toml.dump(data, f) + print(f"Updated {cargo_path}") + +def main(): + parser = argparse.ArgumentParser(description='Bump version in Lance Namespace project') + parser.add_argument('--version', required=True, help='New version to set') + parser.add_argument('--dry-run', action='store_true', help='Show what would be changed without making changes') + + args = parser.parse_args() + new_version = args.version + + print(f"Bumping version to: {new_version}") + + if args.dry_run: + print("\nDry run mode - no changes will be made") + + # Update Makefiles + makefiles = [ + Path('java/Makefile'), + Path('python/Makefile'), + Path('rust/Makefile') + ] + + for makefile in makefiles: + if makefile.exists(): + if not args.dry_run: + update_makefile_version(makefile, new_version) + else: + print(f"Would update {makefile}") + + # Update Java pom.xml files (excluding auto-generated ones) + java_poms = [ + Path('java/pom.xml'), + Path('java/lance-namespace-core/pom.xml'), + Path('java/lance-namespace-adapter/pom.xml'), + Path('java/lance-namespace-hive2/pom.xml'), + Path('java/lance-namespace-hive3/pom.xml'), + Path('java/lance-namespace-glue/pom.xml'), + Path('java/lance-namespace-unity/pom.xml'), + Path('java/lance-namespace-lancedb/pom.xml') + ] + + for pom in java_poms: + if pom.exists(): + if not args.dry_run: + update_java_pom_version(pom, new_version) + else: + print(f"Would update {pom}") + + # Update Python pyproject.toml files (excluding auto-generated ones) + python_projects = [ + Path('python/lance_namespace/pyproject.toml'), + Path('pyproject.toml') # Root pyproject.toml if exists + ] + + for pyproject in python_projects: + if pyproject.exists(): + if not args.dry_run: + update_python_pyproject_version(pyproject, new_version) + else: + print(f"Would update {pyproject}") + + # Update Rust Cargo.toml files (excluding auto-generated ones) + rust_cargos = [ + Path('rust/Cargo.toml'), + Path('rust/lance-namespace/Cargo.toml') + ] + + for cargo in rust_cargos: + if cargo.exists(): + if not args.dry_run: + update_rust_cargo_version(cargo, new_version) + else: + print(f"Would update {cargo}") + + if not args.dry_run: + print(f"\nSuccessfully updated version to {new_version}") + else: + print(f"\nDry run complete - would update version to {new_version}") + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/ci/calculate_version.py b/ci/calculate_version.py new file mode 100755 index 000000000..8810a9f0e --- /dev/null +++ b/ci/calculate_version.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +""" +Script to calculate the next version based on release type +""" + +import argparse +import sys +from packaging import version + +def calculate_next_version(current_version, release_type, channel): + """Calculate the next version based on release type and channel""" + + # Parse current version + v = version.parse(current_version) + + # Extract major, minor, patch + if hasattr(v, 'release'): + major, minor, patch = v.release[:3] if len(v.release) >= 3 else (*v.release, 0, 0)[:3] + else: + # Fallback for simple versions + parts = current_version.split('.') + major = int(parts[0]) if len(parts) > 0 else 0 + minor = int(parts[1]) if len(parts) > 1 else 0 + patch = int(parts[2]) if len(parts) > 2 else 0 + + # Calculate new version for stable releases + if channel == 'stable': + if release_type == 'major': + new_version = f"{major + 1}.0.0" + elif release_type == 'minor': + new_version = f"{major}.{minor + 1}.0" + elif release_type == 'patch': + new_version = f"{major}.{minor}.{patch + 1}" + else: + raise ValueError(f"Unknown release type: {release_type}") + else: + # For preview releases, keep the current version + new_version = current_version + + return new_version + +def main(): + parser = argparse.ArgumentParser(description='Calculate next version') + parser.add_argument('--current', required=True, help='Current version') + parser.add_argument('--type', required=True, choices=['major', 'minor', 'patch'], help='Release type') + parser.add_argument('--channel', required=True, choices=['stable', 'preview'], help='Release channel') + + args = parser.parse_args() + + try: + new_version = calculate_next_version(args.current, args.type, args.channel) + + # Output for GitHub Actions + print(f"version={new_version}") + + # Also write to GITHUB_OUTPUT if available + github_output = os.environ.get('GITHUB_OUTPUT') + if github_output: + with open(github_output, 'a') as f: + f.write(f"version={new_version}\n") + + except Exception as e: + print(f"Error: {e}", file=sys.stderr) + sys.exit(1) + +if __name__ == '__main__': + import os + main() \ No newline at end of file diff --git a/ci/generate_release_notes.py b/ci/generate_release_notes.py new file mode 100755 index 000000000..fe1101345 --- /dev/null +++ b/ci/generate_release_notes.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +""" +Generate release notes for a given tag +""" + +import argparse +import subprocess +import sys +from pathlib import Path +import requests +import json + +def get_commits_since_last_tag(tag): + """Get commits since the last tag""" + # Get the previous tag + try: + result = subprocess.run( + ["git", "describe", "--tags", "--abbrev=0", f"{tag}^"], + capture_output=True, + text=True, + check=True + ) + prev_tag = result.stdout.strip() + except subprocess.CalledProcessError: + # No previous tag, use all commits + prev_tag = None + + # Get commits between tags + if prev_tag: + cmd = ["git", "log", f"{prev_tag}..{tag}", "--pretty=format:%H|%s|%an"] + else: + cmd = ["git", "log", tag, "--pretty=format:%H|%s|%an"] + + result = subprocess.run(cmd, capture_output=True, text=True, check=True) + + commits = [] + for line in result.stdout.strip().split('\n'): + if line: + parts = line.split('|', 2) + if len(parts) == 3: + commits.append({ + 'sha': parts[0], + 'message': parts[1], + 'author': parts[2] + }) + + return commits, prev_tag + +def categorize_commits(commits): + """Categorize commits by type""" + categories = { + 'features': [], + 'fixes': [], + 'docs': [], + 'refactor': [], + 'test': [], + 'chore': [], + 'other': [] + } + + for commit in commits: + msg = commit['message'].lower() + if msg.startswith('feat:') or msg.startswith('feature:'): + categories['features'].append(commit) + elif msg.startswith('fix:'): + categories['fixes'].append(commit) + elif msg.startswith('docs:'): + categories['docs'].append(commit) + elif msg.startswith('refactor:'): + categories['refactor'].append(commit) + elif msg.startswith('test:'): + categories['test'].append(commit) + elif msg.startswith('chore:'): + categories['chore'].append(commit) + else: + categories['other'].append(commit) + + return categories + +def generate_markdown(tag, categories, prev_tag, repo): + """Generate markdown release notes""" + lines = [] + + # Header + lines.append(f"# Release {tag}") + lines.append("") + + # Compare link + if prev_tag and repo: + lines.append(f"[Compare with {prev_tag}](https://github.com/{repo}/compare/{prev_tag}...{tag})") + lines.append("") + + # Sections + sections = [ + ('features', 'โœจ Features'), + ('fixes', '๐Ÿ› Bug Fixes'), + ('refactor', 'โ™ป๏ธ Refactoring'), + ('docs', '๐Ÿ“š Documentation'), + ('test', '๐Ÿงช Tests'), + ('chore', '๐Ÿ”ง Chores'), + ('other', '๐Ÿ“ Other Changes') + ] + + for key, title in sections: + if categories[key]: + lines.append(f"## {title}") + lines.append("") + for commit in categories[key]: + msg = commit['message'] + # Remove conventional commit prefix + for prefix in ['feat:', 'feature:', 'fix:', 'docs:', 'refactor:', 'test:', 'chore:']: + if msg.lower().startswith(prefix): + msg = msg[len(prefix):].strip() + break + lines.append(f"- {msg} ({commit['sha'][:7]})") + lines.append("") + + # Contributors section + authors = set(commit['author'] for commit in sum(categories.values(), [])) + if authors: + lines.append("## Contributors") + lines.append("") + for author in sorted(authors): + lines.append(f"- {author}") + lines.append("") + + return '\n'.join(lines) + +def main(): + parser = argparse.ArgumentParser(description='Generate release notes') + parser.add_argument('--tag', required=True, help='Git tag for the release') + parser.add_argument('--repo', help='GitHub repository (owner/name)') + parser.add_argument('--token', help='GitHub token for API access') + parser.add_argument('--output', default='release_notes.md', help='Output file') + + args = parser.parse_args() + + try: + # Get commits + commits, prev_tag = get_commits_since_last_tag(args.tag) + + # Categorize commits + categories = categorize_commits(commits) + + # Generate markdown + markdown = generate_markdown(args.tag, categories, prev_tag, args.repo) + + # Write to file + with open(args.output, 'w') as f: + f.write(markdown) + + print(f"Release notes written to {args.output}") + + except Exception as e: + print(f"Error: {e}", file=sys.stderr) + sys.exit(1) + +if __name__ == '__main__': + main() \ No newline at end of file From 45e306544cb849572fa98efb14598fb3611286c4 Mon Sep 17 00:00:00 2001 From: Jack Ye Date: Sat, 30 Aug 2025 17:19:28 -0700 Subject: [PATCH 02/12] refactor: consolidate publish workflows and remove redundancy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove redundant java-release.yml and python-release.yml workflows - Update existing java-publish.yml with: - Auto-generated code generation (apache-client, springboot-server) - Maven Central availability monitoring - Update existing python-publish.yml with: - Auto-generated urllib3_client generation - Individual package publishing - PyPI availability verification - Rename rust-release.yml to rust-publish.yml with: - Rust caching and proper dependencies (protobuf, ssl) - Auto-generated reqwest-client generation - crates.io publishing support All publish workflows now trigger on GitHub releases and handle auto-generated code regeneration before publishing. ๐Ÿค– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .github/workflows/java-publish.yml | 91 +++++++++ .github/workflows/java-release.yml | 185 ------------------ .github/workflows/python-publish.yml | 68 ++++++- .github/workflows/python-release.yml | 133 ------------- .../{rust-release.yml => rust-publish.yml} | 76 ++++--- 5 files changed, 206 insertions(+), 347 deletions(-) delete mode 100644 .github/workflows/java-release.yml delete mode 100644 .github/workflows/python-release.yml rename .github/workflows/{rust-release.yml => rust-publish.yml} (68%) diff --git a/.github/workflows/java-publish.yml b/.github/workflows/java-publish.yml index 43082cdfb..1f0a4386c 100644 --- a/.github/workflows/java-publish.yml +++ b/.github/workflows/java-publish.yml @@ -72,3 +72,94 @@ jobs: env: SONATYPE_USER: ${{ secrets.SONATYPE_USER }} SONATYPE_TOKEN: ${{ secrets.SONATYPE_TOKEN }} + + - name: Get published version + if: | + (github.event_name == 'release' && github.event.action == 'released') || + (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') + id: get_version + run: | + VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Published version: $VERSION" + + - name: Wait for Maven Central availability + if: | + (github.event_name == 'release' && github.event.action == 'released') || + (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') + run: | + VERSION="${{ steps.get_version.outputs.version }}" + GROUP_ID="com.lancedb" + + # List of artifacts to check (both auto-generated and manual) + ARTIFACTS=( + "lance-namespace-core" + "lance-namespace-adapter" + "lance-namespace-apache-client" + "lance-namespace-springboot-server" + "lance-namespace-hive2" + "lance-namespace-hive3" + "lance-namespace-glue" + "lance-namespace-unity" + "lance-namespace-lancedb" + ) + + echo "Waiting for version $VERSION to be available in Maven Central..." + echo "This typically takes 10-30 minutes after publishing to OSSRH." + + # Maximum wait time: 60 minutes + MAX_WAIT=3600 + INTERVAL=60 + ELAPSED=0 + + while [ $ELAPSED -lt $MAX_WAIT ]; do + ALL_AVAILABLE=true + + for ARTIFACT_ID in "${ARTIFACTS[@]}"; do + URL="https://repo1.maven.org/maven2/com/lancedb/${ARTIFACT_ID}/${VERSION}/${ARTIFACT_ID}-${VERSION}.pom" + + if curl --head --silent --fail "$URL" > /dev/null 2>&1; then + echo "โœ“ ${ARTIFACT_ID} is available" + else + echo "โœ— ${ARTIFACT_ID} is not yet available" + ALL_AVAILABLE=false + fi + done + + if [ "$ALL_AVAILABLE" = true ]; then + echo "" + echo "๐ŸŽ‰ All artifacts are now available in Maven Central!" + echo "" + echo "Users can now add the following dependencies to their projects:" + echo "" + echo "Maven:" + echo "" + echo " com.lancedb" + echo " lance-namespace-core" + echo " ${VERSION}" + echo "" + echo "" + echo "Gradle:" + echo "implementation 'com.lancedb:lance-namespace-core:${VERSION}'" + echo "" + echo "SBT:" + echo "libraryDependencies += \"com.lancedb\" % \"lance-namespace-core\" % \"${VERSION}\"" + exit 0 + fi + + ELAPSED=$((ELAPSED + INTERVAL)) + + if [ $ELAPSED -lt $MAX_WAIT ]; then + echo "" + echo "Artifacts not yet available. Waiting ${INTERVAL} seconds... (${ELAPSED}s elapsed)" + sleep $INTERVAL + fi + done + + echo "" + echo "โš ๏ธ WARNING: Artifacts are not yet available in Maven Central after ${MAX_WAIT} seconds." + echo "This is normal - Maven Central sync can take up to 2 hours." + echo "The artifacts will appear at: https://central.sonatype.com/artifact/com.lancedb/lance-namespace-core/${VERSION}" + echo "" + echo "You can check the sync status at: https://s01.oss.sonatype.org/" + exit 0 diff --git a/.github/workflows/java-release.yml b/.github/workflows/java-release.yml deleted file mode 100644 index fd6d3fac2..000000000 --- a/.github/workflows/java-release.yml +++ /dev/null @@ -1,185 +0,0 @@ -name: Publish Java packages -on: - release: - # Use released instead of published, since we don't publish preview/beta versions - types: [released] - pull_request: - paths: - - .github/workflows/java-release.yml - types: - - opened - - synchronize - - ready_for_review - - reopened - workflow_dispatch: - inputs: - mode: - description: 'Release mode' - required: true - type: choice - default: dry_run - options: - - dry_run - - release - ref: - description: 'The branch, tag or SHA to checkout' - required: false - type: string - -jobs: - release: - name: Release Java Packages - runs-on: ubuntu-24.04 - timeout-minutes: 60 - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - # When triggered by a release, use the release tag - # When triggered manually, use the provided ref - ref: ${{ github.event.release.tag_name || inputs.ref }} - - - name: Set up Java 17 - uses: actions/setup-java@v4 - with: - distribution: corretto - java-version: 17 - cache: "maven" - server-id: ossrh - server-username: SONATYPE_USER - server-password: SONATYPE_TOKEN - gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} - gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }} - - - name: Set github - run: | - git config --global user.email "dev+gha@lancedb.com" - git config --global user.name "Lance Github Runner" - - - name: Install dependencies for code generation - run: | - # Install uv and openapi-generator-cli for auto-generated code - curl -LsSf https://astral.sh/uv/install.sh | sh - export PATH="$HOME/.local/bin:$PATH" - uv tool install openapi-generator-cli - - - name: Generate auto-generated code - run: | - export PATH="$HOME/.local/bin:$PATH" - cd java - make gen - cd .. - - - name: Dry run - if: | - github.event_name == 'pull_request' || - inputs.mode == 'dry_run' - run: | - cd java - mvn --batch-mode -DskipTests package - - - name: Publish to Maven Central - if: | - github.event_name == 'release' || - inputs.mode == 'release' - run: | - echo "use-agent" >> ~/.gnupg/gpg.conf - echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf - export GPG_TTY=$(tty) - cd java - mvn --batch-mode -DskipTests -DpushChanges=false -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }} deploy -P deploy-to-ossrh - env: - SONATYPE_USER: ${{ secrets.SONATYPE_USER }} - SONATYPE_TOKEN: ${{ secrets.SONATYPE_TOKEN }} - - - name: Get published version - if: | - github.event_name == 'release' || - inputs.mode == 'release' - id: get_version - run: | - cd java - VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "Published version: $VERSION" - - - name: Wait for Maven Central availability - if: | - github.event_name == 'release' || - inputs.mode == 'release' - run: | - VERSION="${{ steps.get_version.outputs.version }}" - GROUP_ID="com.lancedb" - - # List of artifacts to check (both auto-generated and manual) - ARTIFACTS=( - "lance-namespace-core" - "lance-namespace-adapter" - "lance-namespace-apache-client" - "lance-namespace-springboot-server" - "lance-namespace-hive2" - "lance-namespace-hive3" - "lance-namespace-glue" - "lance-namespace-unity" - "lance-namespace-lancedb" - ) - - echo "Waiting for version $VERSION to be available in Maven Central..." - echo "This typically takes 10-30 minutes after publishing to OSSRH." - - # Maximum wait time: 60 minutes - MAX_WAIT=3600 - INTERVAL=60 - ELAPSED=0 - - while [ $ELAPSED -lt $MAX_WAIT ]; do - ALL_AVAILABLE=true - - for ARTIFACT_ID in "${ARTIFACTS[@]}"; do - URL="https://repo1.maven.org/maven2/com/lancedb/${ARTIFACT_ID}/${VERSION}/${ARTIFACT_ID}-${VERSION}.pom" - - if curl --head --silent --fail "$URL" > /dev/null 2>&1; then - echo "โœ“ ${ARTIFACT_ID} is available" - else - echo "โœ— ${ARTIFACT_ID} is not yet available" - ALL_AVAILABLE=false - fi - done - - if [ "$ALL_AVAILABLE" = true ]; then - echo "" - echo "๐ŸŽ‰ All artifacts are now available in Maven Central!" - echo "" - echo "Users can now add the following dependencies to their projects:" - echo "" - echo "Maven:" - echo "" - echo " com.lancedb" - echo " lance-namespace-core" - echo " ${VERSION}" - echo "" - echo "" - echo "Gradle:" - echo "implementation 'com.lancedb:lance-namespace-core:${VERSION}'" - echo "" - echo "SBT:" - echo "libraryDependencies += \"com.lancedb\" % \"lance-namespace-core\" % \"${VERSION}\"" - exit 0 - fi - - ELAPSED=$((ELAPSED + INTERVAL)) - - if [ $ELAPSED -lt $MAX_WAIT ]; then - echo "" - echo "Artifacts not yet available. Waiting ${INTERVAL} seconds... (${ELAPSED}s elapsed)" - sleep $INTERVAL - fi - done - - echo "" - echo "โš ๏ธ WARNING: Artifacts are not yet available in Maven Central after ${MAX_WAIT} seconds." - echo "This is normal - Maven Central sync can take up to 2 hours." - echo "The artifacts will appear at: https://central.sonatype.com/artifact/com.lancedb/lance-namespace-core/${VERSION}" - echo "" - echo "You can check the sync status at: https://s01.oss.sonatype.org/" - exit 0 \ No newline at end of file diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 6960922de..b550bdb9a 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -48,14 +48,78 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v4 + - name: Install openapi-generator-cli + run: | + uv tool install openapi-generator-cli + + - name: Generate auto-generated Python client + working-directory: python + run: | + make gen-urllib3-client + - name: Build module dists working-directory: python run: | make publish - - name: Publish to PyPI + - name: Get package versions + id: get_versions + run: | + # Get urllib3_client version + URLLIB3_VERSION=$(python -c "import tomllib; print(tomllib.load(open('python/lance_namespace_urllib3_client/pyproject.toml', 'rb'))['project']['version'])") + echo "urllib3_version=$URLLIB3_VERSION" >> $GITHUB_OUTPUT + + # Get lance_namespace version + NS_VERSION=$(python -c "import tomllib; print(tomllib.load(open('python/lance_namespace/pyproject.toml', 'rb'))['project']['version'])") + echo "ns_version=$NS_VERSION" >> $GITHUB_OUTPUT + + echo "lance_namespace_urllib3_client version: $URLLIB3_VERSION" + echo "lance_namespace version: $NS_VERSION" + + - name: Publish lance_namespace_urllib3_client to PyPI + if: | + (github.event_name == 'release' && github.event.action == 'released') || + (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') + working-directory: python/lance_namespace_urllib3_client + run: | + uv publish --trusted-publishing always + echo "โœ… Successfully published lance_namespace_urllib3_client version ${{ steps.get_versions.outputs.urllib3_version }} to PyPI!" + + - name: Publish lance_namespace to PyPI + if: | + (github.event_name == 'release' && github.event.action == 'released') || + (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') + working-directory: python/lance_namespace + run: | + uv publish --trusted-publishing always + echo "โœ… Successfully published lance_namespace version ${{ steps.get_versions.outputs.ns_version }} to PyPI!" + + - name: Verify PyPI availability if: | (github.event_name == 'release' && github.event.action == 'released') || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') run: | - uv publish --trusted-publishing always \ No newline at end of file + echo "Waiting for packages to be available on PyPI..." + sleep 30 + + # Check urllib3_client + URLLIB3_VERSION="${{ steps.get_versions.outputs.urllib3_version }}" + if pip index versions lance-namespace-urllib3-client | grep -q "$URLLIB3_VERSION"; then + echo "โœ“ lance-namespace-urllib3-client $URLLIB3_VERSION is available on PyPI" + else + echo "โš ๏ธ lance-namespace-urllib3-client $URLLIB3_VERSION not yet visible on PyPI (this is normal, may take a few minutes)" + fi + + # Check lance_namespace + NS_VERSION="${{ steps.get_versions.outputs.ns_version }}" + if pip index versions lance-namespace | grep -q "$NS_VERSION"; then + echo "โœ“ lance-namespace $NS_VERSION is available on PyPI" + else + echo "โš ๏ธ lance-namespace $NS_VERSION not yet visible on PyPI (this is normal, may take a few minutes)" + fi + + echo "" + echo "Users can install the packages with:" + echo "" + echo "pip install lance-namespace==$NS_VERSION" + echo "pip install lance-namespace-urllib3-client==$URLLIB3_VERSION" \ No newline at end of file diff --git a/.github/workflows/python-release.yml b/.github/workflows/python-release.yml deleted file mode 100644 index 6ce984296..000000000 --- a/.github/workflows/python-release.yml +++ /dev/null @@ -1,133 +0,0 @@ -name: Python Release - -on: - release: - types: - - released - pull_request: - paths: - - .github/workflows/python-release.yml - workflow_dispatch: - inputs: - mode: - description: "dry_run: build & test only, release: build & publish to PyPI" - required: true - default: "dry_run" - type: choice - options: - - dry_run - - release - ref: - description: 'The branch, tag or SHA to checkout' - required: false - type: string - -jobs: - publish: - runs-on: ubuntu-latest - permissions: - id-token: write # Required for PyPI trusted publishing - contents: read - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - # When triggered by a release, use the release tag - # When triggered manually, use the provided ref - ref: ${{ github.event.release.tag_name || inputs.ref }} - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: Install uv - uses: astral-sh/setup-uv@v4 - - - name: Install openapi-generator-cli - run: | - uv tool install openapi-generator-cli - - - name: Generate auto-generated Python client - run: | - cd python - make gen-urllib3-client - cd .. - - - name: Build lance_namespace_urllib3_client - run: | - cd python/lance_namespace_urllib3_client - uv build - cd ../.. - - - name: Build lance_namespace - run: | - cd python/lance_namespace - # Copy README for package - cp ../../README.md README.md - uv build - cd ../.. - - - name: Get package versions - id: get_versions - run: | - # Get urllib3_client version - URLLIB3_VERSION=$(python -c "import tomllib; print(tomllib.load(open('python/lance_namespace_urllib3_client/pyproject.toml', 'rb'))['project']['version'])") - echo "urllib3_version=$URLLIB3_VERSION" >> $GITHUB_OUTPUT - - # Get lance_namespace version - NS_VERSION=$(python -c "import tomllib; print(tomllib.load(open('python/lance_namespace/pyproject.toml', 'rb'))['project']['version'])") - echo "ns_version=$NS_VERSION" >> $GITHUB_OUTPUT - - echo "lance_namespace_urllib3_client version: $URLLIB3_VERSION" - echo "lance_namespace version: $NS_VERSION" - - - name: Publish lance_namespace_urllib3_client to PyPI - if: | - (github.event_name == 'release' && github.event.action == 'released') || - (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') - run: | - cd python/lance_namespace_urllib3_client - uv publish --trusted-publishing always - echo "โœ… Successfully published lance_namespace_urllib3_client version ${{ steps.get_versions.outputs.urllib3_version }} to PyPI!" - cd ../.. - - - name: Publish lance_namespace to PyPI - if: | - (github.event_name == 'release' && github.event.action == 'released') || - (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') - run: | - cd python/lance_namespace - uv publish --trusted-publishing always - echo "โœ… Successfully published lance_namespace version ${{ steps.get_versions.outputs.ns_version }} to PyPI!" - cd ../.. - - - name: Verify PyPI availability - if: | - (github.event_name == 'release' && github.event.action == 'released') || - (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') - run: | - echo "Waiting for packages to be available on PyPI..." - sleep 30 - - # Check urllib3_client - URLLIB3_VERSION="${{ steps.get_versions.outputs.urllib3_version }}" - if pip index versions lance_namespace_urllib3_client | grep -q "$URLLIB3_VERSION"; then - echo "โœ“ lance_namespace_urllib3_client $URLLIB3_VERSION is available on PyPI" - else - echo "โš ๏ธ lance_namespace_urllib3_client $URLLIB3_VERSION not yet visible on PyPI (this is normal, may take a few minutes)" - fi - - # Check lance_namespace - NS_VERSION="${{ steps.get_versions.outputs.ns_version }}" - if pip index versions lance_namespace | grep -q "$NS_VERSION"; then - echo "โœ“ lance_namespace $NS_VERSION is available on PyPI" - else - echo "โš ๏ธ lance_namespace $NS_VERSION not yet visible on PyPI (this is normal, may take a few minutes)" - fi - - echo "" - echo "Users can install the packages with:" - echo "" - echo "pip install lance-namespace==$NS_VERSION" - echo "pip install lance-namespace-urllib3-client==$URLLIB3_VERSION" \ No newline at end of file diff --git a/.github/workflows/rust-release.yml b/.github/workflows/rust-publish.yml similarity index 68% rename from .github/workflows/rust-release.yml rename to .github/workflows/rust-publish.yml index bb27ef9e6..89ddf90ff 100644 --- a/.github/workflows/rust-release.yml +++ b/.github/workflows/rust-publish.yml @@ -1,4 +1,16 @@ -name: Rust Release +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Rust Publish on: release: @@ -6,7 +18,7 @@ on: - released pull_request: paths: - - .github/workflows/rust-release.yml + - .github/workflows/rust-publish.yml workflow_dispatch: inputs: mode: @@ -17,24 +29,43 @@ on: options: - dry_run - release - ref: - description: 'The branch, tag or SHA to checkout' - required: false - type: string + +env: + # This env var is used by Swatinem/rust-cache@v2 for the cache + # key, so we set it to make sure it is always consistent. + CARGO_TERM_COLOR: always + # Disable full debug symbol generation to speed up CI build and keep memory down + # "1" means line tables only, which is useful for panic tracebacks. + RUSTFLAGS: "-C debuginfo=1" + RUST_BACKTRACE: "1" + # according to: https://matklad.github.io/2021/09/04/fast-rust-builds.html + # CI builds are faster with incremental disabled. + CARGO_INCREMENTAL: "0" + CARGO_BUILD_JOBS: "1" jobs: publish: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 + timeout-minutes: 60 steps: - name: Checkout code uses: actions/checkout@v4 + + - name: Install dependencies + run: | + sudo apt update + sudo apt install -y protobuf-compiler libssl-dev + + # pin the toolchain version to avoid surprises + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: - # When triggered by a release, use the release tag - # When triggered manually, use the provided ref - ref: ${{ github.event.release.tag_name || inputs.ref }} + toolchain: stable + + - uses: rui314/setup-mold@v1 - - name: Set up Rust - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + with: + workspaces: rust - name: Set up Python for code generation uses: actions/setup-python@v5 @@ -44,22 +75,13 @@ jobs: - name: Install uv and openapi-generator-cli run: | curl -LsSf https://astral.sh/uv/install.sh | sh - export PATH="$HOME/.local/bin:$PATH" - uv tool install openapi-generator-cli + echo "$HOME/.local/bin" >> $GITHUB_PATH + $HOME/.local/bin/uv tool install openapi-generator-cli - name: Generate auto-generated Rust client + working-directory: rust run: | - export PATH="$HOME/.local/bin:$PATH" - cd rust make gen-reqwest-client - cd .. - - - name: Build and test - run: | - cd rust - cargo build --all - cargo test --all - cd .. - name: Get package versions id: get_versions @@ -78,7 +100,7 @@ jobs: - name: Dry run - check publishability if: | github.event_name == 'pull_request' || - inputs.mode == 'dry_run' + (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'dry_run') run: | cd rust @@ -98,8 +120,8 @@ jobs: if: | (github.event_name == 'release' && github.event.action == 'released') || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') + working-directory: rust/lance-namespace-reqwest-client run: | - cd rust/lance-namespace-reqwest-client cargo publish --token ${{ secrets.CRATES_IO_TOKEN }} echo "โœ… Successfully published lance-namespace-reqwest-client version ${{ steps.get_versions.outputs.reqwest_version }} to crates.io!" env: @@ -117,8 +139,8 @@ jobs: if: | (github.event_name == 'release' && github.event.action == 'released') || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') + working-directory: rust/lance-namespace run: | - cd rust/lance-namespace cargo publish --token ${{ secrets.CRATES_IO_TOKEN }} echo "โœ… Successfully published lance-namespace version ${{ steps.get_versions.outputs.ns_version }} to crates.io!" env: From 37e379a5fad321771cc7c72f29ae9ecaa1b2c022 Mon Sep 17 00:00:00 2001 From: Jack Ye Date: Sat, 30 Aug 2025 17:25:15 -0700 Subject: [PATCH 03/12] commit --- .github/workflows/java-publish.yml | 9 +--- .github/workflows/python-publish.yml | 66 +--------------------------- .github/workflows/rust-publish.yml | 57 +++--------------------- 3 files changed, 8 insertions(+), 124 deletions(-) diff --git a/.github/workflows/java-publish.yml b/.github/workflows/java-publish.yml index 1f0a4386c..18508d69b 100644 --- a/.github/workflows/java-publish.yml +++ b/.github/workflows/java-publish.yml @@ -91,17 +91,10 @@ jobs: VERSION="${{ steps.get_version.outputs.version }}" GROUP_ID="com.lancedb" - # List of artifacts to check (both auto-generated and manual) + # List of some artifacts to check ARTIFACTS=( "lance-namespace-core" - "lance-namespace-adapter" "lance-namespace-apache-client" - "lance-namespace-springboot-server" - "lance-namespace-hive2" - "lance-namespace-hive3" - "lance-namespace-glue" - "lance-namespace-unity" - "lance-namespace-lancedb" ) echo "Waiting for version $VERSION to be available in Maven Central..." diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index b550bdb9a..eafc0d004 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -48,78 +48,16 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v4 - - name: Install openapi-generator-cli - run: | - uv tool install openapi-generator-cli - - - name: Generate auto-generated Python client - working-directory: python - run: | - make gen-urllib3-client - - name: Build module dists working-directory: python run: | make publish - - name: Get package versions - id: get_versions - run: | - # Get urllib3_client version - URLLIB3_VERSION=$(python -c "import tomllib; print(tomllib.load(open('python/lance_namespace_urllib3_client/pyproject.toml', 'rb'))['project']['version'])") - echo "urllib3_version=$URLLIB3_VERSION" >> $GITHUB_OUTPUT - - # Get lance_namespace version - NS_VERSION=$(python -c "import tomllib; print(tomllib.load(open('python/lance_namespace/pyproject.toml', 'rb'))['project']['version'])") - echo "ns_version=$NS_VERSION" >> $GITHUB_OUTPUT - - echo "lance_namespace_urllib3_client version: $URLLIB3_VERSION" - echo "lance_namespace version: $NS_VERSION" - - - name: Publish lance_namespace_urllib3_client to PyPI + - name: Publish to PyPI if: | (github.event_name == 'release' && github.event.action == 'released') || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') working-directory: python/lance_namespace_urllib3_client run: | uv publish --trusted-publishing always - echo "โœ… Successfully published lance_namespace_urllib3_client version ${{ steps.get_versions.outputs.urllib3_version }} to PyPI!" - - - name: Publish lance_namespace to PyPI - if: | - (github.event_name == 'release' && github.event.action == 'released') || - (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') - working-directory: python/lance_namespace - run: | - uv publish --trusted-publishing always - echo "โœ… Successfully published lance_namespace version ${{ steps.get_versions.outputs.ns_version }} to PyPI!" - - - name: Verify PyPI availability - if: | - (github.event_name == 'release' && github.event.action == 'released') || - (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') - run: | - echo "Waiting for packages to be available on PyPI..." - sleep 30 - - # Check urllib3_client - URLLIB3_VERSION="${{ steps.get_versions.outputs.urllib3_version }}" - if pip index versions lance-namespace-urllib3-client | grep -q "$URLLIB3_VERSION"; then - echo "โœ“ lance-namespace-urllib3-client $URLLIB3_VERSION is available on PyPI" - else - echo "โš ๏ธ lance-namespace-urllib3-client $URLLIB3_VERSION not yet visible on PyPI (this is normal, may take a few minutes)" - fi - - # Check lance_namespace - NS_VERSION="${{ steps.get_versions.outputs.ns_version }}" - if pip index versions lance-namespace | grep -q "$NS_VERSION"; then - echo "โœ“ lance-namespace $NS_VERSION is available on PyPI" - else - echo "โš ๏ธ lance-namespace $NS_VERSION not yet visible on PyPI (this is normal, may take a few minutes)" - fi - - echo "" - echo "Users can install the packages with:" - echo "" - echo "pip install lance-namespace==$NS_VERSION" - echo "pip install lance-namespace-urllib3-client==$URLLIB3_VERSION" \ No newline at end of file + echo "โœ… Successfully published version ${{ steps.get_versions.outputs.urllib3_version }} to PyPI!" diff --git a/.github/workflows/rust-publish.yml b/.github/workflows/rust-publish.yml index 89ddf90ff..b0cd914a0 100644 --- a/.github/workflows/rust-publish.yml +++ b/.github/workflows/rust-publish.yml @@ -67,36 +67,6 @@ jobs: with: workspaces: rust - - name: Set up Python for code generation - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: Install uv and openapi-generator-cli - run: | - curl -LsSf https://astral.sh/uv/install.sh | sh - echo "$HOME/.local/bin" >> $GITHUB_PATH - $HOME/.local/bin/uv tool install openapi-generator-cli - - - name: Generate auto-generated Rust client - working-directory: rust - run: | - make gen-reqwest-client - - - name: Get package versions - id: get_versions - run: | - # Get reqwest-client version - REQWEST_VERSION=$(grep "^version = " rust/lance-namespace-reqwest-client/Cargo.toml | cut -d'"' -f2) - echo "reqwest_version=$REQWEST_VERSION" >> $GITHUB_OUTPUT - - # Get lance-namespace version - NS_VERSION=$(grep "^version = " rust/lance-namespace/Cargo.toml | cut -d'"' -f2) - echo "ns_version=$NS_VERSION" >> $GITHUB_OUTPUT - - echo "lance-namespace-reqwest-client version: $REQWEST_VERSION" - echo "lance-namespace version: $NS_VERSION" - - name: Dry run - check publishability if: | github.event_name == 'pull_request' || @@ -122,8 +92,8 @@ jobs: (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') working-directory: rust/lance-namespace-reqwest-client run: | - cargo publish --token ${{ secrets.CRATES_IO_TOKEN }} - echo "โœ… Successfully published lance-namespace-reqwest-client version ${{ steps.get_versions.outputs.reqwest_version }} to crates.io!" + cargo publish + echo "โœ… Successfully published version ${{ steps.get_versions.outputs.reqwest_version }} to crates.io!" env: CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} @@ -141,24 +111,7 @@ jobs: (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') working-directory: rust/lance-namespace run: | - cargo publish --token ${{ secrets.CRATES_IO_TOKEN }} - echo "โœ… Successfully published lance-namespace version ${{ steps.get_versions.outputs.ns_version }} to crates.io!" + cargo publish + echo "โœ… Successfully publishedversion ${{ steps.get_versions.outputs.ns_version }} to crates.io!" env: - CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} - - - name: Verify crates.io availability - if: | - (github.event_name == 'release' && github.event.action == 'released') || - (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') - run: | - echo "Packages published to crates.io!" - echo "" - echo "Users can add the following to their Cargo.toml:" - echo "" - echo "[dependencies]" - echo "lance-namespace = \"${{ steps.get_versions.outputs.ns_version }}\"" - echo "lance-namespace-reqwest-client = \"${{ steps.get_versions.outputs.reqwest_version }}\"" - echo "" - echo "View on crates.io:" - echo "- https://crates.io/crates/lance-namespace" - echo "- https://crates.io/crates/lance-namespace-reqwest-client" \ No newline at end of file + CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} \ No newline at end of file From c52f20efa49b1652db37e9aa305920f15ec76d59 Mon Sep 17 00:00:00 2001 From: Jack Ye Date: Sat, 30 Aug 2025 17:40:23 -0700 Subject: [PATCH 04/12] commit --- .github/workflows/rust-publish.yml | 60 ++++-------------------------- 1 file changed, 7 insertions(+), 53 deletions(-) diff --git a/.github/workflows/rust-publish.yml b/.github/workflows/rust-publish.yml index b0cd914a0..12b30777b 100644 --- a/.github/workflows/rust-publish.yml +++ b/.github/workflows/rust-publish.yml @@ -50,68 +50,22 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - - name: Install dependencies run: | sudo apt update sudo apt install -y protobuf-compiler libssl-dev - # pin the toolchain version to avoid surprises - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - - uses: rui314/setup-mold@v1 - - uses: Swatinem/rust-cache@v2 with: workspaces: rust - - - name: Dry run - check publishability - if: | - github.event_name == 'pull_request' || - (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'dry_run') - run: | - cd rust - - # Check lance-namespace-reqwest-client - cd lance-namespace-reqwest-client - cargo publish --dry-run - cd .. - - # Check lance-namespace - cd lance-namespace - cargo publish --dry-run - cd .. - - echo "โœ… Dry run successful - packages are ready to publish" - - - name: Publish lance-namespace-reqwest-client to crates.io - if: | - (github.event_name == 'release' && github.event.action == 'released') || - (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') - working-directory: rust/lance-namespace-reqwest-client - run: | - cargo publish - echo "โœ… Successfully published version ${{ steps.get_versions.outputs.reqwest_version }} to crates.io!" - env: - CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} - - - name: Wait for dependency availability - if: | - (github.event_name == 'release' && github.event.action == 'released') || - (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') - run: | - echo "Waiting for lance-namespace-reqwest-client to be available on crates.io..." - sleep 60 - - - name: Publish lance-namespace to crates.io - if: | - (github.event_name == 'release' && github.event.action == 'released') || - (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') - working-directory: rust/lance-namespace - run: | - cargo publish - echo "โœ… Successfully publishedversion ${{ steps.get_versions.outputs.ns_version }} to crates.io!" - env: - CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} \ No newline at end of file + - uses: albertlockett/publish-crates@v2.2 + with: + # registry-token: ${{ steps.auth.outputs.token }} + registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }} + args: "--all-features" + path: rust + dry-run: ${{ github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'dry_run') }} \ No newline at end of file From d181b5917128970646759204c058b5791c911872 Mon Sep 17 00:00:00 2001 From: Jack Ye Date: Sat, 30 Aug 2025 17:43:28 -0700 Subject: [PATCH 05/12] use katyo --- .github/workflows/rust-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust-publish.yml b/.github/workflows/rust-publish.yml index 12b30777b..bfe1cc46b 100644 --- a/.github/workflows/rust-publish.yml +++ b/.github/workflows/rust-publish.yml @@ -62,7 +62,7 @@ jobs: - uses: Swatinem/rust-cache@v2 with: workspaces: rust - - uses: albertlockett/publish-crates@v2.2 + - uses: katyo/publish-crates@v2.2 with: # registry-token: ${{ steps.auth.outputs.token }} registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }} From b5203120964b5a9e44a5d824ef50133199fa3c3c Mon Sep 17 00:00:00 2001 From: Jack Ye Date: Sat, 30 Aug 2025 18:02:02 -0700 Subject: [PATCH 06/12] feat: use bump-my-version for version management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add .bumpversion.toml configuration for all project files - Update ci/bump_version.py to use bump-my-version - Modify workflows to use bump-my-version for version bumping - Regenerate auto-generated modules using 'make build' after version bump - Simplify version management across Java, Python, and Rust modules The version bumping now: 1. Uses bump-my-version to update all configured files 2. Runs 'make build' to regenerate auto-generated modules 3. Ensures consistent versioning across all components ๐Ÿค– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .bumpversion.toml | 97 ++++++++++++++ .github/workflows/auto-bump.yml | 37 ++--- .github/workflows/python-publish.yml | 1 - .github/workflows/release.yml | 40 ++---- ci/bump_version.py | 194 +++++++-------------------- 5 files changed, 171 insertions(+), 198 deletions(-) create mode 100644 .bumpversion.toml diff --git a/.bumpversion.toml b/.bumpversion.toml new file mode 100644 index 000000000..38fccef08 --- /dev/null +++ b/.bumpversion.toml @@ -0,0 +1,97 @@ +[tool.bumpversion] +current_version = "0.0.9" +parse = "(?P\\d+)\\.(?P\\d+)\\.(?P\\d+)" +serialize = ["{major}.{minor}.{patch}"] +search = "{current_version}" +replace = "{new_version}" +regex = false +ignore_missing_files = false +ignore_missing_version = false +tag = false +sign_tags = false +tag_name = "v{new_version}" +tag_message = "Release version {new_version}" +allow_dirty = false +commit = false +message = "chore: bump version {current_version} โ†’ {new_version}" + +# Makefiles - VERSION variable +[[tool.bumpversion.files]] +filename = "java/Makefile" +search = "VERSION = {current_version}" +replace = "VERSION = {new_version}" + +[[tool.bumpversion.files]] +filename = "python/Makefile" +search = "VERSION = {current_version}" +replace = "VERSION = {new_version}" + +[[tool.bumpversion.files]] +filename = "rust/Makefile" +search = "VERSION = {current_version}" +replace = "VERSION = {new_version}" + +# Java pom.xml files (non-auto-generated) +[[tool.bumpversion.files]] +filename = "java/pom.xml" +search = "{current_version}" +replace = "{new_version}" + +[[tool.bumpversion.files]] +filename = "java/lance-namespace-core/pom.xml" +search = "{current_version}" +replace = "{new_version}" + +[[tool.bumpversion.files]] +filename = "java/lance-namespace-adapter/pom.xml" +search = "{current_version}" +replace = "{new_version}" + +[[tool.bumpversion.files]] +filename = "java/lance-namespace-hive2/pom.xml" +search = "{current_version}" +replace = "{new_version}" + +[[tool.bumpversion.files]] +filename = "java/lance-namespace-hive3/pom.xml" +search = "{current_version}" +replace = "{new_version}" + +[[tool.bumpversion.files]] +filename = "java/lance-namespace-glue/pom.xml" +search = "{current_version}" +replace = "{new_version}" + +[[tool.bumpversion.files]] +filename = "java/lance-namespace-unity/pom.xml" +search = "{current_version}" +replace = "{new_version}" + +[[tool.bumpversion.files]] +filename = "java/lance-namespace-lancedb/pom.xml" +search = "{current_version}" +replace = "{new_version}" + +# Python pyproject.toml files (non-auto-generated) +[[tool.bumpversion.files]] +filename = "python/lance_namespace/pyproject.toml" +search = 'version = "{current_version}"' +replace = 'version = "{new_version}"' + +# Root pyproject.toml if exists +[[tool.bumpversion.files]] +filename = "pyproject.toml" +search = 'version = "{current_version}"' +replace = 'version = "{new_version}"' +ignore_missing_files = true + +# Rust Cargo.toml files (non-auto-generated) +[[tool.bumpversion.files]] +filename = "rust/Cargo.toml" +search = 'version = "{current_version}"' +replace = 'version = "{new_version}"' + +[[tool.bumpversion.files]] +filename = "rust/lance-namespace/Cargo.toml" +search = 'version = "{current_version}"' +replace = 'version = "{new_version}"' \ No newline at end of file diff --git a/.github/workflows/auto-bump.yml b/.github/workflows/auto-bump.yml index d81ee4ced..9f10cd561 100644 --- a/.github/workflows/auto-bump.yml +++ b/.github/workflows/auto-bump.yml @@ -105,12 +105,12 @@ jobs: - name: Install dependencies run: | - pip install packaging lxml toml + pip install packaging bump-my-version toml - - name: Get current version from Java Makefile + - name: Get current version id: current_version run: | - CURRENT_VERSION=$(grep "^VERSION = " java/Makefile | cut -d' ' -f3) + CURRENT_VERSION=$(python -c "import toml; print(toml.load('.bumpversion.toml')['tool']['bumpversion']['current_version'])") echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT echo "Current version: $CURRENT_VERSION" @@ -128,33 +128,18 @@ jobs: git checkout -b $BRANCH_NAME echo "branch=$BRANCH_NAME" >> $GITHUB_ENV - - name: Bump version + - name: Install uv for code generation run: | - python ci/bump_version.py --version "${{ steps.new_version.outputs.version }}" + curl -LsSf https://astral.sh/uv/install.sh | sh + echo "$HOME/.local/bin" >> $GITHUB_PATH - - name: Regenerate auto-generated code + - name: Install openapi-generator-cli run: | - # Install uv for Python code generation - curl -LsSf https://astral.sh/uv/install.sh | sh - export PATH="$HOME/.local/bin:$PATH" - - # Install openapi-generator-cli uv tool install openapi-generator-cli - - # Generate Java auto-generated code - cd java - make gen - cd .. - - # Generate Python auto-generated code - cd python - make gen - cd .. - - # Generate Rust auto-generated code - cd rust - make gen - cd .. + + - name: Bump version and regenerate auto-generated code + run: | + python ci/bump_version.py --version "${{ steps.new_version.outputs.version }}" - name: Configure git run: | diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index eafc0d004..398f0b88d 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -60,4 +60,3 @@ jobs: working-directory: python/lance_namespace_urllib3_client run: | uv publish --trusted-publishing always - echo "โœ… Successfully published version ${{ steps.get_versions.outputs.urllib3_version }} to PyPI!" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e69b9f447..72f91f7a2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,12 +50,12 @@ jobs: - name: Install dependencies run: | - pip install packaging lxml toml + pip install packaging bump-my-version toml - - name: Get current version from Java Makefile + - name: Get current version id: current_version run: | - CURRENT_VERSION=$(grep "^VERSION = " java/Makefile | cut -d' ' -f3) + CURRENT_VERSION=$(python -c "import toml; print(toml.load('.bumpversion.toml')['tool']['bumpversion']['current_version'])") echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT echo "Current version: $CURRENT_VERSION" @@ -91,33 +91,21 @@ jobs: echo "tag=$TAG" >> $GITHUB_OUTPUT echo "Tag will be: $TAG" - - name: Update version (stable releases only) + - name: Install uv for code generation (stable releases only) if: inputs.release_channel == 'stable' run: | - python ci/bump_version.py --version "${{ steps.new_version.outputs.version }}" - - # Regenerate auto-generated code with new version - # Install uv for Python code generation curl -LsSf https://astral.sh/uv/install.sh | sh - export PATH="$HOME/.local/bin:$PATH" - - # Install openapi-generator-cli + echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: Install openapi-generator-cli (stable releases only) + if: inputs.release_channel == 'stable' + run: | uv tool install openapi-generator-cli - - # Generate Java auto-generated code - cd java - make gen - cd .. - - # Generate Python auto-generated code - cd python - make gen - cd .. - - # Generate Rust auto-generated code - cd rust - make gen - cd .. + + - name: Update version (stable releases only) + if: inputs.release_channel == 'stable' + run: | + python ci/bump_version.py --version "${{ steps.new_version.outputs.version }}" - name: Configure git identity run: | diff --git a/ci/bump_version.py b/ci/bump_version.py index fc54c3e59..02edbbc56 100755 --- a/ci/bump_version.py +++ b/ci/bump_version.py @@ -1,173 +1,77 @@ #!/usr/bin/env python3 """ Version management script for Lance Namespace project. -Updates version in multiple locations: -- Java: Makefiles and pom.xml files (excluding auto-generated ones) -- Python: Makefiles and pyproject.toml files (excluding auto-generated ones) -- Rust: Makefiles and Cargo.toml files (excluding auto-generated ones) +Uses bump-my-version to handle version bumping across all project components. """ import argparse import subprocess import sys -import re from pathlib import Path -import toml -from lxml import etree -def update_makefile_version(makefile_path, new_version): - """Update VERSION variable in Makefile""" - content = makefile_path.read_text() - updated_content = re.sub( - r'^VERSION\s*=\s*.*$', - f'VERSION = {new_version}', - content, - flags=re.MULTILINE - ) - makefile_path.write_text(updated_content) - print(f"Updated {makefile_path}") -def update_java_pom_version(pom_path, new_version): - """Update version in pom.xml""" - parser = etree.XMLParser(remove_blank_text=False, remove_comments=False) - tree = etree.parse(str(pom_path), parser) - root = tree.getroot() - - # Handle namespace - nsmap = root.nsmap - ns = nsmap[None] if None in nsmap else None - - # Create namespace prefix for XPath - if ns: - xpath_ns = {'m': ns} - version_xpath = '//m:project/m:version' - parent_version_xpath = '//m:project/m:parent/m:version' - else: - xpath_ns = None - version_xpath = '//project/version' - parent_version_xpath = '//project/parent/version' - - # Update project version - version_elements = tree.xpath(version_xpath, namespaces=xpath_ns) - for elem in version_elements: - elem.text = new_version - - # Update parent version in root pom - if 'pom.xml' in str(pom_path) and pom_path.parent.name == 'java': - parent_version_elements = tree.xpath(parent_version_xpath, namespaces=xpath_ns) - for elem in parent_version_elements: - elem.text = new_version - - # Write back with proper formatting - tree.write(str(pom_path), pretty_print=True, xml_declaration=True, encoding='UTF-8') - print(f"Updated {pom_path}") +def run_command(cmd: list[str], capture_output: bool = True) -> subprocess.CompletedProcess: + """Run a command and return the result.""" + print(f"Running: {' '.join(cmd)}") + result = subprocess.run(cmd, capture_output=capture_output, text=True) + if result.returncode != 0: + print(f"Error running command: {' '.join(cmd)}") + if capture_output: + print(f"stderr: {result.stderr}") + sys.exit(result.returncode) + return result -def update_python_pyproject_version(pyproject_path, new_version): - """Update version in pyproject.toml""" - data = toml.load(pyproject_path) - - # Update version in [project] section - if 'project' in data and 'version' in data['project']: - data['project']['version'] = new_version - - # Update version in [tool.poetry] section if exists - if 'tool' in data and 'poetry' in data['tool'] and 'version' in data['tool']['poetry']: - data['tool']['poetry']['version'] = new_version - - # Write back - with open(pyproject_path, 'w') as f: - toml.dump(data, f) - print(f"Updated {pyproject_path}") -def update_rust_cargo_version(cargo_path, new_version): - """Update version in Cargo.toml""" - data = toml.load(cargo_path) - - # Update package version - if 'package' in data and 'version' in data['package']: - data['package']['version'] = new_version - - # Write back - with open(cargo_path, 'w') as f: - toml.dump(data, f) - print(f"Updated {cargo_path}") +def get_current_version() -> str: + """Get the current version from .bumpversion.toml.""" + config_path = Path(".bumpversion.toml") + if not config_path.exists(): + raise FileNotFoundError(".bumpversion.toml not found in current directory") + + with open(config_path, "r") as f: + for line in f: + if line.strip().startswith('current_version = "'): + return line.split('"')[1] + raise ValueError("Could not find current_version in .bumpversion.toml") + def main(): - parser = argparse.ArgumentParser(description='Bump version in Lance Namespace project') + parser = argparse.ArgumentParser(description='Bump version using bump-my-version') parser.add_argument('--version', required=True, help='New version to set') parser.add_argument('--dry-run', action='store_true', help='Show what would be changed without making changes') args = parser.parse_args() + + # Get current version + current_version = get_current_version() new_version = args.version - print(f"Bumping version to: {new_version}") + print(f"Current version: {current_version}") + print(f"New version: {new_version}") if args.dry_run: print("\nDry run mode - no changes will be made") - - # Update Makefiles - makefiles = [ - Path('java/Makefile'), - Path('python/Makefile'), - Path('rust/Makefile') - ] - - for makefile in makefiles: - if makefile.exists(): - if not args.dry_run: - update_makefile_version(makefile, new_version) - else: - print(f"Would update {makefile}") - - # Update Java pom.xml files (excluding auto-generated ones) - java_poms = [ - Path('java/pom.xml'), - Path('java/lance-namespace-core/pom.xml'), - Path('java/lance-namespace-adapter/pom.xml'), - Path('java/lance-namespace-hive2/pom.xml'), - Path('java/lance-namespace-hive3/pom.xml'), - Path('java/lance-namespace-glue/pom.xml'), - Path('java/lance-namespace-unity/pom.xml'), - Path('java/lance-namespace-lancedb/pom.xml') - ] - - for pom in java_poms: - if pom.exists(): - if not args.dry_run: - update_java_pom_version(pom, new_version) - else: - print(f"Would update {pom}") - - # Update Python pyproject.toml files (excluding auto-generated ones) - python_projects = [ - Path('python/lance_namespace/pyproject.toml'), - Path('pyproject.toml') # Root pyproject.toml if exists - ] - - for pyproject in python_projects: - if pyproject.exists(): - if not args.dry_run: - update_python_pyproject_version(pyproject, new_version) - else: - print(f"Would update {pyproject}") - - # Update Rust Cargo.toml files (excluding auto-generated ones) - rust_cargos = [ - Path('rust/Cargo.toml'), - Path('rust/lance-namespace/Cargo.toml') - ] - - for cargo in rust_cargos: - if cargo.exists(): - if not args.dry_run: - update_rust_cargo_version(cargo, new_version) - else: - print(f"Would update {cargo}") - - if not args.dry_run: - print(f"\nSuccessfully updated version to {new_version}") + # Run bump-my-version in dry-run mode + cmd = ["bump-my-version", "bump", "--current-version", current_version, + "--new-version", new_version, "--dry-run", "--verbose", "--allow-dirty"] + run_command(cmd, capture_output=False) else: - print(f"\nDry run complete - would update version to {new_version}") + # Use bump-my-version to update all files + print("\nUpdating version in all files...") + cmd = ["bump-my-version", "bump", "--current-version", current_version, + "--new-version", new_version, "--no-commit", "--no-tag", "--allow-dirty"] + run_command(cmd) + + # Now regenerate auto-generated modules with the new version + print("\nRegenerating auto-generated modules with new version...") + + # Build all modules (this will regenerate auto-generated code with new versions) + print("Running make build to regenerate auto-generated modules...") + run_command(["make", "build"], capture_output=False) + + print(f"\nSuccessfully updated version from {current_version} to {new_version}") + print("Auto-generated modules have been regenerated with the new version.") + if __name__ == '__main__': main() \ No newline at end of file From 2fc0fa770300c5b8a83f251e4131190dafb19303 Mon Sep 17 00:00:00 2001 From: Jack Ye Date: Sat, 30 Aug 2025 20:48:20 -0700 Subject: [PATCH 07/12] refactor: move make build to workflows instead of bump_version.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove 'make build' from bump_version.py script - Add 'make build' as separate step in auto-bump workflow - Add 'make build' as separate step in release workflow - This provides better visibility and control in CI/CD pipelines ๐Ÿค– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .github/workflows/auto-bump.yml | 6 +++++- .github/workflows/python-publish.yml | 1 - .github/workflows/release.yml | 5 +++++ ci/bump_version.py | 8 -------- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/auto-bump.yml b/.github/workflows/auto-bump.yml index 9f10cd561..25323a02c 100644 --- a/.github/workflows/auto-bump.yml +++ b/.github/workflows/auto-bump.yml @@ -137,10 +137,14 @@ jobs: run: | uv tool install openapi-generator-cli - - name: Bump version and regenerate auto-generated code + - name: Bump version run: | python ci/bump_version.py --version "${{ steps.new_version.outputs.version }}" + - name: Regenerate auto-generated code + run: | + make build + - name: Configure git run: | git config user.name 'github-actions[bot]' diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 398f0b88d..3c30ce112 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -57,6 +57,5 @@ jobs: if: | (github.event_name == 'release' && github.event.action == 'released') || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') - working-directory: python/lance_namespace_urllib3_client run: | uv publish --trusted-publishing always diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 72f91f7a2..7f6c8f452 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -107,6 +107,11 @@ jobs: run: | python ci/bump_version.py --version "${{ steps.new_version.outputs.version }}" + - name: Regenerate auto-generated code (stable releases only) + if: inputs.release_channel == 'stable' + run: | + make build + - name: Configure git identity run: | git config user.name 'github-actions[bot]' diff --git a/ci/bump_version.py b/ci/bump_version.py index 02edbbc56..313707ddf 100755 --- a/ci/bump_version.py +++ b/ci/bump_version.py @@ -62,15 +62,7 @@ def main(): "--new-version", new_version, "--no-commit", "--no-tag", "--allow-dirty"] run_command(cmd) - # Now regenerate auto-generated modules with the new version - print("\nRegenerating auto-generated modules with new version...") - - # Build all modules (this will regenerate auto-generated code with new versions) - print("Running make build to regenerate auto-generated modules...") - run_command(["make", "build"], capture_output=False) - print(f"\nSuccessfully updated version from {current_version} to {new_version}") - print("Auto-generated modules have been regenerated with the new version.") if __name__ == '__main__': From 884cc2594ca3faf7993d2f3723e12280f5ed37c4 Mon Sep 17 00:00:00 2001 From: Jack Ye Date: Sat, 30 Aug 2025 20:48:41 -0700 Subject: [PATCH 08/12] remove bump --- .github/workflows/auto-bump.yml | 214 -------------------------------- 1 file changed, 214 deletions(-) delete mode 100644 .github/workflows/auto-bump.yml diff --git a/.github/workflows/auto-bump.yml b/.github/workflows/auto-bump.yml deleted file mode 100644 index 25323a02c..000000000 --- a/.github/workflows/auto-bump.yml +++ /dev/null @@ -1,214 +0,0 @@ -name: Auto Bump Version - -on: - workflow_dispatch: - inputs: - bump_type: - description: 'Type of version bump' - required: false - default: 'auto' - type: choice - options: - - auto - - patch - - minor - - major - -jobs: - check-for-changes: - runs-on: ubuntu-latest - outputs: - should_bump: ${{ steps.check.outputs.should_bump }} - bump_type: ${{ steps.check.outputs.bump_type }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Check for unreleased changes - id: check - run: | - # Get the last tag - LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") - - if [ -z "$LAST_TAG" ]; then - echo "No tags found, should create initial release" - echo "should_bump=true" >> $GITHUB_OUTPUT - echo "bump_type=patch" >> $GITHUB_OUTPUT - exit 0 - fi - - # Check for commits since last tag - COMMITS_SINCE_TAG=$(git rev-list --count ${LAST_TAG}..HEAD) - - if [ "$COMMITS_SINCE_TAG" -gt 0 ]; then - echo "Found $COMMITS_SINCE_TAG commits since last tag $LAST_TAG" - - # Determine bump type based on input or commit analysis - if [ "${{ inputs.bump_type }}" != "auto" ] && [ -n "${{ inputs.bump_type }}" ]; then - # Use manual input if provided and not "auto" - BUMP_TYPE="${{ inputs.bump_type }}" - else - # Analyze commit messages to determine bump type - BUMP_TYPE="patch" - - # Check for breaking changes (major bump) - if git log ${LAST_TAG}..HEAD --grep="BREAKING CHANGE" --grep="!:" | grep -q .; then - BUMP_TYPE="major" - # Check for features (minor bump) - elif git log ${LAST_TAG}..HEAD --grep="^feat" --grep="^feature" | grep -q .; then - BUMP_TYPE="minor" - fi - fi - - echo "should_bump=true" >> $GITHUB_OUTPUT - echo "bump_type=$BUMP_TYPE" >> $GITHUB_OUTPUT - else - echo "No commits since last tag $LAST_TAG" - echo "should_bump=false" >> $GITHUB_OUTPUT - fi - - - name: Summary - run: | - echo "## Auto Bump Check" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - if [ "${{ steps.check.outputs.should_bump }}" == "true" ]; then - echo "โœ… Version bump needed" >> $GITHUB_STEP_SUMMARY - echo "- **Bump Type:** ${{ steps.check.outputs.bump_type }}" >> $GITHUB_STEP_SUMMARY - else - echo "โญ๏ธ No version bump needed" >> $GITHUB_STEP_SUMMARY - fi - - create-bump-pr: - needs: check-for-changes - if: needs.check-for-changes.outputs.should_bump == 'true' - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - fetch-depth: 0 - - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - java-version: '17' - distribution: 'temurin' - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: Install dependencies - run: | - pip install packaging bump-my-version toml - - - name: Get current version - id: current_version - run: | - CURRENT_VERSION=$(python -c "import toml; print(toml.load('.bumpversion.toml')['tool']['bumpversion']['current_version'])") - echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT - echo "Current version: $CURRENT_VERSION" - - - name: Calculate new version - id: new_version - run: | - python ci/calculate_version.py \ - --current "${{ steps.current_version.outputs.version }}" \ - --type "${{ needs.check-for-changes.outputs.bump_type }}" \ - --channel "stable" - - - name: Create feature branch - run: | - BRANCH_NAME="auto-bump-${{ steps.new_version.outputs.version }}" - git checkout -b $BRANCH_NAME - echo "branch=$BRANCH_NAME" >> $GITHUB_ENV - - - name: Install uv for code generation - run: | - curl -LsSf https://astral.sh/uv/install.sh | sh - echo "$HOME/.local/bin" >> $GITHUB_PATH - - - name: Install openapi-generator-cli - run: | - uv tool install openapi-generator-cli - - - name: Bump version - run: | - python ci/bump_version.py --version "${{ steps.new_version.outputs.version }}" - - - name: Regenerate auto-generated code - run: | - make build - - - name: Configure git - run: | - git config user.name 'github-actions[bot]' - git config user.email 'github-actions[bot]@users.noreply.github.com' - - - name: Commit changes - run: | - git add -A - git commit -m "chore: bump version to ${{ steps.new_version.outputs.version }} - - Automated version bump from ${{ steps.current_version.outputs.version }} to ${{ steps.new_version.outputs.version }}. - Bump type: ${{ needs.check-for-changes.outputs.bump_type }}" - - - name: Push changes - run: | - git push origin ${{ env.branch }} - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v5 - with: - token: ${{ secrets.GITHUB_TOKEN }} - branch: ${{ env.branch }} - base: main - title: "chore: bump version to ${{ steps.new_version.outputs.version }}" - body: | - ## Automated Version Bump - - This PR automatically bumps the version from `${{ steps.current_version.outputs.version }}` to `${{ steps.new_version.outputs.version }}`. - - ### Details - - **Bump Type:** ${{ needs.check-for-changes.outputs.bump_type }} - - **Triggered By:** Manual trigger - - ### Updated Files - - All Makefiles (Java, Python, Rust) - - Java: pom.xml files (including auto-generated) - - Python: pyproject.toml files (including auto-generated) - - Rust: Cargo.toml files (including auto-generated) - - ### Checklist - - [ ] Review version bump changes - - [ ] Verify all version files are updated - - [ ] Confirm CI checks pass - - ### Next Steps - After merging this PR, you can create a release by: - 1. Going to Actions โ†’ Create Release workflow - 2. Selecting the release channel (stable/preview) - 3. Running the workflow - - --- - *This PR was automatically generated by the auto-bump workflow.* - labels: | - version-bump - automated - assignees: ${{ github.actor }} - - - name: Summary - run: | - echo "## Version Bump PR Created" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "- **Current Version:** ${{ steps.current_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY - echo "- **New Version:** ${{ steps.new_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY - echo "- **Bump Type:** ${{ needs.check-for-changes.outputs.bump_type }}" >> $GITHUB_STEP_SUMMARY - echo "- **Branch:** ${{ env.branch }}" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "โœ… Pull request created successfully!" >> $GITHUB_STEP_SUMMARY \ No newline at end of file From 0755674156634b0986eebd38492fec4df1f05865 Mon Sep 17 00:00:00 2001 From: Jack Ye Date: Sat, 30 Aug 2025 20:55:31 -0700 Subject: [PATCH 09/12] update contributing --- CONTRIBUTING.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b64f193e3..5828670a5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -83,4 +83,30 @@ After code merge, the contents are added to the during the Lance doc CI build time, and is presented in the Lance website under [Lance Namespace Spec](https://lancedb.github.io/lance/format/namespace). -The CONTRIBUTING.md document is auto-built to the [Lance Contributing Guide](https://lancedb.github.io/lance/community/contributing/) \ No newline at end of file +The CONTRIBUTING.md document is auto-built to the [Lance Contributing Guide](https://lancedb.github.io/lance/community/contributing/) + +## Release Process + +This section describes the CI/CD workflows for automated version management, releases, and publishing. + +### Version Scheme + +- **Stable releases:** `X.Y.Z` (e.g., 1.2.3) +- **Preview releases:** `X.Y.Z-beta.N` (e.g., 1.2.3-beta.1) + +### Creating a Release + +1. **Create Release Draft** + - Go to Actions โ†’ "Create Release" + - Select parameters: + - Release type (major/minor/patch) + - Release channel (stable/preview) + - Dry run (test without pushing) + - Run workflow (creates a draft release) + +2. **Review and Publish** + - Go to the [Releases page](../../releases) to review the draft + - Edit release notes if needed + - Click "Publish release" to: + - For stable releases: Trigger automatic publishing for Java, Python, Rust + - For preview releases: Create a beta release (not published) From bc1844201396fe1a1c6abf5dbde19349ece13733 Mon Sep 17 00:00:00 2001 From: Jack Ye Date: Sat, 30 Aug 2025 21:03:43 -0700 Subject: [PATCH 10/12] update bump current --- .bumpversion.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bumpversion.toml b/.bumpversion.toml index 38fccef08..f9863e556 100644 --- a/.bumpversion.toml +++ b/.bumpversion.toml @@ -1,5 +1,5 @@ [tool.bumpversion] -current_version = "0.0.9" +current_version = "0.0.10" parse = "(?P\\d+)\\.(?P\\d+)\\.(?P\\d+)" serialize = ["{major}.{minor}.{patch}"] search = "{current_version}" From 400b1ec1262def36644491f27deb0ec8afecaee6 Mon Sep 17 00:00:00 2001 From: Jack Ye Date: Sat, 30 Aug 2025 21:08:07 -0700 Subject: [PATCH 11/12] fix version --- .bumpversion.toml | 9 +-------- rust/lance-namespace/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/.bumpversion.toml b/.bumpversion.toml index f9863e556..429dc4dfe 100644 --- a/.bumpversion.toml +++ b/.bumpversion.toml @@ -78,19 +78,12 @@ filename = "python/lance_namespace/pyproject.toml" search = 'version = "{current_version}"' replace = 'version = "{new_version}"' -# Root pyproject.toml if exists [[tool.bumpversion.files]] -filename = "pyproject.toml" +filename = "python/pyproject.urllib3_client.toml" search = 'version = "{current_version}"' replace = 'version = "{new_version}"' -ignore_missing_files = true # Rust Cargo.toml files (non-auto-generated) -[[tool.bumpversion.files]] -filename = "rust/Cargo.toml" -search = 'version = "{current_version}"' -replace = 'version = "{new_version}"' - [[tool.bumpversion.files]] filename = "rust/lance-namespace/Cargo.toml" search = 'version = "{current_version}"' diff --git a/rust/lance-namespace/Cargo.toml b/rust/lance-namespace/Cargo.toml index 7c3eb289d..0a9ba7bb5 100644 --- a/rust/lance-namespace/Cargo.toml +++ b/rust/lance-namespace/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lance-namespace" -version = "0.1.0" +version = "0.0.10" edition = "2021" authors = ["Lance Namespace Contributors"] description = "Lance Namespace Rust Client - A unified interface for managing namespaces and tables" From 236314c6df77584779cada3493e6a4c4247db1f5 Mon Sep 17 00:00:00 2001 From: Jack Ye Date: Sat, 30 Aug 2025 21:11:09 -0700 Subject: [PATCH 12/12] fix version --- .github/workflows/rust-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust-publish.yml b/.github/workflows/rust-publish.yml index bfe1cc46b..b7b53943c 100644 --- a/.github/workflows/rust-publish.yml +++ b/.github/workflows/rust-publish.yml @@ -62,7 +62,7 @@ jobs: - uses: Swatinem/rust-cache@v2 with: workspaces: rust - - uses: katyo/publish-crates@v2.2 + - uses: katyo/publish-crates@v2 with: # registry-token: ${{ steps.auth.outputs.token }} registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}