From 21059be0c857d833f4bed68fe15df120f8f8b9bf Mon Sep 17 00:00:00 2001 From: Jon Myers Date: Mon, 8 Sep 2025 13:42:28 -0400 Subject: [PATCH 01/10] feat: implement automated version bumping and PyPI publishing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add python-semantic-release with patch-only configuration - Create GitHub Actions workflows for PR testing and automated releases - Configure OIDC trusted publishing for PyPI (no API tokens needed) - Update CLAUDE.md with complete automation documentation - All commits now auto-increment patch version (0.1.14 → 0.1.15) - Manual control available for minor/major bumps when needed Resolves #14 --- .github/workflows/release.yml | 85 +++++++++++++ .github/workflows/test-pr.yml | 69 +++++++++++ CLAUDE.md | 87 ++++++++++++- Pipfile.lock | 226 +++++++++++++++++----------------- pyproject.toml | 32 ++++- 5 files changed, 379 insertions(+), 120 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/test-pr.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..c563fc4 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,85 @@ +name: Automated Release + +on: + push: + branches: [ main ] + +jobs: + release: + runs-on: ubuntu-latest + concurrency: release + permissions: + id-token: write # OIDC for PyPI trusted publishing + contents: write # Create releases and tags + actions: write # Update workflow permissions if needed + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Needed for semantic-release to work properly + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e .[dev] + + - name: Check if version bump is needed + id: release-check + run: | + # Check if there are commits since last tag that would trigger a release + echo "Checking for version bump..." + NEW_VERSION=$(semantic-release version --print --no-commit --no-tag --no-push --no-vcs-release 2>/dev/null || echo "") + if [ "$NEW_VERSION" != "" ]; then + echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "should_release=true" >> $GITHUB_OUTPUT + echo "New version will be: $NEW_VERSION" + else + echo "should_release=false" >> $GITHUB_OUTPUT + echo "No version bump needed" + fi + + - name: Run tests + if: steps.release-check.outputs.should_release == 'true' + run: | + echo "Running tests before release..." + pytest idtap/tests/ + + - name: Configure git + if: steps.release-check.outputs.should_release == 'true' + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + + - name: Bump version and create release + if: steps.release-check.outputs.should_release == 'true' + run: | + echo "Creating release for version: ${{ steps.release-check.outputs.new_version }}" + semantic-release version + + - name: Build package + if: steps.release-check.outputs.should_release == 'true' + run: | + echo "Building package..." + python -m build + + - name: Publish to PyPI + if: steps.release-check.outputs.should_release == 'true' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + # Using trusted publishing - no username/password needed + # PyPI trusted publisher must be configured for this repo + print-hash: true + + - name: Output release info + if: steps.release-check.outputs.should_release == 'true' + run: | + echo "🎉 Successfully released version ${{ steps.release-check.outputs.new_version }}" + echo "📦 Package published to PyPI: https://pypi.org/project/idtap/${{ steps.release-check.outputs.new_version }}/" + echo "🏷️ GitHub release created with tag: v${{ steps.release-check.outputs.new_version }}" \ No newline at end of file diff --git a/.github/workflows/test-pr.yml b/.github/workflows/test-pr.yml new file mode 100644 index 0000000..3b452a3 --- /dev/null +++ b/.github/workflows/test-pr.yml @@ -0,0 +1,69 @@ +name: Test PR + +on: + pull_request: + branches: [ main ] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Needed for semantic-release + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e .[dev] + + - name: Run tests + run: pytest idtap/tests/ + + - name: Build package + run: python -m build + + - name: Test semantic-release dry run + run: | + semantic-release version --print --no-commit --no-tag --no-push --no-vcs-release || echo "No version bump needed" + + - name: Test upload to TestPyPI + if: github.event.pull_request.head.repo.full_name == github.repository + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ + skip-existing: true + password: ${{ secrets.TESTPYPI_API_TOKEN }} + + - name: Comment PR with TestPyPI link + if: github.event.pull_request.head.repo.full_name == github.repository + uses: actions/github-script@v7 + with: + script: | + const prNumber = context.issue.number; + const testPypiUrl = `https://test.pypi.org/project/idtap/`; + + github.rest.issues.createComment({ + issue_number: prNumber, + owner: context.repo.owner, + repo: context.repo.repo, + body: `📦 **Test Package Built Successfully!** + + This PR has been automatically built and uploaded to TestPyPI for testing. + + 🔗 **TestPyPI Link**: ${testPypiUrl} + + To test this version: + \`\`\`bash + pip install --index-url https://test.pypi.org/simple/ idtap + \`\`\` + + ✅ All tests passed and package builds successfully.` + }); \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index ac0df62..762648e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,7 +16,10 @@ The Python API (`idtap`) is a sophisticated client library for interacting with - **Integration tests**: `python python/api_testing/api_test.py` (requires live server auth) - Test structure: Complete coverage of data models, client functionality, and authentication -### Build/Package/Publish +### Build/Package/Publish - AUTOMATED via GitHub Actions +**⚠️ IMPORTANT: Manual publishing is now automated. See "Automated Version Management" section below.** + +Manual publishing (for local testing only): ```bash python -m build python -m twine upload dist/* # or --repository testpypi for testing @@ -86,12 +89,84 @@ python/idtap/ - **Multi-instrument**: Sitar, Vocal (Male/Female) with instrument-specific features - **Analytical Tools**: Trajectory categorization, phrase grouping, temporal analysis -## Development Workflow +## Automated Version Management & Publishing + +### 🤖 How It Works (python-semantic-release + GitHub Actions) + +**PATCH-ONLY MODE**: All commits automatically increment patch version (0.1.14 → 0.1.15) regardless of commit message. + +#### Automatic Workflow +1. **Make changes** → Commit with any message +2. **Create PR** → GitHub Actions test + upload to TestPyPI automatically +3. **Merge to main** → Version bumps + PyPI published + GitHub release created +4. **Zero manual intervention** required! + +#### Version Locations (Auto-Updated) +- `idtap/__init__.py:3` - `__version__ = "0.1.14"` +- `pyproject.toml:7` - `version = "0.1.14"` +- `docs/conf.py:16-17` - `release = '0.1.14'` and `version = '0.1.14'` + +### 🎛️ Manual Version Control Commands + +**For normal development (patch bumps)**: +```bash +# Any commit message works - always bumps patch +git commit -m "fix something" # 0.1.14 → 0.1.15 +git commit -m "add new feature" # 0.1.14 → 0.1.15 +git commit -m "update docs" # 0.1.14 → 0.1.15 +``` + +**When Jon wants to control version bumps manually**: +```bash +# Force minor version bump (0.1.15 → 0.2.0) +semantic-release version --increment minor + +# Force major version bump (0.2.0 → 1.0.0) +semantic-release version --increment major + +# Dry run to see what would happen +semantic-release version --print --no-commit --no-tag --no-push --no-vcs-release +``` + +### 🔧 Configuration Details + +**Location**: `pyproject.toml` `[tool.semantic_release]` section +- **patch_tags**: ALL commit types → patch version increment +- **minor_tags**: `[]` (empty - no automatic minor bumps) +- **major_tags**: `[]` (empty - no automatic major bumps) +- **Files updated**: `__init__.py`, `pyproject.toml`, `docs/conf.py` + +### 🚀 GitHub Actions Workflows + +**`.github/workflows/test-pr.yml`**: +- Runs on every PR +- Tests + builds package + uploads to TestPyPI +- Comments PR with TestPyPI install link + +**`.github/workflows/release.yml`**: +- Runs on merge to main +- Tests → version bump → build → PyPI publish → GitHub release + +### 📋 Required Setup (One-Time) + +**GitHub Secrets**: +- `TESTPYPI_API_TOKEN` - For PR testing uploads + +**PyPI Trusted Publisher** (configured): +- Owner: `UCSC-IDTAP` +- Repository: `Python-API` +- Workflow: `release.yml` +- Uses OIDC - no API tokens needed for production PyPI + +**⚠️ CLAUDE: When Jon asks to update version in special way, use the manual commands above!** + +## Development Workflow (Updated for Automation) 1. **Data Model Development**: Create/modify classes in `/classes/` with proper serialization -2. **Client Method Development**: Add HTTP methods in `client.py` with authentication -3. **Testing**: Write unit tests (mocked) + integration tests (live API) -4. **Sync Dependencies**: Update both `Pipfile` and `pyproject.toml` -5. **Build/Test/Publish**: Use standard Python packaging tools +2. **Client Method Development**: Add HTTP methods in `client.py` with authentication +3. **Testing**: Write unit tests (mocked) + integration tests (live API) +4. **PR Creation**: GitHub Actions automatically test + upload to TestPyPI +5. **Merge to main**: Automatic version bump + PyPI publish + GitHub release +6. **No manual version management needed!** ## Installation Commands ```bash diff --git a/Pipfile.lock b/Pipfile.lock index 4467f71..a44a0cd 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -201,55 +201,55 @@ }, "cryptography": { "hashes": [ - "sha256:00e8724bdad672d75e6f069b27970883179bd472cd24a63f6e620ca7e41cc0c5", - "sha256:048e7ad9e08cf4c0ab07ff7f36cc3115924e22e2266e034450a890d9e312dd74", - "sha256:0d9ef57b6768d9fa58e92f4947cea96ade1233c0e236db22ba44748ffedca394", - "sha256:18f878a34b90d688982e43f4b700408b478102dd58b3e39de21b5ebf6509c301", - "sha256:1b7fa6a1c1188c7ee32e47590d16a5a0646270921f8020efc9a511648e1b2e08", - "sha256:20ae4906a13716139d6d762ceb3e0e7e110f7955f3bc3876e3a07f5daadec5f3", - "sha256:20d15aed3ee522faac1a39fbfdfee25d17b1284bafd808e1640a74846d7c4d1b", - "sha256:2384f2ab18d9be88a6e4f8972923405e2dbb8d3e16c6b43f15ca491d7831bd18", - "sha256:275ba5cc0d9e320cd70f8e7b96d9e59903c815ca579ab96c1e37278d231fc402", - "sha256:2dac5ec199038b8e131365e2324c03d20e97fe214af051d20c49db129844e8b3", - "sha256:31a2b9a10530a1cb04ffd6aa1cd4d3be9ed49f7d77a4dafe198f3b382f41545c", - "sha256:3436128a60a5e5490603ab2adbabc8763613f638513ffa7d311c900a8349a2a0", - "sha256:3b5bf5267e98661b9b888a9250d05b063220dfa917a8203744454573c7eb79db", - "sha256:3de77e4df42ac8d4e4d6cdb342d989803ad37707cf8f3fbf7b088c9cbdd46427", - "sha256:44647c5d796f5fc042bbc6d61307d04bf29bccb74d188f18051b635f20a9c75f", - "sha256:550ae02148206beb722cfe4ef0933f9352bab26b087af00e48fdfb9ade35c5b3", - "sha256:599c8d7df950aa68baa7e98f7b73f4f414c9f02d0e8104a30c0182a07732638b", - "sha256:5b64e668fc3528e77efa51ca70fadcd6610e8ab231e3e06ae2bab3b31c2b8ed9", - "sha256:5bd6020c80c5b2b2242d6c48487d7b85700f5e0038e67b29d706f98440d66eb5", - "sha256:5c966c732cf6e4a276ce83b6e4c729edda2df6929083a952cc7da973c539c719", - "sha256:629127cfdcdc6806dfe234734d7cb8ac54edaf572148274fa377a7d3405b0043", - "sha256:705bb7c7ecc3d79a50f236adda12ca331c8e7ecfbea51edd931ce5a7a7c4f012", - "sha256:780c40fb751c7d2b0c6786ceee6b6f871e86e8718a8ff4bc35073ac353c7cd02", - "sha256:7a3085d1b319d35296176af31c90338eeb2ddac8104661df79f80e1d9787b8b2", - "sha256:826b46dae41a1155a0c0e66fafba43d0ede1dc16570b95e40c4d83bfcf0a451d", - "sha256:833dc32dfc1e39b7376a87b9a6a4288a10aae234631268486558920029b086ec", - "sha256:cc4d66f5dc4dc37b89cfef1bd5044387f7a1f6f0abb490815628501909332d5d", - "sha256:d063341378d7ee9c91f9d23b431a3502fc8bfacd54ef0a27baa72a0843b29159", - "sha256:e2a21a8eda2d86bb604934b6b37691585bd095c1f788530c1fcefc53a82b3453", - "sha256:e40b80ecf35ec265c452eea0ba94c9587ca763e739b8e559c128d23bff7ebbbf", - "sha256:e5b3dda1b00fb41da3af4c5ef3f922a200e33ee5ba0f0bc9ecf0b0c173958385", - "sha256:ea3c42f2016a5bbf71825537c2ad753f2870191134933196bee408aac397b3d9", - "sha256:eccddbd986e43014263eda489abbddfbc287af5cddfd690477993dbb31e31016", - "sha256:ee411a1b977f40bd075392c80c10b58025ee5c6b47a822a33c1198598a7a5f05", - "sha256:f4028f29a9f38a2025abedb2e409973709c660d44319c61762202206ed577c42", - "sha256:f68f833a9d445cc49f01097d95c83a850795921b3f7cc6488731e69bde3288da", - "sha256:fc022c1fa5acff6def2fc6d7819bbbd31ccddfe67d075331a65d9cfb28a20983" + "sha256:06ce84dc14df0bf6ea84666f958e6080cdb6fe1231be2a51f3fc1267d9f3fb34", + "sha256:16ede8a4f7929b4b7ff3642eba2bf79aa1d71f24ab6ee443935c0d269b6bc513", + "sha256:18fcf70f243fe07252dcb1b268a687f2358025ce32f9f88028ca5c364b123ef5", + "sha256:1993a1bb7e4eccfb922b6cd414f072e08ff5816702a0bdb8941c247a6b1b287c", + "sha256:1f3d56f73595376f4244646dd5c5870c14c196949807be39e79e7bd9bac3da63", + "sha256:258e0dff86d1d891169b5af222d362468a9570e2532923088658aa866eb11130", + "sha256:2f641b64acc00811da98df63df7d59fd4706c0df449da71cb7ac39a0732b40ae", + "sha256:3808e6b2e5f0b46d981c24d79648e5c25c35e59902ea4391a0dcb3e667bf7443", + "sha256:3994c809c17fc570c2af12c9b840d7cea85a9fd3e5c0e0491f4fa3c029216d59", + "sha256:3be4f21c6245930688bd9e162829480de027f8bf962ede33d4f8ba7d67a00cee", + "sha256:465ccac9d70115cd4de7186e60cfe989de73f7bb23e8a7aa45af18f7412e75bf", + "sha256:48c41a44ef8b8c2e80ca4527ee81daa4c527df3ecbc9423c41a420a9559d0e27", + "sha256:4a862753b36620af6fc54209264f92c716367f2f0ff4624952276a6bbd18cbde", + "sha256:4b1654dfc64ea479c242508eb8c724044f1e964a47d1d1cacc5132292d851971", + "sha256:4bd3e5c4b9682bc112d634f2c6ccc6736ed3635fc3319ac2bb11d768cc5a00d8", + "sha256:577470e39e60a6cd7780793202e63536026d9b8641de011ed9d8174da9ca5339", + "sha256:67285f8a611b0ebc0857ced2081e30302909f571a46bfa7a3cc0ad303fe015c6", + "sha256:7285a89df4900ed3bfaad5679b1e668cb4b38a8de1ccbfc84b05f34512da0a90", + "sha256:81823935e2f8d476707e85a78a405953a03ef7b7b4f55f93f7c2d9680e5e0691", + "sha256:8978132287a9d3ad6b54fcd1e08548033cc09dc6aacacb6c004c73c3eb5d3ac3", + "sha256:a20e442e917889d1a6b3c570c9e3fa2fdc398c20868abcea268ea33c024c4083", + "sha256:a24ee598d10befaec178efdff6054bc4d7e883f615bfbcd08126a0f4931c83a6", + "sha256:b04f85ac3a90c227b6e5890acb0edbaf3140938dbecf07bff618bf3638578cf1", + "sha256:b6a0e535baec27b528cb07a119f321ac024592388c5681a5ced167ae98e9fff3", + "sha256:bef32a5e327bd8e5af915d3416ffefdbe65ed975b646b3805be81b23580b57b8", + "sha256:bfb4c801f65dd61cedfc61a83732327fafbac55a47282e6f26f073ca7a41c3b2", + "sha256:c13b1e3afd29a5b3b2656257f14669ca8fa8d7956d509926f0b130b600b50ab7", + "sha256:c987dad82e8c65ebc985f5dae5e74a3beda9d0a2a4daf8a1115f3772b59e5141", + "sha256:ce7a453385e4c4693985b4a4a3533e041558851eae061a58a5405363b098fcd3", + "sha256:d0c5c6bac22b177bf8da7435d9d27a6834ee130309749d162b26c3105c0795a9", + "sha256:d97cf502abe2ab9eff8bd5e4aca274da8d06dd3ef08b759a8d6143f4ad65d4b4", + "sha256:dad43797959a74103cb59c5dac71409f9c27d34c8a05921341fb64ea8ccb1dd4", + "sha256:dd342f085542f6eb894ca00ef70236ea46070c8a13824c6bde0dfdcd36065b9b", + "sha256:de58755d723e86175756f463f2f0bddd45cc36fbd62601228a3f8761c9f58252", + "sha256:f3df7b3d0f91b88b2106031fd995802a2e9ae13e02c36c1fc075b43f420f3a17", + "sha256:f5414a788ecc6ee6bc58560e85ca624258a55ca434884445440a810796ea0e0b", + "sha256:fa26fa54c0a9384c27fcdc905a2fb7d60ac6e47d14bc2692145f2b3b1e2cfdbd" ], "index": "pypi", "markers": "python_version >= '3.7' and python_full_version not in '3.9.0, 3.9.1'", - "version": "==45.0.6" + "version": "==45.0.7" }, "dnspython": { "hashes": [ - "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", - "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1" + "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", + "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f" ], - "markers": "python_version >= '3.9'", - "version": "==2.7.0" + "markers": "python_version >= '3.10'", + "version": "==2.8.0" }, "docutils": { "hashes": [ @@ -294,12 +294,12 @@ }, "idtap": { "hashes": [ - "sha256:3358a6daea8932a65ff08f78bfe48ca3a1b05882188ae29b669045b88c573020", - "sha256:762aab1c4e8b0703850344d0d49a88177705d7d79a16050ff1f5829b84b69a30" + "sha256:3c8581b6a435e34ab3f17d95358b96c8c5b1b9c34355d3844c06e1f61fc940bb", + "sha256:5289b594d36ba90862c238618b9e92222ccd4fa5adecacfcbc6f27905af3d433" ], "index": "pypi", "markers": "python_version >= '3.10'", - "version": "==0.1.9" + "version": "==0.1.14" }, "jaraco.classes": { "hashes": [ @@ -319,11 +319,11 @@ }, "jaraco.functools": { "hashes": [ - "sha256:590486285803805f4b1f99c60ca9e94ed348d4added84b74c7a12885561e524e", - "sha256:be634abfccabce56fa3053f8c7ebe37b682683a4ee7793670ced17bab0087353" + "sha256:227ff8ed6f7b8f62c56deff101545fa7543cf2c8e7b82a7c2116e672f29c26e8", + "sha256:cfd13ad0dd2c47a3600b439ef72d8615d482cedcff1632930d6f28924d92f294" ], "markers": "python_version >= '3.9'", - "version": "==4.2.1" + "version": "==4.3.0" }, "keyring": { "hashes": [ @@ -352,11 +352,11 @@ }, "more-itertools": { "hashes": [ - "sha256:9fddd5403be01a94b204faadcff459ec3568cf110265d3c54323e1e866ad29d3", - "sha256:d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e" + "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", + "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd" ], "markers": "python_version >= '3.9'", - "version": "==10.7.0" + "version": "==10.8.0" }, "nh3": { "hashes": [ @@ -457,67 +457,67 @@ }, "pymongo": { "hashes": [ - "sha256:05152a2ca55805c37f77ac473e51915f44bba9a6b32fed875fa9df61d81681ca", - "sha256:0ec6666e599ee10cc5cde0cc6a8519373384a14af3a310ede1bf177105f38fb0", - "sha256:1462fc2bb39527f01eea5378172b66c45d62e22fa4be957afe2ec747c4d2ff51", - "sha256:15674e3fddce78cf134fc4e55f90abf1608a48430130cd35efdf3802fd47a1d1", - "sha256:1914e06a443db7e32ddb992050983910bd6861e690200005d7eb1418ad2dc4be", - "sha256:1c0fa103f978c15f7c2f0d7b2e010c24c327432a0310503bc0ec93c5f9be9e81", - "sha256:22805d4fa587b526ac3129ee634a8761abbeb76883045718438f5b8e72f91ce6", - "sha256:23d48bf539f581603a7425e4eeaea279bdb89caa0462aab29e163c11c5d02a9c", - "sha256:2fa071c00fd5556b79c0d94d95b2b778d70ff4ea701aeecb63dd5353d7e025f7", - "sha256:34e1a670892b0435456bbc068e244c71ae3dc0994f7abdf5a0b06db73e32dd86", - "sha256:3866d031fcbe81d7677c078026e650aeef8915560ba758a28051debce38f6b77", - "sha256:4220f42630b260c2594589202efaa4916f3799e87c9fdc479fb6ed62457c74fe", - "sha256:4bdf65bf8167a92b70de44d28ed9df1c2dec83fe2a82e26c01fc89da8ca6bc34", - "sha256:502cd551679753fb7838221c3bbb963da4b4aa0576848192afb1f78128ff729a", - "sha256:54576faf8e6fefe17886a201f9df61bdf728ccac9a7a0847095a0e8480cd6ec1", - "sha256:5f1c0cdddf9783065bf55d3fe025843c0974a828bafc9bb5514ae28dd2828a40", - "sha256:5fe93676afe37794f01b8df5cf16528dce4d7d174cdf51ea1586c234eb5263c2", - "sha256:6513474970fdf3afd9dc9de9065a31a1efc8288ca9068510e5e973fa80200c8f", - "sha256:66c70cea48a6d8eba16f7435033fe3f948335132f807a85e9d861f908ea43fe7", - "sha256:67225d5fb1be2a34c6f73cde9d81a8041a095a94ed2433e2cf9e2f1657443def", - "sha256:69956f971a6f8dafc62e5c83ac21ebf15d5757e13758284f12218ad7fbd3c0fe", - "sha256:71a6915825716edc65239b5658b7de6a09af5d30517706122df66579ddba9349", - "sha256:74fb430c98c5a7f871bfa40f77c8158af8bde256215296d7cfe1ec9c5a417718", - "sha256:7698c8cf749988b7fd259ea65a5fcd409ebde1c6bc1bf75ab7fadbfbd154a3a4", - "sha256:7c3e6e669cf36b27694de2730f5d5b31ef492ffe99446563192c4e8ee84ca859", - "sha256:7e6b1f34db93856b083760fe2848562c0b39433fc1a0827155ea02fee5733c64", - "sha256:85d8d145e06916db46b1e25f39b5361fdf62d58e127b1b1652a0df4ea8081b2f", - "sha256:864f005459ef9b19c60cb96ca755124e0291d211000859f33c62a166f55eba27", - "sha256:88d6f5aceab3528b8760942a57635599925f7fd743691f9d759a02124207dfd0", - "sha256:88f9c415c59450c0ac4133aa4745459101619ca7997dc468209bf395563667d2", - "sha256:8f63035da92f923d966fb07017969b5c42d0450412ceb6c3f837a02b72a5a69d", - "sha256:91200f47453a1cb97136629e28f4091a109756ec37067b622f90c4b626b4af8d", - "sha256:91b8de871a40225bbe4f92d6dc3f20c26bf838e49d3563592131401af0d665a6", - "sha256:9763a2477d5388df65ab6f591cf0cb7fd34f4a66f873c31e63288fd79887742c", - "sha256:a203cb757f75804c43aec48f23cb138e890a24219716ce9958041dace39ba470", - "sha256:a29b62d421a512833e99d4781b64e695cfe23b4c4a9159ea83e56fc2660f2480", - "sha256:a5af18f9239e672c2b9713a8e5f0267e927c9dcc3960dce9599712f304fd377f", - "sha256:a809a982a843bb561c7030059d54ea7f1dcc967cc72a45f1435695e2a2a515a5", - "sha256:aa25505e36e32bef3fa135578461f24735e9d4b7b62e6aa21eb8f2d163cef86d", - "sha256:b7f61561cbc7426ffc2d37b46e65ab5323fc366644f70c8e2240ed5452e2c402", - "sha256:bbf0dbe8554978c1271bdc82366852245a03ab124a1387b6f3531f64adac3c39", - "sha256:c1f79fdd99db135dbc1678477793764c156c11623d0d9dbe4c57767d081b79b8", - "sha256:c32f5e23e9dd31e20800d993f3695b6627664dc7da30ac1669f9716833b33175", - "sha256:c57aef3b48e8c7818689604ff24e54524e164056ec56ee5ea48384264360bf59", - "sha256:c64ef5e58adedecb853a680eb5d1aea50770197f212e202d6eb50c801797b576", - "sha256:cba6b59afef2b47c4859bf36115fa577330601b93e39d04f39fcc6103e801286", - "sha256:ced2a58339aeb2e0f4e347778a5b5130acca0384c0146135e1afe7bf2b9a2701", - "sha256:d60c0e9b13603317062f316906fb5be4000f5b5fe288eb6e9df4ef8695863cd8", - "sha256:e08f4dcd8f23f7ea2c9ae1bb5a043d9b77dfbf03fc489b7e1de91422b0c4772a", - "sha256:e283feafde118cbbb03adc036b882be042b0a2eca121ec5d6bbec3e12980e8fa", - "sha256:e506af9b25aac77cc5c5ea4a72f81764e4f5ea90ca799aac43d665ab269f291d", - "sha256:ee0e677b2139c5b560b63d745a5f26d2e985f624848132deb366c6d3322836bb", - "sha256:f4407c1ab7514e08d4af0f58cf9d7eddc86e45e458fe46f99a72a5d18dbc71dc", - "sha256:f4712911b6dc07aaa00aaa87749b63370ca5900714a2b4b19ba1385163e90295", - "sha256:f51b4885ed197a874272f1bff99d15d0c1f35c665d86b9a2a6572a10246af974", - "sha256:f7e34bd3fe6e5034e22d47d685391ae0f2f2b22d150e9a36a6b77f0c0234e21d", - "sha256:f8874b1ac78b204a3df69351b3c594971be91dba80f7a9189b95097595601223" + "sha256:019f8f9b8a61a5780450c5908c38f63e4248f286d804163d3728bc544f0b07b2", + "sha256:04e780ff2854278d24f7a2011aed45b3df89520c89ca29a7c1ccf9a9f0d513d0", + "sha256:06e2e8996324823e19bccea4dfd7ed543513410bbc7be9860502b62822d62bd4", + "sha256:0e679c8f62ec0e6ba64799ce55b22d76c80cd042f7d99fa2cfbb4d935ac61bea", + "sha256:10a37312c841be2c2edd090b49861dab2e6117ff15cabf801f5910931105740e", + "sha256:147711a3b95d45dd11377a078e77fa302142b67656a8f57076693aa7fba124c1", + "sha256:1604d9f669b044d30ca1775ebe37ddbd1972eaa7ffd041dde9e026b0334c69bd", + "sha256:184b0b6c3663bec2c13d7e2f0a99233c24b1bc7d8163b8b9a019a3ab159b1ade", + "sha256:1f5a4223c6acecb0ab25202a5b4ed6f2b6a41c30204ef44d3d46525e8ea455a9", + "sha256:27cb44c71e6f220b163e1d3c0dd18559e534d5d7cb7e16afa0cf1b7761403492", + "sha256:3176250b89ecc0db8120caf9945ded340eacebec7183f2093e58370041c2d5a8", + "sha256:33a8b2c47db66f3bb33d62e3884fb531b77a58efd412b67b0539c685950c2382", + "sha256:414a999a5b9212635f51c8b23481626406b731abaea16659a39df00f538d06d8", + "sha256:44beff3470a6b1736f9e9cf7fb6477fdb2342b6f19a722cab3bbc989c5f3f693", + "sha256:4812d168f9cd5f257805807a44637afcd0bb7fd22ac4738321bc6aa50ebd9d4f", + "sha256:49a2bf594ce1693f8a3cc4123ec3fa3a86215b395333b22be83c9eb765b24ecb", + "sha256:4c93d1f5db2bf63b4958aef2a914520c7103187d68359b512a8d6d62f5d7a752", + "sha256:573b1ed740dbb51be0819ede005012f4fa37df2c27c94d7d2e18288e16e1ef10", + "sha256:5c95ce2e0dcd9a556e1f51a4132db88c40e8e0a49c0b16d1dddba624f640895b", + "sha256:5f08880ad8bd6bdd4bdb5c93c4a6946c5c4e429b648c3b665c435af02005e7db", + "sha256:6649018ae12a28b8d8399ddda5cb662ac364e338faf0a621e6b9e5ec643134df", + "sha256:6b945dda0359ba13171201fa2f1e32d4b5e73f57606b8c6dd560eeebf4a69d84", + "sha256:6eeea7c92fd8ccd24ad156e2f9c2a117220f1ba0a41968b26d953dc6b8082b1d", + "sha256:714589ce1df891e91f808b1e6e678990040997972d2c70454efebfefd1c8e299", + "sha256:71500e97dbbda5d3e5dc9354dca865246c7502eea9d041c1ce0ae2c3fa018fd2", + "sha256:78e9ec6345a14e2144a514f501e3bfe69ec8c8fefd0759757e4f47bf0b243522", + "sha256:89c1f6804ae16101d5dd6cf0bd06b10e70e5e870aa98a198824c772ce3cb8ba3", + "sha256:8a4fe1b1603865e44c3dbce2b91ac2f18b1672208ff49203e8a480ab68a2d8f5", + "sha256:91f9a3d771ab86229244098125b1c22111aa3e3679534d626db8d05cd9c59ea4", + "sha256:92f8c2a3d0f17c432d68304d3abcab36a8a7ba78db93a143ac77eef6b70bc126", + "sha256:9375cf27c04d2be7d02986262e0593ece1e78fa1934744bdd74c0c0b0cd2c2f2", + "sha256:9485278fed0a8933c8ce8f97ab518158b82e884d4a7bc34e1d784b751c7b69f3", + "sha256:95bfb5fe10a8aa11029868c403939945092fb8d160ca3a10d386778ed9623533", + "sha256:97f0da391fb32f989f0afcd1838faff5595456d24c56d196174eddbb7c3a494c", + "sha256:98c36403c97ec3a439a9ea5cdea730e34f0bf3c39eacfcab3fb07b34f5ef42a7", + "sha256:9fba1dcad4260a9c96aa5bd576bf96edeea5682cd6da6b5777c644ef103f16f6", + "sha256:a76afb1375f6914fecfdc3bfe6fb7c8c36b682c4707b7fb8ded5c2e17a1c2d77", + "sha256:af4e667902314bcc05c90ea4ac0351bb759410ae0c5496ae47aef80659a12a44", + "sha256:b7d6114f4a60b04205b4fce120567955402816ac75329b9282fc8a603ac615ef", + "sha256:c6d426e70a35d1dd5003a535ac8c0683998bea783949daa980d70272baa5cb05", + "sha256:cb147d0d77863ae89fa73cf8c0cc1a68d7dd7c5689cf0381501505307136b2bd", + "sha256:d2cafb545a77738f0506cd538be1b14e9f40ad0b62634d89e1845dee3c726ad5", + "sha256:d78f5b0b569f4320e2485599d89b088aa6d750aad17cc98fd81a323b544ed3d0", + "sha256:d8945b11c4e39c13b47ec79dd0ee05126a6cf4753cf5fdceabf8cc51c02e21e6", + "sha256:df5cc411dbe2b064945114598fdb3e36c3eeb38ed2559e459d5a7b2d91074a54", + "sha256:e09e59bb15edf0d948de6fa2b6f1cbb25ee63e7beba6d45ef6e94609e759efaa", + "sha256:e0a9bdb95e6fab64c8453dae84834dfd7a8b91cfbc7a3e288d9cdd161621a867", + "sha256:e0bd1a446b39216453f53d55143a82e8617730723f100de940f1611ee35e78d6", + "sha256:e0fe8e7bbb59cb0652df0efd285e80e6a92207f5ced4a0f7de56275fd9c21b77", + "sha256:e386721b57a50a5acd6e19c3c14cb975cbc0bf1a0364227d6cc15b486bb094cc", + "sha256:eaef22550ba1034e9b0ed309395ec72944348c277e27cc973cd5b07322b1d088", + "sha256:ebb6679929e5bab898e9c5b46ee6fd025f6eb14380e9d4a210e122d79b223548", + "sha256:ec160c4e1184da11d375a4315917f5a04180ea0ff522f0a97cf78acbb65810d8", + "sha256:ed9c0e22f874419f07022a9133e8d62aa8b665ceb2d89218ee88450c2824185e", + "sha256:f7b965614c16ac7d2cf297fbfb16a9ec81c0493bd5916f455a8e8020e432300b", + "sha256:f81e8156a862ad8b44a065bd89978361a3054571e61b5e802ebdef91bb13ccad", + "sha256:fcbea95a877b2c7c4e4a18527c4eecbe91bdcb0b202f93d5713d50386138ffa3" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==4.14.0" + "version": "==4.14.1" }, "pyproject-hooks": { "hashes": [ @@ -537,12 +537,12 @@ }, "requests": { "hashes": [ - "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", - "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422" + "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", + "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==2.32.4" + "markers": "python_version >= '3.9'", + "version": "==2.32.5" }, "requests-oauthlib": { "hashes": [ diff --git a/pyproject.toml b/pyproject.toml index d97cf2d..1eecfd7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,7 +58,8 @@ dev = [ "black>=23.0.0", "isort>=5.12.0", "mypy>=1.0.0", - "flake8>=6.0.0" + "flake8>=6.0.0", + "python-semantic-release>=9.0.0" ] linux = [ "secretstorage>=3.3.0" @@ -107,3 +108,32 @@ markers = [ "slow: marks tests as slow (deselect with '-m \"not slow\"')", "integration: marks tests as integration tests", ] + +# Python Semantic Release Configuration +# This handles automatic version bumping and PyPI publishing +[tool.semantic_release] +version_variables = [ + "idtap/__init__.py:__version__", +] +version_toml = [ + "pyproject.toml:project.version", +] +version_pattern = [ + "docs/conf.py:release = '{version}'", + "docs/conf.py:version = '{version}'", +] + +# Project settings +major_on_zero = false +branch = "main" +upload_to_pypi = false # Handled by GitHub Actions +upload_to_release = true +hvcs = "github" + +# PATCH-ONLY MODE: All commits increment patch version only +# Manual control for minor/major bumps via command line +[tool.semantic_release.commit_parser_options] +allowed_tags = ["build", "chore", "ci", "docs", "feat", "fix", "perf", "style", "refactor", "test"] +minor_tags = [] # No automatic minor bumps +patch_tags = ["build", "chore", "ci", "docs", "feat", "fix", "perf", "style", "refactor", "test"] # Everything is patch +major_tags = [] # No automatic major bumps From fe4a45aa722d406b86180b1f32be2f74e41da96e Mon Sep 17 00:00:00 2001 From: Jon Myers Date: Mon, 8 Sep 2025 13:45:28 -0400 Subject: [PATCH 02/10] fix: add README.md version tracking to semantic-release config - Configure semantic-release to also update README.md version references - Update current README.md version to match current release (0.1.14) --- README.md | 2 +- pyproject.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 136cece..ce8cb1d 100644 --- a/README.md +++ b/README.md @@ -314,7 +314,7 @@ python api_testing/api_test.py ## Release Notes -### v0.1.13 (Latest) +### v0.1.14 (Latest) **🐛 Bug Fixes** - **Fixed Issue #17**: Raga class incorrectly transforms stored ratios during loading - Rageshree and other ragas now correctly preserve transcription ratios (6 pitches for Rageshree, no Pa) diff --git a/pyproject.toml b/pyproject.toml index 1eecfd7..0c8fc14 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -121,6 +121,7 @@ version_toml = [ version_pattern = [ "docs/conf.py:release = '{version}'", "docs/conf.py:version = '{version}'", + "README.md:### v{version} (Latest)", ] # Project settings From 186322412815d1a8a3b8fbac9bfcadafb5de0f1b Mon Sep 17 00:00:00 2001 From: Jon Myers Date: Mon, 8 Sep 2025 13:49:25 -0400 Subject: [PATCH 03/10] fix: skip integration tests in CI to avoid authentication issues - Mark integration tests with @pytest.mark.integration - Update GitHub Actions to run 'pytest -m "not integration"' - This skips tests that require live authentication to IDTAP server - Unit tests with mocked authentication will still run --- .github/workflows/release.yml | 2 +- .github/workflows/test-pr.yml | 2 +- idtap/tests/query_integration_test.py | 1 + idtap/tests/test_realistic_queries.py | 2 ++ 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c563fc4..6ff11f8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,7 +49,7 @@ jobs: if: steps.release-check.outputs.should_release == 'true' run: | echo "Running tests before release..." - pytest idtap/tests/ + pytest idtap/tests/ -m "not integration" - name: Configure git if: steps.release-check.outputs.should_release == 'true' diff --git a/.github/workflows/test-pr.yml b/.github/workflows/test-pr.yml index 3b452a3..0b3626c 100644 --- a/.github/workflows/test-pr.yml +++ b/.github/workflows/test-pr.yml @@ -25,7 +25,7 @@ jobs: pip install -e .[dev] - name: Run tests - run: pytest idtap/tests/ + run: pytest idtap/tests/ -m "not integration" - name: Build package run: python -m build diff --git a/idtap/tests/query_integration_test.py b/idtap/tests/query_integration_test.py index 3395acd..c2b371a 100644 --- a/idtap/tests/query_integration_test.py +++ b/idtap/tests/query_integration_test.py @@ -15,6 +15,7 @@ TEST_TRANSCRIPTION_ID = "645ff354deeaf2d1e33b3c44" +@pytest.mark.integration class TestRealTranscriptionQueries: """Test queries against real transcription data.""" diff --git a/idtap/tests/test_realistic_queries.py b/idtap/tests/test_realistic_queries.py index 1badf2c..caa872c 100644 --- a/idtap/tests/test_realistic_queries.py +++ b/idtap/tests/test_realistic_queries.py @@ -5,6 +5,7 @@ import sys import os +import pytest # Add the parent directory to Python path so we can import idtap sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..'))) @@ -13,6 +14,7 @@ # Test transcription ID TRANSCRIPTION_ID = "645ff354deeaf2d1e33b3c44" +@pytest.mark.integration def test_realistic_consonant_vowel_query(): """Test the query you mentioned: trajectories starting with consonant 'ba' and vowel 'a'.""" From cd578f6e6e702d69cb0ab752dfda7cc0f3cbbf95 Mon Sep 17 00:00:00 2001 From: Jon Myers Date: Mon, 8 Sep 2025 13:55:13 -0400 Subject: [PATCH 04/10] fix: mark all remaining integration test functions - Mark test_trajectory_sequence_patterns, test_duration_and_segmentation, and test_serialization_compatibility as integration tests - These all use SwaraClient() without mocking and pull data from web --- idtap/tests/test_realistic_queries.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/idtap/tests/test_realistic_queries.py b/idtap/tests/test_realistic_queries.py index caa872c..5e7f5e1 100644 --- a/idtap/tests/test_realistic_queries.py +++ b/idtap/tests/test_realistic_queries.py @@ -130,6 +130,7 @@ def test_realistic_consonant_vowel_query(): print(f" Error: {e}") +@pytest.mark.integration def test_trajectory_sequence_patterns(): """Test trajectory sequence patterns with the actual common IDs.""" @@ -166,6 +167,7 @@ def test_trajectory_sequence_patterns(): print(f"Error testing sequence {sequence}: {e}") +@pytest.mark.integration def test_duration_and_segmentation(): """Test different segmentation types and duration filtering.""" @@ -224,6 +226,7 @@ def test_duration_and_segmentation(): print(f"Duration filtering error: {e}") +@pytest.mark.integration def test_serialization_compatibility(): """Test that results can be serialized for cross-platform use.""" From 5a3ba3f64a0d0dd3a4e2c4444cf243b31402a537 Mon Sep 17 00:00:00 2001 From: Jon Myers Date: Mon, 8 Sep 2025 13:57:24 -0400 Subject: [PATCH 05/10] fix: mark all SwaraClient() auth tests as integration - All logout tests trigger auto_login on SwaraClient() initialization - These tests would fail in CI without authentication credentials - Marking as integration tests excludes them from PR workflows --- idtap/tests/auth_logout_test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/idtap/tests/auth_logout_test.py b/idtap/tests/auth_logout_test.py index fde3710..68b9759 100644 --- a/idtap/tests/auth_logout_test.py +++ b/idtap/tests/auth_logout_test.py @@ -9,6 +9,7 @@ class TestLogoutFunctionality: """Test cases for the logout method.""" + @pytest.mark.integration @patch('idtap.client.login_google') def test_logout_success(self, mock_login): """Test successful logout.""" @@ -36,6 +37,7 @@ def test_logout_success(self, mock_login): assert client.user is None client.secure_storage.clear_tokens.assert_called_once() + @pytest.mark.integration @patch('idtap.client.login_google') def test_logout_cancelled(self, mock_login): """Test logout cancellation.""" @@ -62,6 +64,7 @@ def test_logout_cancelled(self, mock_login): assert client.user == {'name': 'Test User', '_id': 'test123'} client.secure_storage.clear_tokens.assert_not_called() + @pytest.mark.integration @patch('idtap.client.login_google') def test_logout_programmatic(self, mock_login): """Test programmatic logout without confirmation.""" @@ -87,6 +90,7 @@ def test_logout_programmatic(self, mock_login): assert client.user is None client.secure_storage.clear_tokens.assert_called_once() + @pytest.mark.integration @patch('idtap.client.login_google') def test_logout_storage_failure(self, mock_login): """Test logout when storage clearing fails.""" @@ -110,6 +114,7 @@ def test_logout_storage_failure(self, mock_login): assert result is False client.secure_storage.clear_tokens.assert_called_once() + @pytest.mark.integration @patch('idtap.client.login_google') def test_logout_exception_handling(self, mock_login): """Test logout exception handling.""" From fd21a8def121093c8cb18b6c47f2b30dcda14ef4 Mon Sep 17 00:00:00 2001 From: Jon Myers Date: Mon, 8 Sep 2025 14:00:48 -0400 Subject: [PATCH 06/10] fix: mark test_large_query_performance as integration test - This test creates SwaraClient() and calls single_query() which requires authentication - Would cause CI to hang at 61% when trying to authenticate to live server --- idtap/tests/query_integration_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/idtap/tests/query_integration_test.py b/idtap/tests/query_integration_test.py index c2b371a..c3fcaae 100644 --- a/idtap/tests/query_integration_test.py +++ b/idtap/tests/query_integration_test.py @@ -331,6 +331,7 @@ def test_query_result_serialization(self, client): class TestQueryPerformance: """Test query performance with real data.""" + @pytest.mark.integration def test_large_query_performance(self, client=None): """Test performance of queries on real transcription.""" if client is None: From bb6ae6a85943ccee60644bf59cbbee40db2fc8e6 Mon Sep 17 00:00:00 2001 From: Jon Myers Date: Mon, 8 Sep 2025 14:03:04 -0400 Subject: [PATCH 07/10] fix: add missing build dependencies to GitHub workflows - Add build, twine, and python-semantic-release to workflow installs - These packages are needed for building and publishing to PyPI --- .github/workflows/release.yml | 1 + .github/workflows/test-pr.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6ff11f8..bfed418 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,6 +29,7 @@ jobs: run: | python -m pip install --upgrade pip pip install -e .[dev] + pip install build twine python-semantic-release - name: Check if version bump is needed id: release-check diff --git a/.github/workflows/test-pr.yml b/.github/workflows/test-pr.yml index 0b3626c..8ee2ddb 100644 --- a/.github/workflows/test-pr.yml +++ b/.github/workflows/test-pr.yml @@ -23,6 +23,7 @@ jobs: run: | python -m pip install --upgrade pip pip install -e .[dev] + pip install build twine python-semantic-release - name: Run tests run: pytest idtap/tests/ -m "not integration" From 34987a59795f4a3cb8a5e57c068314a4b1c1e7af Mon Sep 17 00:00:00 2001 From: Jon Myers Date: Mon, 8 Sep 2025 14:05:20 -0400 Subject: [PATCH 08/10] fix: make PR comment step non-critical in workflow - Add continue-on-error to comment step since it's not essential - Everything important works: tests, build, semantic-release, TestPyPI upload - Comment permissions vary based on GitHub token configuration --- .github/workflows/test-pr.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-pr.yml b/.github/workflows/test-pr.yml index 8ee2ddb..6bd4079 100644 --- a/.github/workflows/test-pr.yml +++ b/.github/workflows/test-pr.yml @@ -45,6 +45,7 @@ jobs: - name: Comment PR with TestPyPI link if: github.event.pull_request.head.repo.full_name == github.repository + continue-on-error: true # Don't fail if commenting isn't allowed uses: actions/github-script@v7 with: script: | From 60513a5598fefb727f2452b1b39d24a0a5f45d37 Mon Sep 17 00:00:00 2001 From: Jon Myers Date: Mon, 8 Sep 2025 14:06:00 -0400 Subject: [PATCH 09/10] fix: grant pull-request write permission for PR comments - Add explicit permissions block to allow PR commenting - Remove continue-on-error since it should now work properly - This allows the workflow to post TestPyPI links as PR comments --- .github/workflows/test-pr.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-pr.yml b/.github/workflows/test-pr.yml index 6bd4079..d8fa027 100644 --- a/.github/workflows/test-pr.yml +++ b/.github/workflows/test-pr.yml @@ -7,6 +7,9 @@ on: jobs: test: runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write # Allow commenting on PRs steps: - name: Checkout code @@ -45,7 +48,6 @@ jobs: - name: Comment PR with TestPyPI link if: github.event.pull_request.head.repo.full_name == github.repository - continue-on-error: true # Don't fail if commenting isn't allowed uses: actions/github-script@v7 with: script: | From 43ddc487db01d855cd1730489ac96388cec1a910 Mon Sep 17 00:00:00 2001 From: Jon Myers Date: Mon, 8 Sep 2025 14:11:40 -0400 Subject: [PATCH 10/10] feat: implement all three workflow improvements from review - Update Python setup action from v4 to v5 (latest version) - Add dependency caching to speed up CI runs by ~30-50% - Add version validation step to ensure __init__.py and pyproject.toml stay in sync - Applied to both test-pr.yml and release.yml workflows --- .github/workflows/release.yml | 30 ++++++++++++++++++++++++++++-- .github/workflows/test-pr.yml | 30 ++++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bfed418..267e9d2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,15 +21,41 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.10' + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml', '**/Pipfile.lock') }} + restore-keys: | + ${{ runner.os }}-pip- + ${{ runner.os }}- + - name: Install dependencies run: | python -m pip install --upgrade pip pip install -e .[dev] - pip install build twine python-semantic-release + pip install build twine python-semantic-release toml + + - name: Validate version consistency + run: | + echo "Checking version consistency across files..." + INIT_VERSION=$(python -c "import idtap; print(idtap.__version__)") + TOML_VERSION=$(python -c "import toml; print(toml.load('pyproject.toml')['project']['version'])") + + echo "__init__.py version: $INIT_VERSION" + echo "pyproject.toml version: $TOML_VERSION" + + if [ "$INIT_VERSION" != "$TOML_VERSION" ]; then + echo "❌ Version mismatch detected!" + echo "__init__.py: $INIT_VERSION" + echo "pyproject.toml: $TOML_VERSION" + exit 1 + fi + echo "✅ Versions are consistent" - name: Check if version bump is needed id: release-check diff --git a/.github/workflows/test-pr.yml b/.github/workflows/test-pr.yml index d8fa027..0b1f342 100644 --- a/.github/workflows/test-pr.yml +++ b/.github/workflows/test-pr.yml @@ -18,19 +18,45 @@ jobs: fetch-depth: 0 # Needed for semantic-release - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.10' + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml', '**/Pipfile.lock') }} + restore-keys: | + ${{ runner.os }}-pip- + ${{ runner.os }}- + - name: Install dependencies run: | python -m pip install --upgrade pip pip install -e .[dev] - pip install build twine python-semantic-release + pip install build twine python-semantic-release toml - name: Run tests run: pytest idtap/tests/ -m "not integration" + - name: Validate version consistency + run: | + echo "Checking version consistency across files..." + INIT_VERSION=$(python -c "import idtap; print(idtap.__version__)") + TOML_VERSION=$(python -c "import toml; print(toml.load('pyproject.toml')['project']['version'])") + + echo "__init__.py version: $INIT_VERSION" + echo "pyproject.toml version: $TOML_VERSION" + + if [ "$INIT_VERSION" != "$TOML_VERSION" ]; then + echo "❌ Version mismatch detected!" + echo "__init__.py: $INIT_VERSION" + echo "pyproject.toml: $TOML_VERSION" + exit 1 + fi + echo "✅ Versions are consistent" + - name: Build package run: python -m build