Skip to content

Commit 6b9359f

Browse files
committed
feat: Add enable-lint-feature command
1 parent 4d1e886 commit 6b9359f

File tree

2 files changed

+280
-7
lines changed

2 files changed

+280
-7
lines changed
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
import { flow } from 'lodash-es'
2+
import * as pull from './pull.mjs'
3+
import { commit } from './_common.mjs'
4+
import { EXIT } from '../worker/thread.mjs'
5+
import { satisfies } from 'semver'
6+
7+
export const type = pull.type
8+
9+
export const filter = [
10+
...pull.filter,
11+
(item) => item.name !== 'cli',
12+
(item) => {
13+
return (
14+
item.pkg &&
15+
Object.hasOwn(item.pkg.devDependencies || {}, '@npmcli/template-oss')
16+
)
17+
},
18+
(item, _, __, opts) =>
19+
item.pkg.templateOSS[opts.argv.configName] === 'true',
20+
]
21+
22+
// Example usage (single repo):
23+
// node ./bin/gh.mjs repos enable-lint-feature --filter "name:statusboard" --install --force --dryrun
24+
25+
// The defaults below are all for prettier, but you should be able to use this for linting features like no-unused-vars.
26+
export const args = {
27+
desc: 'Enable lint feature like prettier',
28+
builder: flow(pull.args.builder, (yargs) =>
29+
yargs.options({
30+
configName: {
31+
type: 'string',
32+
default: 'prettier',
33+
desc: 'template-oss config setting name',
34+
},
35+
templateOSSRange: {
36+
type: 'string',
37+
default: '>=4.23.0',
38+
desc: 'required template-oss version range',
39+
},
40+
lintFixCommitMessage: {
41+
type: 'string',
42+
default: 'chore: run prettier',
43+
desc: 'lintfix commit message',
44+
},
45+
prBody: {
46+
type: 'string',
47+
default: 'Enable and run prettier',
48+
desc: 'PR body',
49+
},
50+
branchName: {
51+
type: 'string',
52+
default: 'stafftools/enable-prettier',
53+
desc: 'branch name to use',
54+
},
55+
devDependencies: {
56+
type: 'array',
57+
// based on npm run postlint's output
58+
default: ['prettier@*', 'eslint-config-prettier@*'],
59+
desc: 'devDependencies to install',
60+
},
61+
exactDevDependencies: {
62+
type: 'array',
63+
// Todo: Add this to exactSpecs in template-oss as well
64+
default: ['@github/prettier-config@0.0.6'],
65+
desc: 'devDependencies to install with --save-exact',
66+
},
67+
install: {
68+
type: 'boolean',
69+
default: false,
70+
desc: 'install deps',
71+
},
72+
force: {
73+
type: 'boolean',
74+
default: false,
75+
desc: 'delete existing branch',
76+
},
77+
})
78+
),
79+
}
80+
81+
export const success = ({ state }) => state.success
82+
83+
export default [
84+
({ argv, run, state }) => {
85+
const url = run('gh', [
86+
'pr',
87+
'list',
88+
'-L=1',
89+
'-l=Dependencies',
90+
`-S=templateOSS.${argv.configName}`,
91+
'--json=url',
92+
'-q',
93+
'.[].url',
94+
])
95+
if (url) {
96+
state.success = url
97+
return ['echo', [], { status: () => EXIT }]
98+
}
99+
},
100+
...pull.default,
101+
({ argv }) => [
102+
'npm',
103+
['pkg', 'get', `templateOSS.${argv.configName}`],
104+
{
105+
status: ({ status, output }) => output.includes('true') ? EXIT : status,
106+
},
107+
],
108+
({ argv }) => [
109+
'npm',
110+
['pkg', 'get', 'templateOSS.version'],
111+
{
112+
status: ({ status, output }) => {
113+
if (status !== 0) {
114+
return status
115+
}
116+
const version = output.replaceAll('"', '')
117+
if (!satisfies(version, argv.templateOSSRange)) {
118+
throw new Error(`template-oss version (${version}) doesn't satisfy the required range` +
119+
` (${argv.templateOSSRange})`)
120+
}
121+
return 0
122+
},
123+
},
124+
],
125+
({ argv }) =>
126+
argv.install && [
127+
['npm', ['i']],
128+
],
129+
({ argv }) => argv.force && [
130+
'git',
131+
['branch', '-D', argv.branchName],
132+
{
133+
status: () => 0,
134+
}],
135+
({ argv }) => ['git', ['checkout', '-b', argv.branchName]],
136+
({ argv }) => [
137+
// Note: npm pkg set assigns a string value, not a boolean value
138+
// We'll settle for truthy, instead of jumping through a lot of hoops
139+
'npm',
140+
['pkg', 'set', `templateOSS.${argv.configName}=true`],
141+
],
142+
() => [
143+
'npx',
144+
['template-oss-apply', '--force'],
145+
],
146+
({ argv }) => argv.devDependencies.length && [
147+
// Q: Why aren't these required devDependencies installed by template-oss-apply --force?
148+
'npm',
149+
['i', ...argv.devDependencies, '--save-dev'],
150+
],
151+
({ argv }) => argv.exactDevDependencies.length && [
152+
'npm',
153+
['i', ...argv.exactDevDependencies, '--save-dev', '--save-exact'],
154+
],
155+
({ argv }) => {
156+
return commit({
157+
argv: { message: `chore: enable templateOSS.${argv.configName}` },
158+
})
159+
},
160+
() => [
161+
'npm',
162+
['run', 'lintfix'],
163+
],
164+
({ argv }) => {
165+
return commit({
166+
argv: { message: argv.lintFixCommitMessage },
167+
})
168+
},
169+
({ argv }) => !argv.dryrun && [
170+
'git',
171+
['push', argv.remote, argv.branchName, '--force-with-lease'],
172+
],
173+
({ argv, state }) => !argv.dryrun && [
174+
'gh',
175+
[
176+
'pr',
177+
'create',
178+
'--title',
179+
`"chore: Enable templateOSS.${argv.configName}"`,
180+
'--body',
181+
`"${argv.prBody}"`,
182+
// '--draft',
183+
'--label',
184+
'Dependencies',
185+
'--head',
186+
argv.branchName,
187+
'--base',
188+
state.defaultBranch,
189+
],
190+
],
191+
]

tap-snapshots/test/gh.mjs.test.cjs

Lines changed: 89 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ gh graphql add-template-oss
2121
gh graphql clone
2222
gh graphql comment
2323
gh graphql delete-branches
24+
gh graphql enable-lint-feature
2425
gh graphql merge
2526
gh graphql metrics
2627
gh graphql pr-engines
@@ -53,6 +54,7 @@ gh repos
5354
gh repos add-template-oss
5455
gh repos clone
5556
gh repos delete-branches
57+
gh repos enable-lint-feature
5658
gh repos metrics
5759
gh repos publish-repo
5860
gh repos pull
@@ -386,6 +388,7 @@ Commands:
386388
npx -p @npmcli/stafftools gh graphql clone Clone repos into a directory
387389
npx -p @npmcli/stafftools gh graphql comment Comment on pull requests
388390
npx -p @npmcli/stafftools gh graphql delete-branches Delete branches of repos with no remote counterpart
391+
npx -p @npmcli/stafftools gh graphql enable-lint-feature Enable lint feature like prettier
389392
npx -p @npmcli/stafftools gh graphql merge Merge pull requests
390393
npx -p @npmcli/stafftools gh graphql pr-engines Get engine changes in a pull request
391394
npx -p @npmcli/stafftools gh graphql publish-release Merge pending release PRs and publish the resulting release
@@ -537,6 +540,44 @@ Other Options:
537540
--config Path to JSON config file
538541
`
539542

543+
exports[`test/gh.mjs TAP all commands help graphql enable-lint-feature > must match snapshot 1`] = `
544+
npx -p @npmcli/stafftools gh graphql enable-lint-feature
545+
546+
Enable lint feature like prettier
547+
548+
Command Options:
549+
--query path to a query file passed directly to gh api graphql [string] [required]
550+
--cache how long for gh to cache the query [string] [default: "1m"]
551+
--report shorthand for --template=report [boolean] [default: false]
552+
--remote name of the remote [required] [default: "origin"]
553+
--force delete existing branch [boolean] [default: false]
554+
--sync whether to sync the repo [boolean] [default: true]
555+
--configName template-oss config setting name [string] [default: "prettier"]
556+
--templateOSSRange required template-oss version range [string] [default: ">=4.23.0"]
557+
--lintFixCommitMessage lintfix commit message [string] [default: "chore: run prettier"]
558+
--prBody PR body [string] [default: "Enable and run prettier"]
559+
--branchName branch name to use [string] [default: "stafftools/enable-prettier"]
560+
--devDependencies devDependencies to install [array] [default: ["prettier@*","eslint-config-prettier@*"]]
561+
--exactDevDependencies devDependencies to install with --save-exact [array] [default: ["@github/prettier-config@0.0.6"]]
562+
--install install deps [boolean] [default: false]
563+
564+
Global Options:
565+
-c, --cwd base directory to run filesystem related commands [string] [default: "$HOME/projects"]
566+
-l, --limit number of worker threads to spawn [number] [default: $NUM_CORES]
567+
-f, --filter filters to be parsed as relaxed json and applied to the data [array]
568+
-r, --reject rejectors to be parsed as relaxed json and applied to the data [array]
569+
--clean whether to rimraf the cwd first [boolean] [default: false]
570+
--template how to format the final output [string] [required] [choices: "json", "silent", "report"] [default: "report"]
571+
--sort key to sort results by [string] [default: "id"]
572+
--json shorthand for --template=json [boolean] [default: false]
573+
--silent shorthand for --template=silent [boolean] [default: false]
574+
575+
Other Options:
576+
--help Show help [boolean]
577+
--version Show version number [boolean]
578+
--config Path to JSON config file
579+
`
580+
540581
exports[`test/gh.mjs TAP all commands help graphql merge > must match snapshot 1`] = `
541582
npx -p @npmcli/stafftools gh graphql merge
542583
@@ -1397,13 +1438,14 @@ npx -p @npmcli/stafftools gh repos
13971438
Fetch repos
13981439
13991440
Commands:
1400-
npx -p @npmcli/stafftools gh repos add-template-oss Add template-oss to a repo
1401-
npx -p @npmcli/stafftools gh repos clone Clone repos into a directory
1402-
npx -p @npmcli/stafftools gh repos delete-branches Delete branches of repos with no remote counterpart
1403-
npx -p @npmcli/stafftools gh repos publish-repo Publish repos from their default branch
1404-
npx -p @npmcli/stafftools gh repos pull Checkout and pull default branch of repos
1405-
npx -p @npmcli/stafftools gh repos repo-settings Set common settings on all repos
1406-
npx -p @npmcli/stafftools gh repos set-secret Set Publish Tokens
1441+
npx -p @npmcli/stafftools gh repos add-template-oss Add template-oss to a repo
1442+
npx -p @npmcli/stafftools gh repos clone Clone repos into a directory
1443+
npx -p @npmcli/stafftools gh repos delete-branches Delete branches of repos with no remote counterpart
1444+
npx -p @npmcli/stafftools gh repos enable-lint-feature Enable lint feature like prettier
1445+
npx -p @npmcli/stafftools gh repos publish-repo Publish repos from their default branch
1446+
npx -p @npmcli/stafftools gh repos pull Checkout and pull default branch of repos
1447+
npx -p @npmcli/stafftools gh repos repo-settings Set common settings on all repos
1448+
npx -p @npmcli/stafftools gh repos set-secret Set Publish Tokens
14071449
14081450
Command Options:
14091451
--cache how long for gh to cache the query [string] [default: "1h"]
@@ -1525,6 +1567,46 @@ Other Options:
15251567
--config Path to JSON config file
15261568
`
15271569

1570+
exports[`test/gh.mjs TAP all commands help repos enable-lint-feature > must match snapshot 1`] = `
1571+
npx -p @npmcli/stafftools gh repos enable-lint-feature
1572+
1573+
Enable lint feature like prettier
1574+
1575+
Command Options:
1576+
--cache how long for gh to cache the query [string] [default: "1h"]
1577+
--repos query to filter repos [string] [required] [default: "org:npm topic:npm-cli fork:true archived:false"]
1578+
--table shorthand for --template=table [boolean] [default: false]
1579+
--confirm shorthand for --template=confirm [boolean] [default: false]
1580+
--report shorthand for --template=report [boolean] [default: false]
1581+
--remote name of the remote [required] [default: "origin"]
1582+
--force delete existing branch [boolean] [default: false]
1583+
--sync whether to sync the repo [boolean] [default: true]
1584+
--configName template-oss config setting name [string] [default: "prettier"]
1585+
--templateOSSRange required template-oss version range [string] [default: ">=4.23.0"]
1586+
--lintFixCommitMessage lintfix commit message [string] [default: "chore: run prettier"]
1587+
--prBody PR body [string] [default: "Enable and run prettier"]
1588+
--branchName branch name to use [string] [default: "stafftools/enable-prettier"]
1589+
--devDependencies devDependencies to install [array] [default: ["prettier@*","eslint-config-prettier@*"]]
1590+
--exactDevDependencies devDependencies to install with --save-exact [array] [default: ["@github/prettier-config@0.0.6"]]
1591+
--install install deps [boolean] [default: false]
1592+
1593+
Global Options:
1594+
-c, --cwd base directory to run filesystem related commands [string] [default: "$HOME/projects"]
1595+
-l, --limit number of worker threads to spawn [number] [default: $NUM_CORES]
1596+
-f, --filter filters to be parsed as relaxed json and applied to the data [array]
1597+
-r, --reject rejectors to be parsed as relaxed json and applied to the data [array]
1598+
--clean whether to rimraf the cwd first [boolean] [default: false]
1599+
--template how to format the final output [string] [required] [choices: "json", "silent", "table", "confirm", "report"] [default: "report"]
1600+
--sort key to sort results by [string] [default: "id"]
1601+
--json shorthand for --template=json [boolean] [default: false]
1602+
--silent shorthand for --template=silent [boolean] [default: false]
1603+
1604+
Other Options:
1605+
--help Show help [boolean]
1606+
--version Show version number [boolean]
1607+
--config Path to JSON config file
1608+
`
1609+
15281610
exports[`test/gh.mjs TAP all commands help repos metrics > must match snapshot 1`] = `
15291611
npx -p @npmcli/stafftools gh repos metrics
15301612

0 commit comments

Comments
 (0)