|
4 | 4 | name: Publish |
5 | 5 |
|
6 | 6 | on: |
7 | | - push: |
8 | | - tags: |
9 | | - - "data-designer-*/v*" |
| 7 | + release: |
| 8 | + types: [published] |
10 | 9 |
|
11 | 10 | jobs: |
12 | 11 | publish: |
| 12 | + if: startsWith(github.event.release.tag_name, 'data-designer-') && contains(github.event.release.tag_name, '/v') |
13 | 13 | runs-on: ubuntu-latest |
14 | 14 | permissions: |
15 | 15 | contents: write |
|
22 | 22 | - uses: actions/checkout@v4 |
23 | 23 | with: |
24 | 24 | fetch-depth: 0 # full history needed for merge-base check |
| 25 | + ref: ${{ github.event.release.tag_name }} |
25 | 26 |
|
26 | 27 | - uses: astral-sh/setup-uv@v4 |
27 | 28 | with: |
|
30 | 31 |
|
31 | 32 | - name: Parse tag |
32 | 33 | id: tag |
| 34 | + env: |
| 35 | + RELEASE_TAG: ${{ github.event.release.tag_name }} |
| 36 | + RELEASE_PRERELEASE: ${{ github.event.release.prerelease }} |
33 | 37 | run: | |
34 | | - TAG="${GITHUB_REF_NAME}" |
| 38 | + TAG="${RELEASE_TAG}" |
| 39 | + if [ "${RELEASE_PRERELEASE}" = "true" ]; then |
| 40 | + echo "ERROR: prerelease plugin package publication is not supported" |
| 41 | + exit 1 |
| 42 | + fi |
| 43 | + if [[ ! "${TAG}" =~ ^data-designer-[a-z0-9]+([._-][a-z0-9]+)*/v[0-9]+[.][0-9]+[.][0-9]+$ ]]; then |
| 44 | + echo "ERROR: release tag must match <plugin-package>/vX.Y.Z, got ${TAG}" |
| 45 | + exit 1 |
| 46 | + fi |
35 | 47 | PLUGIN_NAME="${TAG%%/v*}" |
36 | 48 | TAG_VERSION="${TAG#*/v}" |
37 | 49 | PLUGIN_DIR="plugins/${PLUGIN_NAME}" |
|
47 | 59 | - name: Validate tagged commit is on main |
48 | 60 | run: | |
49 | 61 | git fetch origin main |
50 | | - git merge-base --is-ancestor "${GITHUB_SHA}" origin/main \ |
| 62 | + git merge-base --is-ancestor HEAD origin/main \ |
51 | 63 | || { echo "ERROR: tagged commit is not on main"; exit 1; } |
52 | 64 |
|
53 | 65 | - name: Sync workspace |
|
56 | 68 | - name: Validate version match and metadata |
57 | 69 | run: uv run ddp check-release "${{ steps.tag.outputs.plugin_name }}" "${{ steps.tag.outputs.tag_version }}" |
58 | 70 |
|
59 | | - - name: Authorize tag pusher against CODEOWNERS |
60 | | - env: |
61 | | - ACTOR: ${{ github.actor }} |
62 | | - PLUGIN_DIR: ${{ steps.tag.outputs.plugin_dir }} |
63 | | - # Team lookups require a token with read:org scope. The default |
64 | | - # GITHUB_TOKEN usually works for public teams; set MEMBERSHIP_TOKEN |
65 | | - # as a PAT secret if team resolution fails. |
66 | | - GH_TOKEN: ${{ secrets.MEMBERSHIP_TOKEN || secrets.GITHUB_TOKEN }} |
67 | | - run: | |
68 | | - ALL_OWNERS=$(uv run python -m ddp.release_owners --all "${PLUGIN_DIR}/CODEOWNERS") |
69 | | - OWNERS=$(uv run python -m ddp.release_owners "${PLUGIN_DIR}/CODEOWNERS") |
70 | | - MATCH=0 |
71 | | - for owner in $OWNERS; do |
72 | | - case "$owner" in |
73 | | - @*/*) |
74 | | - ORG="${owner#@}"; ORG="${ORG%%/*}" |
75 | | - TEAM_SLUG="${owner##*/}" |
76 | | - if gh api "orgs/${ORG}/teams/${TEAM_SLUG}/memberships/${ACTOR}" >/dev/null 2>&1; then |
77 | | - MATCH=1; break |
78 | | - fi |
79 | | - ;; |
80 | | - @*) |
81 | | - if [ "$owner" = "@${ACTOR}" ]; then MATCH=1; break; fi |
82 | | - ;; |
83 | | - esac |
84 | | - done |
85 | | - if [ "$MATCH" -eq 0 ]; then |
86 | | - echo "ERROR: @${ACTOR} is not an authorized owner of ${PLUGIN_DIR}/CODEOWNERS" |
87 | | - echo "Listed owners: $ALL_OWNERS" |
88 | | - exit 1 |
89 | | - fi |
90 | | -
|
91 | 71 | - name: Run plugin tests in isolated venv |
92 | 72 | env: |
93 | 73 | PLUGIN_NAME: ${{ steps.tag.outputs.plugin_name }} |
|
0 commit comments