1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192 |
- import { createInterface } from 'node:readline'
- import { createWriteStream } from 'node:fs'
- import { spawn } from 'node:child_process'
- import prompts from 'prompts'
- const subsystem = /((?<=^packages\/)@uppy\/[a-z0-9-]+|(?<=^)(?:docs|e2e|examples))\//
- async function inferPackageForCommit (sha, spawnOptions) {
- const cp = spawn('git', ['--no-pager', 'log', '-1', '--name-only', sha], spawnOptions)
- const candidates = {}
- for await (const path of createInterface({ input: cp.stdout })) {
- const match = subsystem.exec(path)
- if (match != null) {
- candidates[match[1]] ??= 0
- candidates[match[1]]++
- }
- }
- const maxVal = Math.max(...Object.values(candidates))
- return {
- inferredPackages: Number.isFinite(maxVal)
- ? Object.entries(candidates).flatMap(
- ([pkg, nbOfFiles]) => (nbOfFiles === maxVal || nbOfFiles === maxVal - 1 ? [pkg] : []),
- ).join(',')
- : 'meta',
- candidates,
- }
- }
- export default async function formatChangeLog (
- spawnOptions,
- LAST_RELEASE_COMMIT,
- changeLogUrl,
- ) {
- const changeLogCommits = createWriteStream(changeLogUrl)
- const gitLog = spawn('git', [
- '--no-pager',
- 'log',
- '--format="%H::%s::%an"',
- `${LAST_RELEASE_COMMIT}..HEAD`,
- ], spawnOptions)
- const expectedFormat = /^"([a-f0-9]+)::(?:((?:@uppy\/[a-z0-9-]+(?:,@uppy\/[a-z0-9-]+)*)|meta|docs|e2e|examples):\s?)?(.+?)(\s\(#\d+\))?::(.+)"$/ // eslint-disable-line max-len
- for await (const log of createInterface({ input: gitLog.stdout })) {
- const [, sha, packageName, title, PR, authorName] = expectedFormat.exec(log)
- const formattedCommitTitle = {
- packageName,
- title,
- authorInfo: PR ? `${authorName} / #${PR.slice(3, -1)}` : authorName,
- }
- if (!packageName) {
- console.log(
- `No package info found in commit title: ${sha} (https://github.com/transloadit/uppy/commit/${sha})`,
- )
- console.log(log)
- const { inferredPackages, candidates } = await inferPackageForCommit(sha, spawnOptions)
- const { useInferred } = await prompts({
- type: 'confirm',
- name: 'useInferred',
- message: `Assign commit to ${inferredPackages} (inferred from the files it touches)?`,
- initial: true,
- })
- if (useInferred) {
- formattedCommitTitle.packageName = inferredPackages
- } else {
- const response = await prompts({
- type: 'autocompleteMultiselect',
- name: 'value',
- message: 'Which package(s) does this commit belong to?',
- min: 1,
- choices: [
- { title: 'Docs', value: 'docs' },
- { title: 'Meta', value: 'meta' },
- ...Object.entries(candidates)
- .sort((a, b) => a[1] > b[1])
- .map(([value]) => ({ title: value, value })),
- ],
- })
- if (!Array.isArray(response.value)) throw new Error('Aborting release')
- formattedCommitTitle.packageName = response.value.join(',')
- }
- }
- changeLogCommits.write(
- `- ${formattedCommitTitle.packageName}: ${formattedCommitTitle.title} (${formattedCommitTitle.authorInfo})\n`,
- )
- }
- changeLogCommits.close()
- }
|