@npmcli/template-oss 4.10.0 → 4.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -53,7 +53,7 @@ const DEFAULT_RELEASE_PROCESS = `
53
53
  Release Please will run on the just pushed release commit and create GitHub releases and tags for each package.
54
54
 
55
55
  \`\`\`
56
- gh run watch \`gh run list -w release -b <BASE-BRANCH> -L 1 --json databaseId -q ".[0].databaseId"\`
56
+ gh run watch \`gh run list -R {NWO} -w release -b <BASE-BRANCH> -L 1 --json databaseId -q ".[0].databaseId"\`
57
57
  \`\`\`
58
58
  ` /* eslint-enable max-len */
59
59
 
@@ -82,7 +82,7 @@ const getReleaseProcess = async ({ owner, repo }) => {
82
82
  } catch (e) {
83
83
  log('Release wiki not found', e.message)
84
84
  log('Using default release process')
85
- releaseProcess = DEFAULT_RELEASE_PROCESS.trim() + '\n'
85
+ releaseProcess = DEFAULT_RELEASE_PROCESS.replace(/\{NWO\}/g, `${owner}/${repo}`).trim() + '\n'
86
86
  }
87
87
 
88
88
  // XXX: the release steps need to always be the last thing in the doc for this to work
@@ -28,6 +28,18 @@ const debugPr = (val) => {
28
28
  }
29
29
  }
30
30
 
31
+ const debugRelease = (val) => {
32
+ if (dryRun) {
33
+ console.log('ROOT RELEASE:', JSON.stringify(val, null, 2))
34
+ }
35
+ }
36
+
37
+ const debugReleases = (val) => {
38
+ if (dryRun) {
39
+ console.log('ALL RELEASES:', JSON.stringify(val, null, 2))
40
+ }
41
+ }
42
+
31
43
  main({
32
44
  token: process.env.GITHUB_TOKEN,
33
45
  repo: process.env.GITHUB_REPOSITORY,
@@ -44,18 +56,13 @@ main({
44
56
  }
45
57
 
46
58
  if (release) {
59
+ debugRelease(release)
47
60
  core.setOutput('release', JSON.stringify(release))
48
- core.setOutput('release-path', release.path)
49
- core.setOutput('release-version', release.version)
50
- core.setOutput('release-tag', release.tagName)
51
- core.setOutput('release-url', release.url)
52
61
  }
53
62
 
54
63
  if (releases) {
64
+ debugReleases(releases)
55
65
  core.setOutput('releases', JSON.stringify(releases))
56
- core.setOutput('release-flags', JSON.stringify(releases.map((r) => {
57
- return r.path === '.' ? '-iwr' : `-w ${r.path}`
58
- })))
59
66
  }
60
67
 
61
68
  return null
@@ -0,0 +1,12 @@
1
+ runs-on: ubuntu-latest
2
+ defaults:
3
+ run:
4
+ shell: bash
5
+ steps:
6
+ {{> stepGit }}
7
+ {{> stepNode }}
8
+ - name: View in Registry
9
+ run: |
10
+ name=$(cat package.json | jq -r .name)
11
+ version="$\{{ fromJSON(needs.release.output.release).version }}"
12
+ npm view ${name}@${version}
@@ -18,8 +18,8 @@ jobs:
18
18
  release:
19
19
  outputs:
20
20
  pr: $\{{ steps.release.outputs.pr }}
21
+ release: $\{{ steps.release.outputs.release }}
21
22
  releases: $\{{ steps.release.outputs.releases }}
22
- release-flags: $\{{ steps.release.outputs.release-flags }}
23
23
  branch: $\{{ steps.release.outputs.pr-branch }}
24
24
  pr-number: $\{{ steps.release.outputs.pr-number }}
25
25
  comment-id: $\{{ steps.pr-comment.outputs.result }}
@@ -40,26 +40,25 @@ jobs:
40
40
  REF_NAME: $\{{ github.ref_name }}
41
41
  with:
42
42
  script: |
43
- const { REF_NAME, PR_NUMBER } = process.env
44
- const repo = { owner: context.repo.owner, repo: context.repo.repo }
45
- const issue = { ...repo, issue_number: PR_NUMBER }
43
+ const { REF_NAME, PR_NUMBER: issue_number } = process.env
44
+ const { runId, repo: { owner, repo } } = context
46
45
 
47
- const { data: workflow } = await github.rest.actions.getWorkflowRun({ ...repo, run_id: context.runId })
46
+ const { data: workflow } = await github.rest.actions.getWorkflowRun({ owner, repo, run_id: runId })
48
47
 
49
48
  let body = '## Release Manager\n\n'
50
49
 
51
- const comments = await github.paginate(github.rest.issues.listComments, issue)
52
- let commentId = comments?.find(c => c.user.login === 'github-actions[bot]' && c.body.startsWith(body))?.id
50
+ const comments = await github.paginate(github.rest.issues.listComments, { owner, repo, issue_number })
51
+ let commentId = comments.find(c => c.user.login === 'github-actions[bot]' && c.body.startsWith(body))?.id
53
52
 
54
53
  body += `Release workflow run: ${workflow.html_url}\n\n#### Force CI to Update This Release\n\n`
55
54
  body += `This PR will be updated and CI will run for every non-\`chore:\` commit that is pushed to \`{{ defaultBranch }}\`. `
56
55
  body += `To force CI to update this PR, run this command:\n\n`
57
- body += `\`\`\`\ngh workflow run release.yml -r ${REF_NAME}\n\`\`\``
56
+ body += `\`\`\`\ngh workflow run release.yml -r ${REF_NAME} -R ${owner}/${repo}\n\`\`\``
58
57
 
59
58
  if (commentId) {
60
- await github.rest.issues.updateComment({ ...repo, comment_id: commentId, body })
59
+ await github.rest.issues.updateComment({ owner, repo, comment_id: commentId, body })
61
60
  } else {
62
- const { data: comment } = await github.rest.issues.createComment({ ...issue, body })
61
+ const { data: comment } = await github.rest.issues.createComment({ owner, repo, issue_number, body })
63
62
  commentId = comment?.id
64
63
  }
65
64
 
@@ -123,9 +122,79 @@ jobs:
123
122
 
124
123
  post-release:
125
124
  needs: release
126
- {{> job jobName="Post Release - Release" jobIf="needs.release.outputs.releases" }}
127
- - name: Run Post Release Actions
125
+ {{> job jobName="Post Release - Release" jobIf="needs.release.outputs.releases" jobSkipSetup=true }}
126
+ - name: Create Release PR Comment
127
+ uses: actions/github-script@v6
128
128
  env:
129
129
  RELEASES: $\{{ needs.release.outputs.releases }}
130
+ with:
131
+ script: |
132
+ const releases = JSON.parse(process.env.RELEASES)
133
+ const { runId, repo: { owner, repo } } = context
134
+ const issue_number = releases[0].prNumber
135
+
136
+ let body = '## Release Workflow\n\n'
137
+ for (const { pkgName, version, url } of releases) {
138
+ body += `- \`${pkgName}@${version}\` ${url}\n`
139
+ }
140
+
141
+ const comments = await github.paginate(github.rest.issues.listComments, { owner, repo, issue_number })
142
+ const releaseComments = comments.filter(c => c.user.login === 'github-actions[bot]' && c.body.includes('Release is at'))
143
+
144
+ for (const comment of releaseComments) {
145
+ await github.rest.issues.deleteComment({ owner, repo, comment_id: comment.id })
146
+ }
147
+
148
+ const runUrl = `https://github.com/${owner}/${repo}/actions/runs/${runId}`
149
+ await github.rest.issues.createComment({
150
+ owner,
151
+ repo,
152
+ issue_number,
153
+ body: `${body}- Workflow run: :arrows_counterclockwise: ${runUrl}`,
154
+ })
155
+
156
+ release-integration:
157
+ needs: release
158
+ name: Release Integration
159
+ if: needs.release.outputs.release
160
+ {{> jobReleaseIntegration }}
161
+
162
+ post-release-integration:
163
+ needs: [release, release-integration]
164
+ {{> job jobName="Post Release Integration - Release" jobIf="needs.release.outputs.release && always()" jobSkipSetup=true }}
165
+ - name: Get Needs Result
166
+ id: needs-result
130
167
  run: |
131
- {{ rootNpmPath }} run rp-release --ignore-scripts --if-present $\{{ join(fromJSON(needs.release.outputs.release-flags), ' ') }}
168
+ result=""
169
+ if [[ "$\{{ contains(needs.*.result, 'failure') }}" == "true" ]]; then
170
+ result="x"
171
+ elif [[ "$\{{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then
172
+ result="heavy_multiplication_x"
173
+ else
174
+ result="white_check_mark"
175
+ fi
176
+ echo "::set-output name=result::$result"
177
+ - name: Update Release PR Comment
178
+ uses: actions/github-script@v6
179
+ env:
180
+ PR_NUMBER: $\{{ fromJSON(needs.release.outputs.release).prNumber }}
181
+ RESULT: $\{{ steps.needs-result.outputs.result }}
182
+ with:
183
+ script: |
184
+ const { PR_NUMBER: issue_number, RESULT } = process.env
185
+ const { repo: { owner, repo } } = context
186
+
187
+ const comments = await github.paginate(github.rest.issues.listComments, { owner, repo, issue_number })
188
+ const updateComment = comments.find(c => c.user.login === 'github-actions[bot]' && c.body.startsWith('## Release Workflow\n\n'))
189
+
190
+ if (updateComment) {
191
+ console.log('Found comment to update:', JSON.stringify(updateComment, null, 2))
192
+ await github.rest.issues.updateComment({
193
+ owner,
194
+ repo,
195
+ comment_id: updateComment.id,
196
+ body: updateComment.body.replace(/Workflow run: :[a-z_]+:/, `Workflow run: :${RESULT}:`),
197
+ })
198
+ } else {
199
+ console.log('No matching comments found:', JSON.stringify(comments, null, 2))
200
+ }
@@ -52,5 +52,6 @@ module.exports = (gh) => {
52
52
  pull: (number) => url('pull', number),
53
53
  commit: (sha) => url('commit', sha),
54
54
  compare: (a, b) => a ? url('compare', `${a.toString()}...${b.toString()}`) : null,
55
+ release: (tag) => url('releases', 'tag', tag.toString()),
55
56
  }
56
57
  }
@@ -9,17 +9,21 @@ RP.registerChangelogNotes('default', (o) => new ChangelogNotes(o))
9
9
  RP.registerVersioningStrategy('default', (o) => new Version(o))
10
10
  RP.registerPlugin('node-workspace', (o) => new NodeWs(o.github, o.targetBranch, o.repositoryConfig))
11
11
 
12
- const main = async ({ repo: fullRepo, token, dryRun, branch, force }) => {
12
+ const main = async ({ repo: _fullRepo, token, dryRun, branch, force }) => {
13
13
  if (!token) {
14
14
  throw new Error('Token is required')
15
15
  }
16
16
 
17
- if (!fullRepo) {
17
+ if (!_fullRepo) {
18
18
  throw new Error('Repo is required')
19
19
  }
20
20
 
21
- const [owner, repo] = fullRepo.split('/')
22
- const github = await RP.GitHub.create({ owner, repo, token })
21
+ const fullRepo = _fullRepo.split('/')
22
+ const github = await RP.GitHub.create({ owner: fullRepo[0], repo: fullRepo[1], token })
23
+ const {
24
+ octokit,
25
+ repository: { owner, repo, defaultBranch },
26
+ } = github
23
27
 
24
28
  // This is mostly for testing and debugging. Use environs with the
25
29
  // format `RELEASE_PLEASE_<manfiestOverrideConfigName>` (eg
@@ -29,7 +33,7 @@ const main = async ({ repo: fullRepo, token, dryRun, branch, force }) => {
29
33
  .filter(([k, v]) => k.startsWith('RELEASE_PLEASE_') && v != null)
30
34
  .map(([k, v]) => [k.replace('RELEASE_PLEASE_', ''), v])
31
35
 
32
- const baseBranch = branch ?? github.repository.defaultBranch
36
+ const baseBranch = branch ?? defaultBranch
33
37
 
34
38
  const manifest = await RP.Manifest.fromManifest(
35
39
  github,
@@ -40,7 +44,7 @@ const main = async ({ repo: fullRepo, token, dryRun, branch, force }) => {
40
44
  )
41
45
 
42
46
  if (force) {
43
- const { data: releasePrs } = await github.octokit.pulls.list({
47
+ const { data: releasePrs } = await octokit.pulls.list({
44
48
  owner,
45
49
  repo,
46
50
  head: `release-please--branches--${baseBranch}`,
@@ -59,7 +63,7 @@ const main = async ({ repo: fullRepo, token, dryRun, branch, force }) => {
59
63
  // to have a different body string so we append a message a message that CI
60
64
  // is running. This will force release-please to rebase the PR but it
61
65
  // wont update the body again, so we only append to it.
62
- await github.octokit.pulls.update({
66
+ await octokit.pulls.update({
63
67
  owner,
64
68
  repo,
65
69
  pull_number: releasePr.number,
@@ -73,29 +77,46 @@ const main = async ({ repo: fullRepo, token, dryRun, branch, force }) => {
73
77
  // We only ever get a single pull request with our current release-please settings
74
78
  const rootPr = pullRequests.filter(Boolean)?.[0]
75
79
  if (rootPr?.number) {
76
- const commits = await github.octokit.paginate(github.octokit.rest.pulls.listCommits, {
77
- owner: github.repository.owner,
78
- repo: github.repository.repo,
80
+ const commits = await octokit.paginate(octokit.rest.pulls.listCommits, {
81
+ owner,
82
+ repo,
79
83
  pull_number: rootPr.number,
80
84
  })
81
85
  rootPr.sha = commits?.[commits.length - 1]?.sha
82
86
  }
83
87
 
84
88
  const releases = allReleases.filter(Boolean)
85
- const [rootRelease, workspaceReleases] = releases.reduce((acc, r) => {
86
- if (r.path === '.') {
87
- acc[0] = r
88
- } else {
89
- acc[1].push(r)
89
+ let rootRelease = releases[0]
90
+
91
+ for (const release of releases) {
92
+ const prefix = release.path === '.' ? '' : release.path
93
+
94
+ if (!prefix) {
95
+ rootRelease = release
90
96
  }
91
- return acc
92
- }, [null, []])
97
+
98
+ const [releasePr, releasePkg] = await Promise.all([
99
+ octokit.rest.repos.listPullRequestsAssociatedWithCommit({
100
+ owner,
101
+ repo,
102
+ commit_sha: release.sha,
103
+ }).then(r => r.data[0]),
104
+ octokit.rest.repos.getContent({
105
+ owner,
106
+ repo,
107
+ ref: baseBranch,
108
+ path: `${prefix}/package.json`,
109
+ }).then(r => JSON.parse(Buffer.from(r.data.content, r.data.encoding))),
110
+ ])
111
+
112
+ release.prNumber = releasePr.number
113
+ release.pkgName = releasePkg.name
114
+ }
93
115
 
94
116
  return {
95
117
  pr: rootPr,
96
118
  release: rootRelease,
97
119
  releases: releases.length ? releases : null,
98
- workspaceReleases: workspaceReleases.length ? workspaceReleases : null,
99
120
  }
100
121
  }
101
122
 
@@ -99,7 +99,6 @@ module.exports = class extends NodeWorkspace {
99
99
  this.releasesByPackage.set(packageName, {
100
100
  path,
101
101
  component,
102
- currentTag: releasesByPath[path]?.tag,
103
102
  })
104
103
  }
105
104
 
@@ -139,9 +138,9 @@ module.exports = class extends NodeWorkspace {
139
138
  // Update notes with a link to each workspaces release notes
140
139
  // now that we have all of the releases in a single pull request
141
140
  release.notes = release.notes.replace(WORKSPACE_DEP, (_, depName, depVersion) => {
142
- const { currentTag, path, component } = this.releasesByPackage.get(depName)
141
+ const { path, component } = this.releasesByPackage.get(depName)
143
142
 
144
- const url = this.gh.compare(currentTag, new TagName(
143
+ const url = this.gh.release(new TagName(
145
144
  depVersion,
146
145
  component,
147
146
  this.repositoryConfig[path].tagSeparator,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@npmcli/template-oss",
3
- "version": "4.10.0",
3
+ "version": "4.11.1",
4
4
  "description": "templated files used in npm CLI team oss projects",
5
5
  "main": "lib/content/index.js",
6
6
  "bin": {
@@ -76,8 +76,7 @@
76
76
  "test-ignore": "^(workspace/test-workspace)/"
77
77
  },
78
78
  "templateOSS": {
79
- "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
80
- "npmSpec": "8"
79
+ "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten."
81
80
  },
82
81
  "engines": {
83
82
  "node": "^14.17.0 || ^16.13.0 || >=18.0.0"