Releasing¶
Release Management Process¶
This document describes the release management process for AI Guardian.
Automated Release Script (Recommended)¶
The fastest way to create a release — no AI agent required:
scripts/release.sh minor # minor release (X.Y.Z -> X.(Y+1).0)
scripts/release.sh patch # patch release (X.Y.Z -> X.Y.(Z+1))
scripts/release.sh major # major release (X.Y.Z -> (X+1).0.0)
scripts/release.sh --dry-run minor # preview without executing
scripts/release.sh --skip-cursor patch # skip Cursor hook verification
The script automates all steps documented below: prerequisite validation, release readiness CI, optional Cursor hook verification, version bump, CHANGELOG update, README URL updates, docs export generation, TestPyPI verification, tagging, CI and versioned Read the Docs verification, bounded retry verification of both container repositories, and post-release merge back. Re-runnable — if it fails mid-way, just fix the issue and re-run.
Requirements: gh CLI (authenticated), python3, git, sed, curl, git-cliff (brew install git-cliff).
One-time Read the Docs setup¶
The release script pushes semantic version tags but does not manage Read the Docs project settings. Configure this once in Read the Docs → Admin → Automation Rules:
- Match: SemVer versions
- Version type: Tag
- Action: Activate version
The GitHub integration then builds each vX.Y.Z tag automatically. Read the Docs maps the greatest stable semantic version to /en/stable/, while /en/latest/ continues to track main. The release script waits for and verifies the exact /en/vX.Y.Z/ URL after pushing the production tag.
Table of Contents¶
- Automated Release Script
- Release Authorization Policy
- Version Numbering
- Branch Strategy
- Release Workflow
- Patch / Hotfix Workflow
- Release Checklist
- Version Infrastructure
- Testing Releases with TestPyPI
Release Authorization Policy¶
IMPORTANT: Only repository maintainers can create release tags that trigger PyPI publication.
Repository Access Model¶
This repository uses a fork-based workflow:
- Maintainers (@itdove): Have Write/Admin access
- Can push to branches
- Can create and push tags
- Can create releases
-
Handle all PyPI publications
-
Contributors: Must use forks (no direct access)
- Cannot push tags
- Cannot push to branches
- All contributions via pull requests from forks
- See CONTRIBUTING.md for workflow details
Why Fork-Based Workflow?¶
Technical Enforcement: Since GitHub free accounts don't support tag protection rules, the fork-based workflow provides:
- ✅ Prevents unauthorized tag creation - Only maintainers have push access
- ✅ Standard open source practice - Common workflow for OSS projects
- ✅ Code review required - All changes go through PRs
- ✅ Release control - Maintainers control all PyPI publications
Authorized Release Managers¶
Currently authorized to create release tags:
- @itdove (Repository Owner)
For Contributors¶
You CANNOT create release tags. Instead:
- ✅ Fork the repository (see CONTRIBUTING.md)
- ✅ Submit pull requests with features/fixes
- ✅ Update CHANGELOG.md in your PR under
[Unreleased]section - ✅ Maintainers handle releases - they will create tags and publish
DO NOT attempt to: - ❌ Create version tags (v1.2.0, etc.) - ❌ Push tags to the main repository - ❌ Modify version numbers in pyproject.toml or init.py
Test Releases (TestPyPI)¶
Maintainers only can create test tags for TestPyPI validation:
# Use the /release skill
/release test
# Or manually
git tag -a v1.2.0-test1 -m "Test release"
git push origin v1.2.0-test1
Contributors can test locally but cannot push test tags to the repository.
Automation Tools¶
Use scripts/release.sh for fully automated releases (no AI agent required):
scripts/release.sh minor # Create minor version release
scripts/release.sh patch # Create patch version release
scripts/release.sh major # Create major version release
The /release skill is also available for AI-assisted releases via Claude Code.
The automated script also runs scripts/sync_release_versions.py so the
normal and OpenShell container defaults, pinned container examples, and root
README release image references move to the new stable version together. The
script fails if one of those active references is missing. CI repeats the
guard with:
Note: Only maintainers should push release tags.
Tag Monitoring¶
The tag-monitor.yml workflow provides additional security:
- Logs all tag creation events
- Verifies authorization for production tags
- Creates security issues for unauthorized attempts
- Provides audit trail
Protected via CODEOWNERS:
- .github/workflows/publish.yml - Production PyPI publishing
- .github/workflows/publish-test.yml - TestPyPI publishing
- .github/workflows/tag-monitor.yml - Tag creation monitoring
- RELEASING.md - This file
Changes to these files require maintainer approval.
Version Numbering¶
We follow Semantic Versioning (MAJOR.MINOR.PATCH):
- MAJOR: Breaking changes (incompatible API changes)
- MINOR: New features (backward compatible)
- PATCH: Bug fixes (backward compatible)
- Development: X.Y.Z-dev (on main branch)
Examples:
- 1.0.0 - First stable release
- 1.1.0 - Added new features
- 1.1.1 - Bug fixes only
- 1.2.0-dev - Development version on main branch
Branch Strategy¶
Main Branches¶
- main: Active development branch (latest features, version X.Y.0-dev)
- release-X.Y: Release branches (e.g., release-1.0, release-1.1)
- hotfix-X.Y.Z: Hotfix branches for critical fixes to released versions
Tags¶
- vX.Y.Z: Git tags for each release (e.g., v1.0.0, v1.0.1, v1.1.0)
Branch Lifecycle¶
main (v1.1.0-dev)
|
|--- release-1.0 (created from main when ready for v1.0.0)
| |
| |--- v1.0.0 (tagged after testing)
| |
| |--- cherry-pick fix from main (preferred for patch releases)
| | |
| | |--- v1.0.1 (tagged on release-1.0)
| |
| |--- (if release-1.0 deleted) hotfix-1.0.2 (created from v1.0.1 tag)
| |
| |--- v1.0.2 (tagged after fix)
|
|--- release-1.1 (created from main when ready for v1.1.0)
|
|--- v1.1.0 (tagged after testing)
Release Workflow¶
Prerequisites¶
- All features for the release are merged to
main - All tests pass on
main - CHANGELOG.md is up-to-date in the Unreleased section
- GitHub issues for the release are complete
Cursor Hook Compatibility Verification¶
Before creating the release branch, verify that Cursor still supports hooks via ~/.cursor/hooks.json. The /release skill automates this check as a mandatory gate.
If running manually:
1. Run: python .claude/skills/release/release_helper.py cursor-verify-setup
2. Perform manual Cursor test (see instructions printed by setup)
3. Run: python .claude/skills/release/release_helper.py cursor-verify-analyze
4. Run: python .claude/skills/release/release_helper.py cursor-verify-cleanup
If any hook event fails, investigate before proceeding with the release.
Step-by-Step Release Process¶
1. Create Release Branch¶
# Ensure main is up-to-date
git checkout main
git pull origin main
# Create release branch (e.g., release-1.0)
git checkout -b release-1.0 main
# Push release branch
git push -u origin release-1.0
2. Update Version Numbers¶
Update version in pyproject.toml:
Update version in src/ai_guardian/init.py:
Commit the version bump:
git add pyproject.toml
git commit -m "$(cat <<'EOF'
chore: bump version to 1.0.0 for release
Prepare for v1.0.0 release:
- Update version in pyproject.toml
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
EOF
)"
3. Update CHANGELOG.md¶
Move Unreleased section entries to a new version section:
## [1.0.0] - 2025-01-15
### Added
- Initial stable release
- [List of features added]
### Changed
- [List of changes]
### Fixed
- [List of bug fixes]
[1.0.0]: https://github.com/RedHatProductSecurity/ai-guardian/releases/tag/v1.0.0
Commit the changelog:
git add CHANGELOG.md
git commit -m "$(cat <<'EOF'
docs: update CHANGELOG.md for v1.0.0 release
Move unreleased items to v1.0.0 section with release date.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
EOF
)"
4. Run Tests and Final Validation¶
# Run full test suite (if tests exist)
pytest
# Verify version command
python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])"
# Test installation in clean environment
python -m venv /tmp/test-ai-guardian-install
source /tmp/test-ai-guardian-install/bin/activate
pip install .
ai-guardian --help
deactivate
rm -rf /tmp/test-ai-guardian-install
5. Push Release Branch¶
6. Create Git Tag¶
# Create annotated tag
git tag -a v1.0.0 -m "Release version 1.0.0
See CHANGELOG.md for details.
"
# Push tag to remote - this triggers the GitHub Actions publish workflow
git push origin v1.0.0
Important: Pushing the tag will automatically trigger two GitHub Actions workflows:
1. Publish Package — builds and publishes to PyPI, creates a GitHub Release
2. Build Container Images — builds and pushes the normal image to
quay.io/redhatproductsecurity/ai-guardian:<version> and the dedicated
OpenShell image to quay.io/redhatproductsecurity/ai-guardian-openshell:<version>
The Read the Docs GitHub integration also builds the activated version tag. This requires the one-time SemVer tag activation rule described above.
Note: :latest tracks the main branch (updated on every merge), not releases,
in both primary Quay repositories. The OpenShell image has its own repository;
it is not represented by an openshell tag in the normal image repository.
7. Verify GitHub Actions Workflows¶
After pushing the tag:
- Go to GitHub Actions: https://github.com/RedHatProductSecurity/ai-guardian/actions
- Check the "Publish Package" workflow run — verify it completes successfully
- Check the "Build Container Image" workflow run — verify it completes successfully
- Check PyPI: https://pypi.org/project/ai-guardian/
- Check GitHub Releases: https://github.com/RedHatProductSecurity/ai-guardian/releases
- Verify the versioned container image on quay.io:
podman pull quay.io/redhatproductsecurity/ai-guardian:<version> podman run -it quay.io/redhatproductsecurity/ai-guardian:<version> ai-guardian --version podman pull quay.io/redhatproductsecurity/ai-guardian-openshell:<version> podman run --rm --entrypoint /usr/local/bin/claude \ quay.io/redhatproductsecurity/ai-guardian-openshell:<version> --version - Verify the versioned documentation at
https://ai-guardian.readthedocs.io/en/v<version>/
If the workflow fails, you may need to:
- Fix the issue
- Delete the tag: git tag -d v1.0.0 && git push origin :refs/tags/v1.0.0
- Increment the patch version and try again
8. Update Install URLs in README.md¶
The README.md contains curl install commands that reference a specific git ref for install.sh and install.ps1. These URLs must point to the correct ref depending on the branch:
- Release branches (
release-X.Y): URLs point to the release tag (e.g.,v1.11.1) so users install the exact released version - Main branch: URLs point to
mainsince there is no PyPI release for the dev version — developers browsing main get the latest install script
On the release branch (already done during the release):
# Replace all occurrences of the old version tag with the new one
# e.g., v1.11.0 → v1.11.1
sed -i '' 's/v1.0.0/v1.1.0/g' README.md # macOS
On main (during merge-back):
# Ensure main's README points to main, not a version tag
# This should already be the case if main was set up correctly
grep 'raw.githubusercontent.com' README.md
# Should show: .../main/install.sh and .../main/install.ps1
Why this convention? - Release branches serve stable users who want a known-good version - Main serves developers who want the latest code - There is no PyPI package for dev versions, so a version tag URL on main would be misleading
9. Merge Back to Main and Bump Dev Version¶
# Switch to main
git checkout main
# Cherry-pick CHANGELOG update (NOT full merge — avoids version conflicts)
# For patch releases where main already has all the code changes:
git cherry-pick <changelog-commit-sha> # Or manually add the version section
# For minor/major releases, merge the release branch:
git merge release-1.0 --no-ff -m "Merge release-1.0 into main"
# Bump version to next dev cycle in pyproject.toml
# Update version to "1.1.0-dev"
Edit pyproject.toml:
Commit and push:
git add pyproject.toml
git commit -m "$(cat <<'EOF'
chore: bump version to 1.1.0-dev
Begin development cycle for v1.1.0.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
EOF
)"
# Push to remote
git push origin main
Patch / Hotfix Workflow¶
When to Use¶
Use patch releases for: - Critical bugs in production releases - Security vulnerabilities - Data corruption issues - Severe performance problems
Do NOT use patch releases for: - Minor bugs (wait for next minor release) - New features - Refactoring
Which Approach to Use¶
| Situation | Approach |
|---|---|
Minor release branch (release-x.y) still exists |
Preferred: Apply fix on release-x.y directly |
| Minor release branch deleted | Create hotfix-x.y.z from last release tag |
| Emergency fix, no time to cherry-pick | Create hotfix-x.y.z from last release tag |
Preferred: Patch on Existing Release Branch¶
When the release-x.y branch still exists, apply the patch fix there directly instead of creating a separate hotfix branch.
1. Switch to the Release Branch¶
2. Apply the Fix¶
Cherry-pick the fix from main, or make the fix directly on the release branch:
# Option A: Cherry-pick from main (preferred when fix already merged to main)
git cherry-pick <commit-sha-of-the-fix>
# Option B: Make the fix directly on the release branch
# Make your fixes, write tests
pytest
git add <files>
git commit -m "$(cat <<'EOF'
fix: critical bug in permission validation
Fixes timeout issue when validating MCP permissions.
Fixes: #123
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
EOF
)"
3. Update Version Numbers¶
Update to patch version in pyproject.toml:
Update to patch version in src/ai_guardian/init.py:
4. Update CHANGELOG.md¶
Add a new section for the patch:
## [1.0.1] - 2025-01-20
### Fixed
- Critical timeout issue in permission validation (#123)
[1.0.1]: https://github.com/RedHatProductSecurity/ai-guardian/releases/tag/v1.0.1
5. Tag and Release¶
# Create tag on the release branch
git tag -a v1.0.1 -m "Patch release 1.0.1
Critical fix for permission validation timeout.
"
# Push release branch and tag
git push origin release-1.0
git push origin v1.0.1
The GitHub Actions workflow will automatically publish to PyPI and create a release.
6. Cherry-pick to Main¶
# Cherry-pick the fix to main (if not already there)
git checkout main
git cherry-pick <commit-sha-of-the-fix> # Only the fix commit, not version bumps
git push origin main
Fallback: Hotfix Branch from Tag¶
When the release-x.y branch has been deleted or in emergencies, create a hotfix branch from the last release tag.
1. Create Hotfix Branch¶
2. Fix the Bug¶
Make the necessary code changes to fix the critical bug.
# Make your fixes
# Write tests to verify the fix
pytest
# Commit the fix
git add <files>
git commit -m "$(cat <<'EOF'
fix: critical bug in permission validation
Fixes timeout issue when validating MCP permissions.
Fixes: #123
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
EOF
)"
3. Update Version Numbers¶
Update to patch version in pyproject.toml:
Update to patch version in src/ai_guardian/init.py:
4. Update CHANGELOG.md¶
Add a new section for the hotfix:
## [1.0.1] - 2025-01-20
### Fixed
- Critical timeout issue in permission validation (#123)
[1.0.1]: https://github.com/RedHatProductSecurity/ai-guardian/releases/tag/v1.0.1
5. Tag and Release¶
# Create tag
git tag -a v1.0.1 -m "Hotfix release 1.0.1
Critical fix for permission validation timeout.
"
# Push hotfix branch and tag
git push origin hotfix-1.0.1
git push origin v1.0.1
The GitHub Actions workflow will automatically publish to PyPI and create a release.
6. Merge Back and Clean Up¶
# Cherry-pick the fix to main (NOT merge the version bumps)
git checkout main
git cherry-pick <commit-sha-of-the-fix> # Only the fix commit, not version bumps
git push origin main
# Delete hotfix branch
git branch -d hotfix-1.0.1
git push origin --delete hotfix-1.0.1
Release Checklist¶
Use this checklist for each release:
Pre-Release¶
- [ ] All planned features merged to
main - [ ] All tests pass (
pytest) - [ ] CHANGELOG.md updated with all changes
- [ ] Version bump PR reviewed and approved
- [ ] GitHub issues marked as complete
- [ ] Cursor hook compatibility verified (
/releaseautomates this)
Release Branch¶
- [ ] Create release branch (
release-X.Y) - [ ] Update version in
pyproject.toml(remove-dev) - [ ] Synchronize stable container references (
python scripts/sync_release_versions.py --stable-version X.Y.Z) - [ ] Update CHANGELOG.md (move Unreleased to version section)
- [ ] Run full test suite
- [ ] Test installation in clean environment
- [ ] Push release branch
- [ ] Create and push git tag (
vX.Y.Z)
GitHub Actions & Release¶
- [ ] Verify GitHub Actions workflow completes successfully
- [ ] Verify package published to PyPI
- [ ] Verify GitHub Release created
- [ ] Test installation from PyPI:
uv tool install ai-guardian(orpip install ai-guardian) - [ ] Verify
quay.io/redhatproductsecurity/ai-guardian:<version>is available - [ ] Verify
quay.io/redhatproductsecurity/ai-guardian-openshell:<version>is available - [ ] Verify versioned documentation published on Read the Docs
Post-Release¶
- [ ] Merge release branch back to
main - [ ] Bump version to next dev cycle (
X.Y+1.0-dev) - [ ] Announce release (if applicable)
Patch / Hotfix (if needed)¶
- [ ] Check if
release-x.ybranch exists (preferred) or createhotfix-x.y.zfrom tag (fallback) - [ ] Apply fix (cherry-pick from main or fix directly)
- [ ] Update version to patch level
- [ ] Update CHANGELOG.md
- [ ] Create and push tag
- [ ] Verify GitHub Actions completes
- [ ] Cherry-pick fix to
main(if not already there) - [ ] (Hotfix branch only) Delete hotfix branch after merge
Version Infrastructure¶
Version Storage¶
Version number is stored in two locations that must be kept in sync:
-
pyproject.toml - Package metadata
-
src/ai_guardian/init.py - Runtime version
Important: Always update both files when bumping versions.
This uses the modern Python packaging standard (PEP 621) with hatchling as the build backend.
Active Stable Release References¶
The two package files above are the runtime/package version. main continues
to use a -dev package version, so stable container fallbacks and pinned
examples are maintained separately in:
container/Dockerfilecontainer/Dockerfile.openshellcontainer/README.mdREADME.mddocs/notebooklm-export.md
Do not update historical examples or changelog entries. For a release, run the
project synchronizer with the new stable version; after merge-back, use its
--check mode to confirm the references still match the latest stable
CHANGELOG.md heading.
Version Display¶
Users can check the version using:
Development Versions¶
Development versions on main branch always have the -dev suffix:
- 1.0.0-dev - Developing towards v1.0.0
- 1.1.0-dev - Developing towards v1.1.0
This helps distinguish development builds from stable releases.
GitHub Actions CI/CD¶
Workflows¶
The repository includes four GitHub Actions workflows:
- test.yml - Runs tests on Python 3.9, 3.10, 3.11, 3.12
- Triggered on: push to main, pull requests
-
Includes coverage reporting
-
lint.yml - Runs code quality checks (pylint, black, ruff)
-
Triggered on: pull requests
-
publish-test.yml - Publishes to TestPyPI for testing (see Testing Releases with TestPyPI)
- Triggered on: test tags (v-test), manual workflow dispatch
-
Requires: TestPyPI trusted publishing configured
-
publish.yml - Publishes to PyPI and creates GitHub Release
- Triggered on: version tags (v*)
- Requires: PyPI trusted publishing configured
Ubuntu Runner Policy¶
All Linux release-readiness, wheel, PyPI, and container publishing jobs are
pinned to ubuntu-24.04. This keeps release artifacts and trusted-publishing
jobs independent of the moving ubuntu-latest image label. The
.github/workflows/ubuntu-26-compatibility.yml workflow separately exercises
Python 3.9 on the pinned Ubuntu baseline and Python 3.10 through 3.14,
scanners, smoke tests, scenario containers, Docker Buildx, and QEMU on
ubuntu-26.04; release readiness invokes it as a migration gate while normal
release and publishing jobs remain pinned. Python 3.9 remains on the baseline
because the current setup-python version manifest does not provide it for
Ubuntu 26.04.
Setting Up PyPI Trusted Publishing¶
To enable automatic PyPI publishing:
- Go to PyPI project settings: https://pypi.org/manage/project/ai-guardian/settings/
- Navigate to "Publishing" section
- Add a new publisher:
- PyPI Project Name: ai-guardian
- Owner: itdove (your GitHub org/user)
- Repository: ai-guardian
- Workflow: publish.yml
- Environment: (leave blank)
This allows GitHub Actions to publish without storing API tokens.
Setting Up TestPyPI Trusted Publishing¶
To enable automatic TestPyPI publishing for testing (recommended):
- Create TestPyPI account: https://test.pypi.org/account/register/
- Verify your email address
- Go to TestPyPI publishing settings: https://test.pypi.org/manage/account/publishing/
- Click "Add a new pending publisher"
- Configure publisher:
- PyPI Project Name: ai-guardian
- Owner: itdove (your GitHub org/user)
- Repository: ai-guardian
- Workflow: publish-test.yml
- Environment: testpypi
- Create GitHub environment at https://github.com/RedHatProductSecurity/ai-guardian/settings/environments:
- Name:
testpypi - (Optional) Add protection rules
See Testing Releases with TestPyPI for detailed usage instructions.
Testing Releases with TestPyPI¶
Before publishing to production PyPI, you can test the entire release process using TestPyPI.
Why TestPyPI?¶
Benefits: - ✅ Test the entire release process without touching production - ✅ Verify PyPI Trusted Publishing configuration works - ✅ Catch packaging/metadata issues early - ✅ Safe experimentation with workflow changes - ✅ Standard best practice for Python projects
Prerequisites¶
1. TestPyPI Account¶
Create an account at https://test.pypi.org/account/register/ and verify your email.
2. Configure Trusted Publishing on TestPyPI¶
- Go to https://test.pypi.org/manage/account/publishing/
- Click "Add a new pending publisher"
- Configure publisher settings:
- PyPI Project Name:
ai-guardian - Owner:
itdove - Repository name:
ai-guardian - Workflow name:
publish-test.yml - Environment name:
testpypi - Save configuration
3. Create GitHub Environment¶
- Go to https://github.com/RedHatProductSecurity/ai-guardian/settings/environments
- Click "New environment"
- Name:
testpypi - (Optional) Add protection rules:
- Required reviewers: yourself
- Deployment branches: only
release-*branches - Save environment
Testing a Release¶
Step 1: Create Test Release Branch¶
# Update main branch
git checkout main
git pull origin main
# Create test release branch
git checkout -b release-1.2-test main
Step 2: Update Version to Test Version¶
Update version in pyproject.toml:
Update version in src/ai_guardian/init.py:
Commit changes:
git add pyproject.toml src/ai_guardian/__init__.py
git commit -m "$(cat <<'EOF'
chore: bump version to 1.2.0-test1 for TestPyPI
Prepare test release for TestPyPI to verify release process.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
EOF
)"
Step 3: Create and Push Test Tag¶
# Create test tag
git tag -a v1.2.0-test1 -m "Test release for TestPyPI
Testing release process before production release.
"
# Push tag to trigger workflow
git push origin v1.2.0-test1
Note: The tag MUST match the pattern v*-test* to trigger the TestPyPI workflow.
Step 4: Monitor GitHub Actions¶
- Go to https://github.com/RedHatProductSecurity/ai-guardian/actions
- Check the "Publish to TestPyPI" workflow run
- Verify it completes successfully
Step 5: Verify TestPyPI Publication¶
- Check TestPyPI: https://test.pypi.org/project/ai-guardian/
- Verify the test version appears (e.g., 1.2.0-test1)
Step 6: Test Installation from TestPyPI¶
# Create clean test environment
python -m venv /tmp/test-ai-guardian-testpypi
source /tmp/test-ai-guardian-testpypi/bin/activate
# Install from TestPyPI
# Note: --extra-index-url allows installing dependencies from production PyPI
pip install --index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple/ \
ai-guardian==1.2.0-test1
# Test the package
ai-guardian --version
ai-guardian --help
# Clean up
deactivate
rm -rf /tmp/test-ai-guardian-testpypi
Step 7: Proceed with Production Release (if successful)¶
If the TestPyPI release works correctly:
-
Delete test tag and branch:
-
Follow the normal Release Workflow to create production release
Tag Naming Convention¶
- TestPyPI:
v1.2.0-test,v1.2.0-test1,v1.2.0-test2 - Pattern:
v*-test*triggers TestPyPI workflow -
Use sequential numbers for multiple test attempts
-
Production PyPI:
v1.2.0,v1.2.1,v1.3.0 - Pattern:
v*(without-testsuffix) triggers production workflow - Only create after TestPyPI validation succeeds
Manual Workflow Trigger¶
You can also trigger the TestPyPI workflow manually without creating a tag:
- Go to https://github.com/RedHatProductSecurity/ai-guardian/actions/workflows/publish-test.yml
- Click "Run workflow"
- Select the branch you want to test
- Click "Run workflow" button
This is useful for testing workflow changes without creating tags.
Troubleshooting¶
Workflow fails with authentication error:
- Verify TestPyPI Trusted Publishing is configured correctly
- Check that the GitHub environment testpypi exists
- Ensure workflow name matches: publish-test.yml
Package upload fails:
- Verify version number is unique (TestPyPI doesn't allow re-uploading same version)
- Increment test number (e.g., v1.2.0-test2)
Installation from TestPyPI fails:
- TestPyPI may not have all dependencies
- Use --extra-index-url https://pypi.org/simple/ to fetch dependencies from production PyPI
Manual PyPI Publishing¶
If you need to publish manually (without GitHub Actions):
1. Install Build Tools¶
2. Build Distribution Packages¶
3. Test on TestPyPI (Optional)¶
# Upload to TestPyPI
python -m twine upload --repository testpypi dist/*
# Test installation
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple ai-guardian
4. Publish to Production PyPI¶
Note: You'll need PyPI credentials configured in ~/.pypirc or via TWINE_USERNAME and TWINE_PASSWORD environment variables. See PyPI publishing docs for details.