 fb01c94511
			
		
	
	
	
	
	fb01c94511* build: move zip manifest logic in zip_manifests dir * build: remove unused get-version.py script * chore: move all release/sudowoodo related scripts into script/releases * chore: update paths to zip manifests in CI configs * build: fix path to ci release build script for arm tests
		
			
				
	
	
		
			186 lines
		
	
	
	
		
			5.6 KiB
			
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			186 lines
		
	
	
	
		
			5.6 KiB
			
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable file
		
	
	
	
	
| #!/usr/bin/env node
 | |
| 
 | |
| const { GitProcess } = require('dugite')
 | |
| const minimist = require('minimist')
 | |
| const path = require('path')
 | |
| const semver = require('semver')
 | |
| 
 | |
| const { ELECTRON_DIR } = require('../../lib/utils')
 | |
| const notesGenerator = require('./notes.js')
 | |
| 
 | |
| const semverify = version => version.replace(/^origin\//, '').replace('x', '0').replace(/-/g, '.')
 | |
| 
 | |
| const runGit = async (args) => {
 | |
|   const response = await GitProcess.exec(args, ELECTRON_DIR)
 | |
|   if (response.exitCode !== 0) {
 | |
|     throw new Error(response.stderr.trim())
 | |
|   }
 | |
|   return response.stdout.trim()
 | |
| }
 | |
| 
 | |
| const tagIsSupported = tag => tag && !tag.includes('nightly') && !tag.includes('unsupported')
 | |
| const tagIsBeta = tag => tag.includes('beta')
 | |
| const tagIsStable = tag => tagIsSupported(tag) && !tagIsBeta(tag)
 | |
| 
 | |
| const getTagsOf = async (point) => {
 | |
|   return (await runGit(['tag', '--merged', point]))
 | |
|     .split('\n')
 | |
|     .map(tag => tag.trim())
 | |
|     .filter(tag => semver.valid(tag))
 | |
|     .sort(semver.compare)
 | |
| }
 | |
| 
 | |
| const getTagsOnBranch = async (point) => {
 | |
|   const masterTags = await getTagsOf('master')
 | |
|   if (point === 'master') {
 | |
|     return masterTags
 | |
|   }
 | |
| 
 | |
|   const masterTagsSet = new Set(masterTags)
 | |
|   return (await getTagsOf(point)).filter(tag => !masterTagsSet.has(tag))
 | |
| }
 | |
| 
 | |
| const getBranchOf = async (point) => {
 | |
|   const branches = (await runGit(['branch', '-a', '--contains', point]))
 | |
|     .split('\n')
 | |
|     .map(branch => branch.trim())
 | |
|     .filter(branch => !!branch)
 | |
|   const current = branches.find(branch => branch.startsWith('* '))
 | |
|   return current ? current.slice(2) : branches.shift()
 | |
| }
 | |
| 
 | |
| const getAllBranches = async () => {
 | |
|   return (await runGit(['branch', '--remote']))
 | |
|     .split('\n')
 | |
|     .map(branch => branch.trim())
 | |
|     .filter(branch => !!branch)
 | |
|     .filter(branch => branch !== 'origin/HEAD -> origin/master')
 | |
|     .sort()
 | |
| }
 | |
| 
 | |
| const getStabilizationBranches = async () => {
 | |
|   return (await getAllBranches())
 | |
|     .filter(branch => /^origin\/\d+-\d+-x$/.test(branch))
 | |
| }
 | |
| 
 | |
| const getPreviousStabilizationBranch = async (current) => {
 | |
|   const stabilizationBranches = (await getStabilizationBranches())
 | |
|     .filter(branch => branch !== current && branch !== `origin/${current}`)
 | |
| 
 | |
|   if (!semver.valid(current)) {
 | |
|     // since we don't seem to be on a stabilization branch right now,
 | |
|     // pick a placeholder name that will yield the newest branch
 | |
|     // as a comparison point.
 | |
|     current = 'v999.999.999'
 | |
|   }
 | |
| 
 | |
|   let newestMatch = null
 | |
|   for (const branch of stabilizationBranches) {
 | |
|     if (semver.gte(semverify(branch), semverify(current))) {
 | |
|       continue
 | |
|     }
 | |
|     if (newestMatch && semver.lte(semverify(branch), semverify(newestMatch))) {
 | |
|       continue
 | |
|     }
 | |
|     newestMatch = branch
 | |
|   }
 | |
|   return newestMatch
 | |
| }
 | |
| 
 | |
| const getPreviousPoint = async (point) => {
 | |
|   const currentBranch = await getBranchOf(point)
 | |
|   const currentTag = (await getTagsOf(point)).filter(tag => tagIsSupported(tag)).pop()
 | |
|   const currentIsStable = tagIsStable(currentTag)
 | |
| 
 | |
|   try {
 | |
|     // First see if there's an earlier tag on the same branch
 | |
|     // that can serve as a reference point.
 | |
|     let tags = (await getTagsOnBranch(`${point}^`)).filter(tag => tagIsSupported(tag))
 | |
|     if (currentIsStable) {
 | |
|       tags = tags.filter(tag => tagIsStable(tag))
 | |
|     }
 | |
|     if (tags.length) {
 | |
|       return tags.pop()
 | |
|     }
 | |
|   } catch (error) {
 | |
|     console.log('error', error)
 | |
|   }
 | |
| 
 | |
|   // Otherwise, use the newest stable release that preceeds this branch.
 | |
|   // To reach that you may have to walk past >1 branch, e.g. to get past
 | |
|   // 2-1-x which never had a stable release.
 | |
|   let branch = currentBranch
 | |
|   while (branch) {
 | |
|     const prevBranch = await getPreviousStabilizationBranch(branch)
 | |
|     const tags = (await getTagsOnBranch(prevBranch)).filter(tag => tagIsStable(tag))
 | |
|     if (tags.length) {
 | |
|       return tags.pop()
 | |
|     }
 | |
|     branch = prevBranch
 | |
|   }
 | |
| }
 | |
| 
 | |
| async function getReleaseNotes (range, newVersion, explicitLinks) {
 | |
|   const rangeList = range.split('..') || ['HEAD']
 | |
|   const to = rangeList.pop()
 | |
|   const from = rangeList.pop() || (await getPreviousPoint(to))
 | |
| 
 | |
|   if (!newVersion) {
 | |
|     newVersion = to
 | |
|   }
 | |
| 
 | |
|   console.log(`Generating release notes between ${from} and ${to} for version ${newVersion}`)
 | |
|   const notes = await notesGenerator.get(from, to, newVersion)
 | |
|   const ret = {
 | |
|     text: notesGenerator.render(notes, explicitLinks)
 | |
|   }
 | |
| 
 | |
|   if (notes.unknown.length) {
 | |
|     ret.warning = `You have ${notes.unknown.length} unknown release notes. Please fix them before releasing.`
 | |
|   }
 | |
| 
 | |
|   return ret
 | |
| }
 | |
| 
 | |
| async function main () {
 | |
|   const opts = minimist(process.argv.slice(2), {
 | |
|     boolean: [ 'explicit-links', 'help' ],
 | |
|     string: [ 'version' ]
 | |
|   })
 | |
|   opts.range = opts._.shift()
 | |
|   if (opts.help || !opts.range) {
 | |
|     const name = path.basename(process.argv[1])
 | |
|     console.log(`
 | |
| easy usage: ${name} version
 | |
| 
 | |
| full usage: ${name} [begin..]end [--version version] [--explicit-links]
 | |
| 
 | |
|  * 'begin' and 'end' are two git references -- tags, branches, etc --
 | |
|    from which the release notes are generated.
 | |
|  * if omitted, 'begin' defaults to the previous tag in end's branch.
 | |
|  * if omitted, 'version' defaults to 'end'. Specifying a version is
 | |
|    useful if you're making notes on a new version that isn't tagged yet.
 | |
|  * 'explicit-links' makes every note's issue, commit, or pull an MD link
 | |
| 
 | |
| For example, these invocations are equivalent:
 | |
|   ${process.argv[1]} v4.0.1
 | |
|   ${process.argv[1]} v4.0.0..v4.0.1 --version v4.0.1
 | |
| `)
 | |
|     return 0
 | |
|   }
 | |
| 
 | |
|   const notes = await getReleaseNotes(opts.range, opts.version, opts['explicit-links'])
 | |
|   console.log(notes.text)
 | |
|   if (notes.warning) {
 | |
|     throw new Error(notes.warning)
 | |
|   }
 | |
| }
 | |
| 
 | |
| if (process.mainModule === module) {
 | |
|   main().catch((err) => {
 | |
|     console.error('Error Occurred:', err)
 | |
|     process.exit(1)
 | |
|   })
 | |
| }
 | |
| 
 | |
| module.exports = getReleaseNotes
 |