diff --git a/RELEASE.md b/RELEASE.md index 3b85a05..43eb05d 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -16,7 +16,7 @@ This document describes the steps to create a new release of NanoFed. make release-prepare version= # e.g., make release-prepare version=0.1.3 ``` This script will: - - Validate the version format + - Update the library version in `pyproject.toml` - Run all tests - Check types - Run linting @@ -25,44 +25,32 @@ This document describes the steps to create a new release of NanoFed. ## Release Steps -1. **Generate Changelog and Release Notes** +The release process is automated via a single command after the pre-release checks: - ```bash - python scripts/changelog.py v # e.g., python scripts/changelog.py v0.1.3 - ``` +```bash +make release +``` -2. **Review and Edit Release Notes** +This command will: + +1. Validate that you're on the main branch with a clean working directory +2. Generate the changelog automatically +3. Pause for you to review and edit the release notes: - Edit `docs/source/release_notes/v.rst` - - Review/edit the generated `CHANGELOG.md` - Add any additional notes, breaking changes, or important updates +4. Commit all changes +6. Create and push the version tag -3. **Commit Changes** +### Next Steps - ```bash - git add pyproject.toml CHANGELOG.md docs/source/release_notes - git commit -m "chore: prepare release v" - ``` +After running `make release`, you should: -4. **Create and Push Tag** - - ```bash - git tag -a v -m "Release v" - git push origin main - git push origin v - ``` +1. Wait for CI to compelte +2. Monitor PyPI release +3. Verify documentation update ## Troubleshooting -### Version Mismatch - -If you get a version mismatch error in GitHub Actions: - -```bash -git push origin --delete v # Delete remote tag -git tag -d # Delete local tag -# Then repeats 3-4 from Release Steps -``` - ### PyPi Upload Issues - Versions can never be reused on PyPi, even if deleted diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100644 index 0000000..e1fecaf --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,97 @@ +#!/bin/bash +set -eou pipefail + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +step() { + echo -e "${GREEN}==>${NC} $1" +} + +error() { + echo -e "${RED}Error: $1${NC}" >&2 + exit 1 +} + +# Check if command exists +check_command() { + if ! command -v "$1" >/dev/null 2>&1; then + error "Required command '$1' not found" + fi +} + +validate_requirements() { + check_command git + check_command poetry + check_command python + + current_branch=$(git branch --show-current) + if [ "$current_branch" != "main" ]; then + error "Must be on main branch to release (currently on '$current_branch')" + fi + + # Check for clean working directory + if [ -n "$(git status --porcelain)" ]; then + error "Working directory must be clean" + fi + + step "Pulling latest changes from main..." + git pull origin main +} + +get_version() { + poetry version --short +} + +check_release_notes() { + local version=$1 + local release_notes="docs/source/release_notes/v${version}.rst" + + if [ ! -f "$release_notes" ]; then + error "Release notes file not found: $release_notes" + fi + + local notes_time=$(stat -f %m "$release_notes" 2>/dev/null || stat -c %Y "$release_notes") + local changelog_time=$(stat -f %m "CHANGELOG.md" 2>/dev/null || stat -c %Y "CHANGELOG.md") + + if [ "$notes_time" -lt "$changelog_time" ]; then + error "Release notes must be updated after changelog generation" + fi +} + +main() { + step "Validating requirements..." + validate_requirements + + VERSION=$(get_version) + step "Preparing release for version v${VERSION}" + + step "Generating changelog..." + python scripts/changelog.py "v${VERSION}" + + echo -e "\n${YELLOW}Please review and update the release notes now:${NC}" + echo " docs/source/release_notes/v${VERSION}.rst" + echo -e "${YELLOW}Press Enter once you've reviewed the updated release notes...${NC}" + read -r + + step "Verifying release notes..." + check_release_notes "$VERSION" + + step "Committing changes..." + git add . + git commit -m "chore: prepare release v${VERSION}" + + step "Creating and pushing tag..." + git tag -a "v${VERSION}" -m "Release v${VERSION}" + git push origin main + + echo -e "\n${GREEN}Release v${VERSION} has been prepared and pushed!${NC}" + echo -e "\nNext steps:" + echo "1. Wait for CI to complete" + echo "2. Monitor PyPI release" + echo "3. Verify documentation update" +} + +main "$@"