De-duplicate docker workflow pipelines #498
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: PR Preview | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, ready_for_review] | |
| # Cancel an in-flight preview when the PR is pushed again -- previews are slow | |
| # (publish + multi-step Docker build), so superseded runs shouldn't keep going. | |
| concurrency: | |
| group: pr-preview-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| jobs: | |
| preview: | |
| # Skip on: | |
| # - PRs from forks (no access to publish secrets) | |
| # - Dependabot PRs: preview-publishing a dependency bump to Test PyPI / | |
| # Docker Hub is pointless and fails (no version bump, secret access). | |
| if: >- | |
| github.event.pull_request.head.repo.full_name == github.repository && | |
| github.event.pull_request.user.login != 'dependabot[bot]' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| id-token: write | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 | |
| with: | |
| python-version: '3.13' | |
| - name: Install build tooling | |
| uses: ./.github/actions/setup-hatch | |
| - name: Inject full dynamic version | |
| run: python .hooks/sync_version.py --dev | |
| - name: Clean previous builds | |
| run: rm -rf dist/ build/ *.egg-info | |
| - name: Get Hatch version | |
| id: version | |
| run: | | |
| VERSION=$(hatch version | cut -d+ -f1) | |
| echo "VERSION=$VERSION" >> $GITHUB_ENV | |
| - name: Check if version already exists on Test PyPI | |
| id: version_check | |
| env: | |
| VERSION: ${{ env.VERSION }} | |
| run: | | |
| if curl -s -f https://test.pypi.org/pypi/socketsecurity/${VERSION}/json > /dev/null; then | |
| echo "exists=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Build package | |
| if: steps.version_check.outputs.exists != 'true' | |
| run: | | |
| hatch build | |
| - name: Publish to Test PyPI | |
| if: steps.version_check.outputs.exists != 'true' | |
| uses: pypa/gh-action-pypi-publish@ab69e431e9c9f48a3310be0a56527c679f56e04d | |
| with: | |
| repository-url: https://test.pypi.org/legacy/ | |
| verbose: true | |
| - name: Comment on PR | |
| if: steps.version_check.outputs.exists != 'true' | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea | |
| env: | |
| VERSION: ${{ env.VERSION }} | |
| with: | |
| script: | | |
| const version = process.env.VERSION; | |
| const prNumber = context.payload.pull_request.number; | |
| const owner = context.repo.owner; | |
| const repo = context.repo.repo; | |
| // Find existing bot comments | |
| const comments = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| }); | |
| const botComment = comments.data.find(comment => | |
| comment.user.type === 'Bot' && | |
| comment.body.includes('🚀 Preview package published!') | |
| ); | |
| const comment = ` | |
| 🚀 Preview package published! | |
| Install with: | |
| \`\`\`bash | |
| pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple socketsecurity==${version} | |
| \`\`\` | |
| Docker image: \`socketdev/cli:pr-${prNumber}\` | |
| `; | |
| if (botComment) { | |
| // Update existing comment | |
| await github.rest.issues.updateComment({ | |
| owner: owner, | |
| repo: repo, | |
| comment_id: botComment.id, | |
| body: comment | |
| }); | |
| } else { | |
| // Create new comment | |
| await github.rest.issues.createComment({ | |
| owner: owner, | |
| repo: repo, | |
| issue_number: prNumber, | |
| body: comment | |
| }); | |
| } | |
| - name: Verify package is available | |
| if: steps.version_check.outputs.exists != 'true' | |
| id: verify_package | |
| env: | |
| VERSION: ${{ env.VERSION }} | |
| run: | | |
| for i in {1..30}; do | |
| if pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple socketsecurity==${VERSION}; then | |
| echo "Package ${VERSION} is now available and installable on Test PyPI" | |
| pip uninstall -y socketsecurity | |
| echo "success=true" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| echo "Attempt $i: Package not yet installable, waiting 20s... (${i}/30)" | |
| sleep 20 | |
| done | |
| echo "success=false" >> $GITHUB_OUTPUT | |
| exit 1 | |
| - name: Set up Docker publishing | |
| if: steps.verify_package.outputs.success == 'true' | |
| uses: ./.github/actions/setup-docker-publish | |
| with: | |
| dockerhub-username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Build & Push Docker Preview | |
| if: steps.verify_package.outputs.success == 'true' | |
| uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 | |
| env: | |
| VERSION: ${{ env.VERSION }} | |
| with: | |
| push: true | |
| # Preview images are for quick testing -- build amd64 only. arm64 via | |
| # QEMU emulation is the slowest part of the job; release builds keep | |
| # multi-arch. GHA layer cache speeds up repeated preview builds. | |
| platforms: linux/amd64 | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| tags: | | |
| socketdev/cli:pr-${{ github.event.pull_request.number }} | |
| build-args: | | |
| CLI_VERSION=${{ env.VERSION }} | |
| PIP_INDEX_URL=https://test.pypi.org/simple | |
| PIP_EXTRA_INDEX_URL=https://pypi.org/simple |