Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 98 additions & 68 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,81 +1,111 @@

name: Auto-version
name: Release version tag

on:
pull_request:
types:
- closed
push:
tags:
- "v*.*.*"

jobs:
build:
if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main' && github.event.pull_request.head.ref != 'update-cargo-toml'
runs-on: ubuntu-latest
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

steps:
- name: Checkout repository
uses: actions/checkout@v2
permissions:
contents: read

- name: Run Build Script
run: |
git config user.name "GitHub Actions Bot"
git config user.email "<>"

- name: run script
run: |
python scripts/update.py
jobs:
release:
# Pin the package build environment so the generated .deb does not silently
# raise its minimum glibc version when ubuntu-latest advances.
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- name: Check out tagged source
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
fetch-depth: 0

- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
- name: Set up pinned Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "Updated code"
title: "Update Cargo.toml"
body: "This pull request updates the Cargo.toml file."
branch: update-cargo-toml
reviewers: tapishr
python-version: "3.11"

- name: Build Rust CLI
run: |
cd vibi-dpu
cargo build --release

- name: Get version from Cargo.toml
id: get_version
run: |
cd vibi-dpu
echo "::set-output name=version::$(grep -Po '(?<=version = ")[\d.]+(?=")' Cargo.toml)"

- name: Create Release
id: create_release
uses: actions/create-release@v1
- name: Verify tag, source, manifest, lockfile, and release state
id: version
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.get_version.outputs.version }}
release_name: Release ${{ steps.get_version.outputs.version }}
draft: false
prerelease: false

- name: cargo deb
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
run: |
cargo install cargo-deb

- name: build binary
set -euo pipefail
test "$(git rev-parse "${TAG}^{commit}")" = "$GITHUB_SHA"
git merge-base --is-ancestor "$GITHUB_SHA" origin/main

release_state="absent"
error_file="$(mktemp)"
if is_draft="$(gh release view "$TAG" --json isDraft --jq .isDraft 2>"$error_file")"; then
if [[ "$is_draft" != "true" ]]; then
echo "A published release already exists for $TAG" >&2
exit 1
fi
release_state="draft"
elif ! grep -Fxq "release not found" "$error_file"; then
cat "$error_file" >&2
exit 1
fi

version="$(python scripts/verify_release.py --tag "$TAG")"
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "release_state=$release_state" >> "$GITHUB_OUTPUT"

- name: Validate package
run: |
cd vibi-dpu
cargo deb

- name: Rename Debian Package
run: mv ./vibi-dpu/target/debian/*.deb ./vibi-dpu/target/debian/vibi-dpu.deb

- name: Upload .deb Package
id: upload_deb
uses: actions/upload-release-asset@v1
set -euo pipefail
cargo metadata --manifest-path vibi-dpu/Cargo.toml --locked --no-deps --format-version 1 >/dev/null
cargo test --manifest-path vibi-dpu/Cargo.toml --locked
cargo build --manifest-path vibi-dpu/Cargo.toml --release --locked
git diff --exit-code

- name: Install pinned cargo-deb
run: cargo install cargo-deb --version 3.7.0 --locked

- name: Build, inspect, and checksum Debian package
id: package
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./vibi-dpu/target/debian/vibi-dpu.deb
asset_name: vibi-dpu.deb
asset_content_type: application/octet-stream
VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail
rm -rf vibi-dpu/target/debian
cargo deb --manifest-path vibi-dpu/Cargo.toml --locked
mapfile -t packages < <(find vibi-dpu/target/debian -maxdepth 1 -type f -name '*.deb')
test "${#packages[@]}" -eq 1
package="${packages[0]}"
test "$(dpkg-deb --field "$package" Package)" = "vibi-dpu"
test "$(dpkg-deb --field "$package" Version)" = "${VERSION}-1"
test "$(dpkg-deb --field "$package" Architecture)" = "amd64"
dpkg-deb --contents "$package" | grep -Eq '[[:space:]]\./usr/bin/vibi-dpu$'
mkdir -p dist
asset="dist/vibi-dpu_${VERSION}_amd64.deb"
cp "$package" "$asset"
sha256sum "$asset" > "${asset}.sha256"
sha256sum --check "${asset}.sha256"
echo "asset=$asset" >> "$GITHUB_OUTPUT"

- name: Create or resume draft with assets, then publish
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
ASSET: ${{ steps.package.outputs.asset }}
RELEASE_STATE: ${{ steps.version.outputs.release_state }}
run: |
set -euo pipefail
if [[ "$RELEASE_STATE" = "draft" ]]; then
gh release upload "$TAG" "$ASSET" "${ASSET}.sha256" --clobber
else
gh release create "$TAG" \
--verify-tag \
--draft \
--generate-notes \
--title "vibi-dpu $TAG" \
"$ASSET" "${ASSET}.sha256"
fi
gh release edit "$TAG" --title "vibi-dpu $TAG" --draft=false
33 changes: 18 additions & 15 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,30 @@ name: Rust

on:
push:
branches: [ "main" ]
branches: [main]
pull_request:
branches: [ "main" ]
branches: [main]

permissions:
contents: read

env:
CARGO_TERM_COLOR: always

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Test version update script
run: python3 -m unittest scripts/test_update.py
- name: Build
run: |
cd vibi-dpu
cargo build --verbose
- name: Run tests
run: |
cd vibi-dpu
cargo test --verbose
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- name: Set up pinned Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.11"
- name: Test release automation scripts
run: python -m unittest scripts/test_update.py scripts/test_verify_release.py
- name: Check locked metadata
run: cargo metadata --manifest-path vibi-dpu/Cargo.toml --locked --no-deps --format-version 1 >/dev/null
- name: Build
run: cargo build --manifest-path vibi-dpu/Cargo.toml --locked --verbose
- name: Run tests
run: cargo test --manifest-path vibi-dpu/Cargo.toml --locked --verbose
82 changes: 82 additions & 0 deletions .github/workflows/version-bump.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Propose version bump

on:
pull_request_target:
types: [closed]

concurrency:
group: version-bump-main
cancel-in-progress: false

permissions:
contents: write
pull-requests: write

jobs:
propose:
if: >-
github.event.pull_request.merged == true &&
github.event.pull_request.base.ref == 'main' &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.pull_request.head.ref != 'automation/version-bump'
Comment thread
coderabbitai[bot] marked this conversation as resolved.
runs-on: ubuntu-latest
steps:
- name: Check out merged main
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
ref: main
fetch-depth: 0

- name: Set up pinned Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.11"

- name: Update manifest and lockfile
run: python scripts/update.py

- name: Validate release automation and proposed package metadata
run: |
python -m unittest scripts/test_update.py scripts/test_verify_release.py
cargo metadata --manifest-path vibi-dpu/Cargo.toml --locked --no-deps --format-version 1 >/dev/null

- name: Open or update version-bump pull request
env:
GH_TOKEN: ${{ github.token }}
MERGED_PR: ${{ github.event.pull_request.number }}
run: |
set -euo pipefail
branch="automation/version-bump"
version="$(python -c 'import tomllib; print(tomllib.load(open("vibi-dpu/Cargo.toml", "rb"))["package"]["version"])')"
git config user.name "nia-sg-bot"
git config user.email "nia-sg-bot@users.noreply.github.com"
git fetch origin "$branch" || true
previous="$(git rev-parse "origin/${branch}" 2>/dev/null || true)"
git switch -C "$branch"
git add vibi-dpu/Cargo.toml vibi-dpu/Cargo.lock
git commit -m "chore: propose vibi-dpu ${version}"
if [[ -n "$previous" ]]; then
git push --force-with-lease="${branch}:${previous}" origin "$branch"
else
git push origin "$branch"
fi

run_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
body_file="$(mktemp)"
cat >"$body_file" <<EOF
Automated version proposal after #${MERGED_PR}.

Review and merge this PR before deliberately creating tag \`v${version}\`; merging an ordinary PR does not publish a release. The trusted-main generation run validated the synchronized manifest and lockfile: ${run_url}
EOF
existing="$(gh pr list --state open --head "$branch" --json number,headRepository --jq '[.[] | select(.headRepository.nameWithOwner == env.GITHUB_REPOSITORY)][0].number // empty')"
if [[ -n "$existing" ]]; then
gh pr edit "$existing" \
--title "chore: release vibi-dpu ${version}" \
--body-file "$body_file"
else
gh pr create \
--base main \
--head "$branch" \
--title "chore: release vibi-dpu ${version}" \
--body-file "$body_file"
fi
55 changes: 49 additions & 6 deletions scripts/test_update.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,68 @@
import subprocess
import sys
import importlib.util
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch


SCRIPT = Path(__file__).resolve().with_name("update.py")
SPEC = importlib.util.spec_from_file_location("update", SCRIPT)
update = importlib.util.module_from_spec(SPEC)
assert SPEC.loader is not None
SPEC.loader.exec_module(update)


class UpdateVersionTest(unittest.TestCase):
def test_increments_vibi_dpu_patch_version(self):
def test_increments_manifest_and_lockfile_together(self):
with tempfile.TemporaryDirectory() as directory:
manifest = Path(directory) / "vibi-dpu" / "Cargo.toml"
manifest.parent.mkdir()
root = Path(directory)
manifest = root / "Cargo.toml"
lockfile = root / "Cargo.lock"
manifest.write_text(
'[package]\nname = "vibi-dpu"\nversion = "1.2.3"\nedition = "2021"\n'
)
lockfile.write_text(
'version = 3\n\n[[package]]\nname = "vibi-dpu"\nversion = "1.2.3"\n'
)

subprocess.run([sys.executable, str(SCRIPT)], cwd=directory, check=True)
with patch.object(update, "MANIFEST", manifest), patch.object(
update, "LOCKFILE", lockfile
):
update.main(tags=set())

self.assertIn('version = "1.2.4"', manifest.read_text())
self.assertIn('version = "1.2.4"', lockfile.read_text())

def test_refuses_mismatched_lockfile_without_writing(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
manifest = root / "Cargo.toml"
lockfile = root / "Cargo.lock"
manifest_text = '[package]\nname = "vibi-dpu"\nversion = "1.2.3"\n'
lockfile_text = (
'version = 3\n\n[[package]]\nname = "vibi-dpu"\nversion = "1.2.2"\n'
)
manifest.write_text(manifest_text)
lockfile.write_text(lockfile_text)

with patch.object(update, "MANIFEST", manifest), patch.object(
update, "LOCKFILE", lockfile
), self.assertRaisesRegex(ValueError, "does not match"):
update.main(tags=set())

self.assertEqual(manifest.read_text(), manifest_text)
self.assertEqual(lockfile.read_text(), lockfile_text)

def test_skips_versions_that_already_have_release_tags(self):
for existing_tag in ("2.2.1", "v2.2.1"):
with self.subTest(existing_tag=existing_tag):
self.assertEqual(
update.next_untagged_patch("2.2.0", {existing_tag}), "2.2.2"
)

def test_rejects_non_stable_version(self):
with self.assertRaisesRegex(ValueError, "stable MAJOR.MINOR.PATCH"):
update.next_patch("1.2.3-rc.1")


if __name__ == "__main__":
Expand Down
Loading
Loading