diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 9ba1eb48a..a2f31490a 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -8,13 +8,18 @@ on: branches: [develop] tags: ["v*"] +# Add concurrency to cancel in-progress runs on the same ref +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + # Add permissions block for GitHub Container Registry access permissions: contents: read packages: write env: - PUSH_CONDITION: ${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && contains(fromJSON('["refs/head/main", "refs/head/develop"]'), github.event.workflow_dispatch.ref)) }} + PUSH_CONDITION: ${{ github.event_name == 'push' && (contains(fromJSON('["refs/heads/develop"]'), github.ref) || startsWith(github.ref, 'refs/tags/')) || github.event_name == 'workflow_dispatch' && contains(fromJSON('["refs/heads/develop"]'), github.ref) }} jobs: build-base-image: @@ -23,7 +28,10 @@ jobs: version: ${{ steps.version.outputs.version }} steps: - - uses: actions/checkout@v4 + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: @@ -82,7 +90,10 @@ jobs: rocksdb_backup, ] steps: - - uses: actions/checkout@v4 # Need to checkout code for Dockerfile + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: @@ -142,7 +153,8 @@ jobs: runs-on: ubuntu-latest needs: [build-base-image, build-binary-images] steps: - - name: Repository dispatch + - name: Repository dispatch for development + if: startsWith(github.ref, 'refs/heads/develop') run: | curl -X POST \ -H "Authorization: token ${{ secrets.DISPATCH_TOKEN_DEV }}" \ @@ -155,3 +167,18 @@ jobs: "version": "${{ needs.build-base-image.outputs.version }}" } }' + + - name: Repository dispatch for production + if: startsWith(github.ref, 'refs/tags/') + run: | + curl -X POST \ + -H "Authorization: token ${{ secrets.DISPATCH_TOKEN_PROD }}" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/adm-metaex/aura-config-prod/dispatches \ + -d '{ + "event_type": "deploy", + "client_payload": { + "services": "${{ env.PUSH_CONDITION && 'ingester,slot_persister,backfill,api,synchronizer,rocksdb_backup' || '' }}", + "version": "${{ needs.build-base-image.outputs.version }}" + } + }' diff --git a/.github/workflows/release-finalize.yml b/.github/workflows/release-finalize.yml new file mode 100644 index 000000000..300e62a10 --- /dev/null +++ b/.github/workflows/release-finalize.yml @@ -0,0 +1,124 @@ +name: Finalize Release + +on: + pull_request: + types: [closed] + branches: + - main + +# Add permissions for GitHub operations +permissions: + contents: write + pull-requests: write + +jobs: + finalize-release: + if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/v') + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch all history for proper tagging + + - name: Setup Git Identity + run: | + set -e + git config --global user.name "GitHub Actions" + git config --global user.email "actions@github.com" + + - name: Download changelog artifact + uses: actions/download-artifact@v4 + with: + name: changelog + path: . + + - name: Get release version + id: get_version + run: | + set -e + BRANCH_NAME="${{ github.event.pull_request.head.ref }}" + # We only support release/v* format now + VERSION=${BRANCH_NAME#release/} + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "tag_name=$VERSION" >> $GITHUB_OUTPUT + + - name: Create and push tag + run: | + set -e + git tag -a ${{ steps.get_version.outputs.tag_name }} -m "Release ${{ steps.get_version.outputs.tag_name }}" + git push origin ${{ steps.get_version.outputs.tag_name }} + # This tag push will automatically trigger the docker.yml workflow for building images + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.get_version.outputs.tag_name }} + name: Release ${{ steps.get_version.outputs.tag_name }} + body_path: CHANGELOG.md # Use the downloaded changelog + generate_release_notes: false # We're using our own changelog + draft: false + prerelease: false + + - name: Create PR to develop + run: | + set -e + gh pr create --base develop --head ${{ github.event.pull_request.head.ref }} \ + --title "Merge ${{ github.event.pull_request.head.ref }} into develop" \ + --body "Merge release branch into develop." + + - name: Merge into develop + run: | + set -e + PR_NUMBER=$(gh pr list --head ${{ github.event.pull_request.head.ref }} --base develop --json number --jq '.[0].number') + if [ -n "$PR_NUMBER" ]; then + gh pr merge --repo ${{ github.repository }} --merge --auto $PR_NUMBER + else + echo "No PR found to merge into develop" + exit 1 + fi + + # --- Post-Release Version Bump --- + + - name: Checkout develop branch for version bump + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch all history for proper tagging + ref: develop + + - name: Install dependencies for version bump + run: | + set -e + sudo apt-get update && sudo apt-get install -y protobuf-compiler + cargo install cargo-edit + + - name: Calculate and apply next development version + id: calculate_next_version + run: | + set -e + # Extract version without 'v' prefix + RAW_VERSION=${{ steps.get_version.outputs.version }} + VERSION_WITHOUT_V="${RAW_VERSION#v}" + + IFS='.' read -ra VERSION_PARTS <<< "$VERSION_WITHOUT_V" + MAJOR="${VERSION_PARTS[0]}" + MINOR="${VERSION_PARTS[1]}" + PATCH=$((VERSION_PARTS[2] + 1)) # Increment the patch version + NEXT_VERSION="${MAJOR}.${MINOR}.${PATCH}-dev" + echo "next_version=$NEXT_VERSION" >> $GITHUB_OUTPUT + echo "Setting develop version to $NEXT_VERSION" + + # Update Cargo.toml versions + find . -name "Cargo.toml" -type f -exec cargo set-version $NEXT_VERSION --manifest-path {} \; + + # Update any other version references + if [ -f "VERSION" ]; then + echo "$NEXT_VERSION" > VERSION + fi + + # Commit and push the version bump directly to develop + git add -A + git commit -m "chore: bump version to $NEXT_VERSION [skip ci]" + git push origin develop diff --git a/.github/workflows/release-prepare.yml b/.github/workflows/release-prepare.yml new file mode 100644 index 000000000..d0942acef --- /dev/null +++ b/.github/workflows/release-prepare.yml @@ -0,0 +1,147 @@ +name: Prepare Release + +on: + workflow_dispatch: + inputs: + version: + description: 'Version number (without v prefix, e.g. 0.5.0)' + required: true + type: string + base_commit: + description: 'Base commit SHA (leave empty to use latest develop)' + required: false + type: string + default: '' + +# Add permissions for GitHub operations +permissions: + contents: write + pull-requests: write + +jobs: + prepare-release: + runs-on: ubuntu-latest + outputs: + version: ${{ inputs.version }} # Output the version for use in other jobs + tag_name: v${{ inputs.version }} + release_branch: release/v${{ inputs.version }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + ref: ${{ inputs.base_commit || 'develop' }} + fetch-depth: 0 # Fetch all history for changelog generation + + - name: Validate input version + run: | + set -e + # Make sure the version follows semantic versioning format + if ! echo "${{ inputs.version }}" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$'; then + echo "Error: Version must follow semantic versioning format (e.g., 0.5.0)" + exit 1 + fi + + - name: Setup Git Identity + run: | + set -e + git config --global user.name "GitHub Actions" + git config --global user.email "actions@github.com" + + - name: Install dependencies + run: | + set -e + sudo apt-get update && sudo apt-get install -y protobuf-compiler + cargo install cargo-edit + cargo install git-cliff + + - name: Create release branch + run: | + set -e + # Using standardized format: release/v{version} + RELEASE_BRANCH="release/v${{ inputs.version }}" + echo "Creating branch $RELEASE_BRANCH" + git checkout -b $RELEASE_BRANCH + echo "RELEASE_BRANCH=$RELEASE_BRANCH" >> $GITHUB_ENV + + - name: Update version numbers + run: | + set -e + # Update Cargo.toml versions + find . -name "Cargo.toml" -type f -exec cargo set-version ${{ inputs.version }} --manifest-path {} \; + + # Update any other version references (add any other files that contain version numbers) + if [ -f "VERSION" ]; then + echo "${{ inputs.version }}" > VERSION + fi + + git add -A + git commit -m "chore: bump version to ${{ inputs.version }}" + + - name: Generate changelog + id: changelog + run: | + set -e + # Generate changelog using git-cliff + git-cliff --config cliff.toml --tag "v${{ inputs.version }}" --output CHANGELOG.md + + # Generate a shorter version for PR description + git-cliff --config cliff.toml --tag "v${{ inputs.version }}" --strip header,footer > .changelog_content + + git add CHANGELOG.md + git commit -m "docs: add changelog for v${{ inputs.version }}" + + - name: Verify changelog + run: | + set -e + # Check that the changelog file exists and has content + if [ ! -s CHANGELOG.md ]; then + echo "Error: CHANGELOG.md is empty or does not exist" + exit 1 + fi + + # Check that the changelog contains the version we're releasing + if ! grep -q "v${{ inputs.version }}" CHANGELOG.md; then + echo "Error: CHANGELOG.md does not contain version v${{ inputs.version }}" + echo "Contents of CHANGELOG.md:" + cat CHANGELOG.md + exit 1 + fi + + # Check that the changelog has sections + if ! grep -q "###" CHANGELOG.md; then + echo "Warning: CHANGELOG.md does not contain any sections (###)" + echo "This might be ok if there are no conventional commits, but please verify" + fi + + echo "Changelog verification passed!" + + - name: Push release branch + run: | + set -e + git push -u origin $RELEASE_BRANCH + + - name: Create Pull Request + id: create-pr + uses: peter-evans/create-pull-request@v5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + base: main + head: ${{ env.RELEASE_BRANCH }} + title: "Release v${{ inputs.version }}" + body-path: .changelog_content + draft: false + + - name: PR info + run: | + set -e + echo "Pull Request created: ${{ steps.create-pr.outputs.pull-request-url }}" + echo "Please review the PR, make any necessary adjustments, and merge when ready." + + - name: Upload changelog artifact + uses: actions/upload-artifact@v4 + with: + name: changelog + path: CHANGELOG.md diff --git a/Cargo.lock b/Cargo.lock index 008330066..af14d9c86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4781,7 +4781,7 @@ dependencies = [ [[package]] name = "nft_ingester" -version = "0.7.2" +version = "0.1.0" dependencies = [ "anchor-lang 0.30.1", "arweave-rs", diff --git a/Makefile b/Makefile index 307ac35e7..04ed81ce9 100644 --- a/Makefile +++ b/Makefile @@ -47,3 +47,11 @@ clippy: test: @cargo clean -p postgre-client -p rocks-db -p interface @cargo test --features integration_tests + +# Ensure git-cliff is installed +ensure-git-cliff: + @which git-cliff > /dev/null || cargo install git-cliff + +# Generate a changelog using git-cliff +changelog: + @git-cliff --output CHANGELOG.md diff --git a/RELEASE_PROCESS.md b/RELEASE_PROCESS.md new file mode 100644 index 000000000..66ca12ef1 --- /dev/null +++ b/RELEASE_PROCESS.md @@ -0,0 +1,75 @@ +# Release Process + +This document outlines the process to follow when releasing a new version of the project. + +## Releasing a New Version + +### 1. Prepare for Release + +1. Decide on a version number for the new release following [Semantic Versioning](https://semver.org/) (e.g., `0.5.0`). + +2. Locally or using the GitHub UI, trigger the `release-prepare` workflow: + ```bash + make release VERSION=0.5.0 + ``` + or manually trigger the workflow via GitHub Actions UI. + +3. This will: + - Create a new branch `release/v0.5.0` from the latest `develop` branch + - Update version numbers in all `Cargo.toml` files to `0.5.0` + - Generate a CHANGELOG.md file + - Create a pull request from `release/v0.5.0` to `main` + +### 2. Review and Merge the Release PR + +1. Review the generated PR to ensure the changelog and version changes are correct. +2. Request reviews from other team members as necessary. +3. Make any final adjustments directly to the `release/v0.5.0` branch. +4. Once approved, merge the PR into `main`. + +### 3. Automatic Release Finalization + +When the release PR is merged to `main`, the `release-finalize` workflow will automatically: + +1. Create and push a tag for the release (e.g., `v0.5.0`) +2. Create a GitHub Release with the changelog content +3. Build and publish Docker images for the release +4. Create a PR to merge changes back to `develop` +5. Automatically merge this PR into `develop` +6. Automatically bump the version on `develop` to the next development version (e.g., `0.5.1-dev`) + +No manual intervention is required for these steps unless there are conflicts when merging back to `develop`. + +## Hotfix Process + +For urgent fixes that need to bypass the normal release flow: + +1. Create a branch `hotfix/v0.5.1` from `main` +2. Make your changes and commit them +3. Update version numbers in all `Cargo.toml` files to `0.5.1` +4. Create a PR from `hotfix/v0.5.1` to `main` +5. After the PR is merged, the same automatic finalization steps listed above will occur + +## Version Numbering + +We follow [Semantic Versioning](https://semver.org/): + +- MAJOR version for incompatible API changes +- MINOR version for backwards-compatible functionality +- PATCH version for backwards-compatible bug fixes + +Development versions on the `develop` branch have a `-dev` suffix appended to the patch number (e.g., `0.5.1-dev`). + +## Changelog Generation + +The changelog is generated automatically using [git-cliff](https://github.com/orhun/git-cliff), which parses [Conventional Commits](https://www.conventionalcommits.org/) to generate a structured changelog. + +To ensure your commits appear correctly in the changelog, prefix them with: + +- `feat:` for new features +- `fix:` for bug fixes +- `chore:` for maintenance tasks +- `docs:` for documentation updates +- `refactor:` for code refactoring +- `test:` for adding or updating tests +- `perf:` for performance improvements \ No newline at end of file diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 000000000..c279ac1c4 --- /dev/null +++ b/cliff.toml @@ -0,0 +1,79 @@ +# Configuration for git-cliff changelog generator +# See https://git-cliff.org/docs/configuration + +[changelog] +# changelog header +header = """ +# Changelog\n +All notable changes to this project will be documented in this file.\n +""" +# template for the changelog body +# https://tera.netlify.app/docs +body = """ +{% if version %}\ +## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} +{% else %}\ +## [unreleased] +{% endif %}\ + +{% if previous %}\ +{% if previous.version %}\ +[{{ version | trim_start_matches(pat="v") }}]: https://github.com/metaplex-foundation/aura/compare/{{ previous.version }}...{{ version }} +{% else %}\ +[{{ version | trim_start_matches(pat="v") }}]: https://github.com/metaplex-foundation/aura/releases/tag/{{ version }} +{% endif %}\ +{% endif %}\ + +{% for group, commits in commits | group_by(attribute="group") %} +### {{ group | upper_first }} +{% for commit in commits %} +- {% if commit.breaking %}**BREAKING**: {% endif %}{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}](https://github.com/metaplex-foundation/aura/commit/{{ commit.id }})){% if commit.footers %} {% for footer in commit.footers %}{{ footer }}{% endfor %}{% endif %} +{% endfor %} +{% endfor %}\n +""" +# remove the leading and trailing whitespace from the templates +trim = true +# changelog footer +footer = "" + +# postprocessors +postprocessors = [ + { pattern = '', replace = "<" }, # needed to escape jinja2 templates +] + +[git] +# parse the commits based on https://www.conventionalcommits.org +conventional_commits = true +# filter out the commits that are not conventional +filter_unconventional = true +# process each line of a commit as an individual commit +split_commits = false +# regex for parsing and grouping commits +commit_parsers = [ + { message = "^feat", group = "Features" }, + { message = "^fix", group = "Bug Fixes" }, + { message = "^doc", group = "Documentation" }, + { message = "^perf", group = "Performance" }, + { message = "^refactor", group = "Refactor" }, + { message = "^style", group = "Styling" }, + { message = "^test", group = "Testing" }, + { message = "^chore\\(release\\): prepare for", skip = true }, + { message = "^chore\\(deps\\)", group = "Dependencies" }, + { message = "^chore", group = "Miscellaneous Tasks" }, + { message = "^ci", group = "CI/CD" }, + { body = ".*security", group = "Security" }, +] +# filter out the commits that are not matched by commit parsers +filter_commits = false +# glob pattern for matching git tags +tag_pattern = "v[0-9]*.[0-9]*.[0-9]*" +# regex for skipping tags +skip_tags = "" +# regex for ignoring tags +ignore_tags = "" +# sort the tags chronologically +date_order = false +# sort the commits inside sections by oldest/newest order +sort_commits = "oldest" +# limit the number of commits included in the changelog +limit_commits = 0 diff --git a/nft_ingester/Cargo.toml b/nft_ingester/Cargo.toml index 8176922fd..e1002a857 100644 --- a/nft_ingester/Cargo.toml +++ b/nft_ingester/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nft_ingester" -version = "0.7.2" +version = "0.1.0" edition = "2021" publish = false