-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathpublish.test.js
More file actions
277 lines (247 loc) · 8.8 KB
/
publish.test.js
File metadata and controls
277 lines (247 loc) · 8.8 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
import * as cook from 'repo-cooker/actions'
import { buildWebsite, publishWebsite } from './actions'
import { join, resolve } from '../../src/helpers/path'
import { Cooker } from 'repo-cooker'
import MockAdapter from 'axios-mock-adapter'
import assert from 'test-utils/assert'
import axios from 'axios'
import { mockNpmRegistry } from 'test-utils/npm'
import { runCommandMock } from 'test-utils'
const isoString = '2017-07-09T19:06:31.620Z'
describe('publish script', () => {
let mock
const url = 'https://api.github.com/repos/cerebral/repo-cooker-test/releases'
beforeAll(() => {
mock = new MockAdapter(axios)
mockNpmRegistry(mock)
mock.onPost(url).reply(function (config) {
return [
201,
{
name: config.data.name,
tag_name: config.data.tag_name,
body: config.data.body,
created_at: new Date().toISOString(),
},
]
})
})
beforeEach(() => {
jest.spyOn(Date.prototype, 'toISOString').mockReturnValue(isoString)
})
afterEach(() => {
jest.restoreAllMocks()
})
afterAll(() => {
mock.restore()
})
it('should run a publish script without error', (done) => {
const dryRun = runCommandMock()
const basePath = resolve('test', 'repo')
const cooker = Cooker({
devtools: null,
dryRun,
path: basePath,
packagesGlobs: [
'packages/node_modules/*',
'packages/node_modules/@repo-cooker-test/*',
'!packages/node_modules/@repo-cooker-test',
],
})
const versions = {
'@repo-cooker-test/commis': '3.0.0-dabd05',
// '@repo-cooker-test/entremetier': '1.3.4-dabd05', ==> not released
'@repo-cooker-test/poissonier': '1.0.0-dabd05',
}
const released = [
'@repo-cooker-test/commis',
// '@repo-cooker-test/entremetier', ==> not release because it is only listed as dev dependency
'@repo-cooker-test/poissonier',
].map((name) => ({
cwd: resolve(basePath, 'packages', 'node_modules', name),
name,
version: versions[name],
}))
const commands = [
// No ... because we want to sort them to avoid inconsistent test failures.
released.map((r) => ({
cmd: 'writeFile',
args: [join(r.cwd, 'package.json'), '[data]', { encoding: 'utf8' }],
})),
...released.map((r) => ({
cmd: 'npm',
args: ['publish', '--tag', 'next', '--access', 'public'],
options: { cwd: r.cwd, pause: true },
})),
// ...released.map((r) => ({
// cmd: 'npm',
// args: ['dist-tag', 'add', `${r.name}@${r.version}`, 'next'],
// options: { cwd: r.cwd, pause: true },
// })),
// ...released.map((r) => ({
// cmd: 'npm',
// args: ['dist-tag', 'rm', r.name, 'releasing'],
// options: { cwd: r.cwd },
// })),
{
cmd: 'restoreRepository',
args: [basePath],
},
{
cmd: 'git',
args: ['tag', '-a', 'v2017-07-09_1906', '-m', '""'],
},
{
// Due to issues with credentials, it is simpler to just run a
// git command for this operation.
cmd: 'git',
args: ['push', 'origin', 'v2017-07-09_1906'],
},
{
cmd: 'createRelease',
args: [basePath, 'v2017-07-09_1906', 'some release notes'],
},
]
// Normal usage would use cooker.cook() because this catches and displays
// errors.
cooker
.run([
cook.getLatestReleaseHash,
// { hash: "e654cd..." }
// Get list of commit hashes from `props.hash` to release hash. If `props.hash` is 'Big Bang', returns
// the full history up to current commit. An invalid hash returns an empty list.
cook.getHistoryFromHash,
// { history: ["c456e...", "4d76f..."] }
// Resolve history list of hash to raw commits.
cook.getRawCommitsFromHistory,
// { rawCommits: [{hash, author:{name,email}, message, files}] }
cook.parseCommits,
// { commits: [{hash, author, ..., type, scope, summary, issues, breaks, body}]}
// Groups commits by matching files changed by defined packages paths
cook.groupCommitsByPackage,
// {commitsByPackage: {
// 'firebase': [{hash: "2424", ...}],
// 'http': [{hash: "2424", ...}]
// }
cook.evaluateSemverByPackage,
// Based on parsed commit figure out type of release
// repo-cooker will automatically use the highest in
// 'major' > 'minor' > 'patch' > 'noop'
// {semverByPackage: [
// {name: 'firebase', type: 'major'},
// {name: 'http', type: 'minor'},
// ]}
cook.relatedPackagesByPackage,
// Returns {relatedPackagesByPackage: {cerebral: ['function-tree']}}
// This is needed to evaluate change of version bump related to related
// package update
cook.getCurrentVersionByPackage,
// Go to NPM and grab current version of packages
// {currentVersionByPackage: {
// 'firebase': '1.6.0',
// 'http': '1.6.4',
// }}
cook.evaluateNewVersionByPackage,
// Based on type of change, use semver bumping
// {newVersionByPackage: {
// 'firebase': '1.6.1',
// 'http': '1.7.0',
// }}
cook.remap(
'newVersionByPackage',
(_, version, { props }) => `${version}-${props.hash.slice(0, 6)}`
),
cook.writeVersionsToPackages,
// Just write the new version to package.json of packages
// this is temporary for release and does not need to be pushed to repo
cook.runNpmScript('prepare'),
// Run the `prepare` script in all packages if it exists. The `npm publish`
// script also runs them but we want to make sure none fail before moving
// forward.
// cook.publishUnderTemporaryNpmTag,
// Needs npm to be logged in:
// > npm login
//
// Need to ensure successful release of all packages, so
// we publish under a temporary tag first
// {temporaryNpmTagByPackage: [
// {name: 'firebase', tag: 'releasing'},
// {name: 'http', tag: 'releasing'},
// }
// cook.mapTemporaryNpmTagTo('next'),
// If successful we just map published tags to official release tag
cook.publishUnderFinalNpmTag('next'),
// When publishing with the npm trusted publishing workflow we're not able to
// change the tag on publish, so we need to publish under the final tag directly
cook.restoreRepository,
// Version information is not stored in package.json so we
// cleanup repo now.
cook.tagCurrentCommit,
// Tag current commit with the name format:
// { tag: {
// name: 'release_2018-08-20_0800',
// date: '2017-07-09T19:06:31.620Z', // ISO string
// }
// }
cook.pushTagToRemote,
// Pushes tag to remote repository
cook.createReleaseNotes((_release) => `some release notes`),
// The `release` object has this format:
// {
// tag: 'release_2017-09-07_0900',
// date: '2017-07-09T19:06:31.620Z', // ISO string
// fix: [
// {
// name: 'packageName',
// version: 'new.package.version',
// commits: [], // see above for commit format
// },
// {
// name: 'otherPackage',
// version: 'new.other.version',
// commits: [], // see above for commit format
// },
// ],
// feat: [
// // same as 'fix'
// ],
// breaks: [
// // same as 'fix'
// ],
// }
//
// The action outputs this:
// { releaseNotes: "Woop woop" }
cook.createGithubRelease,
// Needs a REPO_COOKER_GITHUB_TOKEN in ENV. Get one from
// https://github.com/settings/tokens
//
// Send release notes to github on release tag, using name format:
// Release 2018-08-20 08:00
// { githubRelease } // See https://developer.github.com/v3/repos/releases/#create-a-release
buildWebsite,
// Yeah... you know
publishWebsite,
// Jup
cook.fireworks,
])
.then(() => {
const result = []
let writtenFiles
dryRun.commands.forEach((cmd) => {
if (cmd.cmd === 'writeFile') {
if (writtenFiles === undefined) {
writtenFiles = []
result.push(writtenFiles)
}
writtenFiles.push(cmd)
} else {
result.push(cmd)
}
})
writtenFiles.sort((a, b) => (a.args[0] < b.args[0] ? -1 : 1))
assert.deepEqual(result, commands, done)
})
.catch(done)
}, 10000)
})