docs: Update README examples to use v2.1.0 #6
Workflow file for this run
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_target: | |
| types: [opened, synchronize, reopened] | |
| jobs: | |
| request-approval: | |
| name: Request Approval | |
| runs-on: ubuntu-latest | |
| permissions: | |
| pull-requests: write | |
| steps: | |
| - name: Comment requesting approval | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 | |
| with: | |
| script: | | |
| // Check if approval comment already exists | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const approvalComment = comments.find(comment => | |
| comment.body.includes('<!-- approval-request-comment -->') | |
| ); | |
| // Only create comment if it doesn't exist | |
| if (!approvalComment) { | |
| const body = `<!-- approval-request-comment --> | |
| ## ⚠️ Manual approval required | |
| A repository owner must approve the Docker preview deployment for this PR. | |
| **PR Author:** @${{ github.event.pull_request.user.login }} | |
| **Head SHA:** \`${{ github.event.pull_request.head.sha }}\` | |
| [Review and approve in Actions →](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})`; | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body | |
| }); | |
| } | |
| pr-preview: | |
| name: Deploy on Docker | |
| runs-on: ubuntu-latest | |
| needs: request-approval | |
| environment: | |
| name: "PR Preview" | |
| url: https://github.com/${{ github.repository }}/pkgs/container/actions-clever-cloud | |
| permissions: | |
| contents: read | |
| packages: write | |
| pull-requests: write | |
| steps: | |
| # SECURITY: Checkout the base ref (trusted code) for the workflow | |
| # This prevents untrusted PR code from accessing secrets | |
| - name: Checkout base (trusted) | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| with: | |
| ref: ${{ github.event.pull_request.base.sha }} | |
| - name: Get PR head SHA | |
| id: sha | |
| run: echo "sha=${{ github.event.pull_request.head.sha }}" >> $GITHUB_OUTPUT | |
| - name: Get Docker tag | |
| id: docker-tag | |
| run: echo "tag=pr-${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT | |
| - name: Get package version | |
| id: package | |
| run: | | |
| VERSION=$(jq -r ' | |
| .version | | |
| if test("^[0-9]+\\.[0-9]+\\.[0-9]+(-[0-9A-Za-z.-]+)?(\\+[0-9A-Za-z.-]+)?$") | |
| then . | |
| else error("Invalid semver format in package.json") | |
| end | |
| ' package.json 2>&1) | |
| if [ $? -ne 0 ]; then | |
| echo "::error::$VERSION" # Expand the error into an annotation | |
| exit 1 | |
| fi | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| - name: Validate inputs (security check) | |
| run: | | |
| # Ensure tag matches expected pattern | |
| if [[ ! "${{ steps.docker-tag.outputs.tag }}" =~ ^pr-[0-9]+$ ]]; then | |
| echo "::error::Security violation: Invalid PR tag pattern" | |
| exit 1 | |
| fi | |
| # Ensure version is a valid semver | |
| if ! echo "${{ steps.package.outputs.version }}" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$'; then | |
| echo "::error::Security violation: Invalid version format" | |
| exit 1 | |
| fi | |
| - name: Collect Docker labels & tags | |
| id: docker-labels-tags | |
| run: | | |
| echo 'labels<<__LABELS_EOF__' >> $GITHUB_OUTPUT | |
| echo "org.opencontainers.image.title=47ng/actions-clever-cloud" >> $GITHUB_OUTPUT | |
| echo "org.opencontainers.image.description=GitHub action to deploy to Clever Cloud (PR preview)" >> $GITHUB_OUTPUT | |
| echo "org.opencontainers.image.version=${{ steps.package.outputs.version }}-pr.${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT | |
| echo "org.opencontainers.image.revision=${{ steps.sha.outputs.sha }}" >> $GITHUB_OUTPUT | |
| echo "org.opencontainers.image.licenses=MIT" >> $GITHUB_OUTPUT | |
| echo "org.opencontainers.image.source=https://github.com/${{github.repository}}/tree/${{ steps.sha.outputs.sha }}" >> $GITHUB_OUTPUT | |
| echo "org.opencontainers.image.documentation=https://github.com/${{github.repository}}/pull/${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT | |
| echo "org.opencontainers.image.url=https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}" >> $GITHUB_OUTPUT | |
| echo '__LABELS_EOF__' >> $GITHUB_OUTPUT | |
| echo 'tags<<__TAGS_EOF__' >> $GITHUB_OUTPUT | |
| echo "ghcr.io/47ng/actions-clever-cloud:${{ steps.docker-tag.outputs.tag }}" >> $GITHUB_OUTPUT | |
| echo "ghcr.io/47ng/actions-clever-cloud:git-${{ steps.sha.outputs.sha }}" >> $GITHUB_OUTPUT | |
| echo '__TAGS_EOF__' >> $GITHUB_OUTPUT | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 | |
| - name: Login to GitHub Container Registry | |
| uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.repository_owner }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # SECURITY: Checkout the PR head for building | |
| # We do this AFTER extracting all metadata to prevent tampering | |
| - name: Checkout PR head (untrusted code) | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| with: | |
| ref: ${{ steps.sha.outputs.sha }} | |
| - name: Build and push | |
| id: docker-build-push | |
| uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 | |
| with: | |
| context: . | |
| labels: "${{ steps.docker-labels-tags.outputs.labels }}" | |
| tags: "${{ steps.docker-labels-tags.outputs.tags }}" | |
| push: true | |
| - name: Generate step summary | |
| run: | | |
| echo "## 🐳 Docker image" >> $GITHUB_STEP_SUMMARY | |
| echo "Digest: \`${{ steps.docker-build-push.outputs.digest }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "### 📌 Tags" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| echo "${{ steps.docker-labels-tags.outputs.tags }}" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| echo "### 🏷 Labels" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| echo "${{ steps.docker-labels-tags.outputs.labels }}" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| - name: Comment on PR | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 | |
| with: | |
| script: | | |
| const body = `<!-- docker-build-comment --> | |
| ## 🐳 Docker image preview | |
| Preview this PR in your workflow: | |
| \`\`\`yaml | |
| # Use the PR number to follow changes in this PR | |
| - uses: docker://ghcr.io/47ng/actions-clever-cloud:${{ steps.docker-tag.outputs.tag }} | |
| # Use the git SHA for pinning to a specific commit | |
| - uses: docker://ghcr.io/47ng/actions-clever-cloud:git-${{ steps.sha.outputs.sha }} | |
| \`\`\` | |
| <details> | |
| <summary>Image metadata</summary> | |
| <br/> | |
| Digest: \`${{ steps.docker-build-push.outputs.digest }}\` | |
| ### 📌 Tags | |
| \`\`\` | |
| ${{ steps.docker-labels-tags.outputs.tags }} | |
| \`\`\` | |
| ### 🏷 Labels | |
| \`\`\` | |
| ${{ steps.docker-labels-tags.outputs.labels }} | |
| \`\`\` | |
| </details> | |
| --- | |
| <sub>🤖 This comment is updated on every push</sub>`; | |
| // Find existing comment by marker | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const botComment = comments.find(comment => | |
| comment.body.startsWith('<!-- docker-build-comment -->') | |
| ); | |
| if (botComment) { | |
| // Update existing comment | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: body | |
| }); | |
| } else { | |
| // Create new comment | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: body | |
| }); | |
| } |