-
Notifications
You must be signed in to change notification settings - Fork 0
feat: implement v0 #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,5 +8,4 @@ | |
| .pnp.* | ||
| dist | ||
|
|
||
| .nx/cache | ||
| .nx/workspace-data | ||
| *.tgz | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,108 @@ | ||
| # Codeowners-kit | ||
| # 💪 Pull up | ||
|
|
||
| Collect scattered config files from your monorepo and generate them where your systems expect. | ||
|
|
||
| ## The Problem | ||
|
|
||
| Many tools require config files in specific locations: | ||
|
|
||
| - GitHub reads `CODEOWNERS` from `.github/CODEOWNERS` | ||
| - GitHub Actions workflows must live in `.github/workflows/` | ||
| - And more... | ||
|
|
||
| In a monorepo, each package has its own context. But these systems only look at root-level paths. You end up with a single massive file that every team has to edit, leading to merge conflicts and unclear ownership. | ||
|
|
||
| ## The Solution | ||
|
|
||
| **Pull up** lets you keep config files next to the code they describe, then collects and generates them to the locations your systems expect. | ||
|
|
||
| ``` | ||
| packages/ | ||
| core/ | ||
| CODEOWNERS # * @core-team | ||
| web/ | ||
| CODEOWNERS # * @frontend-team | ||
| api/ | ||
| CODEOWNERS # * @backend-team | ||
|
|
||
| ↓ pullup sync | ||
|
|
||
| .github/ | ||
| CODEOWNERS # All entries merged with correct paths | ||
| ``` | ||
|
|
||
| ## Installation | ||
|
|
||
| ```bash | ||
| npm install -D pull-up | ||
| # or | ||
| yarn add -D pull-up | ||
| # or | ||
| pnpm add -D pull-up | ||
| ``` | ||
|
|
||
| ## Usage | ||
|
|
||
| ### Sync | ||
|
|
||
| Generate files from scattered sources: | ||
|
|
||
| ```bash | ||
| pullup sync | ||
| ``` | ||
|
|
||
| Preview changes without writing: | ||
|
|
||
| ```bash | ||
| pullup sync --dry-run | ||
| ``` | ||
|
|
||
| ### Check | ||
|
|
||
| Verify generated files are up to date (useful in CI): | ||
|
|
||
| ```bash | ||
| pullup check | ||
| ``` | ||
|
|
||
| ## Example: CODEOWNERS | ||
|
|
||
| Place `CODEOWNERS` files in each package: | ||
|
|
||
| ``` | ||
| # packages/core/CODEOWNERS | ||
| * @core-team | ||
| ``` | ||
|
|
||
| ``` | ||
| # packages/web/CODEOWNERS | ||
| * @frontend-team | ||
| *.css @design-team | ||
| ``` | ||
|
|
||
| Run `pullup sync --rule codeowners` to generate `.github/CODEOWNERS`: | ||
|
|
||
| ``` | ||
| # @generated by pullup - do not edit manually | ||
|
|
||
| /packages/core/ @core-team | ||
| /packages/web/ @frontend-team | ||
| /packages/web/*.css @design-team | ||
|
|
||
| # @end-generated | ||
| ``` | ||
|
|
||
| Existing manual entries in the file are preserved outside the generated markers. | ||
|
|
||
| ## CLI Options | ||
|
|
||
| | Option | Description | | ||
| | --------------- | -------------------------------------- | | ||
| | `--rule <name>` | Run specific rule(s) only (repeatable) | | ||
| | `--root <path>` | Repository root path | | ||
| | `--cwd <path>` | Working directory | | ||
| | `--dry-run` | Preview without writing (sync only) | | ||
|
|
||
| ## License | ||
|
|
||
| MIT |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,23 +1,40 @@ | ||
| { | ||
| "name": "codeowners-kit-monorepo", | ||
| "private": true, | ||
| "workspaces": [ | ||
| "packages/*" | ||
| "name": "pull-up", | ||
| "type": "module", | ||
| "version": "0.0.1-alpha.0", | ||
| "bin": { | ||
| "pullup": "dist/index.mjs" | ||
| }, | ||
| "main": "dist/index.mjs", | ||
| "types": "dist/index.d.ts", | ||
| "files": [ | ||
| "dist" | ||
| ], | ||
| "scripts": { | ||
| "build:all": "nx run-many -t build", | ||
| "typecheck:all": "nx run-many -t typecheck" | ||
| "build": "tsdown", | ||
| "dev": "tsdown --watch", | ||
| "pullup": "yarn build && node dist/index.mjs", | ||
| "prepack": "yarn build", | ||
| "lint": "eslint .", | ||
| "format": "prettier --write .", | ||
| "typecheck": "tsc --noEmit" | ||
| }, | ||
| "devDependencies": { | ||
| "@nx/js": "^22.3.3", | ||
| "eslint": "^9.39.2", | ||
| "@types/node": "^24.10.0", | ||
| "eslint": "^9.7.0", | ||
| "eslint-plugin-import-x": "^4.0.0", | ||
| "eslint-plugin-simple-import-sort": "^12.1.1", | ||
| "globals": "^17.0.0", | ||
| "nx": "^22.3.3", | ||
| "prettier": "^3.8.0", | ||
| "tsdown": "^0.19.0", | ||
| "typescript": "^5.9.2", | ||
| "typescript-eslint": "^8.27.0" | ||
| }, | ||
| "dependencies": { | ||
| "clipanion": "^4.0.0-rc.4", | ||
| "fast-glob": "^3.3.3", | ||
| "find-up": "^8.0.0", | ||
| "picocolors": "^1.1.1" | ||
| }, | ||
| "packageManager": "yarn@4.12.0" | ||
| } |
Binary file not shown.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| import { Command, Option } from "clipanion"; | ||
| import pc from "picocolors"; | ||
| import { resolveRule, Rule } from "../../core"; | ||
| import fs from "node:fs/promises"; | ||
| import { defaultRules } from "../constants"; | ||
| import { getRepositoryRoot } from "../utils"; | ||
| import path from "node:path"; | ||
|
|
||
| export class CheckCommand extends Command { | ||
| static paths = [["check"]]; | ||
| static usage = Command.Usage({ | ||
| description: "Check if generated files are up to date", | ||
| examples: [["Check all rules", "pullup check"]], | ||
| }); | ||
|
|
||
| root = Option.String("--root", { | ||
| description: "The path to the repository root", | ||
| required: false, | ||
| }); | ||
|
|
||
| cwd = Option.String("--cwd", { | ||
| description: "The path to the working directory", | ||
| required: false, | ||
| }); | ||
|
|
||
| rules = Option.Array("--rule", { | ||
| description: "The rules to check", | ||
| required: false, | ||
| }); | ||
|
|
||
| async execute() { | ||
| const repoRoot = await this.resolveRoot(); | ||
| const resolvedRules = this.resolveRules(); | ||
|
|
||
| if (resolvedRules.length === 0) { | ||
| console.log(pc.yellow("✘ No rules found to check")); | ||
| return; | ||
| } | ||
|
|
||
| const results = await Promise.all( | ||
| resolvedRules.map(([name, rule]) => this.checkRule(name, rule, repoRoot)), | ||
| ); | ||
|
|
||
| const failures = results.filter((r) => !r.ok); | ||
|
|
||
| if (failures.length > 0) { | ||
| failures.forEach((f) => | ||
| console.error( | ||
| pc.red(`✘ ${f.name} is outdated. Run 'pullup sync' to update.`), | ||
| ), | ||
| ); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| console.log(pc.green("✔ All files are up to date")); | ||
| } | ||
|
|
||
| private async resolveRoot(): Promise<string> { | ||
| if (this.root != null) return this.root; | ||
|
|
||
| const cwd = this.cwd ?? process.cwd(); | ||
| const root = await getRepositoryRoot(cwd); | ||
|
|
||
| if (root == null) throw new Error("Repository root not found"); | ||
| return root; | ||
ho991217 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| private async checkRule( | ||
| name: string, | ||
| rule: Rule, | ||
| repoRoot: string, | ||
| ): Promise<{ name: string; ok: boolean }> { | ||
| const outputPath = path.resolve(repoRoot, rule.output); | ||
| const existing = await readFileOrNull(outputPath); | ||
| const resolved = await resolveRule(rule, repoRoot); | ||
|
|
||
| return { name, ok: existing === resolved.contents }; | ||
| } | ||
|
|
||
| private resolveRules(): [string, Rule][] { | ||
| const ruleKeys = | ||
| this.rules != null ? this.rules : Object.keys(defaultRules); | ||
| return Object.entries(defaultRules).filter(([name]) => | ||
| ruleKeys.includes(name), | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| async function readFileOrNull(absPath: string): Promise<string | null> { | ||
| try { | ||
| return await fs.readFile(absPath, "utf-8"); | ||
| } catch { | ||
| return null; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| export * from "./check.js"; | ||
| export * from "./sync.js"; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.