Release Pypi, Docker and GitHub #55
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 Pypi, Docker and GitHub" | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "The version to tag, without the leading 'v'. If omitted, will initiate a dry run (no uploads)." | |
| type: string | |
| sha: | |
| description: "The full sha of the commit to be released. If omitted, the latest commit on the default branch will be used." | |
| default: "" | |
| type: string | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| sdist_wheels: | |
| name: Build Python sdist and wheel | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Configure git | |
| run: | | |
| git config --global user.email "[email protected]" | |
| git config --global user.name "FireFighter Release CI" | |
| - name: Set local tag for version | |
| if: ${{ inputs.tag }} | |
| run: | | |
| git tag -m "v${{ inputs.tag }}" "v${{ inputs.tag }}" | |
| - name: Set version environment | |
| if: ${{ inputs.tag }} | |
| run: | | |
| echo "SETUPTOOLS_SCM_PRETEND_VERSION=${{ inputs.tag }}" >> $GITHUB_ENV | |
| - name: Fake .git for act | |
| if: ${{ env.ACT }} | |
| run: | | |
| git init | |
| git add . | |
| git commit -a -m "chore(act): fake commit" | |
| git log | |
| - uses: jdx/mise-action@v3 | |
| - name: "Build wheel" | |
| run: pdm build --no-sdist --no-clean | |
| - name: "Build sdist" | |
| run: pdm build --no-wheel --no-clean | |
| - name: "Upload wheel and sdist" | |
| uses: actions/upload-artifact@v4 | |
| if: ${{ !env.ACT }} | |
| with: | |
| name: dist | |
| path: dist | |
| - name: Export frozen requirements.txt | |
| run: | | |
| pdm export --prod -f requirements -o requirements.txt | |
| - name: Publish frozen requirements.txt | |
| if: ${{ !env.ACT }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: requirements | |
| path: requirements.txt | |
| validate-tag: | |
| name: Validate tag | |
| runs-on: ubuntu-latest | |
| # If you don't set an input tag, it's a dry run (no uploads). | |
| if: ${{ inputs.tag }} | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: main # We checkout the main branch to check for the commit | |
| fetch-depth: 0 | |
| - name: Check main branch | |
| if: ${{ inputs.sha }} | |
| run: | | |
| # Fetch the main branch since a shallow checkout is used by default | |
| git fetch origin main --unshallow | |
| if ! git branch --contains ${{ inputs.sha }} | grep -E '(^|\s)main$'; then | |
| echo "The specified sha is not on the main branch" >&2 | |
| exit 1 | |
| fi | |
| upload-release: | |
| name: Upload to PyPI | |
| runs-on: ubuntu-latest | |
| needs: | |
| - sdist_wheels | |
| # If you don't set an input tag, it's a dry run (no uploads). | |
| if: ${{ inputs.tag }} | |
| environment: | |
| name: release | |
| permissions: | |
| # For pypi trusted publishing | |
| id-token: write | |
| steps: | |
| - uses: actions/download-artifact@v5 | |
| with: | |
| name: dist | |
| path: dist | |
| - name: Publish to PyPi | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| skip-existing: true | |
| verbose: true | |
| tag-release: | |
| name: Tag release | |
| runs-on: ubuntu-latest | |
| needs: upload-release | |
| # If you don't set an input tag, it's a dry run (no uploads). | |
| if: ${{ inputs.tag }} | |
| permissions: | |
| # For git tag | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.sha }} | |
| fetch-depth: 0 | |
| - name: git tag | |
| run: | | |
| git config user.email "[email protected]" | |
| git config user.name "FireFighter Release CI" | |
| git tag -m "v${{ inputs.tag }}" "v${{ inputs.tag }}" | |
| # If there is duplicate tag, this will fail. The publish to pypi action will have been a noop (due to skip | |
| # existing), so we make a non-destructive exit here | |
| git push --tags | |
| publish-release: | |
| name: Publish to GitHub | |
| runs-on: ubuntu-latest | |
| needs: tag-release | |
| # If you don't set an input tag, it's a dry run (no uploads). | |
| if: ${{ inputs.tag }} | |
| permissions: | |
| # For GitHub release publishing | |
| contents: write | |
| steps: | |
| - uses: actions/download-artifact@v5 | |
| with: | |
| name: dist | |
| path: dist | |
| - name: "Publish to GitHub" | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| draft: true | |
| files: dist/* | |
| tag_name: v${{ inputs.tag }} | |
| docker-publish: | |
| # This action doesn't need to wait on any other task, it's easy to re-tag if something failed and we're validating | |
| # the tag here also | |
| name: Push Docker image ghcr.io/ManoManoTech/firefighter-incident | |
| runs-on: ubuntu-latest | |
| needs: | |
| - sdist_wheels | |
| environment: | |
| name: release | |
| permissions: | |
| # For the docker push and the git clone | |
| packages: write | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.sha }} | |
| fetch-depth: 0 | |
| - uses: actions/download-artifact@v5 | |
| name: Download Python artifacts | |
| with: | |
| name: dist | |
| path: dist | |
| - uses: actions/download-artifact@v5 | |
| name: Download Python frozen requirements | |
| with: | |
| name: requirements | |
| path: requirements | |
| - name: Move requirements.txt to root | |
| run: mv requirements/requirements.txt . | |
| - uses: docker/setup-buildx-action@v3 | |
| - uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.repository_owner }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract metadata (tags, labels) for Docker | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ghcr.io/ManoManoTech/firefighter-incident | |
| - name: "Build and push Docker image" | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| platforms: linux/amd64,linux/arm64 | |
| # Reuse the builder | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| push: ${{ inputs.tag != '' }} | |
| # Repository name must be lowercase | |
| tags: ghcr.io/manomanotech/firefighter-incident:latest,ghcr.io/manomanotech/firefighter-incident:${{ inputs.tag || 'dry-run' }} | |
| labels: ${{ steps.meta.outputs.labels }} |