@npmcli/template-oss 4.5.0 → 4.6.0

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.
@@ -4,7 +4,7 @@ const core = require('@actions/core')
4
4
  const main = require('../lib/release-please/index.js')
5
5
 
6
6
  const dryRun = !process.env.CI
7
- const [branch] = process.argv.slice(2)
7
+ const [branch, eventName] = process.argv.slice(2)
8
8
 
9
9
  const debugPr = (val) => {
10
10
  if (dryRun) {
@@ -33,6 +33,7 @@ main({
33
33
  repo: process.env.GITHUB_REPOSITORY,
34
34
  dryRun,
35
35
  branch,
36
+ force: eventName === 'workflow_dispatch',
36
37
  }).then(({ pr, release, releases }) => {
37
38
  if (pr) {
38
39
  debugPr(pr)
@@ -1,4 +1,4 @@
1
- const fs = require('@npmcli/fs')
1
+ const fs = require('fs/promises')
2
2
  const log = require('proc-log')
3
3
  const { rmEach, parseEach } = require('../util/files.js')
4
4
 
@@ -1,4 +1,5 @@
1
- const fs = require('@npmcli/fs')
1
+ const fs = require('fs/promises')
2
+ const { existsSync } = require('fs')
2
3
  const { join, relative } = require('path')
3
4
 
4
5
  const run = async ({ root, path }) => {
@@ -7,7 +8,7 @@ const run = async ({ root, path }) => {
7
8
  // make this glob for possible matches
8
9
  const changelog = join(path, 'CHANGELOG.md')
9
10
 
10
- if (await fs.exists(changelog)) {
11
+ if (existsSync(changelog)) {
11
12
  const content = await fs.readFile(changelog, { encoding: 'utf8' })
12
13
  const mustStart = /^#\s+Changelog\r?\n\r?\n#/
13
14
  if (!mustStart.test(content)) {
@@ -1,6 +1,7 @@
1
1
  const log = require('proc-log')
2
2
  const { resolve, relative, basename } = require('path')
3
- const fs = require('@npmcli/fs')
3
+ const fs = require('fs/promises')
4
+ const { existsSync } = require('fs')
4
5
  const git = require('@npmcli/git')
5
6
 
6
7
  const NAME = 'check-gitignore'
@@ -17,7 +18,7 @@ const run = async ({ root, path, config }) => {
17
18
  // use the root to detect a git repo but the project directory (path) for the
18
19
  // ignore check
19
20
  const ignoreFile = resolve(path, '.gitignore')
20
- if (!await git.is({ cwd: root }) || !await fs.exists(ignoreFile)) {
21
+ if (!await git.is({ cwd: root }) || !existsSync(ignoreFile)) {
21
22
  log.verbose(NAME, 'no git or no gitignore')
22
23
  return null
23
24
  }
package/lib/config.js CHANGED
@@ -99,6 +99,10 @@ const getFullConfig = async ({
99
99
  pkgConfig: _pkgConfig,
100
100
  }) => {
101
101
  const isRoot = root === path
102
+ const isWorkspace = !isRoot
103
+ const isMono = !!workspaces.length
104
+ const isRootMono = isRoot && isMono
105
+
102
106
  const isLatest = _pkgConfig.version === LATEST_VERSION
103
107
  const isDogFood = pkgJson.name === NAME
104
108
  const isForce = process.argv.includes('--force')
@@ -154,14 +158,14 @@ const getFullConfig = async ({
154
158
  // all derived keys
155
159
  const derived = {
156
160
  isRoot,
157
- isWorkspace: !isRoot,
161
+ isWorkspace,
158
162
  // Some files are written to the base of a repo but will
159
163
  // include configuration for all packages within a monorepo
160
164
  // For these cases it is helpful to know if we are in a
161
165
  // monorepo since template-oss might be used only for
162
166
  // workspaces and not the root or vice versa.
163
- isRootMono: isRoot && !!workspaces.length,
164
- isMono: !!workspaces.length,
167
+ isRootMono,
168
+ isMono,
165
169
  // repo
166
170
  repoDir: root,
167
171
  repoFiles,
@@ -177,8 +181,8 @@ const getFullConfig = async ({
177
181
  pkgPath,
178
182
  pkgDir: posixDir(pkgPath),
179
183
  pkgGlob: posixGlob(pkgPath),
180
- pkgFlags: isRoot ? '-iwr' : `-w ${pkgJson.name}`,
181
- allFlags: `${workspaces.length ? '-ws -iwr' : ''} --if-present`.trim(),
184
+ pkgFlags: isWorkspace ? `-w ${pkgJson.name}` : '',
185
+ allFlags: isMono ? '-ws -iwr --if-present' : '',
182
186
  workspacePaths,
183
187
  workspaceGlobs: workspacePaths.map(posixGlob),
184
188
  // booleans to control application of updates
@@ -0,0 +1,2 @@
1
+ - name: Run Audit
2
+ run: {{ rootNpmPath }} audit
@@ -1,3 +1,38 @@
1
+ {{#if jobCheck.sha}}
2
+ - name: Get Workflow Job
3
+ uses: actions/github-script@v6
4
+ {{#if jobCheck.if}}if: {{ jobCheck.if }}{{/if}}
5
+ id: check-output
6
+ env:
7
+ JOB_NAME: "{{#if jobName}}{{ jobName }}{{else}}{{ jobCheck.name }}{{/if}}"
8
+ MATRIX_NAME: "{{#if jobIsMatrix}} - $\{{ matrix.platform.name }} - $\{{ matrix.node-version }}{{/if}}"
9
+ with:
10
+ script: |
11
+ const { owner, repo } = context.repo
12
+
13
+ const { data } = await github.rest.actions.listJobsForWorkflowRun({
14
+ owner,
15
+ repo,
16
+ run_id: context.runId,
17
+ per_page: 100
18
+ })
19
+
20
+ const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME
21
+ const job = data.jobs.find(j => j.name.endsWith(jobName))
22
+ const jobUrl = job?.html_url
23
+
24
+ const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/{{ jobCheck.sha }}`
25
+
26
+ let summary = `This check is assosciated with ${shaUrl}\n\n`
27
+
28
+ if (jobUrl) {
29
+ summary += `For run logs, click here: ${jobUrl}`
30
+ } else {
31
+ summary += `Run logs could not be found for a job with name: "${jobName}"`
32
+ }
33
+
34
+ return { summary }
35
+ {{/if}}
1
36
  - name: {{#if jobCheck.sha}}Create{{else}}Conclude{{/if}} Check
2
37
  uses: LouisBrunner/checks-action@v1.3.1
3
38
  {{#if jobCheck.sha}}
@@ -12,12 +47,7 @@
12
47
  status: {{#if jobCheck.status}}{{ jobCheck.status }}{{else}}in_progress{{/if}}
13
48
  name: {{#if jobCheck.name}}{{ jobCheck.name }}{{else}}{{ jobName }}{{/if}}{{#if jobIsMatrix}} - $\{{ matrix.platform.name }} - $\{{ matrix.node-version }}{{/if}}
14
49
  sha: {{ jobCheck.sha }}
15
- # XXX: this does not work when using the default GITHUB_TOKEN.
16
- # Instead we post the main job url to the PR as a comment which
17
- # will link to all the other checks. To work around this we would
18
- # need to create a GitHub that would create on-demand tokens.
19
- # https://github.com/LouisBrunner/checks-action/issues/18
20
- # details_url:
50
+ output: $\{{ steps.check-output.outputs.result }}
21
51
  {{else}}
22
52
  conclusion: {{#if jobCheck.status}}{{ jobCheck.status }}{{else}}$\{{ job.status }}{{/if}}
23
53
  check_id: {{#if jobCheck.id}}{{ jobCheck.id }}{{else}}$\{{ steps.check.outputs.check_id }}{{/if}}
@@ -1,4 +1,4 @@
1
1
  - name: Lint
2
- run: {{ rootNpmPath }} run lint --ignore-scripts
2
+ run: {{ rootNpmPath }} run lint --ignore-scripts {{~#if jobRunFlags}} {{ jobRunFlags }}{{/if}}
3
3
  - name: Post Lint
4
- run: {{ rootNpmPath }} run postlint --ignore-scripts
4
+ run: {{ rootNpmPath }} run postlint --ignore-scripts {{~#if jobRunFlags}} {{ jobRunFlags }}{{/if}}
@@ -9,5 +9,4 @@ on:
9
9
  jobs:
10
10
  audit:
11
11
  {{> job jobName="Audit Dependencies" jobDepFlags="--package-lock" }}
12
- - name: Run Audit
13
- run: {{ rootNpmPath }} audit
12
+ {{> stepAudit }}
@@ -1,6 +1,7 @@
1
1
  name: Release
2
2
 
3
3
  on:
4
+ workflow_dispatch:
4
5
  push:
5
6
  branches:
6
7
  {{#each branches}}
@@ -31,17 +32,19 @@ jobs:
31
32
  env:
32
33
  GITHUB_TOKEN: $\{{ secrets.GITHUB_TOKEN }}
33
34
  run: |
34
- {{ rootNpxPath }} --offline template-oss-release-please $\{{ github.ref_name }}
35
+ {{ rootNpxPath }} --offline template-oss-release-please $\{{ github.ref_name }} $\{{ github.event_name }}
35
36
  - name: Post Pull Request Comment
36
37
  if: steps.release.outputs.pr-number
37
38
  uses: actions/github-script@v6
38
39
  id: pr-comment
39
40
  env:
40
41
  PR_NUMBER: $\{{ steps.release.outputs.pr-number }}
42
+ REF_NAME: $\{{ github.ref_name }}
41
43
  with:
42
44
  script: |
45
+ const { REF_NAME, PR_NUMBER } = process.env
43
46
  const repo = { owner: context.repo.owner, repo: context.repo.repo }
44
- const issue = { ...repo, issue_number: process.env.PR_NUMBER }
47
+ const issue = { ...repo, issue_number: PR_NUMBER }
45
48
 
46
49
  const { data: workflow } = await github.rest.actions.getWorkflowRun({ ...repo, run_id: context.runId })
47
50
 
@@ -50,7 +53,11 @@ jobs:
50
53
  const comments = await github.paginate(github.rest.issues.listComments, issue)
51
54
  let commentId = comments?.find(c => c.user.login === 'github-actions[bot]' && c.body.startsWith(body))?.id
52
55
 
53
- body += `- Release workflow run: ${workflow.html_url}`
56
+ body += `Release workflow run: ${workflow.html_url}\n\n#### Force CI to Rerun for This Release\n\n`
57
+ body += `This PR will be updated and CI will run for every non-\`chore:\` commit that is pushed to \`main\`. `
58
+ body += `To force CI to rerun, run this command:\n\n`
59
+ body += `\`\`\`\ngh workflow run release.yml -r ${REF_NAME}\n\`\`\``
60
+
54
61
  if (commentId) {
55
62
  await github.rest.issues.updateComment({ ...repo, comment_id: commentId, body })
56
63
  } else {
@@ -78,7 +85,7 @@ jobs:
78
85
  GITHUB_TOKEN: $\{{ secrets.GITHUB_TOKEN }}
79
86
  run: |
80
87
  {{ rootNpmPath }} exec --offline -- template-oss-release-manager
81
- {{ rootNpmPath }} run rp-pull-request --ignore-scripts {{ allFlags }}
88
+ {{ rootNpmPath }} run rp-pull-request --ignore-scripts {{~#if allFlags}} {{ allFlags }}{{else}} --if-present{{/if}}
82
89
  - name: Commit
83
90
  id: commit
84
91
  env:
@@ -87,7 +94,7 @@ jobs:
87
94
  git commit --all --amend --no-edit || true
88
95
  git push --force-with-lease
89
96
  echo "::set-output name=sha::$(git rev-parse HEAD)"
90
- {{> stepChecks jobCheck=(obj sha="${{ steps.commit.outputs.sha }}" name="Release" )}}
97
+ {{> stepChecks jobName="Update - Release" jobCheck=(obj sha="${{ steps.commit.outputs.sha }}" name="Release" )}}
91
98
  {{> stepChecks jobCheck=(obj id="${{ needs.release.outputs.check-id }}" )}}
92
99
 
93
100
  ci:
@@ -9,7 +9,7 @@ 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 }) => {
12
+ const main = async ({ repo: fullRepo, token, dryRun, branch, force }) => {
13
13
  if (!token) {
14
14
  throw new Error('Token is required')
15
15
  }
@@ -37,11 +37,36 @@ const main = async ({ repo: fullRepo, token, dryRun, branch }) => {
37
37
  Object.fromEntries(manifestOverrides)
38
38
  )
39
39
 
40
- const pullRequests = await (dryRun ? manifest.buildPullRequests() : manifest.createPullRequests())
41
- const allReleases = await (dryRun ? manifest.buildReleases() : manifest.createReleases())
40
+ let pullRequests = []
41
+ let allReleases = []
42
+ if (force) {
43
+ // If we are forcing the release CI to run again, then we get
44
+ // the release PR from the repo and return it, which will trigger
45
+ // the rest of the steps in the workflow to run
46
+ const prNumber = await github.octokit.issues.listForRepo({
47
+ owner,
48
+ repo,
49
+ labels: 'autorelease: pending',
50
+ per_page: 1,
51
+ }).then(res => res.data[0]?.number)
52
+ if (prNumber) {
53
+ pullRequests = await github.octokit.pulls.get({
54
+ owner,
55
+ repo,
56
+ pull_number: prNumber,
57
+ }).then(res => [{
58
+ ...res.data,
59
+ headBranchName: res.data.head.ref,
60
+ updates: [],
61
+ }])
62
+ }
63
+ } else {
64
+ pullRequests = await (dryRun ? manifest.buildPullRequests() : manifest.createPullRequests())
65
+ allReleases = await (dryRun ? manifest.buildReleases() : manifest.createReleases())
66
+ }
42
67
 
43
68
  // We only ever get a single pull request with our current release-please settings
44
- const rootPr = pullRequests.filter(Boolean)[0]
69
+ const rootPr = pullRequests.filter(Boolean)?.[0]
45
70
  if (rootPr?.number) {
46
71
  const commits = await github.octokit.paginate(github.octokit.rest.pulls.listCommits, {
47
72
  owner: github.repository.owner,
@@ -1,7 +1,7 @@
1
1
  const semver = require('semver')
2
2
  const npa = require('npm-package-arg')
3
3
  const { has } = require('lodash')
4
- const { join } = require('path')
4
+ const { join, extname } = require('path')
5
5
  const { name: NAME } = require('../../package.json')
6
6
 
7
7
  const installLocations = [
@@ -31,6 +31,10 @@ const getSpecVersion = (spec, where) => {
31
31
  const pkg = require(join(arg.fetchSpec, 'package.json'))
32
32
  return new semver.SemVer(pkg.version)
33
33
  }
34
+ case 'file': {
35
+ // allows this repo to be installed as a tarball for testing
36
+ return extname(arg.fetchSpec) === '.tgz'
37
+ }
34
38
  case 'git': {
35
39
  // allow installing only this project from git to test in other projects
36
40
  return arg.name === NAME
@@ -1,4 +1,4 @@
1
- const fs = require('@npmcli/fs')
1
+ const fs = require('fs/promises')
2
2
  const { basename, extname, dirname } = require('path')
3
3
  const yaml = require('yaml')
4
4
  const NpmPackageJson = require('@npmcli/package-json')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@npmcli/template-oss",
3
- "version": "4.5.0",
3
+ "version": "4.6.0",
4
4
  "description": "templated files used in npm CLI team oss projects",
5
5
  "main": "lib/content/index.js",
6
6
  "bin": {
@@ -34,22 +34,21 @@
34
34
  "@commitlint/cli": "^17.1.1",
35
35
  "@commitlint/config-conventional": "^17.1.0",
36
36
  "@isaacs/string-locale-compare": "^1.1.0",
37
- "@npmcli/fs": "^2.0.1",
38
- "@npmcli/git": "^3.0.0",
39
- "@npmcli/map-workspaces": "^2.0.2",
40
- "@npmcli/package-json": "^2.0.0",
37
+ "@npmcli/git": "^4.0.0",
38
+ "@npmcli/map-workspaces": "^3.0.0",
39
+ "@npmcli/package-json": "^3.0.0",
41
40
  "@octokit/rest": "^19.0.4",
42
41
  "diff": "^5.0.0",
43
42
  "glob": "^8.0.1",
44
43
  "handlebars": "^4.7.7",
45
- "hosted-git-info": "^5.0.0",
46
- "json-parse-even-better-errors": "^2.3.1",
44
+ "hosted-git-info": "^6.0.0",
45
+ "json-parse-even-better-errors": "^3.0.0",
47
46
  "just-deep-map-values": "^1.1.1",
48
47
  "just-diff": "^5.0.1",
49
48
  "lodash": "^4.17.21",
50
49
  "npm-package-arg": "^9.0.1",
51
- "proc-log": "^2.0.0",
52
- "release-please": "npm:@npmcli/release-please@^14.2.5",
50
+ "proc-log": "^3.0.0",
51
+ "release-please": "npm:@npmcli/release-please@^14.2.6",
53
52
  "semver": "^7.3.5",
54
53
  "yaml": "^2.1.1"
55
54
  },
@@ -58,7 +57,7 @@
58
57
  "lib/"
59
58
  ],
60
59
  "devDependencies": {
61
- "@npmcli/eslint-config": "^3.0.1",
60
+ "@npmcli/eslint-config": "^4.0.0",
62
61
  "@npmcli/template-oss": "file:./",
63
62
  "tap": "^16.0.0"
64
63
  },