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
270 changes: 270 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
name: CI/CD Pipeline

on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch:
inputs:
bump_type:
description: 'Version bump type'
required: true
type: choice
options:
- patch
- minor
- major
description:
description: 'Release description (optional)'
required: false
type: string

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always

jobs:
# Test on multiple OS - main CI job
test:
name: Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4

- name: Setup Rust (nightly-2022-08-22)
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2022-08-22

- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-

- name: Run tests
run: cargo test --all-features --verbose

- name: Run doc tests
run: cargo test --doc --verbose

# Build package - only runs if tests pass
build:
name: Build Package
runs-on: ubuntu-latest
needs: [test]
steps:
- uses: actions/checkout@v4

- name: Setup Rust (nightly-2022-08-22)
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2022-08-22

- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-build-

- name: Build release
run: cargo build --release --verbose

- name: Check package
run: cargo package --list

# Check for changelog fragments in PRs
changelog:
name: Changelog Fragment Check
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Check for changelog fragments
run: |
# Get list of fragment files (excluding README and template)
FRAGMENTS=$(find changelog.d -name "*.md" ! -name "README.md" 2>/dev/null | wc -l)

# Get changed files in PR
CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)

# Check if any source files changed (excluding docs and config)
SOURCE_CHANGED=$(echo "$CHANGED_FILES" | grep -E "^(src/|tests/|scripts/|examples/)" | wc -l)

if [ "$SOURCE_CHANGED" -gt 0 ] && [ "$FRAGMENTS" -eq 0 ]; then
echo "::warning::No changelog fragment found. Please add a changelog entry in changelog.d/"
echo ""
echo "To create a changelog fragment:"
echo " Create a new .md file in changelog.d/ with your changes"
echo ""
echo "See changelog.d/README.md for more information."
# Note: This is a warning, not a failure, to allow flexibility
# Change 'exit 0' to 'exit 1' to make it required
exit 0
fi

echo "Changelog check passed"

# Automatic release on push to main using changelog fragments
# This job automatically bumps version based on fragments in changelog.d/
auto-release:
name: Auto Release
needs: [test, build]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Setup Rust (nightly-2022-08-22)
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2022-08-22

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Determine bump type from changelog fragments
id: bump_type
run: node scripts/get-bump-type.mjs

- name: Check if version already released or no fragments
id: check
run: |
# Check if there are changelog fragments
if [ "${{ steps.bump_type.outputs.has_fragments }}" != "true" ]; then
# No fragments - check if current version tag exists
CURRENT_VERSION=$(grep -Po '(?<=^version = ")[^"]*' Cargo.toml)
if git rev-parse "v$CURRENT_VERSION" >/dev/null 2>&1; then
echo "No changelog fragments and v$CURRENT_VERSION already released"
echo "should_release=false" >> $GITHUB_OUTPUT
else
echo "No changelog fragments but v$CURRENT_VERSION not yet released"
echo "should_release=true" >> $GITHUB_OUTPUT
echo "skip_bump=true" >> $GITHUB_OUTPUT
fi
else
echo "Found changelog fragments, proceeding with release"
echo "should_release=true" >> $GITHUB_OUTPUT
echo "skip_bump=false" >> $GITHUB_OUTPUT
fi

- name: Collect changelog and bump version
id: version
if: steps.check.outputs.should_release == 'true' && steps.check.outputs.skip_bump != 'true'
run: |
node scripts/version-and-commit.mjs \
--bump-type "${{ steps.bump_type.outputs.bump_type }}"

- name: Get current version
id: current_version
if: steps.check.outputs.should_release == 'true'
run: |
CURRENT_VERSION=$(grep -Po '(?<=^version = ")[^"]*' Cargo.toml)
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT

- name: Build release
if: steps.check.outputs.should_release == 'true'
run: cargo build --release

- name: Create GitHub Release
if: steps.check.outputs.should_release == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
node scripts/create-github-release.mjs \
--release-version "${{ steps.current_version.outputs.version }}" \
--repository "${{ github.repository }}"

# Manual release via workflow_dispatch - only after CI passes
manual-release:
name: Manual Release
needs: [test, build]
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Setup Rust (nightly-2022-08-22)
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2022-08-22

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Collect changelog fragments
run: |
# Check if there are any fragments to collect
FRAGMENTS=$(find changelog.d -name "*.md" ! -name "README.md" 2>/dev/null | wc -l)
if [ "$FRAGMENTS" -gt 0 ]; then
echo "Found $FRAGMENTS changelog fragment(s), collecting..."
node scripts/collect-changelog.mjs
else
echo "No changelog fragments found, skipping collection"
fi

- name: Version and commit
id: version
run: |
node scripts/version-and-commit.mjs \
--bump-type "${{ github.event.inputs.bump_type }}" \
--description "${{ github.event.inputs.description }}"

- name: Build release
if: steps.version.outputs.version_committed == 'true' || steps.version.outputs.already_released == 'true'
run: cargo build --release

- name: Create GitHub Release
if: steps.version.outputs.version_committed == 'true' || steps.version.outputs.already_released == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
node scripts/create-github-release.mjs \
--release-version "${{ steps.version.outputs.new_version }}" \
--repository "${{ github.repository }}"
64 changes: 64 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# See https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
# Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

# Generated by cargo mutants
# Contains mutation testing data
**/mutants.out*/

# IDE and editor files
.idea/
.vscode/
*.swp
*.swo
*~

# OS files
.DS_Store
Thumbs.db

# Python virtual environments (for scripts)
.venv/
venv/
__pycache__/
*.pyc
*.pyo

# Coverage reports
*.lcov
coverage/
tarpaulin-report.html

# Benchmark results
criterion/

# Documentation build output
doc/

# Local development files
.env
.env.local
*.local

# Log files
*.log
logs/

# Profiling data
*.profraw
*.profdata

# Temporary files
tmp.file
*.tmp
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

<!-- changelog-insert-here -->
Loading