feat: add sofie-code-preset-setup CLI command#47
Conversation
aaf194e to
31b2f4b
Compare
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (4)
WalkthroughThis PR introduces a complete automated setup CLI tool for the Sofie code standard preset. The setup script configures projects with ESLint flat config, Prettier, Husky pre-commit hooks, lint-staged, and optional monorepo cleanup. The CLI is exported via package.json, documented in updated README instructions, and supported by a minor ESLint config adjustment for handling generated eslint.config.mjs files. ChangesSetup Automation Feature
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
232a96d to
84cdfc3
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@bin/setup.mjs`:
- Line 18: Update the help/usage text string that currently reads "Usage:
sofie-code-preset-setup [--force] [--help]" to the published CLI name
"sofie-code-standard-preset-setup" so the usage shows "Usage:
sofie-code-standard-preset-setup [--force] [--help]"; search for the exact
string literal (the usage line in bin/setup.mjs) and replace it, and also scan
for any other occurrences of "sofie-code-preset-setup" in the same module to
keep help text consistent.
- Around line 75-84: The current check inside the pmField falsy branch allows
projects with no lockfile to slip through; update the logic in bin/setup.mjs
(within the pmField conditional that references pmField, projectDir, path.join
and existsSync) to require explicit Yarn evidence: verify either a yarn.lock
exists (existsSync(path.join(projectDir, 'yarn.lock'))) or pmField indicates
yarn (pmField startsWith 'yarn@'); if neither is true, log an error and exit
(use the existing console.error and process.exit(1)) so non-Yarn projects fail
fast instead of breaking later during install.
- Around line 213-216: The current code unconditionally copies srcEditorconfig
to destEditorconfig (using copyFile), clobbering any existing .editorconfig;
change it to first check for the destination file (e.g., with fs.existsSync or
stat) and skip the copy and success log when destEditorconfig already exists
unless the user explicitly requested overwrite (the script's existing
force/--force flag or equivalent variable), and only call copyFile and
console.log(' ✓ Copied .editorconfig') when the file is absent or the force
flag is true.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 07e861cb-c432-46bc-abda-14ef973d3462
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (4)
README.mdbin/setup.mjseslint/main.mjspackage.json
|
|
||
| if (help) { | ||
| console.log(` | ||
| Usage: sofie-code-preset-setup [--force] [--help] |
There was a problem hiding this comment.
Fix CLI name in help usage text.
Help prints sofie-code-preset-setup, but the published bin is sofie-code-standard-preset-setup. This will mislead users copying the command.
Suggested patch
-Usage: sofie-code-preset-setup [--force] [--help]
+Usage: sofie-code-standard-preset-setup [--force] [--help]📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Usage: sofie-code-preset-setup [--force] [--help] | |
| Usage: sofie-code-standard-preset-setup [--force] [--help] |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@bin/setup.mjs` at line 18, Update the help/usage text string that currently
reads "Usage: sofie-code-preset-setup [--force] [--help]" to the published CLI
name "sofie-code-standard-preset-setup" so the usage shows "Usage:
sofie-code-standard-preset-setup [--force] [--help]"; search for the exact
string literal (the usage line in bin/setup.mjs) and replace it, and also scan
for any other occurrences of "sofie-code-preset-setup" in the same module to
keep help text consistent.
| if (!pmField) { | ||
| if (existsSync(path.join(projectDir, 'package-lock.json'))) { | ||
| console.error('Error: Found a package-lock.json. This tool requires yarn.') | ||
| process.exit(1) | ||
| } | ||
| if (existsSync(path.join(projectDir, 'pnpm-lock.yaml'))) { | ||
| console.error('Error: Found a pnpm-lock.yaml. This tool requires yarn.') | ||
| process.exit(1) | ||
| } | ||
| } |
There was a problem hiding this comment.
Yarn enforcement has a false-negative path.
If packageManager is absent and no npm/pnpm lockfile exists, non-yarn projects pass validation and fail later during install. Require explicit yarn evidence (yarn.lock or packageManager: yarn@...) before continuing.
Suggested patch
if (!pmField) {
+ if (!existsSync(path.join(projectDir, 'yarn.lock'))) {
+ console.error('Error: Could not verify yarn usage (missing packageManager and yarn.lock). This tool requires yarn.')
+ process.exit(1)
+ }
if (existsSync(path.join(projectDir, 'package-lock.json'))) {
console.error('Error: Found a package-lock.json. This tool requires yarn.')
process.exit(1)
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (!pmField) { | |
| if (existsSync(path.join(projectDir, 'package-lock.json'))) { | |
| console.error('Error: Found a package-lock.json. This tool requires yarn.') | |
| process.exit(1) | |
| } | |
| if (existsSync(path.join(projectDir, 'pnpm-lock.yaml'))) { | |
| console.error('Error: Found a pnpm-lock.yaml. This tool requires yarn.') | |
| process.exit(1) | |
| } | |
| } | |
| if (!pmField) { | |
| if (!existsSync(path.join(projectDir, 'yarn.lock'))) { | |
| console.error('Error: Could not verify yarn usage (missing packageManager and yarn.lock). This tool requires yarn.') | |
| process.exit(1) | |
| } | |
| if (existsSync(path.join(projectDir, 'package-lock.json'))) { | |
| console.error('Error: Found a package-lock.json. This tool requires yarn.') | |
| process.exit(1) | |
| } | |
| if (existsSync(path.join(projectDir, 'pnpm-lock.yaml'))) { | |
| console.error('Error: Found a pnpm-lock.yaml. This tool requires yarn.') | |
| process.exit(1) | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@bin/setup.mjs` around lines 75 - 84, The current check inside the pmField
falsy branch allows projects with no lockfile to slip through; update the logic
in bin/setup.mjs (within the pmField conditional that references pmField,
projectDir, path.join and existsSync) to require explicit Yarn evidence: verify
either a yarn.lock exists (existsSync(path.join(projectDir, 'yarn.lock'))) or
pmField indicates yarn (pmField startsWith 'yarn@'); if neither is true, log an
error and exit (use the existing console.error and process.exit(1)) so non-Yarn
projects fail fast instead of breaking later during install.
| const srcEditorconfig = path.join(scriptDir, '..', '.editorconfig') | ||
| const destEditorconfig = path.join(projectDir, '.editorconfig') | ||
| await copyFile(srcEditorconfig, destEditorconfig) | ||
| console.log(' \u2714 Copied .editorconfig') |
There was a problem hiding this comment.
Avoid unconditional overwrite of .editorconfig.
This always clobbers existing .editorconfig, even without --force. Align with the script’s non-destructive default behavior by skipping when present unless forced.
Suggested patch
const srcEditorconfig = path.join(scriptDir, '..', '.editorconfig')
const destEditorconfig = path.join(projectDir, '.editorconfig')
-await copyFile(srcEditorconfig, destEditorconfig)
-console.log(' \u2714 Copied .editorconfig')
+if (!existsSync(destEditorconfig) || force) {
+ await copyFile(srcEditorconfig, destEditorconfig)
+ console.log(' \u2714 Copied .editorconfig')
+} else {
+ console.log(' - .editorconfig already exists, skipping (use --force to overwrite)')
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const srcEditorconfig = path.join(scriptDir, '..', '.editorconfig') | |
| const destEditorconfig = path.join(projectDir, '.editorconfig') | |
| await copyFile(srcEditorconfig, destEditorconfig) | |
| console.log(' \u2714 Copied .editorconfig') | |
| const srcEditorconfig = path.join(scriptDir, '..', '.editorconfig') | |
| const destEditorconfig = path.join(projectDir, '.editorconfig') | |
| if (!existsSync(destEditorconfig) || force) { | |
| await copyFile(srcEditorconfig, destEditorconfig) | |
| console.log(' \u2714 Copied .editorconfig') | |
| } else { | |
| console.log(' - .editorconfig already exists, skipping (use --force to overwrite)') | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@bin/setup.mjs` around lines 213 - 216, The current code unconditionally
copies srcEditorconfig to destEditorconfig (using copyFile), clobbering any
existing .editorconfig; change it to first check for the destination file (e.g.,
with fs.existsSync or stat) and skip the copy and success log when
destEditorconfig already exists unless the user explicitly requested overwrite
(the script's existing force/--force flag or equivalent variable), and only call
copyFile and console.log(' ✓ Copied .editorconfig') when the file is absent or
the force flag is true.
Adds a new `sofie-code-preset-setup` CLI command that automates setting up or updating a project to use this preset. It: - Errors if the project does not use yarn - Sets the `prettier` config key in package.json - Adds/updates lint, lint:fix, lint:eslint, lint:prettier, and license-validate scripts - Adds a prepare script for husky if not already present - Sets up lint-staged config in package.json - Creates eslint.config.mjs if it does not already exist - Copies the .editorconfig from the preset - Creates .husky/pre-commit if it does not already exist Also adds .editorconfig to the published files list.
…force for unknown values
The setup script was running `yarn add --dev eslint` without a version constraint, picking up whatever the latest major was (e.g. eslint@10) instead of the version range declared in this preset's peerDependencies (eslint@^9). This caused ERR_MODULE_NOT_FOUND for @eslint/js because eslint@10 no longer bundles it. Now the script reads its own peerDependencies and appends the range when installing each peer dep (e.g. eslint@^9, typescript@~6.0, prettier@^3).
…cript If the project dir contains a .prettierrc.json pointing to the old .prettierrc.json path (which no longer exists in the preset), update it to prettier.config.mjs. Prettier searches .prettierrc.json before the package.json "prettier" key, so a stale .prettierrc.json silently overrides the correct package.json config.
…figs In a monorepo, prettier and ESLint config files in sub-packages shadow the root config. Running setup with --fix-subpackages will: - Remove the "prettier" key from sub-package package.json files (they inherit from the root via config walk-up) - Delete sub-package .prettierrc* files that are just references to the preset (root config handles this) - Delete legacy .eslintrc* files (replaced by flat config at root) - Note flat eslint.config.mjs files for manual review Without the flag, setup reports any issues found and suggests running with --fix-subpackages.
Pre-commit hooks should fail and notify, not silently auto-fix. Use 'prettier --check' and 'eslint' instead of '--write'/'--fix'.
These are installed by the setup script, so they should be declared as peer dependencies with version constraints, matching what's in use across other Sofie projects.
eslint.config.* files always import devDependencies (ESLint plugins/presets) by design — they are never part of the published package. However, projects without a "files" field in package.json cause npm to default to publishing everything, making eslint.config.* appear to be a published file. In that case the rule fires on line 1 of every project's eslint.config.mjs: "@sofie-automation/code-standard-preset" is not published n/no-unpublished-import We already suppress n/no-extraneous-import for the same files. Add the same exemption for n/no-unpublished-import.
84cdfc3 to
3987872
Compare
About the Contributor
This pull request is posted on behalf of SuperFly.tv.
Type of Contribution
This is a Feature
Current Behavior
Setting up a new project to use
@sofie-automation/code-standard-presetrequires manually editingpackage.json(prettier config, lint scripts, lint-staged), creatingeslint.config.mjs, copying.editorconfig, and creating the husky pre-commit hook — all described in the README.New Behavior
A new
sofie-code-preset-setupCLI command automates the setup (and can be re-run to update an existing project). It:prettierconfig key inpackage.jsonto@sofie-automation/code-standard-preset/prettier.config.mjslint,lint:fix,lint:eslint,lint:prettier, andlicense-validatescripts inpackage.jsonpreparescript for husky if not already presentlint-stagedconfig inpackage.jsoneslint.config.mjsif it does not already exist.editorconfigfrom the preset (also now included in the published package files).husky/pre-commitif it does not already existTesting Instructions
In a fresh yarn project directory (with a
package.jsonandpackageManager: yarn@...):Verify the expected files are created/updated. Re-run and verify it is idempotent (no duplicate entries, no overwrites of
eslint.config.mjs).Also test that running in an npm project (with
package-lock.json) exits with an error.Other Information
.editorconfighas been added to thefilesarray inpackage.jsonso it is included in the published package.Also fixed an issue where projects without a files field in
package.jsonget ann/no-unpublished-importerror on line 1 of their generatedeslint.config.mjs, since config files always import devDependencies by design. This PR supressedn/no-unpublished-importforeslint.config.*files (alongside the existing n/no-extraneous-import suppression).Status