-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Expand file tree
/
Copy pathcreate-single-release.test.ts
More file actions
152 lines (129 loc) · 4.93 KB
/
Copy pathcreate-single-release.test.ts
File metadata and controls
152 lines (129 loc) · 4.93 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
import { execFileSync } from 'node:child_process'
import { mkdtempSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import path from 'node:path'
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
const SCRIPT = path.resolve(import.meta.dirname, 'create-single-release.ts')
interface VersionCommit {
hash: string
version: string
title: string
date: string
author: string
}
interface ReleaseLookup {
current: VersionCommit | null
previous: VersionCommit | null
}
describe('release commit lookup', () => {
let directory: string
let tree: string
let head: string
function git(args: string[], input?: string): string {
return execFileSync('git', args, {
cwd: directory,
encoding: 'utf8',
input,
env: {
...process.env,
GIT_AUTHOR_NAME: 'Release Author',
GIT_AUTHOR_EMAIL: 'release@example.com',
GIT_COMMITTER_NAME: 'Release Author',
GIT_COMMITTER_EMAIL: 'release@example.com',
},
}).trim()
}
function commit(message: string, parents = head ? [head] : []): string {
head = git(['commit-tree', tree, ...parents.flatMap((parent) => ['-p', parent])], message)
git(['update-ref', 'refs/heads/main', head])
return head
}
function lookup(version: string, commitSha = ''): ReleaseLookup {
const output = execFileSync(
'bun',
[
'--no-env-file',
'--eval',
`import { findVersionCommit, findPreviousVersionCommit } from ${JSON.stringify(SCRIPT)};
const current = findVersionCommit(${JSON.stringify(version)});
const previous = current ? findPreviousVersionCommit(current) : null;
process.stdout.write(JSON.stringify({ current, previous }));`,
],
{
cwd: directory,
encoding: 'utf8',
env: { ...process.env, GH_PAT: '', GITHUB_SHA: commitSha, LOG_LEVEL: 'ERROR' },
}
)
return JSON.parse(output)
}
beforeEach(() => {
directory = mkdtempSync(path.join(tmpdir(), 'sim-release-test-'))
head = ''
git(['init', '--initial-branch=main', '--quiet'])
tree = git(['mktree'], '')
})
afterEach(() => {
rmSync(directory, { recursive: true, force: true })
})
it('finds the release boundaries when older history exceeds the subprocess buffer', () => {
for (let index = 0; index < 40; index++) {
commit(`chore: historical change ${index} ${'x'.repeat(32_000)}`)
}
const previous = commit('v0.8.30: previous release')
commit('fix(search): improve indexing (#7720)')
const current = commit('v0.8.31: current release')
expect(() => git(['log', '--format=%H|%s|%ai|%an', 'main'])).toThrow(/ENOBUFS/)
expect(lookup('v0.8.31')).toMatchObject({
current: { hash: current, version: 'v0.8.31' },
previous: { hash: previous, version: 'v0.8.30' },
})
})
it('uses the CI commit when main has advanced and HEAD is detached', () => {
const previous = commit('v0.8.30: previous release')
const current = commit('v0.8.31: current release')
commit('v0.8.32: later release')
git(['checkout', '--detach', '--quiet', current])
git(['branch', '-D', 'main'])
expect(lookup('v0.8.31', current)).toMatchObject({
current: { hash: current },
previous: { hash: previous },
})
})
it('rejects a CI commit whose version differs from the requested release', () => {
commit('v0.8.30: previous release')
const current = commit('v0.8.31: current release')
expect(lookup('v0.8.30', current)).toEqual({ current: null, previous: null })
})
it('supports looking up an older release on main', () => {
const previous = commit('v0.8.30: previous release')
const current = commit('v0.8.31: current release')
commit('v0.8.32: later release')
expect(lookup('v0.8.31')).toMatchObject({
current: { hash: current },
previous: { hash: previous },
})
})
it('ignores release-like commit bodies and releases merged from another branch', () => {
const previous = commit('v0.8.30: previous release')
const sideRelease = commit('v9.0.0: release on staging', [previous])
const mainCommit = commit('chore: mention a version\n\nv8.0.0: not a release', [previous])
const current = commit('v0.8.31: current release', [mainCommit, sideRelease])
commit('v0.8.32: later release\n\nv0.8.31: mentioned in the body')
expect(lookup('v0.8.31')).toMatchObject({
current: { hash: current },
previous: { hash: previous },
})
})
it('preserves pipe characters in release titles', () => {
const current = commit('v0.8.31: parsers | search improvements')
expect(lookup('v0.8.31')).toMatchObject({
current: { hash: current, title: 'parsers | search improvements', author: 'Release Author' },
previous: null,
})
})
it('returns no match for a missing version or a similar version number', () => {
commit('v0.8.310: a different version')
expect(lookup('v0.8.31')).toEqual({ current: null, previous: null })
})
})