@payfit/nx-core 5.3.0-ephemeral-labels-executor.1 → 5.3.0-ephemeral-labels-executor.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/executors/docker-build/executor.js +6 -3
- package/dist/src/executors/docker-build/executor.js.map +1 -1
- package/dist/src/executors/publisher/frontend.js +2 -1
- package/dist/src/executors/publisher/frontend.js.map +1 -1
- package/dist/src/executors/publisher/helm.js +3 -5
- package/dist/src/executors/publisher/helm.js.map +1 -1
- package/dist/src/executors/publisher/lambda.js +1 -1
- package/dist/src/executors/publisher/lambda.js.map +1 -1
- package/dist/src/generators/local-lambda-setup/files/docker-compose/docker-compose.yml.template +21 -0
- package/dist/src/generators/local-lambda-setup/files/scripts/invoke_lambda_local.sh.template +97 -0
- package/dist/src/generators/local-lambda-setup/local-lambda-setup.d.ts +25 -0
- package/dist/src/generators/local-lambda-setup/local-lambda-setup.js +167 -0
- package/dist/src/generators/local-lambda-setup/local-lambda-setup.js.map +1 -0
- package/dist/src/generators/local-lambda-setup/schema.json +24 -0
- package/dist/src/scripts/nx-core-updater.js +311 -60
- package/dist/src/utils/common/oci.d.ts +17 -3
- package/dist/src/utils/common/oci.js +36 -4
- package/dist/src/utils/common/oci.js.map +1 -1
- package/dist/src/utils/docker.d.ts +2 -1
- package/dist/src/utils/docker.js +5 -4
- package/dist/src/utils/docker.js.map +1 -1
- package/dist/src/utils/helm.d.ts +1 -1
- package/dist/src/utils/helm.js +8 -3
- package/dist/src/utils/helm.js.map +1 -1
- package/dist/src/utils/spacelift/lib/__generated__/gql.js +1 -1
- package/dist/src/utils/spacelift/lib/__generated__/graphql.d.ts +4 -4
- package/dist/src/utils/spacelift/lib/__generated__/graphql.js +3 -3
- package/dist/src/utils/spacelift/lib/__generated__/graphql.js.map +1 -1
- package/generators.json +5 -0
- package/package.json +3 -2
|
@@ -7,8 +7,17 @@ const { promisify } = require('util')
|
|
|
7
7
|
|
|
8
8
|
const execAsync = promisify(exec)
|
|
9
9
|
|
|
10
|
-
// Configuration
|
|
11
|
-
const NX_CORE_VERSION = '
|
|
10
|
+
// Configuration (can be overridden via CLI flags)
|
|
11
|
+
const NX_CORE_VERSION = '5.2.4'
|
|
12
|
+
const NX_VERSION = '22.0.2' // e.g. '21.3.11'
|
|
13
|
+
const CHANGELOG_MODE = 'combined' // 'combined' | 'raw'
|
|
14
|
+
|
|
15
|
+
// Read optional Jira ticket URL from env only
|
|
16
|
+
const JIRA_TICKET_URL = undefined
|
|
17
|
+
|
|
18
|
+
// Collect PR URLs created during this run
|
|
19
|
+
const CREATED_PR_URLS = []
|
|
20
|
+
|
|
12
21
|
const REPOSITORIES = [
|
|
13
22
|
'authorization',
|
|
14
23
|
'company-lifecycle',
|
|
@@ -22,6 +31,7 @@ const REPOSITORIES = [
|
|
|
22
31
|
'jetlang',
|
|
23
32
|
'organization-structure',
|
|
24
33
|
'payfit-domains',
|
|
34
|
+
'payroll',
|
|
25
35
|
'talent-management',
|
|
26
36
|
'time-absences',
|
|
27
37
|
]
|
|
@@ -68,117 +78,208 @@ async function run(command, cwd = process.cwd()) {
|
|
|
68
78
|
}
|
|
69
79
|
}
|
|
70
80
|
|
|
71
|
-
// Check if package.json
|
|
72
|
-
async function
|
|
81
|
+
// Check if @payfit/nx-core in package.json needs update
|
|
82
|
+
async function needsNxCoreUpdate(repoPath) {
|
|
73
83
|
try {
|
|
74
84
|
const packageJsonPath = path.join(repoPath, 'package.json')
|
|
75
85
|
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'))
|
|
76
86
|
const currentVersion = packageJson.devDependencies?.['@payfit/nx-core']
|
|
77
87
|
|
|
78
88
|
if (!currentVersion) {
|
|
79
|
-
console.log(
|
|
89
|
+
console.log(`ℹ @payfit/nx-core not found in devDependencies`)
|
|
80
90
|
return { needsUpdate: false, currentVersion: null }
|
|
81
91
|
}
|
|
82
92
|
|
|
83
93
|
if (compareVersions(currentVersion, NX_CORE_VERSION) === 0) {
|
|
84
|
-
console.log(
|
|
94
|
+
console.log(`ℹ Already on version ${NX_CORE_VERSION}`)
|
|
95
|
+
return { needsUpdate: false, currentVersion }
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
console.log(
|
|
99
|
+
`📦 Current version: ${currentVersion}, target: ${NX_CORE_VERSION}`,
|
|
100
|
+
)
|
|
101
|
+
return { needsUpdate: true, currentVersion }
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error(`❌ Could not read package.json: ${error.message}`)
|
|
104
|
+
return { needsUpdate: false, currentVersion: null }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Check if Nx in package.json needs update
|
|
109
|
+
async function needsNxUpdate(repoPath) {
|
|
110
|
+
if (!NX_VERSION) {
|
|
111
|
+
return { needsUpdate: false, currentVersion: null }
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const packageJsonPath = path.join(repoPath, 'package.json')
|
|
115
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'))
|
|
116
|
+
const currentVersion =
|
|
117
|
+
packageJson.devDependencies?.['nx'] ?? packageJson.dependencies?.['nx']
|
|
118
|
+
|
|
119
|
+
if (!currentVersion) {
|
|
120
|
+
console.log(`ℹ nx not found in package.json`)
|
|
121
|
+
return { needsUpdate: false, currentVersion: null }
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (compareVersions(currentVersion, NX_VERSION) === 0) {
|
|
125
|
+
console.log(`ℹ Nx already on version ${NX_VERSION}`)
|
|
85
126
|
return { needsUpdate: false, currentVersion }
|
|
86
127
|
}
|
|
87
128
|
|
|
88
129
|
console.log(
|
|
89
|
-
|
|
130
|
+
`📦 Nx current version: ${currentVersion}, target: ${NX_VERSION}`,
|
|
90
131
|
)
|
|
91
132
|
return { needsUpdate: true, currentVersion }
|
|
92
133
|
} catch (error) {
|
|
93
|
-
console.error(
|
|
134
|
+
console.error(`❌ Could not read package.json for Nx: ${error.message}`)
|
|
94
135
|
return { needsUpdate: false, currentVersion: null }
|
|
95
136
|
}
|
|
96
137
|
}
|
|
97
138
|
|
|
98
139
|
// Process a single repository
|
|
99
140
|
async function processRepo(repoName) {
|
|
100
|
-
console.log(
|
|
141
|
+
console.log(`🚀 Processing ${repoName}`)
|
|
101
142
|
|
|
102
143
|
const repoPath = path.join(WORK_DIR, repoName)
|
|
103
144
|
|
|
104
145
|
try {
|
|
105
146
|
// Clone repo
|
|
106
|
-
console.log(
|
|
147
|
+
console.log(`📥 Cloning repository...`)
|
|
107
148
|
await run(
|
|
108
149
|
`git clone https://github.com/PayFit/${repoName}.git ${repoPath}`,
|
|
109
150
|
WORK_DIR,
|
|
110
151
|
)
|
|
111
152
|
|
|
112
|
-
// Check if
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
153
|
+
// Check if updates needed
|
|
154
|
+
const [nxCoreUpdateInfo, nxUpdateInfo] = await Promise.all([
|
|
155
|
+
needsNxCoreUpdate(repoPath),
|
|
156
|
+
needsNxUpdate(repoPath),
|
|
157
|
+
])
|
|
158
|
+
if (!nxCoreUpdateInfo.needsUpdate && !nxUpdateInfo.needsUpdate) {
|
|
159
|
+
console.log(`⏭️ Skipping ${repoName} - no update needed`)
|
|
116
160
|
return
|
|
117
161
|
}
|
|
118
162
|
|
|
119
|
-
// Get changelogs between current and target version
|
|
120
|
-
const releaseNotes =
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
163
|
+
// Get changelogs between current and target version (nx-core only)
|
|
164
|
+
const releaseNotes = nxCoreUpdateInfo.needsUpdate
|
|
165
|
+
? await getChangelogBetweenVersions(
|
|
166
|
+
nxCoreUpdateInfo.currentVersion,
|
|
167
|
+
NX_CORE_VERSION,
|
|
168
|
+
)
|
|
169
|
+
: ''
|
|
124
170
|
|
|
125
171
|
// Create branch
|
|
126
|
-
const
|
|
127
|
-
|
|
172
|
+
const branchNameParts = []
|
|
173
|
+
if (nxCoreUpdateInfo.needsUpdate)
|
|
174
|
+
branchNameParts.push(`nx-core-v${NX_CORE_VERSION}`)
|
|
175
|
+
if (nxUpdateInfo.needsUpdate) branchNameParts.push(`nx-v${NX_VERSION}`)
|
|
176
|
+
const branchName = branchNameParts.join('-') || `nx-maintenance`
|
|
177
|
+
console.log(`🌿 Creating branch ${branchName}`)
|
|
128
178
|
await run('git checkout main', repoPath)
|
|
129
179
|
await run(`git checkout -b ${branchName}`, repoPath)
|
|
130
180
|
|
|
131
181
|
// Install dependencies and migrate
|
|
132
|
-
console.log(
|
|
182
|
+
console.log(`📦 Installing dependencies...`)
|
|
133
183
|
await run('yarn', repoPath)
|
|
134
184
|
|
|
135
|
-
|
|
136
|
-
|
|
185
|
+
// Plan migrations
|
|
186
|
+
if (nxUpdateInfo.needsUpdate) {
|
|
187
|
+
console.log(`🔄 Planning Nx migration to version ${NX_VERSION}...`)
|
|
188
|
+
await run(`yarn nx migrate 'nx@${NX_VERSION}'`, repoPath)
|
|
189
|
+
}
|
|
190
|
+
if (nxCoreUpdateInfo.needsUpdate) {
|
|
191
|
+
console.log(
|
|
192
|
+
`🔄 Planning nx-core migration to version ${NX_CORE_VERSION}...`,
|
|
193
|
+
)
|
|
194
|
+
await run(
|
|
195
|
+
`yarn nx migrate '@payfit/nx-core@${NX_CORE_VERSION}'`,
|
|
196
|
+
repoPath,
|
|
197
|
+
)
|
|
198
|
+
}
|
|
137
199
|
|
|
138
|
-
console.log(
|
|
200
|
+
console.log(`📦 Installing dependencies after migration...`)
|
|
139
201
|
await run('yarn', repoPath)
|
|
140
202
|
|
|
141
|
-
console.log(
|
|
203
|
+
console.log(`📦 Run migrations...`)
|
|
142
204
|
await run(`yarn nx migrate --run-migrations --ifExists`, repoPath)
|
|
143
205
|
|
|
206
|
+
// If targeting Nx >= 22, ensure nx.json release.version.updateDependents = "auto"
|
|
207
|
+
if (nxUpdateInfo.needsUpdate && NX_VERSION) {
|
|
208
|
+
const major = parseInt(extractVersion(NX_VERSION).split('.')[0], 10) || 0
|
|
209
|
+
if (major >= 22) {
|
|
210
|
+
console.log(
|
|
211
|
+
`🔧 Ensuring nx.json has release.version.updateDependents = "auto" for Nx >= 22...`,
|
|
212
|
+
)
|
|
213
|
+
const nxJsonChanged = await ensureUpdateDependentsAuto(repoPath)
|
|
214
|
+
if (nxJsonChanged) {
|
|
215
|
+
console.log('🧹 Formatting workspace (npx nx format)...')
|
|
216
|
+
await run('npx nx format', repoPath)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
144
221
|
// Stage, commit and push
|
|
145
|
-
console.log(
|
|
222
|
+
console.log(`📝 Staging and committing changes...`)
|
|
146
223
|
await run('git add .', repoPath)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
224
|
+
const commitParts = []
|
|
225
|
+
if (nxUpdateInfo.needsUpdate) {
|
|
226
|
+
commitParts.push(
|
|
227
|
+
`chore(nx): update Nx from ${nxUpdateInfo.currentVersion} to ${NX_VERSION}`,
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
if (nxCoreUpdateInfo.needsUpdate) {
|
|
231
|
+
commitParts.push(
|
|
232
|
+
`chore(nx-core): update nx-core from ${nxCoreUpdateInfo.currentVersion} to ${NX_CORE_VERSION}`,
|
|
233
|
+
)
|
|
234
|
+
}
|
|
235
|
+
const commitMessage = commitParts.join('')
|
|
236
|
+
await run(`git commit -m ${JSON.stringify(commitMessage)}`, repoPath)
|
|
237
|
+
await run(`git push -q origin ${branchName}`, repoPath)
|
|
152
238
|
|
|
153
239
|
// Create PR if it doesn't exist
|
|
154
|
-
console.log(
|
|
240
|
+
console.log(`🔍 Checking for existing pull requests...`)
|
|
155
241
|
const existingPRs = await run(
|
|
156
242
|
`gh pr list --repo PayFit/${repoName} --head ${branchName} --json number`,
|
|
157
243
|
)
|
|
158
244
|
if (JSON.parse(existingPRs).length === 0) {
|
|
159
|
-
console.log(
|
|
245
|
+
console.log(`📋 Creating pull request...`)
|
|
160
246
|
|
|
161
247
|
// Create PR body with release notes
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
248
|
+
const prTitleParts = []
|
|
249
|
+
if (nxUpdateInfo.needsUpdate) prTitleParts.push(`Nx to v${NX_VERSION}`)
|
|
250
|
+
if (nxCoreUpdateInfo.needsUpdate)
|
|
251
|
+
prTitleParts.push(`@payfit/nx-core to v${NX_CORE_VERSION}`)
|
|
252
|
+
const prTitle = `chore(nx): update ${prTitleParts.join(' and ')}`
|
|
253
|
+
|
|
254
|
+
let prBody = ''
|
|
255
|
+
if (nxUpdateInfo.needsUpdate) {
|
|
256
|
+
prBody += `Update Nx from ${nxUpdateInfo.currentVersion} to ${NX_VERSION}\n\n`
|
|
257
|
+
}
|
|
258
|
+
if (nxCoreUpdateInfo.needsUpdate) {
|
|
259
|
+
prBody += `Update @payfit/nx-core from ${nxCoreUpdateInfo.currentVersion} to ${NX_CORE_VERSION}\n\n`
|
|
260
|
+
prBody += `## Changelog\n\n${releaseNotes}\n`
|
|
261
|
+
}
|
|
165
262
|
|
|
166
|
-
|
|
167
|
-
`
|
|
263
|
+
if (JIRA_TICKET_URL) {
|
|
264
|
+
prBody += `\n\nJira: ${JIRA_TICKET_URL}\n`
|
|
265
|
+
}
|
|
168
266
|
|
|
169
267
|
// Write PR body to a file to preserve formatting (newlines, markdown)
|
|
170
268
|
const prBodyPath = path.join(repoPath, 'nx-core-pr-body.md')
|
|
171
269
|
await fs.writeFile(prBodyPath, prBody, 'utf8')
|
|
172
270
|
|
|
173
|
-
await run(
|
|
174
|
-
`gh pr create --repo PayFit/${repoName} --title
|
|
271
|
+
const prUrl = await run(
|
|
272
|
+
`gh pr create --repo PayFit/${repoName} --title ${JSON.stringify(
|
|
273
|
+
prTitle,
|
|
274
|
+
)} --body-file "${prBodyPath}" --head ${branchName}`,
|
|
175
275
|
)
|
|
176
|
-
|
|
276
|
+
if (prUrl) CREATED_PR_URLS.push(prUrl)
|
|
277
|
+
console.log(`✅ Successfully created PR for ${repoName}: ${prUrl}`)
|
|
177
278
|
} else {
|
|
178
|
-
console.log(
|
|
279
|
+
console.log(`ℹ️ PR already exists for ${repoName}`)
|
|
179
280
|
}
|
|
180
281
|
} catch (error) {
|
|
181
|
-
console.error(
|
|
282
|
+
console.error(`❌ Failed to process ${repoName}: ${error.message}`)
|
|
182
283
|
throw error
|
|
183
284
|
}
|
|
184
285
|
}
|
|
@@ -187,7 +288,7 @@ ${releaseNotes}
|
|
|
187
288
|
async function getChangelogBetweenVersions(currentVersion, targetVersion) {
|
|
188
289
|
try {
|
|
189
290
|
console.log(
|
|
190
|
-
|
|
291
|
+
`📋 Fetching changelogs from ${currentVersion} to ${targetVersion}...`,
|
|
191
292
|
)
|
|
192
293
|
|
|
193
294
|
// Get only nx-core releases from the repository, filtered at CLI level
|
|
@@ -222,36 +323,178 @@ async function getChangelogBetweenVersions(currentVersion, targetVersion) {
|
|
|
222
323
|
|
|
223
324
|
// Fetch detailed release notes for each relevant release
|
|
224
325
|
console.log(
|
|
225
|
-
|
|
326
|
+
`📝 Fetching detailed release notes for ${relevantReleases.length} release(s)...`,
|
|
226
327
|
)
|
|
227
|
-
|
|
328
|
+
const releaseEntries = []
|
|
228
329
|
for (const release of relevantReleases) {
|
|
229
330
|
try {
|
|
230
331
|
const releaseBody = await run(
|
|
231
332
|
`gh release view ${release.tagName} --repo PayFit/nx-common-packages --json body --jq '.body'`,
|
|
232
333
|
)
|
|
233
334
|
const body = releaseBody.replace(/^"|"$/g, '') // Remove surrounding quotes from jq output
|
|
234
|
-
|
|
235
|
-
|
|
335
|
+
releaseEntries.push({
|
|
336
|
+
tag: release.tagName,
|
|
337
|
+
body: body || 'No release notes available.',
|
|
338
|
+
})
|
|
236
339
|
} catch (error) {
|
|
237
340
|
console.log(
|
|
238
|
-
`
|
|
341
|
+
` ⚠️ Could not fetch release notes for ${release.tagName}: ${error.message}`,
|
|
239
342
|
)
|
|
240
|
-
|
|
241
|
-
|
|
343
|
+
releaseEntries.push({
|
|
344
|
+
tag: release.tagName,
|
|
345
|
+
body: 'Release notes could not be retrieved.',
|
|
346
|
+
})
|
|
242
347
|
}
|
|
243
348
|
}
|
|
244
349
|
|
|
245
350
|
console.log(
|
|
246
|
-
|
|
351
|
+
`✅ Retrieved ${relevantReleases.length} nx-core release(s) between versions`,
|
|
247
352
|
)
|
|
248
|
-
|
|
353
|
+
|
|
354
|
+
if (CHANGELOG_MODE === 'raw') {
|
|
355
|
+
// Plain concatenation with clear spacing
|
|
356
|
+
let raw = ''
|
|
357
|
+
for (const entry of releaseEntries) {
|
|
358
|
+
raw += `### ${entry.tag}\n\n${entry.body}\n\n`
|
|
359
|
+
}
|
|
360
|
+
return raw.trim()
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Combined/aggregated changelog
|
|
364
|
+
return buildCombinedChangelog(releaseEntries)
|
|
249
365
|
} catch (error) {
|
|
250
|
-
console.log(
|
|
366
|
+
console.log(`⚠️ Could not fetch release notes: ${error.message}`)
|
|
251
367
|
return `Release notes could not be retrieved between ${currentVersion} and ${targetVersion}.`
|
|
252
368
|
}
|
|
253
369
|
}
|
|
254
370
|
|
|
371
|
+
// Normalize a section heading to a canonical bucket
|
|
372
|
+
function normalizeSection(title) {
|
|
373
|
+
const t = String(title).trim().toLowerCase()
|
|
374
|
+
if (/breaking|migration/.test(t)) return 'Breaking Changes'
|
|
375
|
+
if (/feature/.test(t)) return 'Features'
|
|
376
|
+
if (/fix|bug/.test(t)) return 'Bug Fixes'
|
|
377
|
+
if (/perf|performance/.test(t)) return 'Performance'
|
|
378
|
+
if (/refactor/.test(t)) return 'Refactor'
|
|
379
|
+
if (/doc/.test(t)) return 'Docs'
|
|
380
|
+
if (/chore/.test(t)) return 'Chore'
|
|
381
|
+
if (/revert/.test(t)) return 'Reverts'
|
|
382
|
+
return null
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Build a combined changelog from multiple release markdown bodies
|
|
386
|
+
function buildCombinedChangelog(entries) {
|
|
387
|
+
const sectionOrder = [
|
|
388
|
+
'Breaking Changes',
|
|
389
|
+
'Features',
|
|
390
|
+
'Bug Fixes',
|
|
391
|
+
'Performance',
|
|
392
|
+
'Refactor',
|
|
393
|
+
'Docs',
|
|
394
|
+
'Chore',
|
|
395
|
+
'Reverts',
|
|
396
|
+
'Other Changes',
|
|
397
|
+
]
|
|
398
|
+
|
|
399
|
+
const aggregated = new Map()
|
|
400
|
+
for (const key of sectionOrder) aggregated.set(key, [])
|
|
401
|
+
|
|
402
|
+
for (const { tag, body } of entries) {
|
|
403
|
+
const lines = String(body).split('\n')
|
|
404
|
+
let current = null
|
|
405
|
+
let inCodeBlock = false
|
|
406
|
+
let pendingBullet = null
|
|
407
|
+
|
|
408
|
+
const flushPending = () => {
|
|
409
|
+
if (pendingBullet) {
|
|
410
|
+
const bucket = current || 'Other Changes'
|
|
411
|
+
aggregated.get(bucket).push(pendingBullet.trim())
|
|
412
|
+
pendingBullet = null
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
for (const raw of lines) {
|
|
417
|
+
const line = raw.replace(/\r$/, '')
|
|
418
|
+
|
|
419
|
+
// Handle fenced code blocks so we don't ingest code as bullets
|
|
420
|
+
if (/^```/.test(line.trim())) {
|
|
421
|
+
inCodeBlock = !inCodeBlock
|
|
422
|
+
continue
|
|
423
|
+
}
|
|
424
|
+
if (inCodeBlock) continue
|
|
425
|
+
|
|
426
|
+
// Headings like ##, ###, ####
|
|
427
|
+
const headingMatch = line.match(/^#{2,4}\s+(.+?)\s*$/)
|
|
428
|
+
if (headingMatch) {
|
|
429
|
+
flushPending()
|
|
430
|
+
const canonical = normalizeSection(headingMatch[1])
|
|
431
|
+
current = canonical
|
|
432
|
+
continue
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Bullet points
|
|
436
|
+
const bulletMatch = line.match(/^\s*[-*]\s+(.+)$/)
|
|
437
|
+
if (bulletMatch) {
|
|
438
|
+
// Flush previous bullet before starting new
|
|
439
|
+
flushPending()
|
|
440
|
+
pendingBullet = bulletMatch[1]
|
|
441
|
+
continue
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Continuation lines for multi-line bullets
|
|
445
|
+
if (pendingBullet && line.trim().length > 0) {
|
|
446
|
+
pendingBullet += ` ${line.trim()}`
|
|
447
|
+
} else if (!pendingBullet && current && line.trim().length > 0) {
|
|
448
|
+
// Non-bullet content under a recognized section
|
|
449
|
+
aggregated.get(current).push(line.trim())
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
flushPending()
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Build markdown
|
|
456
|
+
let out = ''
|
|
457
|
+
for (const key of sectionOrder) {
|
|
458
|
+
if (key === 'Other Changes') continue // discard Other Changes entirely
|
|
459
|
+
const items = aggregated.get(key)
|
|
460
|
+
if (!items || items.length === 0) continue
|
|
461
|
+
out += `#### ${key}\n\n`
|
|
462
|
+
for (const item of items) {
|
|
463
|
+
out += `- ${item}\n`
|
|
464
|
+
}
|
|
465
|
+
out += `\n`
|
|
466
|
+
}
|
|
467
|
+
return out.trim()
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// Ensure nx.json has release.version.updateDependents = "auto" for Nx >= 22
|
|
471
|
+
async function ensureUpdateDependentsAuto(repoPath) {
|
|
472
|
+
const nxJsonPath = path.join(repoPath, 'nx.json')
|
|
473
|
+
try {
|
|
474
|
+
const content = await fs.readFile(nxJsonPath, 'utf8')
|
|
475
|
+
const data = JSON.parse(content)
|
|
476
|
+
if (!data.release) data.release = {}
|
|
477
|
+
if (!data.release.version) data.release.version = {}
|
|
478
|
+
if (data.release.version.updateDependents === undefined) {
|
|
479
|
+
data.release.version.updateDependents = 'auto'
|
|
480
|
+
await fs.writeFile(
|
|
481
|
+
nxJsonPath,
|
|
482
|
+
JSON.stringify(data, null, 2) + '\n',
|
|
483
|
+
'utf8',
|
|
484
|
+
)
|
|
485
|
+
console.log(
|
|
486
|
+
'🧩 Set release.version.updateDependents to "auto" in nx.json',
|
|
487
|
+
)
|
|
488
|
+
return true
|
|
489
|
+
}
|
|
490
|
+
console.log('ℹ nx.json already has release.version.updateDependents')
|
|
491
|
+
return false
|
|
492
|
+
} catch (error) {
|
|
493
|
+
console.log(`⚠️ Skipped nx.json update: ${error.message}`)
|
|
494
|
+
return false
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
255
498
|
// Check if gh CLI is installed and user is authenticated
|
|
256
499
|
async function checkGhCli() {
|
|
257
500
|
try {
|
|
@@ -274,7 +517,9 @@ async function checkGhCli() {
|
|
|
274
517
|
|
|
275
518
|
// Main function
|
|
276
519
|
async function main() {
|
|
277
|
-
console.log(
|
|
520
|
+
console.log(
|
|
521
|
+
`🎯 nx-core Updater - nx-core target ${NX_CORE_VERSION}${NX_VERSION ? `, Nx target ${NX_VERSION}` : ''}`,
|
|
522
|
+
)
|
|
278
523
|
console.log(`📋 Processing ${REPOSITORIES.length} repositories`)
|
|
279
524
|
|
|
280
525
|
try {
|
|
@@ -289,19 +534,25 @@ async function main() {
|
|
|
289
534
|
await fs.mkdir(WORK_DIR, { recursive: true })
|
|
290
535
|
|
|
291
536
|
// Process repositories sequentially
|
|
292
|
-
console.log(
|
|
537
|
+
console.log(`🔄 Processing repositories...`)
|
|
293
538
|
for (const repo of REPOSITORIES) {
|
|
294
539
|
await processRepo(repo)
|
|
295
540
|
}
|
|
296
541
|
|
|
297
542
|
// Cleanup
|
|
298
|
-
console.log(
|
|
543
|
+
console.log(`🧹 Cleaning up work directory...`)
|
|
299
544
|
await fs.rm(WORK_DIR, { recursive: true, force: true }).catch(() => {
|
|
300
545
|
// ignore error if directory does not exist
|
|
301
546
|
})
|
|
302
|
-
|
|
547
|
+
if (CREATED_PR_URLS.length > 0) {
|
|
548
|
+
console.log('🔗 Created PRs:')
|
|
549
|
+
for (const url of CREATED_PR_URLS) {
|
|
550
|
+
console.log(`- ${url}`)
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
console.log('🎉 Done!')
|
|
303
554
|
} catch (error) {
|
|
304
|
-
console.error(
|
|
555
|
+
console.error(`💥 Script failed: ${error.message}`)
|
|
305
556
|
process.exit(1)
|
|
306
557
|
}
|
|
307
558
|
}
|
|
@@ -1,8 +1,22 @@
|
|
|
1
|
+
import { ArtifactType } from './enums';
|
|
1
2
|
/**
|
|
2
|
-
* Pushes Lambda function package.json as OCI artifact to ECR using ORAS.
|
|
3
|
+
* Pushes Lambda, frontend function package.json as OCI artifact to ECR using ORAS.
|
|
3
4
|
*
|
|
4
5
|
* @param ecrRepository - ECR repository name
|
|
5
6
|
* @param tag - Version tag for the artifact
|
|
6
|
-
* @param
|
|
7
|
+
* @param artifactPath - Path to artifact to package
|
|
8
|
+
* @param type - Artifact type
|
|
9
|
+
* @param ecrRegistry - ECR registry
|
|
7
10
|
*/
|
|
8
|
-
export declare function pushImageToEcr(ecrRepository: string, tag: string,
|
|
11
|
+
export declare function pushImageToEcr(ecrRepository: string, tag: string, artifactPath: string, type: ArtifactType.LAMBDA | ArtifactType.FRONTEND, ecrRegistry: string): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Pushes helm chart as OCI artifact to ECR using ORAS.
|
|
14
|
+
*
|
|
15
|
+
* @param ecrRepository - ECR repository name
|
|
16
|
+
* @param tag - Version tag for the artifact
|
|
17
|
+
* @param artifactPath - Path to artifact to package
|
|
18
|
+
* @param type - Artifact type
|
|
19
|
+
* @param ecrRegistry - ECR registry
|
|
20
|
+
* @param chartConfigPath - Path to chart config file in JSON format
|
|
21
|
+
*/
|
|
22
|
+
export declare function pushHelmOciToEcr(ecrRepository: string, tag: string, artifactPath: string, ecrRegistry: string, chartConfigPath: string): Promise<void>;
|
|
@@ -1,25 +1,57 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.pushImageToEcr = pushImageToEcr;
|
|
4
|
+
exports.pushHelmOciToEcr = pushHelmOciToEcr;
|
|
4
5
|
const consola_1 = require("consola");
|
|
5
6
|
const exec_1 = require("./exec");
|
|
6
7
|
const github_1 = require("./github");
|
|
7
8
|
/**
|
|
8
|
-
* Pushes Lambda function package.json as OCI artifact to ECR using ORAS.
|
|
9
|
+
* Pushes Lambda, frontend function package.json as OCI artifact to ECR using ORAS.
|
|
9
10
|
*
|
|
10
11
|
* @param ecrRepository - ECR repository name
|
|
11
12
|
* @param tag - Version tag for the artifact
|
|
12
|
-
* @param
|
|
13
|
+
* @param artifactPath - Path to artifact to package
|
|
14
|
+
* @param type - Artifact type
|
|
15
|
+
* @param ecrRegistry - ECR registry
|
|
13
16
|
*/
|
|
14
|
-
async function pushImageToEcr(ecrRepository, tag,
|
|
17
|
+
async function pushImageToEcr(ecrRepository, tag, artifactPath, type, ecrRegistry) {
|
|
18
|
+
consola_1.consola.log(`OCI: Pushing image to ECR: ${ecrRegistry}/${ecrRepository}:${tag}`);
|
|
15
19
|
const commitSha = await (0, github_1.getCurrentGitCommitSha)();
|
|
16
20
|
const gitRepoUrl = await (0, github_1.getSanitizedCurrentGitRepoUrl)();
|
|
21
|
+
const artifactType = `application/vnd.payfit.${type}.manifest`;
|
|
17
22
|
const orasPushCommand = [
|
|
18
23
|
`oras push ${ecrRegistry}/${ecrRepository}:${tag}`,
|
|
19
24
|
`--annotation "org.opencontainers.image.source=${gitRepoUrl}"`,
|
|
20
25
|
`--annotation "org.opencontainers.image.revision=${commitSha}"`,
|
|
21
26
|
`--disable-path-validation`,
|
|
22
|
-
`--artifact-type
|
|
27
|
+
`--artifact-type ${artifactType} ${artifactPath}`,
|
|
28
|
+
].join(' ');
|
|
29
|
+
const uploadToOci = await (0, exec_1.exec)(orasPushCommand, {
|
|
30
|
+
throwOnError: true,
|
|
31
|
+
});
|
|
32
|
+
consola_1.consola.log(uploadToOci.stdout);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Pushes helm chart as OCI artifact to ECR using ORAS.
|
|
36
|
+
*
|
|
37
|
+
* @param ecrRepository - ECR repository name
|
|
38
|
+
* @param tag - Version tag for the artifact
|
|
39
|
+
* @param artifactPath - Path to artifact to package
|
|
40
|
+
* @param type - Artifact type
|
|
41
|
+
* @param ecrRegistry - ECR registry
|
|
42
|
+
* @param chartConfigPath - Path to chart config file in JSON format
|
|
43
|
+
*/
|
|
44
|
+
async function pushHelmOciToEcr(ecrRepository, tag, artifactPath, ecrRegistry, chartConfigPath) {
|
|
45
|
+
consola_1.consola.log(`OCI: Pushing image to ECR: ${ecrRegistry}/${ecrRepository}:${tag}`);
|
|
46
|
+
const commitSha = await (0, github_1.getCurrentGitCommitSha)();
|
|
47
|
+
const gitRepoUrl = await (0, github_1.getSanitizedCurrentGitRepoUrl)();
|
|
48
|
+
const orasPushCommand = [
|
|
49
|
+
`oras push ${ecrRegistry}/${ecrRepository}:${tag}`,
|
|
50
|
+
`--annotation "org.opencontainers.image.source=${gitRepoUrl}"`,
|
|
51
|
+
`--annotation "org.opencontainers.image.revision=${commitSha}"`,
|
|
52
|
+
`--disable-path-validation`,
|
|
53
|
+
`--config ${chartConfigPath}:application/vnd.cncf.helm.config.v1+json`,
|
|
54
|
+
`${artifactPath}:application/vnd.cncf.helm.chart.content.v1.tar+gzip`,
|
|
23
55
|
].join(' ');
|
|
24
56
|
const uploadToOci = await (0, exec_1.exec)(orasPushCommand, {
|
|
25
57
|
throwOnError: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oci.js","sourceRoot":"","sources":["../../../../src/utils/common/oci.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"oci.js","sourceRoot":"","sources":["../../../../src/utils/common/oci.ts"],"names":[],"mappings":";;AAeA,wCAwBC;AAYD,4CAwBC;AA3ED,qCAAiC;AAGjC,iCAA6B;AAC7B,qCAAgF;AAEhF;;;;;;;;GAQG;AACI,KAAK,UAAU,cAAc,CAClC,aAAqB,EACrB,GAAW,EACX,YAAoB,EACpB,IAAiD,EACjD,WAAmB;IAEnB,iBAAO,CAAC,GAAG,CACT,8BAA8B,WAAW,IAAI,aAAa,IAAI,GAAG,EAAE,CACpE,CAAA;IACD,MAAM,SAAS,GAAG,MAAM,IAAA,+BAAsB,GAAE,CAAA;IAChD,MAAM,UAAU,GAAG,MAAM,IAAA,sCAA6B,GAAE,CAAA;IACxD,MAAM,YAAY,GAAG,0BAA0B,IAAI,WAAW,CAAA;IAC9D,MAAM,eAAe,GAAG;QACtB,aAAa,WAAW,IAAI,aAAa,IAAI,GAAG,EAAE;QAClD,iDAAiD,UAAU,GAAG;QAC9D,mDAAmD,SAAS,GAAG;QAC/D,2BAA2B;QAC3B,mBAAmB,YAAY,IAAI,YAAY,EAAE;KAClD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACX,MAAM,WAAW,GAAG,MAAM,IAAA,WAAI,EAAC,eAAe,EAAE;QAC9C,YAAY,EAAE,IAAI;KACnB,CAAC,CAAA;IACF,iBAAO,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;AACjC,CAAC;AAED;;;;;;;;;GASG;AACI,KAAK,UAAU,gBAAgB,CACpC,aAAqB,EACrB,GAAW,EACX,YAAoB,EACpB,WAAmB,EACnB,eAAuB;IAEvB,iBAAO,CAAC,GAAG,CACT,8BAA8B,WAAW,IAAI,aAAa,IAAI,GAAG,EAAE,CACpE,CAAA;IACD,MAAM,SAAS,GAAG,MAAM,IAAA,+BAAsB,GAAE,CAAA;IAChD,MAAM,UAAU,GAAG,MAAM,IAAA,sCAA6B,GAAE,CAAA;IACxD,MAAM,eAAe,GAAG;QACtB,aAAa,WAAW,IAAI,aAAa,IAAI,GAAG,EAAE;QAClD,iDAAiD,UAAU,GAAG;QAC9D,mDAAmD,SAAS,GAAG;QAC/D,2BAA2B;QAC3B,YAAY,eAAe,2CAA2C;QACtE,GAAG,YAAY,sDAAsD;KACtE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACX,MAAM,WAAW,GAAG,MAAM,IAAA,WAAI,EAAC,eAAe,EAAE;QAC9C,YAAY,EAAE,IAAI;KACnB,CAAC,CAAA;IACF,iBAAO,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;AACjC,CAAC"}
|
|
@@ -11,6 +11,7 @@ import { Result } from 'tinyexec';
|
|
|
11
11
|
* @param extraTags - Optional additional tags for the image
|
|
12
12
|
* @param appName
|
|
13
13
|
* @param buildArgs - Optional build arguments for the Docker build
|
|
14
|
+
* @param isCI - Are we running this in a CI context, enabling caching & pushing. Default to true as we only need it within the docker-build executor
|
|
14
15
|
* @return {Promise<Result>}
|
|
15
16
|
*/
|
|
16
|
-
export declare function buildAndPushDockerImage(imageName: string, dockerfilePath: string, version: string, gitRepoUrl: string, commitSha: string, registry: string, extraTags: string[], appName: string, buildArgs?: string): Promise<Result>;
|
|
17
|
+
export declare function buildAndPushDockerImage(imageName: string, dockerfilePath: string, version: string, gitRepoUrl: string, commitSha: string, registry: string, extraTags: string[], appName: string, buildArgs?: string, isCI?: boolean): Promise<Result>;
|
package/dist/src/utils/docker.js
CHANGED
|
@@ -45,19 +45,20 @@ async function setupDockerBuilder(appName) {
|
|
|
45
45
|
* @param extraTags - Optional additional tags for the image
|
|
46
46
|
* @param appName
|
|
47
47
|
* @param buildArgs - Optional build arguments for the Docker build
|
|
48
|
+
* @param isCI - Are we running this in a CI context, enabling caching & pushing. Default to true as we only need it within the docker-build executor
|
|
48
49
|
* @return {Promise<Result>}
|
|
49
50
|
*/
|
|
50
|
-
async function buildAndPushDockerImage(imageName, dockerfilePath, version, gitRepoUrl, commitSha, registry, extraTags = [], appName, buildArgs = undefined) {
|
|
51
|
+
async function buildAndPushDockerImage(imageName, dockerfilePath, version, gitRepoUrl, commitSha, registry, extraTags = [], appName, buildArgs = undefined, isCI = true) {
|
|
51
52
|
appName = appName.replaceAll('@', '-').replaceAll('/', '-');
|
|
52
53
|
const buildContextName = await setupDockerBuilder(appName);
|
|
53
54
|
// Build all tags including base version and extra tags
|
|
54
55
|
const tagArgs = [`${version}`, ...extraTags]
|
|
55
|
-
.map(tag => `-t ${registry}/${imageName}:${tag}`)
|
|
56
|
+
.map(tag => isCI ? `-t ${registry}/${imageName}:${tag}` : `-t ${imageName}:${tag}`)
|
|
56
57
|
.join(' ');
|
|
57
58
|
// Setup registry cache (skip for public ECR which doesn't support BuildKit cache backend)
|
|
58
59
|
const isPublicEcr = registry.includes('public.ecr.aws');
|
|
59
60
|
const cacheArgParts = [];
|
|
60
|
-
if (!isPublicEcr) {
|
|
61
|
+
if (!isPublicEcr && isCI) {
|
|
61
62
|
const branch = await (0, github_1.getSanitizedCurrentGitBranch)();
|
|
62
63
|
const branchCacheRef = `${registry}/${imageName}:cache-build-${branch}`;
|
|
63
64
|
const mainCacheRef = `${registry}/${imageName}:cache-build-main`;
|
|
@@ -84,7 +85,7 @@ async function buildAndPushDockerImage(imageName, dockerfilePath, version, gitRe
|
|
|
84
85
|
`--builder ${buildContextName}`,
|
|
85
86
|
`-f ${dockerfilePath}`,
|
|
86
87
|
`--secret id=NPM_TOKEN`,
|
|
87
|
-
|
|
88
|
+
`${isCI ? '--push' : '--load'}`,
|
|
88
89
|
`--provenance=false`,
|
|
89
90
|
...cacheArgParts,
|
|
90
91
|
`--annotation org.opencontainers.image.source=${gitRepoUrl}`,
|