-
-
Notifications
You must be signed in to change notification settings - Fork 711
259 lines (224 loc) · 9.1 KB
/
Copy pathpublish.yml
File metadata and controls
259 lines (224 loc) · 9.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
name: Publish
# Handles two scenarios:
# 1. Dev publish: auto-triggered after "Build and Test" succeeds on master
# 2. PR prerelease: manually triggered by Liz for trusted testers
#
# Manual trigger (Liz uses this via gh CLI):
# gh workflow run publish.yml \
# --repo dexie/Dexie.js \
# --ref <branch-name> \
# -f mode=pr \
# -f pr_number=2253 \
# -f packages=dexie-cloud-addon \
# -f requester_discord_id=321912613246337024 \
# -f build_number=1
on:
workflow_run:
workflows: ["Build and Test"]
types: [completed]
branches: [master]
workflow_dispatch:
inputs:
mode:
description: 'Publish mode'
required: true
default: 'pr'
type: choice
options:
- pr
- dev
pr_number:
description: 'PR number (required for mode=pr, e.g. 2253)'
required: false
type: string
packages:
description: 'Packages to publish (comma-separated or "all")'
required: false
default: 'all'
type: string
build_number:
description: 'Build number suffix for PR mode (increment if re-running)'
required: false
default: '1'
type: string
requester_discord_id:
description: 'Discord user ID of the person who requested the prerelease'
required: false
type: string
jobs:
publish:
name: Publish to npm
runs-on: ubuntu-latest
# For workflow_run trigger: only run if tests passed
# For workflow_dispatch (manual PR prereleases): always run
if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success'
permissions:
contents: read
id-token: write # required for OIDC Trusted Publisher
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 22.14.0
registry-url: https://registry.npmjs.org
# npm 11.5.1+ required for OIDC Trusted Publisher
- name: Upgrade npm
run: npm install -g npm@11.5.1
- name: Install dependencies
run: pnpm install
# Build in dependency order:
# 1. dexie (no workspace deps)
# 2. dexie-cloud-common, dexie-svelte-query (no workspace deps)
# 3. y-dexie (→ dexie)
# 4. dexie-export-import (→ dexie)
# 5. dexie-react-hooks (→ dexie, y-dexie)
# 6. dexie-cloud-addon (→ dexie, dexie-cloud-common, y-dexie)
# Note: dexie-observable and dexie-syncable are excluded (planned deprecation)
- name: Build dexie
run: pnpm run build
- name: Build dexie-cloud-common
working-directory: libs/dexie-cloud-common
run: pnpm run build
- name: Build dexie-svelte-query
working-directory: libs/dexie-svelte-query
run: pnpm run build
- name: Build y-dexie
working-directory: addons/y-dexie
run: pnpm run build
- name: Build dexie-export-import
working-directory: addons/dexie-export-import
run: pnpm run build
- name: Build dexie-react-hooks
working-directory: libs/dexie-react-hooks
run: pnpm run build
- name: Build dexie-cloud-addon
working-directory: addons/dexie-cloud
run: pnpm run build
- name: Publish packages
id: publish
run: |
# Determine mode: push to master = dev, workflow_dispatch = use input
if [ "${{ github.event_name }}" = "workflow_run" ]; then
MODE="dev"
else
MODE="${{ inputs.mode }}"
fi
# Validate pr_number is provided when mode=pr
if [ "$MODE" = "pr" ] && [ -z "${{ inputs.pr_number }}" ]; then
echo "Error: pr_number is required when mode=pr"
exit 1
fi
PR="${{ inputs.pr_number }}"
BUILD="${{ inputs.build_number }}"
PACKAGES="${{ inputs.packages }}"
[ -z "$PACKAGES" ] && PACKAGES="all"
PUBLISHED_VERSIONS=""
PUBLISHED_COUNT=0
publish_pkg() {
local PKG_NAME="$1"
local PKG_DIR="$2"
# Check if this package should be published
local SHOULD_PUBLISH=false
if [ "$PACKAGES" = "all" ]; then
SHOULD_PUBLISH=true
else
IFS=',' read -ra PKG_LIST <<< "$PACKAGES"
for p in "${PKG_LIST[@]}"; do
if [ "$(echo $p | tr -d ' ')" = "$PKG_NAME" ]; then
SHOULD_PUBLISH=true
break
fi
done
fi
if [ "$SHOULD_PUBLISH" = "false" ]; then
echo "Skipping $PKG_NAME (not in requested packages)"
return
fi
local BASE_VERSION=$(node -p "require('./${PKG_DIR}/package.json').version")
if [ "$MODE" = "dev" ]; then
# Dev: publish as-is if not already published
# Use exit code to distinguish "not found" from real errors
if npm show "${PKG_NAME}@${BASE_VERSION}" version >/dev/null 2>&1; then
echo "${PKG_NAME}@${BASE_VERSION} already published, skipping."
return
fi
local PUBLISH_VERSION="$BASE_VERSION"
local TAG="dev"
else
# PR prerelease: append -prNNN.K suffix
local PUBLISH_VERSION="${BASE_VERSION}-pr${PR}.${BUILD}"
local TAG="pr${PR}"
# Temporarily patch version
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('./${PKG_DIR}/package.json', 'utf8'));
pkg.version = '${PUBLISH_VERSION}';
fs.writeFileSync('./${PKG_DIR}/package.json', JSON.stringify(pkg, null, 2) + '\n');
"
fi
echo "Publishing ${PKG_NAME}@${PUBLISH_VERSION} with tag ${TAG}..."
(cd "${PKG_DIR}" && pnpm publish --tag "${TAG}" --provenance --no-git-checks)
# Restore original version after PR publish
if [ "$MODE" = "pr" ]; then
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('./${PKG_DIR}/package.json', 'utf8'));
pkg.version = '${BASE_VERSION}';
fs.writeFileSync('./${PKG_DIR}/package.json', JSON.stringify(pkg, null, 2) + '\n');
"
fi
PUBLISHED_VERSIONS="${PUBLISHED_VERSIONS}\n- \`npm install ${PKG_NAME}@${PUBLISH_VERSION}\`"
PUBLISHED_COUNT=$((PUBLISHED_COUNT + 1))
}
publish_pkg "dexie" "."
publish_pkg "dexie-cloud-common" "libs/dexie-cloud-common"
publish_pkg "dexie-react-hooks" "libs/dexie-react-hooks"
publish_pkg "dexie-svelte-query" "libs/dexie-svelte-query"
publish_pkg "dexie-export-import" "addons/dexie-export-import"
publish_pkg "y-dexie" "addons/y-dexie"
publish_pkg "dexie-cloud-addon" "addons/dexie-cloud"
# Fail fast if no packages were published (likely a typo in inputs.packages)
if [ "$PUBLISHED_COUNT" -eq 0 ] && [ "$PACKAGES" != "all" ]; then
echo "::error::No packages matched inputs.packages='${PACKAGES}'. Valid names: dexie, dexie-cloud-common, dexie-react-hooks, dexie-svelte-query, dexie-export-import, y-dexie, dexie-cloud-addon"
exit 1
fi
echo "mode=$MODE" >> $GITHUB_OUTPUT
echo "published_versions<<EOF" >> $GITHUB_OUTPUT
echo -e "$PUBLISHED_VERSIONS" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Notify via Discord (PR mode only)
if: always() && github.event_name == 'workflow_dispatch' && inputs.mode == 'pr'
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_NPM_RELEASES }}
run: |
PR="${{ inputs.pr_number }}"
REQUESTER="${{ inputs.requester_discord_id }}"
OUTCOME="${{ steps.publish.outcome }}"
BRANCH="${GITHUB_REF_NAME}"
RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
if [ "$OUTCOME" = "success" ]; then
MENTION=""
if [ -n "$REQUESTER" ]; then
MENTION=" (requested by <@${REQUESTER}>)"
fi
VERSIONS="${{ steps.publish.outputs.published_versions }}"
TITLE="✅ PR #${PR} prerelease published${MENTION}"
BODY="Branch: \`${BRANCH}\`\n\n${VERSIONS}\n\n[View run](${RUN_URL})"
else
TITLE="❌ PR #${PR} prerelease FAILED"
BODY="[View run](${RUN_URL})"
fi
# Build JSON payload with python to safely handle special characters
python3 -c "
import json, os, sys
title = os.environ.get('MSG_TITLE', '')
body = os.environ.get('MSG_BODY', '')
content = title + '\n\n' + body
print(json.dumps({'content': content}))
" MSG_TITLE="$TITLE" MSG_BODY="$BODY" | \
curl -s -X POST "$DISCORD_WEBHOOK" \
-H "Content-Type: application/json" \
-d @-