📃 fix(build): wordlist 📃 (#12) #11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| branches: | |
| - master | |
| permissions: | |
| contents: write | |
| id-token: write | |
| jobs: | |
| test: | |
| name: Test | |
| uses: ./.github/workflows/test.yml | |
| version: | |
| name: Version | |
| needs: test # Only release after tests pass | |
| runs-on: ubuntu-latest | |
| outputs: | |
| new_version: ${{ steps.version.outputs.new_tag }} | |
| tag_name: ${{ steps.version.outputs.new_tag }} | |
| pypi_version: ${{ steps.set-version.outputs.pypi_version }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Bump version and push tag | |
| id: version | |
| uses: anothrNick/github-tag-action@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| DEFAULT_BUMP: minor | |
| WITH_V: true | |
| TAG_CONTEXT: repo | |
| BRANCH_HISTORY: compare | |
| INITIAL_VERSION: 1.0.3 | |
| - name: Update version in pyproject.toml | |
| id: set-version | |
| run: | | |
| # Strip 'v' prefix for PyPI-compatible version | |
| PYPI_VERSION="${NEW_TAG#v}" | |
| sed -i "s/^version = .*/version = \"$PYPI_VERSION\"/" pyproject.toml | |
| echo "Tag version: $NEW_TAG" | |
| echo "PyPI version: $PYPI_VERSION" | |
| echo "pypi_version=$PYPI_VERSION" >> $GITHUB_OUTPUT | |
| grep "^version" pyproject.toml | |
| env: | |
| NEW_TAG: ${{ steps.version.outputs.new_tag }} | |
| # Note: Version is injected locally for this job only. | |
| # Not committed to repo - downstream jobs inject version from tag. | |
| publish: | |
| name: Publish PyPI | |
| needs: version | |
| runs-on: ubuntu-latest | |
| environment: | |
| name: pypi | |
| url: https://pypi.org/p/${{ github.event.repository.name }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: master | |
| fetch-depth: 1 | |
| - name: Pull latest changes | |
| run: git pull origin master | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.13' | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Inject version from tag | |
| run: | | |
| PYPI_VERSION="${{ needs.version.outputs.new_version }}" | |
| PYPI_VERSION="${PYPI_VERSION#v}" # Strip 'v' prefix | |
| sed -i "s/^version = .*/version = \"$PYPI_VERSION\"/" pyproject.toml | |
| echo "PyPI version: $PYPI_VERSION" | |
| grep "^version" pyproject.toml | |
| - name: Build distributions | |
| run: | | |
| uv build --sdist | |
| uv build --wheel | |
| - name: Publish to PyPI | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| # Uses OIDC trusted publishing - configure at: | |
| # https://pypi.org/manage/account/publishing/ | |
| build-portable: | |
| name: Build Portable (${{ matrix.os }}) | |
| needs: version | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| include: | |
| - os: ubuntu-latest | |
| artifact_suffix: linux-portable | |
| binary_name: '' | |
| - os: macos-latest | |
| artifact_suffix: macos-portable | |
| binary_name: '' | |
| - os: windows-latest | |
| artifact_suffix: windows-portable.exe | |
| binary_name: .exe | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: master | |
| - name: Pull latest changes | |
| run: git pull origin master | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.13' | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Build onefile binary | |
| env: | |
| MODE: onefile | |
| CI: true | |
| run: make build | |
| shell: bash | |
| - name: Rename binary with platform suffix | |
| run: | | |
| mv ${{ github.event.repository.name }}${{ matrix.binary_name }} ${{ github.event.repository.name }}-${{ matrix.artifact_suffix }} | |
| chmod +x ${{ github.event.repository.name }}-${{ matrix.artifact_suffix }} || true | |
| shell: bash | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: ${{ github.event.repository.name }}-${{ matrix.artifact_suffix }} | |
| path: ${{ github.event.repository.name }}-${{ matrix.artifact_suffix }} | |
| if-no-files-found: error | |
| build-fast: | |
| name: Build Fast (${{ matrix.os }}) | |
| needs: version | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| include: | |
| - os: ubuntu-latest | |
| platform: linux | |
| - os: macos-latest | |
| platform: macos | |
| - os: windows-latest | |
| platform: windows | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: master | |
| - name: Pull latest changes | |
| run: git pull origin master | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.13' | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Build standalone distribution | |
| env: | |
| MODE: standalone | |
| CI: true | |
| run: make build | |
| shell: bash | |
| - name: Create archive | |
| run: tar -czf "${{ github.event.repository.name }}-${{ matrix.platform }}-fast.tar.gz" cli.dist/ | |
| shell: bash | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: ${{ github.event.repository.name }}-${{ matrix.platform }}-fast | |
| path: ${{ github.event.repository.name }}-${{ matrix.platform }}-fast.tar.gz | |
| if-no-files-found: error | |
| release: | |
| name: Release | |
| needs: [version, build-portable, build-fast] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: master | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v5 | |
| with: | |
| path: artifacts | |
| - name: Prepare release assets | |
| run: | | |
| mkdir -p release-assets | |
| find artifacts -type f -exec cp {} release-assets/ \; | |
| ls -lah release-assets/ | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ needs.version.outputs.tag_name }} | |
| files: release-assets/* | |
| body: | | |
| ## 📦 Binary Options | |
| | Variant | Description | Startup Time | | |
| |---------|-------------|--------------| | |
| | **Portable** (`*-portable`) | Single file, no installation needed | ~10 sec | | |
| | **Fast** (`*-fast.tar.gz`) | Optimized for speed, extract and run | ~1 sec | | |
| Choose **Portable** for convenience, **Fast** for performance. | |
| generate_release_notes: true | |
| draft: false | |
| prerelease: ${{ contains(needs.version.outputs.new_version, 'alpha') || contains(needs.version.outputs.new_version, 'beta') || contains(needs.version.outputs.new_version, 'rc') }} | |
| smoke-pypi: | |
| name: Smoke PyPI | |
| needs: [version, publish] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.13' | |
| - name: Wait for PyPI indexing | |
| run: sleep 180 | |
| - name: Install from PyPI | |
| run: pip install ${{ github.event.repository.name }}==${{ needs.version.outputs.pypi_version }} | |
| - name: Run smoke tests | |
| run: python tests/smoke.py ${{ github.event.repository.name }} | |
| smoke-binary: | |
| name: Smoke Binary (${{ matrix.os }}) | |
| needs: [build-portable, build-fast] | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| include: | |
| - os: ubuntu-latest | |
| artifact_suffix: linux-portable | |
| - os: macos-latest | |
| artifact_suffix: macos-portable | |
| - os: windows-latest | |
| artifact_suffix: windows-portable.exe | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.13' | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Install package (for import tests) | |
| run: make install | |
| - name: Download binary | |
| uses: actions/download-artifact@v5 | |
| with: | |
| name: ${{ github.event.repository.name }}-${{ matrix.artifact_suffix }} | |
| - name: Make executable | |
| run: chmod +x ./${{ github.event.repository.name }}-${{ matrix.artifact_suffix }} || true | |
| shell: bash | |
| - name: Run smoke tests | |
| run: make smoke NAME=./${{ github.event.repository.name }}-${{ matrix.artifact_suffix }} | |
| homebrew: | |
| name: Update Homebrew | |
| needs: [version, release] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Generate formula from template | |
| run: | | |
| NAME="${{ github.event.repository.name }}" | |
| TAG="${{ needs.version.outputs.tag_name }}" | |
| REPO="${{ github.repository }}" | |
| # Get description from pyproject.toml | |
| DESCRIPTION=$(grep '^description' pyproject.toml | sed 's/description = "\(.*\)"/\1/') | |
| # Calculate SHA256 of release tarball | |
| TARBALL_URL="https://github.com/${REPO}/archive/refs/tags/${TAG}.tar.gz" | |
| SHA256=$(curl -sL "$TARBALL_URL" | shasum -a 256 | cut -d' ' -f1) | |
| # Convert name to Ruby class name (capitalize, remove hyphens) | |
| CLASS_NAME=$(echo "$NAME" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2))}1' | tr -d ' ') | |
| # Build source lines for release (url + sha256 + head) | |
| SOURCE_LINE="url \"${TARBALL_URL}\"\n sha256 \"${SHA256}\"\n head \"https://github.com/${REPO}.git\", branch: \"master\"" | |
| # Generate formula from template into Formula directory | |
| mkdir -p Formula | |
| sed -e "s|{{NAME}}|${NAME}|g" \ | |
| -e "s|{{CLASS_NAME}}|${CLASS_NAME}|g" \ | |
| -e "s|{{DESCRIPTION}}|${DESCRIPTION}|g" \ | |
| -e "s|{{HOMEPAGE}}|https://github.com/${REPO}|g" \ | |
| -e "s|{{SOURCE_LINE}}|${SOURCE_LINE}|g" \ | |
| .github/templates/formula.rb.template > "Formula/${NAME}.rb" | |
| echo "Generated formula:" | |
| cat "Formula/${NAME}.rb" | |
| - name: Push to homebrew-tap | |
| uses: cpina/github-action-push-to-another-repository@v1 | |
| env: | |
| API_TOKEN_GITHUB: ${{ secrets.HOMEBREW_TAP_TOKEN }} | |
| with: | |
| source-directory: 'Formula' | |
| destination-github-username: '${{ github.repository_owner }}' | |
| destination-repository-name: 'homebrew-tap' | |
| target-directory: 'Formula' | |
| target-branch: 'master' | |
| user-email: 'github-actions[bot]@users.noreply.github.com' | |
| user-name: 'github-actions[bot]' | |
| commit-message: 'Update ${{ github.event.repository.name }} to ${{ needs.version.outputs.tag_name }}' | |
| smoke-homebrew: | |
| name: Smoke Homebrew | |
| needs: [version, homebrew] | |
| runs-on: macos-latest | |
| steps: | |
| - name: Tap and install formula | |
| run: | | |
| brew tap ${{ github.repository_owner }}/tap | |
| brew install ${{ github.event.repository.name }} | |
| - name: Run formula test | |
| run: brew test ${{ github.event.repository.name }} | |
| - name: Verify CLI works | |
| run: | | |
| ${{ github.event.repository.name }} version | |
| ${{ github.event.repository.name }} --help |