Release #54
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: | |
| workflow_run: # would only fire after file is merged to master | |
| workflows: ["Lint and test"] | |
| types: | |
| - completed | |
| branches: | |
| - master | |
| - 'ci/**' # ci testing, pre-releases | |
| #- develop # can emit -dev releases but we do not want to | |
| workflow_dispatch: | |
| inputs: | |
| dry_run: | |
| description: "Run in dry-run mode (no publish)" | |
| required: false | |
| default: "true" | |
| push: # only temporary, until this file lands on master (see above) | |
| branches: | |
| - 'ci/**' | |
| # MUSTHAVE: Trusted publisher access for both repos. | |
| # NOTE: according to docs, 'test' repo accounts are ephemeral and can be wiped at any time | |
| # NOTE: 'test' accs are not that ephmeperal -- losing access to sandbox account (2FA issue) effectively locked us out of project; good test for workarounds though | |
| # NOTE: as a part of regaining-control scenario we may use distinct project names in pyroject.toml (e.g. appmap-dev, appmap-ng) | |
| env: | |
| DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }} | |
| pypi_project: appmap | |
| #testpypi_project: appmap-dev # workaround for lost-access scenario | |
| testpypi_project: appmapcitest | |
| jobs: | |
| setup: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| distribution_name: ${{ steps.configure.outputs.distribution_name }} | |
| publish_to: ${{ steps.configure.outputs.publish_to }} | |
| publish_env: ${{ steps.configure.outputs.publish_env }} | |
| steps: | |
| - id: configure | |
| shell: bash | |
| run: | | |
| case "${{ github.ref_name }}" in | |
| ci/*) | |
| echo "publish_env=testpypi" >> $GITHUB_OUTPUT | |
| echo "distribution_name=${{ env.testpypi_project }}" >> $GITHUB_OUTPUT | |
| echo "publish_to=https://test.pypi.org/project/${{ env.testpypi_project }}" >> $GITHUB_OUTPUT | |
| ;; | |
| master) | |
| echo "publish_env=pypi" >> $GITHUB_OUTPUT | |
| echo "distribution_name=${{ env.pypi_project }}" >> $GITHUB_OUTPUT | |
| echo "publish_to=https://pypi.org/project/${{ env.pypi_project }}" >> $GITHUB_OUTPUT | |
| ;; | |
| *) | |
| echo "publish_env=SKIP" >> $GITHUB_OUTPUT | |
| echo "distribution_name=${{ env.pypi_project }}" >> $GITHUB_OUTPUT | |
| echo "publish_to=https://test.pypi.org/project/${{ env.pypi_project }}" >> $GITHUB_OUTPUT | |
| ;; | |
| esac | |
| release: | |
| runs-on: ubuntu-latest | |
| needs: setup | |
| if: github.event_name == 'workflow_dispatch' || (github.event_name=='push' && startsWith(github.ref_name,'ci/') ) || (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success' && (github.event.workflow_run.head_branch == 'master' || startsWith(github.event.workflow_run.head_branch, 'ci/') ) ) | |
| steps: | |
| - name: Generate token | |
| uses: actions/create-github-app-token@v1 | |
| id: app-token | |
| with: | |
| app-id: ${{ secrets.RELEASE_APP_ID }} | |
| private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} | |
| - uses: actions/checkout@v5 | |
| with: | |
| token: ${{ steps.app-token.outputs.token }} | |
| - uses: ./.github/actions/setup-semantic-release # node+semantic-release | |
| - uses: ./.github/actions/setup # poetry | |
| - name: Prepare release # branch policies defined in .releaserc | |
| env: | |
| GIT_AUTHOR_NAME: appland-release | |
| GIT_AUTHOR_EMAIL: release@app.land | |
| GIT_COMMITTER_NAME: appland-release | |
| GIT_COMMITTER_EMAIL: release@app.land | |
| GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} | |
| DISTRIBUTION_NAME: ${{ needs.setup.outputs.distribution_name }} | |
| run: | | |
| if [ "$DRY_RUN" = "true" ]; then | |
| semantic-release --dry-run | |
| else | |
| semantic-release | |
| fi | |
| - name: Get version | |
| if: env.DRY_RUN != 'true' | |
| id: version | |
| run: | | |
| VERSION=$(grep '^version = ' pyproject.toml | cut -d'"' -f2) | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Version: $VERSION" | |
| - name: dockerhub login (for seamless docker pulling) | |
| if: env.DRY_RUN != 'true' | |
| uses: ./.github/actions/dockerhub-login | |
| env: | |
| DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} | |
| DOCKERHUB_USERNAME: ${{ vars.DOCKERHUB_USERNAME }} | |
| continue-on-error: true | |
| - name: Smoke test | |
| if: env.DRY_RUN != 'true' | |
| run: ci/scripts/run_tests.sh | |
| env: | |
| SMOKETEST_DOCKER_IMAGE: python:3.12-slim | |
| DISTRIBUTION_NAME: ${{ needs.setup.outputs.distribution_name }} | |
| - name: Extract release notes | |
| if: env.DRY_RUN != 'true' | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| sed -n "/^## \[$VERSION\]/,/^## \[/p" CHANGELOG.md | sed '$d' > release-notes.md | |
| # Verify we got something | |
| if [ ! -s release-notes.md ]; then | |
| echo "Error: Could not extract release notes for version $VERSION" | |
| exit 1 | |
| fi | |
| echo "Extracted release notes:" | |
| cat release-notes.md | |
| - name: Commit, tag, and push | |
| if: env.DRY_RUN != 'true' | |
| run: | | |
| git config user.name "appland-release" | |
| git config user.email "release@app.land" | |
| git add pyproject.toml CHANGELOG.md | |
| # Create commit with release notes in body | |
| git commit -F- <<EOF | |
| chore(release): ${{ steps.version.outputs.version }} [skip ci] | |
| $(cat release-notes.md) | |
| EOF | |
| git tag "v${{ steps.version.outputs.version }}" | |
| git push --follow-tags | |
| - name: Upload wheel | |
| if: env.DRY_RUN != 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: wheel | |
| path: dist/*.whl | |
| - name: Upload sdist | |
| if: env.DRY_RUN != 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sdist | |
| path: dist/*.tar.gz | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| # as a workaround to ownership issues (lost access to project) | |
| publish: | |
| name: publish package on PyPI and create GitHub release | |
| needs: ['setup', 'release'] | |
| if: (( github.event.inputs.dry_run != 'true' ) && ( (needs.setup.outputs.publish_env == 'pypi') || (needs.setup.outputs.publish_env == 'testpypi') ) ) | |
| runs-on: ubuntu-latest | |
| environment: | |
| name: ${{ needs.setup.outputs.publish_env }} | |
| url: ${{ needs.setup.outputs.publish_to }} | |
| permissions: | |
| id-token: write | |
| contents: write # needed for creating GitHub releases | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: v${{ needs.release.outputs.version }} # checkout the tag | |
| - uses: ./.github/actions/refetch-artifacts | |
| - name: Create GitHub release | |
| run: | | |
| gh release create "v${{ needs.release.outputs.version }}" \ | |
| dist/*.whl dist/*.tar.gz \ | |
| --notes-from-tag | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| - name: Publish to PyPI | |
| if: needs.setup.outputs.publish_env=='pypi' | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| - name: Publish to TestPyPI | |
| if: needs.setup.outputs.publish_env=='testpypi' | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| repository-url: https://test.pypi.org/legacy/ # trailing slash matters! |