Skip to content

treemapper CD

treemapper CD #27

Workflow file for this run

# .github/workflows/cd.yml
name: TreeMapper CD
permissions:
contents: write
on:
workflow_dispatch:
inputs:
version:
description: 'Version to release (e.g., 1.0.0)'
required: true
publish_to_pypi:
description: 'Publish to PyPI'
required: true
default: 'false'
type: choice
options:
- 'true'
- 'false'
jobs:
prepare-version:
name: Prepare Version Commit
runs-on: ubuntu-latest
outputs:
version: ${{ steps.set_outputs.outputs.version }}
tag_name: ${{ steps.set_outputs.outputs.tag_name }}
commit_sha: ${{ steps.commit_version.outputs.commit_sha }}
steps:
- name: Checkout Code
uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Check that we're on main branch
run: |
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
if [ "$CURRENT_BRANCH" != "main" ]; then
echo "Error: Releases can only be created from the main branch. Current branch: $CURRENT_BRANCH"
exit 1
fi
- name: Set version in version.py
env:
VERSION: ${{ github.event.inputs.version }}
run: |
echo "Setting version to $VERSION"
python - <<'PY'
import os, re, pathlib
ver = os.environ["VERSION"]
p = pathlib.Path("src/treemapper/version.py")
s = p.read_text(encoding="utf-8")
s, n = re.subn(r'__version__\s*=\s*["\'].*?["\']', f'__version__ = "{ver}"', s, count=1)
assert n == 1, "version assignment not found or multiple matches"
p.write_text(s, encoding="utf-8")
PY
echo "version.py content after change:"
cat src/treemapper/version.py
- name: Commit version bump (locally only, no push yet)
id: commit_version
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
git add src/treemapper/version.py
if ! git diff --staged --quiet; then
git commit -m "Release version ${{ github.event.inputs.version }}"
else
echo "No changes to commit."
fi
COMMIT_SHA=$(git rev-parse HEAD)
echo "Commit SHA: $COMMIT_SHA"
echo "commit_sha=$COMMIT_SHA" >> $GITHUB_OUTPUT
- name: Create local tag (no push yet)
run: |
git tag -a "v${{ github.event.inputs.version }}" -m "Release version ${{ github.event.inputs.version }}"
echo "Tag created locally: v${{ github.event.inputs.version }}"
- name: Upload git bundle for other jobs
run: |
git bundle create repo.bundle --all
- name: Upload bundle as artifact
uses: actions/upload-artifact@v4
with:
name: git-repo-bundle
path: repo.bundle
retention-days: 1
- name: Set outputs
id: set_outputs
run: |
echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT
echo "tag_name=v${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT
build-assets:
name: Build Assets
needs: prepare-version
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
asset_name: linux
python-version: '3.11'
- os: macos-latest
asset_name: macos
python-version: '3.11'
- os: windows-latest
asset_name: windows
python-version: '3.11'
runs-on: ${{ matrix.os }}
steps:
- name: Download git bundle
uses: actions/download-artifact@v5
with:
name: git-repo-bundle
- name: Restore repository from bundle
run: |
git clone repo.bundle repo
cd repo
git checkout ${{ needs.prepare-version.outputs.tag_name }}
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Cache pip Dependencies
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('**/pyproject.toml') }}
restore-keys: |
${{ runner.os }}-pip-${{ matrix.python-version }}-
${{ runner.os }}-pip-
- name: Install Dependencies (including PyInstaller)
working-directory: ./repo
run: |
python -m pip install --upgrade pip
pip install .[dev]
- name: Build with PyInstaller
working-directory: ./repo
run: |
python -m PyInstaller --clean -y --dist ./dist/${{ matrix.asset_name }} treemapper.spec
- name: Determine architecture
id: arch
shell: bash
run: |
ARCH=$(uname -m)
if [[ "${{ runner.os }}" == "Windows" ]]; then
if [[ "${{ runner.arch }}" == "X64" ]]; then ARCH="x86_64"; \
elif [[ "${{ runner.arch }}" == "ARM64" ]]; then ARCH="arm64"; \
else ARCH="unknown"; fi
elif [[ "${{ runner.os }}" == "macOS" ]] && [[ "$ARCH" == "arm64" ]]; then
echo "Detected ARM on macOS"
fi
echo "Determined ARCH: $ARCH"
echo "arch=$ARCH" >> $GITHUB_OUTPUT
- name: Rename asset with proper name
shell: bash
working-directory: ./repo
run: |
ASSET_NAME="treemapper-${{ matrix.asset_name }}-${{ steps.arch.outputs.arch }}"
ASSET_NAME="${ASSET_NAME}-v${{ needs.prepare-version.outputs.version }}"
if [[ "${{ runner.os }}" == "Windows" ]]; then
ASSET_NAME="${ASSET_NAME}.exe"
mv "./dist/${{ matrix.asset_name }}/treemapper.exe" "./dist/${ASSET_NAME}"
else
mv "./dist/${{ matrix.asset_name }}/treemapper" "./dist/${ASSET_NAME}"
fi
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.asset_name }}-binary
path: ./repo/dist/treemapper-*
retention-days: 1
publish-to-pypi:
name: Publish to PyPI
needs: [prepare-version, build-assets]
if: github.event.inputs.publish_to_pypi == 'true'
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/treemapper
permissions:
id-token: write
steps:
- name: Download git bundle
uses: actions/download-artifact@v5
with:
name: git-repo-bundle
- name: Restore repository from bundle
run: |
git clone repo.bundle repo
cd repo
git checkout ${{ needs.prepare-version.outputs.tag_name }}
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install build tools
working-directory: ./repo
run: |
python -m pip install --upgrade pip
pip install build
- name: Build sdist and wheel
working-directory: ./repo
run: python -m build
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: ./repo/dist/
finalize-release:
name: Push Release and Create GitHub Release
needs: [prepare-version, build-assets, publish-to-pypi]
if: |
always() &&
needs.prepare-version.result == 'success' &&
needs.build-assets.result == 'success' &&
(needs.publish-to-pypi.result == 'success' ||
needs.publish-to-pypi.result == 'skipped')
runs-on: ubuntu-latest
steps:
- name: Download git bundle
uses: actions/download-artifact@v5
with:
name: git-repo-bundle
- name: Restore repository from bundle
run: |
git clone repo.bundle repo
cd repo
- name: Push commit and tag to main
working-directory: ./repo
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
# Push the version bump commit to main
git push origin HEAD:main
# Push the tag
git push origin ${{ needs.prepare-version.outputs.tag_name }}
echo "Successfully pushed version commit and tag"
- name: Download all build artifacts
uses: actions/download-artifact@v5
with:
path: ./artifacts
- name: Create GitHub Release with assets
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.prepare-version.outputs.tag_name }}
name: Release ${{ needs.prepare-version.outputs.version }}
draft: false
prerelease: false
generate_release_notes: true
files: ./artifacts/**/*-binary/treemapper-*