gitgrip 0.2.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.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +211 -0
  3. package/actions/cross-repo-sync/action.yml +55 -0
  4. package/assets/banner.svg +73 -0
  5. package/assets/icon.svg +30 -0
  6. package/assets/logo-dark.svg +36 -0
  7. package/assets/logo.svg +36 -0
  8. package/dist/commands/add.d.ts +9 -0
  9. package/dist/commands/add.d.ts.map +1 -0
  10. package/dist/commands/add.js +80 -0
  11. package/dist/commands/add.js.map +1 -0
  12. package/dist/commands/bench.d.ts +12 -0
  13. package/dist/commands/bench.d.ts.map +1 -0
  14. package/dist/commands/bench.js +136 -0
  15. package/dist/commands/bench.js.map +1 -0
  16. package/dist/commands/branch.d.ts +15 -0
  17. package/dist/commands/branch.d.ts.map +1 -0
  18. package/dist/commands/branch.js +159 -0
  19. package/dist/commands/branch.js.map +1 -0
  20. package/dist/commands/checkout.d.ts +10 -0
  21. package/dist/commands/checkout.d.ts.map +1 -0
  22. package/dist/commands/checkout.js +85 -0
  23. package/dist/commands/checkout.js.map +1 -0
  24. package/dist/commands/commit.d.ts +10 -0
  25. package/dist/commands/commit.d.ts.map +1 -0
  26. package/dist/commands/commit.js +94 -0
  27. package/dist/commands/commit.js.map +1 -0
  28. package/dist/commands/diff.d.ts +11 -0
  29. package/dist/commands/diff.d.ts.map +1 -0
  30. package/dist/commands/diff.js +105 -0
  31. package/dist/commands/diff.js.map +1 -0
  32. package/dist/commands/env.d.ts +8 -0
  33. package/dist/commands/env.d.ts.map +1 -0
  34. package/dist/commands/env.js +35 -0
  35. package/dist/commands/env.js.map +1 -0
  36. package/dist/commands/forall.d.ts +13 -0
  37. package/dist/commands/forall.d.ts.map +1 -0
  38. package/dist/commands/forall.js +116 -0
  39. package/dist/commands/forall.js.map +1 -0
  40. package/dist/commands/init.d.ts +15 -0
  41. package/dist/commands/init.d.ts.map +1 -0
  42. package/dist/commands/init.js +106 -0
  43. package/dist/commands/init.js.map +1 -0
  44. package/dist/commands/link.d.ts +11 -0
  45. package/dist/commands/link.d.ts.map +1 -0
  46. package/dist/commands/link.js +205 -0
  47. package/dist/commands/link.js.map +1 -0
  48. package/dist/commands/migrate.d.ts +17 -0
  49. package/dist/commands/migrate.d.ts.map +1 -0
  50. package/dist/commands/migrate.js +180 -0
  51. package/dist/commands/migrate.js.map +1 -0
  52. package/dist/commands/pr/create.d.ts +13 -0
  53. package/dist/commands/pr/create.d.ts.map +1 -0
  54. package/dist/commands/pr/create.js +202 -0
  55. package/dist/commands/pr/create.js.map +1 -0
  56. package/dist/commands/pr/index.d.ts +4 -0
  57. package/dist/commands/pr/index.d.ts.map +1 -0
  58. package/dist/commands/pr/index.js +4 -0
  59. package/dist/commands/pr/index.js.map +1 -0
  60. package/dist/commands/pr/merge.d.ts +11 -0
  61. package/dist/commands/pr/merge.d.ts.map +1 -0
  62. package/dist/commands/pr/merge.js +168 -0
  63. package/dist/commands/pr/merge.js.map +1 -0
  64. package/dist/commands/pr/status.d.ts +9 -0
  65. package/dist/commands/pr/status.d.ts.map +1 -0
  66. package/dist/commands/pr/status.js +139 -0
  67. package/dist/commands/pr/status.js.map +1 -0
  68. package/dist/commands/push.d.ts +10 -0
  69. package/dist/commands/push.d.ts.map +1 -0
  70. package/dist/commands/push.js +101 -0
  71. package/dist/commands/push.js.map +1 -0
  72. package/dist/commands/run.d.ts +8 -0
  73. package/dist/commands/run.d.ts.map +1 -0
  74. package/dist/commands/run.js +75 -0
  75. package/dist/commands/run.js.map +1 -0
  76. package/dist/commands/status.d.ts +9 -0
  77. package/dist/commands/status.d.ts.map +1 -0
  78. package/dist/commands/status.js +201 -0
  79. package/dist/commands/status.js.map +1 -0
  80. package/dist/commands/sync.d.ts +13 -0
  81. package/dist/commands/sync.d.ts.map +1 -0
  82. package/dist/commands/sync.js +183 -0
  83. package/dist/commands/sync.js.map +1 -0
  84. package/dist/index.d.ts +3 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +352 -0
  87. package/dist/index.js.map +1 -0
  88. package/dist/lib/__bench__/files.bench.d.ts +2 -0
  89. package/dist/lib/__bench__/files.bench.d.ts.map +1 -0
  90. package/dist/lib/__bench__/files.bench.js +52 -0
  91. package/dist/lib/__bench__/files.bench.js.map +1 -0
  92. package/dist/lib/__bench__/manifest.bench.d.ts +2 -0
  93. package/dist/lib/__bench__/manifest.bench.d.ts.map +1 -0
  94. package/dist/lib/__bench__/manifest.bench.js +74 -0
  95. package/dist/lib/__bench__/manifest.bench.js.map +1 -0
  96. package/dist/lib/files.d.ts +84 -0
  97. package/dist/lib/files.d.ts.map +1 -0
  98. package/dist/lib/files.js +492 -0
  99. package/dist/lib/files.js.map +1 -0
  100. package/dist/lib/git.d.ts +125 -0
  101. package/dist/lib/git.d.ts.map +1 -0
  102. package/dist/lib/git.js +370 -0
  103. package/dist/lib/git.js.map +1 -0
  104. package/dist/lib/github.d.ts +92 -0
  105. package/dist/lib/github.d.ts.map +1 -0
  106. package/dist/lib/github.js +284 -0
  107. package/dist/lib/github.js.map +1 -0
  108. package/dist/lib/hooks.d.ts +19 -0
  109. package/dist/lib/hooks.d.ts.map +1 -0
  110. package/dist/lib/hooks.js +63 -0
  111. package/dist/lib/hooks.js.map +1 -0
  112. package/dist/lib/linker.d.ts +56 -0
  113. package/dist/lib/linker.d.ts.map +1 -0
  114. package/dist/lib/linker.js +185 -0
  115. package/dist/lib/linker.js.map +1 -0
  116. package/dist/lib/manifest.d.ts +73 -0
  117. package/dist/lib/manifest.d.ts.map +1 -0
  118. package/dist/lib/manifest.js +400 -0
  119. package/dist/lib/manifest.js.map +1 -0
  120. package/dist/lib/scripts.d.ts +26 -0
  121. package/dist/lib/scripts.d.ts.map +1 -0
  122. package/dist/lib/scripts.js +123 -0
  123. package/dist/lib/scripts.js.map +1 -0
  124. package/dist/lib/timing.d.ts +100 -0
  125. package/dist/lib/timing.d.ts.map +1 -0
  126. package/dist/lib/timing.js +293 -0
  127. package/dist/lib/timing.js.map +1 -0
  128. package/dist/types.d.ts +312 -0
  129. package/dist/types.d.ts.map +1 -0
  130. package/dist/types.js +2 -0
  131. package/dist/types.js.map +1 -0
  132. package/package.json +60 -0
@@ -0,0 +1,73 @@
1
+ import type { Manifest, RepoInfo, StateFile, GitHubRepoInfo } from '../types.js';
2
+ /**
3
+ * Get the path to the gitgrip directory (.gitgrip or .codi-repo for backward compat)
4
+ * Prefers .gitgrip if it exists, falls back to .codi-repo, defaults to .gitgrip for new workspaces
5
+ */
6
+ export declare function getGitgripDir(workspaceRoot: string): string;
7
+ /**
8
+ * Get the path to the gitgrip directory for new workspaces (always .gitgrip)
9
+ */
10
+ export declare function getNewGitgripDir(workspaceRoot: string): string;
11
+ /**
12
+ * @deprecated Use getGitgripDir instead
13
+ */
14
+ export declare function getCodiRepoDir(workspaceRoot: string): string;
15
+ /**
16
+ * Get the path to the manifests directory
17
+ */
18
+ export declare function getManifestsDir(workspaceRoot: string): string;
19
+ /**
20
+ * Get the path to the manifest file
21
+ */
22
+ export declare function getManifestPath(workspaceRoot: string): string;
23
+ /**
24
+ * Find the manifest file by walking up the directory tree
25
+ * Looks for .codi-repo/manifests/manifest.yaml (new format)
26
+ */
27
+ export declare function findManifestPath(startDir?: string): Promise<string | null>;
28
+ /**
29
+ * Find a legacy manifest file (codi-repos.yaml at root)
30
+ */
31
+ export declare function findLegacyManifestPath(startDir?: string): Promise<string | null>;
32
+ /**
33
+ * Load and parse the manifest file
34
+ * Returns the workspace root (parent of .codi-repo, not the manifests dir)
35
+ */
36
+ export declare function loadManifest(manifestPath?: string): Promise<{
37
+ manifest: Manifest;
38
+ rootDir: string;
39
+ }>;
40
+ /**
41
+ * Create a new manifest file in the manifests directory
42
+ */
43
+ export declare function createManifest(manifestsDir: string, manifest: Manifest): Promise<void>;
44
+ /**
45
+ * Parse GitHub owner/repo from a git URL
46
+ */
47
+ export declare function parseGitHubUrl(url: string): GitHubRepoInfo;
48
+ /**
49
+ * Get full repo info with computed fields
50
+ */
51
+ export declare function getRepoInfo(name: string, config: Manifest['repos'][string], rootDir: string): RepoInfo;
52
+ /**
53
+ * Get all repos as RepoInfo array
54
+ */
55
+ export declare function getAllRepoInfo(manifest: Manifest, rootDir: string): RepoInfo[];
56
+ /**
57
+ * Get manifest repo as RepoInfo (if manifest.url is configured)
58
+ * Returns null if manifest section is not configured, has no URL, or URL is invalid
59
+ */
60
+ export declare function getManifestRepoInfo(manifest: Manifest, rootDir: string): RepoInfo | null;
61
+ /**
62
+ * Load the state file
63
+ */
64
+ export declare function loadState(rootDir: string): Promise<StateFile>;
65
+ /**
66
+ * Save the state file
67
+ */
68
+ export declare function saveState(rootDir: string, state: StateFile): Promise<void>;
69
+ /**
70
+ * Generate a sample manifest for init command
71
+ */
72
+ export declare function generateSampleManifest(): Manifest;
73
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/lib/manifest.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAmD,MAAM,aAAa,CAAC;AA8ElI;;;GAGG;AACH,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAa3D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAc/F;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAcrG;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CA+H1G;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAO5F;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAc1D;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,CAStG;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,EAAE,CAE9E;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CA2BxF;AASD;;GAEG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAWnE;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAShF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,QAAQ,CAoBjD"}
@@ -0,0 +1,400 @@
1
+ import { readFile, writeFile, access } from 'fs/promises';
2
+ import { existsSync } from 'fs';
3
+ import { resolve, dirname, join, normalize } from 'path';
4
+ import YAML from 'yaml';
5
+ // AOSP-style: manifest lives in .gitgrip/manifests/manifest.yaml
6
+ // (Legacy: .codi-repo/manifests/manifest.yaml also supported for backward compatibility)
7
+ const GITGRIP_DIR = '.gitgrip';
8
+ const LEGACY_CODI_REPO_DIR = '.codi-repo';
9
+ const MANIFESTS_DIR = 'manifests';
10
+ const MANIFEST_FILENAME = 'manifest.yaml';
11
+ const STATE_FILENAME = 'state.json';
12
+ // Legacy: old format used codi-repos.yaml at root
13
+ const LEGACY_MANIFEST_FILENAME = 'codi-repos.yaml';
14
+ /**
15
+ * Default manifest settings
16
+ */
17
+ const DEFAULT_SETTINGS = {
18
+ pr_prefix: '[cross-repo]',
19
+ merge_strategy: 'all-or-nothing',
20
+ };
21
+ /**
22
+ * Check if a relative path would escape its parent directory
23
+ */
24
+ function pathEscapesBoundary(relativePath) {
25
+ const normalized = normalize(relativePath);
26
+ // Check for path traversal attempts
27
+ if (normalized.startsWith('..') || normalized.startsWith('/') || normalized.includes('/../')) {
28
+ return true;
29
+ }
30
+ return false;
31
+ }
32
+ /**
33
+ * Validate copyfile/linkfile config
34
+ */
35
+ function validateFileConfig(config, type, repoName) {
36
+ if (!config.src || typeof config.src !== 'string') {
37
+ throw new Error(`${type} in repo '${repoName}' is missing 'src'`);
38
+ }
39
+ if (!config.dest || typeof config.dest !== 'string') {
40
+ throw new Error(`${type} in repo '${repoName}' is missing 'dest'`);
41
+ }
42
+ if (pathEscapesBoundary(config.src)) {
43
+ throw new Error(`${type} in repo '${repoName}': src path '${config.src}' escapes repo boundary`);
44
+ }
45
+ if (pathEscapesBoundary(config.dest)) {
46
+ throw new Error(`${type} in repo '${repoName}': dest path '${config.dest}' escapes workspace boundary`);
47
+ }
48
+ }
49
+ /**
50
+ * Validate workspace script config
51
+ */
52
+ function validateScript(script, scriptName) {
53
+ if (!script.command && !script.steps) {
54
+ throw new Error(`Script '${scriptName}' must have either 'command' or 'steps'`);
55
+ }
56
+ if (script.command && script.steps) {
57
+ throw new Error(`Script '${scriptName}' cannot have both 'command' and 'steps'`);
58
+ }
59
+ if (script.steps) {
60
+ for (let i = 0; i < script.steps.length; i++) {
61
+ const step = script.steps[i];
62
+ if (!step.name) {
63
+ throw new Error(`Script '${scriptName}' step ${i + 1} is missing 'name'`);
64
+ }
65
+ if (!step.command) {
66
+ throw new Error(`Script '${scriptName}' step '${step.name}' is missing 'command'`);
67
+ }
68
+ }
69
+ }
70
+ }
71
+ /**
72
+ * Get the path to the gitgrip directory (.gitgrip or .codi-repo for backward compat)
73
+ * Prefers .gitgrip if it exists, falls back to .codi-repo, defaults to .gitgrip for new workspaces
74
+ */
75
+ export function getGitgripDir(workspaceRoot) {
76
+ const newDir = join(workspaceRoot, GITGRIP_DIR);
77
+ const legacyDir = join(workspaceRoot, LEGACY_CODI_REPO_DIR);
78
+ // Synchronous check for simplicity in path resolution
79
+ if (existsSync(newDir)) {
80
+ return newDir;
81
+ }
82
+ if (existsSync(legacyDir)) {
83
+ return legacyDir;
84
+ }
85
+ // Default to new directory for new workspaces
86
+ return newDir;
87
+ }
88
+ /**
89
+ * Get the path to the gitgrip directory for new workspaces (always .gitgrip)
90
+ */
91
+ export function getNewGitgripDir(workspaceRoot) {
92
+ return join(workspaceRoot, GITGRIP_DIR);
93
+ }
94
+ /**
95
+ * @deprecated Use getGitgripDir instead
96
+ */
97
+ export function getCodiRepoDir(workspaceRoot) {
98
+ return getGitgripDir(workspaceRoot);
99
+ }
100
+ /**
101
+ * Get the path to the manifests directory
102
+ */
103
+ export function getManifestsDir(workspaceRoot) {
104
+ return join(getGitgripDir(workspaceRoot), MANIFESTS_DIR);
105
+ }
106
+ /**
107
+ * Get the path to the manifest file
108
+ */
109
+ export function getManifestPath(workspaceRoot) {
110
+ return join(getManifestsDir(workspaceRoot), MANIFEST_FILENAME);
111
+ }
112
+ /**
113
+ * Find the manifest file by walking up the directory tree
114
+ * Looks for .codi-repo/manifests/manifest.yaml (new format)
115
+ */
116
+ export async function findManifestPath(startDir = process.cwd()) {
117
+ let currentDir = resolve(startDir);
118
+ while (currentDir !== dirname(currentDir)) {
119
+ const manifestPath = getManifestPath(currentDir);
120
+ try {
121
+ await access(manifestPath);
122
+ return manifestPath;
123
+ }
124
+ catch {
125
+ currentDir = dirname(currentDir);
126
+ }
127
+ }
128
+ return null;
129
+ }
130
+ /**
131
+ * Find a legacy manifest file (codi-repos.yaml at root)
132
+ */
133
+ export async function findLegacyManifestPath(startDir = process.cwd()) {
134
+ let currentDir = resolve(startDir);
135
+ while (currentDir !== dirname(currentDir)) {
136
+ const manifestPath = join(currentDir, LEGACY_MANIFEST_FILENAME);
137
+ try {
138
+ await access(manifestPath);
139
+ return manifestPath;
140
+ }
141
+ catch {
142
+ currentDir = dirname(currentDir);
143
+ }
144
+ }
145
+ return null;
146
+ }
147
+ /**
148
+ * Load and parse the manifest file
149
+ * Returns the workspace root (parent of .codi-repo, not the manifests dir)
150
+ */
151
+ export async function loadManifest(manifestPath) {
152
+ const path = manifestPath ?? (await findManifestPath());
153
+ if (!path) {
154
+ throw new Error(`Manifest file not found. Run 'gr init <manifest-url>' first.`);
155
+ }
156
+ const content = await readFile(path, 'utf-8');
157
+ const parsed = YAML.parse(content);
158
+ // Validate and apply defaults
159
+ if (!parsed.version) {
160
+ parsed.version = 1;
161
+ }
162
+ if (!parsed.repos || Object.keys(parsed.repos).length === 0) {
163
+ throw new Error('Manifest must define at least one repository');
164
+ }
165
+ if (!parsed.settings) {
166
+ parsed.settings = DEFAULT_SETTINGS;
167
+ }
168
+ else {
169
+ parsed.settings = { ...DEFAULT_SETTINGS, ...parsed.settings };
170
+ }
171
+ // Validate each repo config
172
+ for (const [name, repo] of Object.entries(parsed.repos)) {
173
+ if (!repo.url) {
174
+ throw new Error(`Repository '${name}' is missing 'url'`);
175
+ }
176
+ if (!repo.path) {
177
+ throw new Error(`Repository '${name}' is missing 'path'`);
178
+ }
179
+ if (!repo.default_branch) {
180
+ repo.default_branch = 'main';
181
+ }
182
+ // Validate copyfile entries
183
+ if (repo.copyfile) {
184
+ if (!Array.isArray(repo.copyfile)) {
185
+ throw new Error(`Repository '${name}': copyfile must be an array`);
186
+ }
187
+ for (const config of repo.copyfile) {
188
+ validateFileConfig(config, 'copyfile', name);
189
+ }
190
+ }
191
+ // Validate linkfile entries
192
+ if (repo.linkfile) {
193
+ if (!Array.isArray(repo.linkfile)) {
194
+ throw new Error(`Repository '${name}': linkfile must be an array`);
195
+ }
196
+ for (const config of repo.linkfile) {
197
+ validateFileConfig(config, 'linkfile', name);
198
+ }
199
+ }
200
+ }
201
+ // Validate manifest-level config
202
+ if (parsed.manifest) {
203
+ // Default manifest branch to 'main'
204
+ if (!parsed.manifest.default_branch) {
205
+ parsed.manifest.default_branch = 'main';
206
+ }
207
+ if (parsed.manifest.copyfile) {
208
+ if (!Array.isArray(parsed.manifest.copyfile)) {
209
+ throw new Error('manifest.copyfile must be an array');
210
+ }
211
+ for (const config of parsed.manifest.copyfile) {
212
+ validateFileConfig(config, 'copyfile', 'manifest');
213
+ }
214
+ }
215
+ if (parsed.manifest.linkfile) {
216
+ if (!Array.isArray(parsed.manifest.linkfile)) {
217
+ throw new Error('manifest.linkfile must be an array');
218
+ }
219
+ for (const config of parsed.manifest.linkfile) {
220
+ validateFileConfig(config, 'linkfile', 'manifest');
221
+ }
222
+ }
223
+ }
224
+ // Validate workspace config
225
+ if (parsed.workspace) {
226
+ // Validate env
227
+ if (parsed.workspace.env) {
228
+ if (typeof parsed.workspace.env !== 'object') {
229
+ throw new Error('workspace.env must be an object');
230
+ }
231
+ }
232
+ // Validate scripts
233
+ if (parsed.workspace.scripts) {
234
+ if (typeof parsed.workspace.scripts !== 'object') {
235
+ throw new Error('workspace.scripts must be an object');
236
+ }
237
+ for (const [scriptName, script] of Object.entries(parsed.workspace.scripts)) {
238
+ validateScript(script, scriptName);
239
+ }
240
+ }
241
+ // Validate hooks
242
+ if (parsed.workspace.hooks) {
243
+ if (typeof parsed.workspace.hooks !== 'object') {
244
+ throw new Error('workspace.hooks must be an object');
245
+ }
246
+ const validHooks = ['post-sync', 'post-checkout'];
247
+ for (const hookName of Object.keys(parsed.workspace.hooks)) {
248
+ if (!validHooks.includes(hookName)) {
249
+ throw new Error(`Unknown hook '${hookName}'. Valid hooks: ${validHooks.join(', ')}`);
250
+ }
251
+ const hooks = parsed.workspace.hooks[hookName];
252
+ if (hooks && !Array.isArray(hooks)) {
253
+ throw new Error(`workspace.hooks.${hookName} must be an array`);
254
+ }
255
+ }
256
+ }
257
+ }
258
+ // rootDir is the workspace root (parent of .codi-repo/manifests/)
259
+ // Path is: <workspace>/.codi-repo/manifests/manifest.yaml
260
+ const manifestsDir = dirname(path);
261
+ const codiRepoDir = dirname(manifestsDir);
262
+ const workspaceRoot = dirname(codiRepoDir);
263
+ return {
264
+ manifest: parsed,
265
+ rootDir: workspaceRoot,
266
+ };
267
+ }
268
+ /**
269
+ * Create a new manifest file in the manifests directory
270
+ */
271
+ export async function createManifest(manifestsDir, manifest) {
272
+ const manifestPath = join(manifestsDir, MANIFEST_FILENAME);
273
+ const content = YAML.stringify(manifest, {
274
+ indent: 2,
275
+ lineWidth: 0,
276
+ });
277
+ await writeFile(manifestPath, content, 'utf-8');
278
+ }
279
+ /**
280
+ * Parse GitHub owner/repo from a git URL
281
+ */
282
+ export function parseGitHubUrl(url) {
283
+ // SSH format: git@github.com:owner/repo.git
284
+ const sshMatch = url.match(/git@github\.com:([^/]+)\/(.+?)(?:\.git)?$/);
285
+ if (sshMatch) {
286
+ return { owner: sshMatch[1], repo: sshMatch[2] };
287
+ }
288
+ // HTTPS format: https://github.com/owner/repo.git
289
+ const httpsMatch = url.match(/https?:\/\/github\.com\/([^/]+)\/(.+?)(?:\.git)?$/);
290
+ if (httpsMatch) {
291
+ return { owner: httpsMatch[1], repo: httpsMatch[2] };
292
+ }
293
+ throw new Error(`Unable to parse GitHub URL: ${url}`);
294
+ }
295
+ /**
296
+ * Get full repo info with computed fields
297
+ */
298
+ export function getRepoInfo(name, config, rootDir) {
299
+ const { owner, repo } = parseGitHubUrl(config.url);
300
+ return {
301
+ ...config,
302
+ name,
303
+ absolutePath: resolve(rootDir, config.path),
304
+ owner,
305
+ repo,
306
+ };
307
+ }
308
+ /**
309
+ * Get all repos as RepoInfo array
310
+ */
311
+ export function getAllRepoInfo(manifest, rootDir) {
312
+ return Object.entries(manifest.repos).map(([name, config]) => getRepoInfo(name, config, rootDir));
313
+ }
314
+ /**
315
+ * Get manifest repo as RepoInfo (if manifest.url is configured)
316
+ * Returns null if manifest section is not configured, has no URL, or URL is invalid
317
+ */
318
+ export function getManifestRepoInfo(manifest, rootDir) {
319
+ if (!manifest.manifest?.url) {
320
+ return null;
321
+ }
322
+ const manifestsDir = getManifestsDir(rootDir);
323
+ try {
324
+ const parsed = parseGitHubUrl(manifest.manifest.url);
325
+ // Determine which directory is in use for the path field
326
+ const gitgripDir = getGitgripDir(rootDir);
327
+ const dirName = gitgripDir.endsWith(LEGACY_CODI_REPO_DIR) ? LEGACY_CODI_REPO_DIR : GITGRIP_DIR;
328
+ return {
329
+ name: 'manifest',
330
+ url: manifest.manifest.url,
331
+ path: `${dirName}/manifests`,
332
+ absolutePath: manifestsDir,
333
+ default_branch: manifest.manifest.default_branch ?? 'main',
334
+ owner: parsed.owner,
335
+ repo: parsed.repo,
336
+ };
337
+ }
338
+ catch {
339
+ // Invalid GitHub URL format
340
+ return null;
341
+ }
342
+ }
343
+ /**
344
+ * Get the state file path
345
+ */
346
+ function getStatePath(rootDir) {
347
+ return join(getCodiRepoDir(rootDir), STATE_FILENAME);
348
+ }
349
+ /**
350
+ * Load the state file
351
+ */
352
+ export async function loadState(rootDir) {
353
+ const statePath = getStatePath(rootDir);
354
+ try {
355
+ const content = await readFile(statePath, 'utf-8');
356
+ return JSON.parse(content);
357
+ }
358
+ catch {
359
+ return {
360
+ branchToPR: {},
361
+ prLinks: {},
362
+ };
363
+ }
364
+ }
365
+ /**
366
+ * Save the state file
367
+ */
368
+ export async function saveState(rootDir, state) {
369
+ const statePath = getStatePath(rootDir);
370
+ const stateDir = dirname(statePath);
371
+ // Ensure state directory exists
372
+ const { mkdir } = await import('fs/promises');
373
+ await mkdir(stateDir, { recursive: true });
374
+ await writeFile(statePath, JSON.stringify(state, null, 2), 'utf-8');
375
+ }
376
+ /**
377
+ * Generate a sample manifest for init command
378
+ */
379
+ export function generateSampleManifest() {
380
+ return {
381
+ version: 1,
382
+ repos: {
383
+ public: {
384
+ url: 'git@github.com:your-org/your-repo.git',
385
+ path: './public',
386
+ default_branch: 'main',
387
+ },
388
+ private: {
389
+ url: 'git@github.com:your-org/your-private-repo.git',
390
+ path: './private',
391
+ default_branch: 'main',
392
+ },
393
+ },
394
+ settings: {
395
+ pr_prefix: '[cross-repo]',
396
+ merge_strategy: 'all-or-nothing',
397
+ },
398
+ };
399
+ }
400
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/lib/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { Manifest } from '../types.js';
2
+ export interface ScriptStepResult {
3
+ name: string;
4
+ command: string;
5
+ cwd: string;
6
+ success: boolean;
7
+ exitCode: number | null;
8
+ error?: string;
9
+ }
10
+ export interface ScriptResult {
11
+ scriptName: string;
12
+ success: boolean;
13
+ steps: ScriptStepResult[];
14
+ }
15
+ /**
16
+ * Run a workspace script by name
17
+ */
18
+ export declare function runScript(scriptName: string, manifest: Manifest, rootDir: string, args?: string[]): Promise<ScriptResult>;
19
+ /**
20
+ * Get list of available scripts
21
+ */
22
+ export declare function listScripts(manifest: Manifest): {
23
+ name: string;
24
+ description?: string;
25
+ }[];
26
+ //# sourceMappingURL=scripts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scripts.d.ts","sourceRoot":"","sources":["../../src/lib/scripts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAA+B,MAAM,aAAa,CAAC;AAEzE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AA0DD;;GAEG;AACH,wBAAsB,SAAS,CAC7B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,MAAM,EAAO,GAClB,OAAO,CAAC,YAAY,CAAC,CA+DvB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,CAUxF"}
@@ -0,0 +1,123 @@
1
+ import { spawn } from 'child_process';
2
+ import { resolve } from 'path';
3
+ /**
4
+ * Run a single command (used for both single commands and steps)
5
+ */
6
+ async function runCommand(command, cwd, env, onStdout, onStderr) {
7
+ return new Promise((resolvePromise) => {
8
+ const proc = spawn(command, [], {
9
+ cwd,
10
+ shell: true,
11
+ stdio: ['inherit', 'pipe', 'pipe'],
12
+ env: {
13
+ ...process.env,
14
+ ...env,
15
+ },
16
+ });
17
+ proc.stdout?.on('data', (data) => {
18
+ const str = data.toString();
19
+ if (onStdout) {
20
+ onStdout(str);
21
+ }
22
+ else {
23
+ process.stdout.write(str);
24
+ }
25
+ });
26
+ proc.stderr?.on('data', (data) => {
27
+ const str = data.toString();
28
+ if (onStderr) {
29
+ onStderr(str);
30
+ }
31
+ else {
32
+ process.stderr.write(str);
33
+ }
34
+ });
35
+ proc.on('close', (exitCode) => {
36
+ resolvePromise({
37
+ success: exitCode === 0,
38
+ exitCode,
39
+ });
40
+ });
41
+ proc.on('error', (error) => {
42
+ resolvePromise({
43
+ success: false,
44
+ exitCode: null,
45
+ error: error.message,
46
+ });
47
+ });
48
+ });
49
+ }
50
+ /**
51
+ * Run a workspace script by name
52
+ */
53
+ export async function runScript(scriptName, manifest, rootDir, args = []) {
54
+ const workspace = manifest.workspace;
55
+ if (!workspace?.scripts) {
56
+ throw new Error('No workspace scripts defined in manifest');
57
+ }
58
+ const script = workspace.scripts[scriptName];
59
+ if (!script) {
60
+ const available = Object.keys(workspace.scripts).join(', ');
61
+ throw new Error(`Script '${scriptName}' not found. Available: ${available}`);
62
+ }
63
+ // Get workspace env
64
+ const env = workspace.env ?? {};
65
+ const result = {
66
+ scriptName,
67
+ success: true,
68
+ steps: [],
69
+ };
70
+ if (script.command) {
71
+ // Single command script
72
+ const cwd = script.cwd ? resolve(rootDir, script.cwd) : rootDir;
73
+ // Append any extra args
74
+ const fullCommand = args.length > 0 ? `${script.command} ${args.join(' ')}` : script.command;
75
+ const stepResult = await runCommand(fullCommand, cwd, env);
76
+ result.steps.push({
77
+ name: scriptName,
78
+ command: fullCommand,
79
+ cwd,
80
+ success: stepResult.success,
81
+ exitCode: stepResult.exitCode,
82
+ error: stepResult.error,
83
+ });
84
+ result.success = stepResult.success;
85
+ }
86
+ else if (script.steps) {
87
+ // Multi-step script
88
+ for (const step of script.steps) {
89
+ const cwd = step.cwd ? resolve(rootDir, step.cwd) : rootDir;
90
+ const stepResult = await runCommand(step.command, cwd, env);
91
+ result.steps.push({
92
+ name: step.name,
93
+ command: step.command,
94
+ cwd,
95
+ success: stepResult.success,
96
+ exitCode: stepResult.exitCode,
97
+ error: stepResult.error,
98
+ });
99
+ if (!stepResult.success) {
100
+ result.success = false;
101
+ break;
102
+ }
103
+ }
104
+ }
105
+ else {
106
+ throw new Error(`Script '${scriptName}' has neither command nor steps defined`);
107
+ }
108
+ return result;
109
+ }
110
+ /**
111
+ * Get list of available scripts
112
+ */
113
+ export function listScripts(manifest) {
114
+ const workspace = manifest.workspace;
115
+ if (!workspace?.scripts) {
116
+ return [];
117
+ }
118
+ return Object.entries(workspace.scripts).map(([name, script]) => ({
119
+ name,
120
+ description: script.description,
121
+ }));
122
+ }
123
+ //# sourceMappingURL=scripts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scripts.js","sourceRoot":"","sources":["../../src/lib/scripts.ts"],"names":[],"mappings":"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"}