-
Notifications
You must be signed in to change notification settings - Fork 83
Expand file tree
/
Copy pathreleases.js
More file actions
585 lines (522 loc) · 23.5 KB
/
releases.js
File metadata and controls
585 lines (522 loc) · 23.5 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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
// NOTE: You cannot use flow on this file. Must be pure JS.
// Use JSDOC for type annotations.
/**
* RELEASE MANAGEMENT HEURISTICS
*
* MULTIPLE RELEASES ALLOWED:
* - The script now supports multiple releases per plugin (previously only allowed one)
* - All existing releases are preserved for historical purposes
* - New releases must have unique version numbers to prevent duplicates
*
* PRUNING RECOMMENDATIONS (the script will make suggestions for pruning, but it will not actually prune anything)
*
* The script provides intelligent pruning suggestions based on these heuristics:
*
* 1. SAFETY NET: Keep at least 3 releases minimum
*
* 2. LATEST STABLE: Always keep the highest version number without pre-release identifiers
*
* 3. RECENT ACTIVITY: Keep all releases from the last 6 months regardless of version
*
* 4. PRE-RELEASE MANAGEMENT: Keep the latest 2-3 pre-release versions if they're recent (a pre-release is any version with a dash and a pre-release identifier, like -alpha.1, -beta.1, -rc.1, -dev, -snapshot, etc.)
*
* 5. OBSOLETE PRE-RELEASES: Prune pre-release versions of a version that has been published as stable for more than 3 months (e.g., if 2.1.0 was published 3+ months ago, prune 2.1.0-alpha1, 2.1.0-beta2, etc.)
*
* 6. AGE-BASED PRUNING: Prune releases older than 2 years (unless they're the latest stable)
*
* 7. PRE-RELEASE LIMITS: Prune excess pre-release versions (more than 5 total pre-releases)
*
* 8. VOLUME LIMITS: Prune non-recent, non-latest-stable releases when more than 5 total releases
*
* The pruning logic is conservative and prioritizes keeping important releases while
* suggesting cleanup of old, redundant, or excessive pre-release versions.
*/
const TEST = false // when set to true, doesn't actually create or delete anything. Just a dry run
const COMMAND = 'Plugin Release'
// $FlowIgnore
const fs = require('fs/promises')
const path = require('path')
const colors = require('chalk')
const Messenger = require('@codedungeon/messenger')
const inquirer = require('inquirer')
// Import shared release management utilities
const { program } = require('commander')
const releaseManagement = require('../src/commands/support/release-management')
const { getFolderFromCommandLine, runShellCommand, getPluginFileContents, fileExists, getCopyTargetPath } = require('./shared')
// Command line options
program.option('-d, --debug', 'Rollup: allow for better JS debugging - no minification or transpiling')
program.parse(process.argv)
// const options = program.opts() //see rollup.js for how to add command line options
// const DEBUGGING = Boolean(options.debug) | false
const installInstructions = `
${colors.yellow(
`Getting Started
===============
In order to create a public release on the NotePlan github repository, you will need to obtain proper permissions on the github repository from @eduardme.
So get that sorted out before moving any further. More than likely, you'll simply want to create a Pull Request for your plugin code to the NotePlan/plugins repository
and get it reviewed so someone can create a release to get it out to the community.`,
)}
If you have necessary permissions to create a release, then here's the next step:\n
- In order to do releases from the command line, you need the "gh" command line tool from github.
The following commands should get you up and running.
${colors.cyan.italic(
`
Note: the first two commands may take awhile (5 minutes each) to run:
`,
)}
git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow
git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask fetch --unshallow
brew update
brew install gh
gh auth login
Actions/Prompts:
[ Select: Github.com > HTTPS > Yes Credentials > Login with web browser ]
[ Log in using your github account and press Enter ]
[ copy the OTP code from command line ]
[ Paste OTP code in browser window ]
If the above doesn't work for you, check out the detailed instructions from github:
- https://github.com/cli/cli#installation
- Once you have "gh" installed and you have received access to repository, come back here to run the command again!
`
if (TEST) {
Messenger.warn('Creating draft release (which should be deleted) and not deleting existing release without permission', 'TEST MODE')
console.log('')
}
/**
* Extract plugin name from tag (removes version suffix like -v1.0.0)
* @param {string} tagName - The full tag name (e.g., "dwertheimer.TaskAutomations-v1.0.0")
* @returns {string} - The plugin name without version (e.g., "dwertheimer.TaskAutomations")
*/
function extractPluginNameFromTag(tagName) {
// Remove version suffix pattern like -v1.0.0, -v1.0, -v1, etc. including pre-release versions
return tagName.replace(/-v\d+(\.\d+)*(\.\d+)*(?:-[a-zA-Z0-9.-]+)?$/, '')
}
/**
* Extract version from tag
* @param {string} tagName - The full tag name (e.g., "dwertheimer.TaskAutomations-v1.0.0")
* @returns {string|null} - The version number (e.g., "1.0.0")
*/
function extractVersionFromTag(tagName) {
const match = tagName.match(/-v(\d+(?:\.\d+)*(?:\.\d+)*(?:-[a-zA-Z0-9.-]+)?)$/)
return match ? match[1] : null
}
/**
* Calculate relative time string (e.g., "3+ years ago", "2 months ago")
* @param {string} publishedAt - ISO date string
* @returns {string} - Relative time string
*/
function getRelativeTime(publishedAt) {
const now = new Date()
const published = new Date(publishedAt)
const diffInMs = now - published
const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24))
const diffInMonths = Math.floor(diffInDays / 30)
const diffInYears = Math.floor(diffInDays / 365)
if (diffInYears >= 1) {
return `${diffInYears}+ year${diffInYears > 1 ? 's' : ''} ago`
} else if (diffInMonths >= 1) {
return `${diffInMonths}+ month${diffInMonths > 1 ? 's' : ''} ago`
} else if (diffInDays >= 7) {
const weeks = Math.floor(diffInDays / 7)
return `${weeks}+ week${weeks > 1 ? 's' : ''} ago`
} else if (diffInDays >= 1) {
return `${diffInDays}+ day${diffInDays > 1 ? 's' : ''} ago`
} else {
return 'today'
}
}
// Use shared utility functions
const { isPreRelease, getBaseVersion, isPreReleaseObsolete, compareVersions, identifyReleasesToPrune, generatePruneCommands } = releaseManagement
/**
* Identify releases to prune for duplicate version scenario (more lenient)
* @param {Array<{name: string, tag: string, version: string, publishedAt: string}>} releases - Array of releases
* @returns {Array<{name: string, tag: string, version: string, publishedAt: string}>} - Releases to prune
*/
function identifyReleasesToPruneForDuplicate(releases) {
if (releases.length <= 1) {
return [] // Keep at least 1 release
}
const now = new Date()
const twoYearsAgo = new Date(now.getTime() - 2 * 365 * 24 * 60 * 60 * 1000)
// Sort releases by version (newest first)
const sortedReleases = [...releases].sort((a, b) => compareVersions(a.version, b.version))
const toPrune = []
const stableReleases = sortedReleases.filter((r) => !isPreRelease(r.version))
// Keep the latest stable release
const latestStable = stableReleases[0]
// For duplicate version scenario, be more aggressive about pruning old releases
for (const release of releases) {
const isOld = new Date(release.publishedAt) < twoYearsAgo
const isLatestStable = release === latestStable
// Prune if it's old (2+ years) AND not the latest stable
if (isOld && !isLatestStable) {
toPrune.push(release)
}
}
return toPrune
}
/**
* Get all existing releases for a specific plugin
* @param {string} pluginName - The plugin name to search for
* @returns {Promise<Array<{name: string, tag: string, version: string, publishedAt: string}> | null>}
*/
async function getExistingReleases(pluginName) {
const limit = 1000
const command = `gh release list --limit ${limit} --json tagName,publishedAt`
console.log('')
Messenger.info(`==> ${COMMAND}: Getting full release list from github.com`)
const releasesJson = await runShellCommand(command)
if (!releasesJson || releasesJson.trim() === '') {
console.log(`==> ${COMMAND}: Did not find pre-existing releases.`)
return null
}
try {
const releases = JSON.parse(releasesJson)
Messenger.info(`==> ${COMMAND}: Found ${releases.length} total releases. Searching for releases matching plugin: "${pluginName}"`)
// Filter releases that match this plugin name
const pluginReleases = releases
.map((release) => {
const pluginNameFromTag = extractPluginNameFromTag(release.tagName)
const version = extractVersionFromTag(release.tagName)
return {
name: pluginNameFromTag,
tag: release.tagName,
version: version,
publishedAt: release.publishedAt,
}
})
.filter((release) => release.name === pluginName && release.version !== null)
.sort((a, b) => new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime()) // Sort by published date, newest first
if (pluginReleases.length === 0) {
Messenger.log(
`==> ${COMMAND}: Did not find any pre-existing releases that matched the pattern for this plugin folder: "${pluginName}" on github.\
\nThat's ok if this is the first release. Or it could be that a pre-existing release did not match this naming convention.`,
)
return null
}
Messenger.note(`==> ${COMMAND}: Found ${pluginReleases.length} existing release(s) for plugin "${pluginName}":`)
pluginReleases.forEach((release, index) => {
const publishedDate = new Date(release.publishedAt).toLocaleDateString()
const relativeTime = getRelativeTime(release.publishedAt)
Messenger.log(` ${index + 1}. ${colors.cyan(release.tag)} (version ${release.version}, published ${publishedDate} -- ${relativeTime})`)
})
// Show pruning recommendations if there are many releases
if (pluginReleases.length > 3) {
const releasesToPrune = identifyReleasesToPrune(pluginReleases)
if (releasesToPrune.length > 0) {
console.log('')
Messenger.warn(`==> ${COMMAND}: Pruning Recommendations (${releasesToPrune.length} releases can be pruned):`)
releasesToPrune.forEach((release, index) => {
const publishedDate = new Date(release.publishedAt).toLocaleDateString()
const relativeTime = getRelativeTime(release.publishedAt)
Messenger.log(` ${index + 1}. ${colors.yellow(release.tag)} (version ${release.version}, published ${publishedDate} -- ${relativeTime})`)
})
console.log('')
console.log(colors.cyan(generatePruneCommands(releasesToPrune)))
console.log('')
}
}
return pluginReleases
} catch (error) {
Messenger.error(`==> ${COMMAND}: Error parsing releases JSON: ${error.message}`)
return null
}
}
/**
* Check if a releaseStatus indicates a pre-release
* @param {string|undefined} releaseStatus - The release status from plugin.json
* @returns {boolean} - True if it's a pre-release
*/
function isPreReleaseStatus(releaseStatus) {
return releaseStatus !== undefined && releaseStatus !== '' && releaseStatus !== 'full'
}
/**
* Generate release tag name from plugin name and version
* @param {string} pluginName - The plugin name
* @param {string} version - The version number
* @param {string|undefined} [releaseStatus] - The release status from plugin.json
* @returns {string} - The formatted tag name
*/
function getReleaseTagName(pluginName, version, releaseStatus) {
let tagVersion = version
if (isPreReleaseStatus(releaseStatus)) {
tagVersion = `${version}-${releaseStatus}`
}
return `${pluginName}-v${tagVersion}`
}
/**
* Get a field value from plugin data
* @param {Object} pluginData - The plugin data object
* @param {string} field - The field name to retrieve
* @returns {*} - The field value
*/
function getPluginDataField(pluginData, field) {
if (!pluginData || typeof pluginData !== 'object') {
console.log(`Could not find value for "${field}" in plugin.json`)
process.exit(0)
}
const data = pluginData[field] || null
if (!data) {
console.log(`Could not find value for "${field}" in plugin.json`)
process.exit(0)
}
return data
}
/**
* Get the list of files to include in the release
* @param {string} pluginDevDirFullPath - Path to the plugin development directory
* @param {string} appPluginsPath - Path to the app plugins directory
* @param {Array<string>} dependencies - Array of dependency file names
* @returns {Promise<{changelog: string|null, files: Array<string>}|null>} - File list object or null if error
*/
// eslint-disable-next-line no-unused-vars
async function getReleaseFileList(pluginDevDirFullPath, appPluginsPath, dependencies) {
let goodToGo = true
const fileList = { changelog: null, files: [] }
const filesInPluginFolder = await fs.readdir(pluginDevDirFullPath, {
withFileTypes: true,
})
const fileLowerMatch = (str) => filesInPluginFolder.filter((f) => f.name.toLowerCase() === str)
const existingFileName = (lowercaseName) => {
const match = fileLowerMatch(lowercaseName)
if (match.length) {
return match[0].name
} else {
return null
}
}
const fullPath = (name) => path.join(pluginDevDirFullPath, name)
let name
if ((name = existingFileName('changelog.md'))) {
//$FlowFixMe - see note above
fileList.changelog = fullPath(name)
} else {
if ((name = existingFileName('readme.md'))) {
//$FlowFixMe - see note above
fileList.changelog = fullPath(name)
} else {
Messenger.note(`==> ${COMMAND}: Missing ${colors.cyan('CHANGELOG.md')} or ${colors.cyan('README.md')} in ${pluginDevDirFullPath}`)
}
}
// Grab the minified/cleaned version of the plugin.json file
// Commenting out: Does not work. JSON5 adds commas that NP doesn't like
// const pluginInAppPluginDirectory = path.join(appPluginsPath, 'plugin.json')
// if (fileExists(pluginInAppPluginDirectory)) {
// fileList.files.push(`${pluginInAppPluginDirectory}`)
// }
if ((name = existingFileName('plugin.json'))) {
fileList.files.push(fullPath(name))
} else {
goodToGo = false
console.log('no plugin.json found')
}
if ((name = existingFileName('script.js'))) {
fileList.files.push(fullPath(name))
} else {
goodToGo = false
console.log('no script.js found')
}
if ((name = existingFileName('readme.md'))) {
fileList.files.push(fullPath(name))
}
const dependendenciesPath = path.join(pluginDevDirFullPath, 'requiredFiles')
for (const dependency of dependencies) {
const dependencyFile = path.join(dependendenciesPath, dependency)
if (await fileExists(dependencyFile)) {
fileList.files.push(dependencyFile)
} else {
goodToGo = false
console.log(`no "${dependency}" file found in "${dependendenciesPath}"`)
}
}
// console.log(`>> Releases fileList:\n${JSON.stringify(fileList)}`)
if (fileList.files.length < 2) goodToGo = false
if (goodToGo === false) {
console.log(
colors.red(
`>> Releases: ERROR. ABORTING: Encountered errors in creating the release. Minimum 2 files required are: plugin.json and script.js. Here are the files I found:\n${JSON.stringify(
fileList,
)}`,
),
)
return null
} else {
return fileList
}
}
/**
* Display error message for wrong arguments
* @param {*} limitToFolders - The folders that were passed as arguments
*/
function wrongArgsMessage(limitToFolders) {
console.log(`==> ${COMMAND}: ${limitToFolders ? String(limitToFolders.length) : ''} file(s): ${JSON.stringify(limitToFolders) || ''}`)
console.log(colors.red(`\nERROR:\n Invalid Arguments (you may only release one plugin at a time)`), colors.yellow(`\n\nUsage:\n npm run release "dwertheimer.dateAutomations"`))
}
/**
* Ensure the version being released is new and not a duplicate
* @param {Array<{name: string, tag: string, version: string, publishedAt: string}>|null} existingReleases - Array of existing releases
* @param {string} versionedTagName - The new version tag name to check
*/
function ensureVersionIsNew(existingReleases, versionedTagName) {
if (existingReleases && existingReleases.length > 0 && versionedTagName) {
const duplicateRelease = existingReleases.find((release) => release.tag === versionedTagName)
if (duplicateRelease) {
Messenger.note(
`==> ${COMMAND}: Found existing release with tag name: ${colors.cyan(versionedTagName)}, which matches the version number in your ${colors.cyan('plugin.json')}`,
)
Messenger.error(
` New releases must contain a unique name/tag. Update ${colors.magenta('plugin.version')} in ${colors.cyan('plugin.json, CHANGELOG.md or README.md')} and try again.`,
)
// Show pruning recommendations even when there's a duplicate version
// Use special logic for duplicate version scenario that's more lenient
const releasesToPrune = identifyReleasesToPruneForDuplicate(existingReleases)
if (releasesToPrune.length > 0) {
console.log('')
Messenger.warn(`==> ${COMMAND}: Pruning Recommendations (${releasesToPrune.length} releases can be pruned):`)
releasesToPrune.forEach((release, index) => {
const publishedDate = new Date(release.publishedAt).toLocaleDateString()
const relativeTime = getRelativeTime(release.publishedAt)
Messenger.log(` ${index + 1}. ${colors.yellow(release.tag)} (version ${release.version}, published ${publishedDate} -- ${relativeTime})`)
})
console.log('')
console.log(colors.cyan(generatePruneCommands(releasesToPrune)))
console.log('')
}
console.log('')
const testMessage = TEST ? '(Test Mode)' : ''
Messenger.error(`${COMMAND} Failed ${testMessage} (duplicate version)`, 'ERROR')
process.exit(0)
}
}
}
/**
* Generate the GitHub release command
* @param {string} version - The version tag
* @param {string} pluginTitle - The plugin title
* @param {Object} fileList - Object containing changelog and files
* @param {boolean} [sendToGithub=false] - Whether to actually send to GitHub
* @returns {string} - The release command
*/
function getReleaseCommand(version, pluginTitle, fileList, sendToGithub = false) {
const changeLog = fileList.changelog ? `-F "${fileList.changelog}"` : ''
const cmd = `gh release create "${version}" -t "${pluginTitle}" ${changeLog} ${!sendToGithub ? `--draft` : ''} ${fileList.files.map((m) => `"${m}"`).join(' ')}`
if (!sendToGithub) {
console.log(`==> ${COMMAND}: Release command:\n\t${cmd}\n\nYou can run that by hand. The script is not doing it in TEST mode.\n`)
}
return cmd
}
/**
* Generate the GitHub release delete command
* @param {string} version - The version tag to delete
* @param {boolean} [sendToGithub=false] - Whether to actually send to GitHub
* @returns {string} - The delete command
*/
function getRemoveCommand(version, sendToGithub = false) {
const cmd = `gh release delete "${version}" ${sendToGithub ? `` : '-y'}` // -y removes the release without prompting
if (!sendToGithub) {
console.log(`==> ${COMMAND}: Pre-existing release remove command:\n\t${cmd}\n\nYou can run that by hand. The script is not doing it in TEST mode.\n`)
}
return cmd
}
/**
* Release a plugin to GitHub
* @param {string} versionedTagName - The versioned tag name for the release
* @param {Object} pluginData - The plugin data object
* @param {Object} fileList - Object containing changelog and files
* @param {boolean} [sendToGithub=false] - Whether to actually send to GitHub
*/
async function releasePlugin(versionedTagName, pluginData, fileList, sendToGithub = false) {
const pluginTitle = getPluginDataField(pluginData, 'plugin.name')
const releaseCommand = getReleaseCommand(versionedTagName, pluginTitle, fileList, sendToGithub)
if (sendToGithub) {
if (releaseCommand) {
console.log(`>>Release: Creating release "${versionedTagName}" on github...`)
const resp = await runShellCommand(releaseCommand)
console.log(`==> ${COMMAND}: New release posted (check on github):\n\t${JSON.stringify(resp.trim())}`)
}
}
}
/**
* Remove a plugin release from GitHub
* @param {string} versionedTagName - The versioned tag name to remove
* @param {boolean} [sendToGithub=false] - Whether to actually send to GitHub
*/
async function _removePlugin(versionedTagName, sendToGithub = false) {
const removeCommand = getRemoveCommand(versionedTagName, sendToGithub)
if (sendToGithub) {
if (removeCommand) {
console.log(`==> ${COMMAND}: Removing previous version "${versionedTagName}" on github...`)
// eslint-disable-next-line no-unused-vars
const resp = await runShellCommand(removeCommand)
// console.log(`...response: ${JSON.stringify(resp.trim())}`)
}
}
}
/**
* Check if GitHub CLI (gh) is installed
*/
async function checkForGh() {
if (!((await fileExists(`/usr/local/bin/gh`)) || (await fileExists(`/opt/homebrew/bin/gh`)))) {
console.log(`${colors.red('==> ${COMMAND}: ERROR: Could not find "gh" command.')}\n${installInstructions}`)
process.exit(0)
}
}
/**
* Main function to handle plugin release process
*/
async function main() {
await checkForGh()
const rootFolderPath = path.join(__dirname, '..')
const rootFolderDirs = await fs.readdir(rootFolderPath, {
withFileTypes: true,
})
const limitToFolders = await getFolderFromCommandLine(rootFolderPath, program.args)
if (limitToFolders.length === 1) {
const pluginName = limitToFolders[0]
const pluginDevDirFullPath = path.join(rootFolderPath, pluginName)
const existingReleases = await getExistingReleases(pluginName)
const pluginData = await getPluginFileContents(path.join(pluginDevDirFullPath, 'plugin.json'))
const versionNumber = getPluginDataField(pluginData, 'plugin.version')
const releaseStatus = pluginData['plugin.releaseStatus']
const copyTargetPath = await getCopyTargetPath(rootFolderDirs)
const fileList = await getReleaseFileList(pluginDevDirFullPath, path.join(copyTargetPath, pluginName), pluginData['plugin.requiredFiles'] || [])
if (fileList) {
const versionedTagName = getReleaseTagName(pluginName, versionNumber, releaseStatus)
// console.log(`==> ${COMMAND}: This version/tag will be:\n\t${versionedTagName}`)
ensureVersionIsNew(existingReleases, versionedTagName)
// Check if this is a pre-release and ask for confirmation
if (isPreReleaseStatus(releaseStatus)) {
console.log('')
const { confirm } = await inquirer.prompt([
{
type: 'confirm',
name: 'confirm',
message: `${pluginName} version ${versionNumber} is marked "${releaseStatus}", continue with pre-release?`,
default: false,
},
])
if (!confirm) {
Messenger.warn('Release cancelled by user', 'ABORT')
process.exit(0)
}
console.log('')
}
await releasePlugin(versionedTagName, pluginData, fileList, !TEST)
// Note: We no longer automatically remove previous releases - they are kept for history
// The user can manually prune old releases if needed in a future step
const newReleaseList = await getExistingReleases(pluginName)
if (newReleaseList && newReleaseList.some((release) => release.tag === versionedTagName)) {
Messenger.success(`Release Completed Successfully. "${versionedTagName}" has been published.`, 'SUCCESS')
if (newReleaseList.length > 1) {
Messenger.note(`Plugin now has ${newReleaseList.length} total releases. Previous releases are preserved for history.`)
}
} else {
Messenger.error(`^^^ Something went wrong. Please check log ^^^`, 'ERROR')
}
}
} else {
wrongArgsMessage()
}
}
// Run the main function
main().catch(console.error)