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
112 changes: 112 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
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@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 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
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/ -m "not integration"

- 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 }}"
99 changes: 99 additions & 0 deletions .github/workflows/test-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: Test PR

on:
pull_request:
branches: [ main ]

jobs:
test:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # Allow commenting on PRs

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Needed for semantic-release

- name: Set up Python
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 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

- 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.`
});
87 changes: 81 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading
Loading