|
1 | 1 | name: Publish |
2 | 2 |
|
3 | 3 | on: |
4 | | - pull_request_target: |
5 | | - types: [closed] |
6 | | - |
7 | | -concurrency: |
8 | | - group: release-main |
9 | | - cancel-in-progress: false |
| 4 | + push: |
| 5 | + tags: ["v*"] |
| 6 | + workflow_dispatch: |
| 7 | + inputs: |
| 8 | + tag: |
| 9 | + description: Tag to publish (for example v0.7.1) |
| 10 | + required: true |
| 11 | + type: string |
10 | 12 |
|
11 | 13 | jobs: |
12 | 14 | publish: |
13 | | - if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main' |
14 | 15 | runs-on: ubuntu-latest |
15 | 16 | permissions: |
16 | 17 | contents: write |
17 | 18 | id-token: write |
18 | 19 |
|
19 | 20 | steps: |
20 | | - - name: Determine release bump from labels |
21 | | - id: release_meta |
22 | | - uses: actions/github-script@v7 |
23 | | - with: |
24 | | - script: | |
25 | | - const labels = (context.payload.pull_request.labels || []).map((label) => label.name); |
26 | | - const candidates = ["major", "minor", "patch"]; |
27 | | - const matched = candidates.filter((candidate) => labels.includes(candidate)); |
28 | | -
|
29 | | - if (matched.length === 0) { |
30 | | - core.notice("No release label found (major|minor|patch). Skipping publish."); |
31 | | - core.setOutput("should_release", "false"); |
32 | | - return; |
33 | | - } |
34 | | -
|
35 | | - if (matched.length > 1) { |
36 | | - core.setFailed(`Multiple release labels found: ${matched.join(", ")}. Keep exactly one of major|minor|patch.`); |
37 | | - return; |
38 | | - } |
39 | | -
|
40 | | - core.info(`Selected release bump: ${matched[0]}`); |
41 | | - core.setOutput("should_release", "true"); |
42 | | - core.setOutput("bump", matched[0]); |
| 21 | + - name: Resolve tag to publish |
| 22 | + id: publish_meta |
| 23 | + shell: bash |
| 24 | + run: | |
| 25 | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then |
| 26 | + TAG="${{ inputs.tag }}" |
| 27 | + else |
| 28 | + TAG="${GITHUB_REF_NAME}" |
| 29 | + fi |
| 30 | + case "$TAG" in |
| 31 | + v*) ;; |
| 32 | + *) |
| 33 | + echo "Tag must start with v: $TAG" |
| 34 | + exit 1 |
| 35 | + ;; |
| 36 | + esac |
| 37 | + echo "tag=$TAG" >> "$GITHUB_OUTPUT" |
43 | 38 |
|
44 | 39 | - uses: actions/checkout@v4 |
45 | | - if: steps.release_meta.outputs.should_release == 'true' |
46 | 40 | with: |
47 | | - ref: main |
| 41 | + ref: ${{ steps.publish_meta.outputs.tag }} |
48 | 42 | fetch-depth: 0 |
49 | 43 |
|
50 | 44 | - uses: actions/setup-node@v4 |
51 | | - if: steps.release_meta.outputs.should_release == 'true' |
52 | 45 | with: |
53 | 46 | node-version: 20 |
54 | 47 | cache: npm |
55 | 48 | registry-url: https://registry.npmjs.org |
56 | 49 |
|
57 | 50 | - run: npm ci |
58 | | - if: steps.release_meta.outputs.should_release == 'true' |
59 | 51 |
|
60 | 52 | - run: npm run check |
61 | | - if: steps.release_meta.outputs.should_release == 'true' |
62 | 53 | env: |
63 | 54 | ARENA_VCR_MODE: replay |
64 | 55 | ARENA_API_URL: https://staging-api.are.na |
65 | 56 |
|
66 | | - - name: Configure git author |
67 | | - if: steps.release_meta.outputs.should_release == 'true' |
| 57 | + - name: Read package version |
| 58 | + id: package_meta |
| 59 | + shell: bash |
68 | 60 | run: | |
69 | | - git config user.name "github-actions[bot]" |
70 | | - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" |
| 61 | + VERSION="$(node -p "require('./package.json').version")" |
| 62 | + echo "version=$VERSION" >> "$GITHUB_OUTPUT" |
71 | 63 |
|
72 | | - - name: Bump version and create tag |
73 | | - id: version |
74 | | - if: steps.release_meta.outputs.should_release == 'true' |
| 64 | + - name: Check whether version is already on npm |
| 65 | + id: npm_state |
| 66 | + shell: bash |
75 | 67 | run: | |
76 | | - NEW_TAG="$(npm version "${{ steps.release_meta.outputs.bump }}" -m "release: %s")" |
77 | | - echo "tag=${NEW_TAG}" >> "$GITHUB_OUTPUT" |
78 | | -
|
79 | | - - name: Push release commit and tags |
80 | | - if: steps.release_meta.outputs.should_release == 'true' |
81 | | - run: git push origin HEAD:main --follow-tags |
| 68 | + if npm view "@aredotna/cli@${{ steps.package_meta.outputs.version }}" version >/dev/null 2>&1; then |
| 69 | + echo "already_published=true" >> "$GITHUB_OUTPUT" |
| 70 | + else |
| 71 | + echo "already_published=false" >> "$GITHUB_OUTPUT" |
| 72 | + fi |
82 | 73 |
|
83 | 74 | - run: npm publish --provenance --access public |
84 | | - if: steps.release_meta.outputs.should_release == 'true' |
| 75 | + if: steps.npm_state.outputs.already_published != 'true' |
85 | 76 |
|
86 | | - - name: Create GitHub Release |
87 | | - if: steps.release_meta.outputs.should_release == 'true' |
| 77 | + - name: Ensure GitHub Release exists |
88 | 78 | env: |
89 | 79 | GH_TOKEN: ${{ github.token }} |
90 | | - run: gh release create "${{ steps.version.outputs.tag }}" --generate-notes |
| 80 | + shell: bash |
| 81 | + run: | |
| 82 | + if gh release view "${{ steps.publish_meta.outputs.tag }}" >/dev/null 2>&1; then |
| 83 | + echo "GitHub Release already exists for ${{ steps.publish_meta.outputs.tag }}" |
| 84 | + else |
| 85 | + gh release create "${{ steps.publish_meta.outputs.tag }}" --generate-notes |
| 86 | + fi |
0 commit comments