Skip to content

Commit c342a0a

Browse files
committed
refactor to use fs ops pattern more
1 parent cc82ce6 commit c342a0a

8 files changed

Lines changed: 84 additions & 23 deletions

File tree

.changeset/rare-pumas-switch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@fuzdev/fuz_gitops': minor
3+
---
4+
5+
refactor to use fs ops pattern more

src/lib/changeset_generator.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
* @module
88
*/
99

10-
import {writeFile, mkdir} from 'node:fs/promises';
1110
import {join} from 'node:path';
12-
import {existsSync} from 'node:fs';
1311
import type {Logger} from '@fuzdev/fuz_util/log.js';
1412
import type {LocalRepo} from './local_repo.js';
1513
import type {PublishedVersion} from './multi_repo_publisher.js';
1614
import {strip_version_prefix} from './version_utils.js';
15+
import type {FsOperations} from './operations.js';
16+
import {default_fs_operations} from './operations_defaults.js';
1717

1818
export interface DependencyVersionChange {
1919
package_name: string;
@@ -30,14 +30,17 @@ export interface DependencyVersionChange {
3030
export const create_changeset_for_dependency_updates = async (
3131
repo: LocalRepo,
3232
updates: Array<DependencyVersionChange>,
33-
options: {log?: Logger} = {},
33+
options: {log?: Logger; fs_ops?: FsOperations} = {},
3434
): Promise<string> => {
35-
const {log} = options;
35+
const {log, fs_ops = default_fs_operations} = options;
3636
const changesets_dir = join(repo.repo_dir, '.changeset');
3737

3838
// Ensure .changeset directory exists
39-
if (!existsSync(changesets_dir)) {
40-
await mkdir(changesets_dir, {recursive: true});
39+
if (!fs_ops.exists({path: changesets_dir})) {
40+
const mkdir_result = await fs_ops.mkdir({path: changesets_dir, recursive: true});
41+
if (!mkdir_result.ok) {
42+
throw new Error(`Failed to create .changeset directory: ${mkdir_result.message}`);
43+
}
4144
}
4245

4346
// Generate a unique filename
@@ -53,7 +56,10 @@ export const create_changeset_for_dependency_updates = async (
5356
const content = generate_changeset_content(repo.library.name, updates, required_bump);
5457

5558
// Write the changeset file
56-
await writeFile(filepath, content, 'utf8');
59+
const write_result = await fs_ops.writeFile({path: filepath, content});
60+
if (!write_result.ok) {
61+
throw new Error(`Failed to write changeset file: ${write_result.message}`);
62+
}
5763

5864
log?.info(` Created changeset: ${filename}`);
5965

src/lib/dependency_updater.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export const update_package_json = async (
145145
const changeset_path = await create_changeset_for_dependency_updates(
146146
repo,
147147
dependency_updates,
148-
{log},
148+
{log, fs_ops},
149149
);
150150

151151
// Add changeset to git

src/lib/operations.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,19 @@ export interface FsOperations {
319319
path: string;
320320
content: string;
321321
}) => Promise<Result<object, {message: string}>>;
322+
323+
/**
324+
* Creates a directory, optionally with recursive creation.
325+
*/
326+
mkdir: (options: {
327+
path: string;
328+
recursive?: boolean;
329+
}) => Promise<Result<object, {message: string}>>;
330+
331+
/**
332+
* Checks if a path exists on the file system.
333+
*/
334+
exists: (options: {path: string}) => boolean;
322335
}
323336

324337
/**

src/lib/operations_defaults.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
*/
99

1010
import {spawn, spawn_out} from '@fuzdev/fuz_util/process.js';
11-
import {readFile, writeFile} from 'node:fs/promises';
11+
import {readFile, writeFile, mkdir} from 'node:fs/promises';
12+
import {existsSync} from 'node:fs';
1213
import {git_checkout, type GitBranch, type GitOrigin} from '@fuzdev/fuz_util/git.js';
1314
import {EMPTY_OBJECT} from '@fuzdev/fuz_util/object.js';
1415

@@ -300,6 +301,15 @@ export const default_fs_operations: FsOperations = {
300301
const {path, content} = options;
301302
return wrap_void(() => writeFile(path, content));
302303
},
304+
305+
mkdir: async (options) => {
306+
const {path, recursive} = options;
307+
return wrap_void(() => mkdir(path, {recursive}));
308+
},
309+
310+
exists: (options) => {
311+
return existsSync(options.path);
312+
},
303313
};
304314

305315
export const default_build_operations: BuildOperations = {

src/routes/library.json

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@
159159
"kind": "function",
160160
"doc_comment": "Creates a changeset file for dependency updates.\nReturns the path to the created changeset file.",
161161
"source_line": 30,
162-
"type_signature": "(repo: LocalRepo, updates: DependencyVersionChange[], options?: { log?: Logger | undefined; }): Promise<string>",
162+
"type_signature": "(repo: LocalRepo, updates: DependencyVersionChange[], options?: { log?: Logger | undefined; fs_ops?: FsOperations | undefined; }): Promise<...>",
163163
"return_type": "Promise<string>",
164164
"parameters": [
165165
{
@@ -172,7 +172,7 @@
172172
},
173173
{
174174
"name": "options",
175-
"type": "{ log?: Logger | undefined; }",
175+
"type": "{ log?: Logger | undefined; fs_ops?: FsOperations | undefined; }",
176176
"default_value": "{}"
177177
}
178178
]
@@ -181,7 +181,7 @@
181181
"name": "generate_changeset_content",
182182
"kind": "function",
183183
"doc_comment": "Generates markdown changeset content for dependency updates.\n\nCreates properly formatted changeset with YAML frontmatter, summary,\nand categorized list of breaking vs regular updates. Output format\nmatches changesets CLI for consistency.",
184-
"source_line": 97,
184+
"source_line": 103,
185185
"type_signature": "(package_name: string, updates: DependencyVersionChange[], bump_type: \"major\" | \"minor\" | \"patch\"): string",
186186
"return_type": "string",
187187
"return_description": "markdown content ready to write to .changeset/*.md file",
@@ -206,7 +206,7 @@
206206
{
207207
"name": "create_dependency_updates",
208208
"kind": "function",
209-
"source_line": 141,
209+
"source_line": 147,
210210
"type_signature": "(dependencies: Map<string, string>, published_versions: Map<string, PublishedVersion>): DependencyVersionChange[]",
211211
"return_type": "DependencyVersionChange[]",
212212
"parameters": [
@@ -222,7 +222,7 @@
222222
}
223223
],
224224
"module_comment": "Auto-generation of changesets for dependency updates during publishing.\n\nCreates changesets when packages need to republish due to updated dependencies.\nFor parsing existing changesets, see `changeset_reader.ts`.",
225-
"dependencies": ["version_utils.ts"],
225+
"dependencies": ["operations_defaults.ts", "version_utils.ts"],
226226
"dependents": ["dependency_updater.ts"]
227227
},
228228
{
@@ -2591,50 +2591,50 @@
25912591
{
25922592
"name": "default_changeset_operations",
25932593
"kind": "variable",
2594-
"source_line": 70,
2594+
"source_line": 71,
25952595
"type_signature": "ChangesetOperations"
25962596
},
25972597
{
25982598
"name": "default_git_operations",
25992599
"kind": "variable",
2600-
"source_line": 95,
2600+
"source_line": 96,
26012601
"type_signature": "GitOperations"
26022602
},
26032603
{
26042604
"name": "default_process_operations",
26052605
"kind": "variable",
2606-
"source_line": 192,
2606+
"source_line": 193,
26072607
"type_signature": "ProcessOperations"
26082608
},
26092609
{
26102610
"name": "default_npm_operations",
26112611
"kind": "variable",
2612-
"source_line": 216,
2612+
"source_line": 217,
26132613
"type_signature": "NpmOperations"
26142614
},
26152615
{
26162616
"name": "default_preflight_operations",
26172617
"kind": "variable",
2618-
"source_line": 287,
2618+
"source_line": 288,
26192619
"type_signature": "PreflightOperations"
26202620
},
26212621
{
26222622
"name": "default_fs_operations",
26232623
"kind": "variable",
2624-
"source_line": 293,
2624+
"source_line": 294,
26252625
"type_signature": "FsOperations"
26262626
},
26272627
{
26282628
"name": "default_build_operations",
26292629
"kind": "variable",
2630-
"source_line": 305,
2630+
"source_line": 315,
26312631
"type_signature": "BuildOperations"
26322632
},
26332633
{
26342634
"name": "default_gitops_operations",
26352635
"kind": "variable",
26362636
"doc_comment": "Combined default operations for all gitops functionality.",
2637-
"source_line": 329,
2637+
"source_line": 339,
26382638
"type_signature": "GitopsOperations"
26392639
}
26402640
],
@@ -2646,6 +2646,7 @@
26462646
"preflight_checks.ts"
26472647
],
26482648
"dependents": [
2649+
"changeset_generator.ts",
26492650
"dependency_updater.ts",
26502651
"local_repo.ts",
26512652
"multi_repo_publisher.ts",
@@ -2902,14 +2903,26 @@
29022903
"kind": "variable",
29032904
"type_signature": "(options: {\n\t\tpath: string;\n\t\tcontent: string;\n\t}) => Promise<Result<object, {message: string}>>",
29042905
"doc_comment": "Writes a file to the file system."
2906+
},
2907+
{
2908+
"name": "mkdir",
2909+
"kind": "variable",
2910+
"type_signature": "(options: {\n\t\tpath: string;\n\t\trecursive?: boolean;\n\t}) => Promise<Result<object, {message: string}>>",
2911+
"doc_comment": "Creates a directory, optionally with recursive creation."
2912+
},
2913+
{
2914+
"name": "exists",
2915+
"kind": "variable",
2916+
"type_signature": "(options: {path: string}) => boolean",
2917+
"doc_comment": "Checks if a path exists on the file system."
29052918
}
29062919
]
29072920
},
29082921
{
29092922
"name": "GitopsOperations",
29102923
"kind": "type",
29112924
"doc_comment": "Combined operations interface grouping all gitops functionality.\nThis is the main interface injected into publishing and validation workflows.",
2912-
"source_line": 328,
2925+
"source_line": 341,
29132926
"type_signature": "GitopsOperations",
29142927
"properties": [
29152928
{

src/test/fixtures/mock_operations.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ export const create_mock_fs_ops = (fixture: RepoFixtureSet): FsOperations => {
154154
},
155155

156156
writeFile: async () => ({ok: true}),
157+
158+
mkdir: async () => ({ok: true}),
159+
160+
exists: () => true,
157161
};
158162
};
159163

src/test/test_helpers.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ export const create_mock_gitops_ops = (
129129
fs: {
130130
readFile: async () => ({ok: true, value: '{}'}),
131131
writeFile: async () => ({ok: true}),
132+
mkdir: async () => ({ok: true}),
133+
exists: () => true,
132134
...overrides.fs,
133135
},
134136
build: create_mock_build_ops(overrides.build),
@@ -280,6 +282,7 @@ export const create_mock_fs_ops = (): FsOperations & {
280282
set: (path: string, content: string) => void;
281283
} => {
282284
const files: Map<string, string> = new Map();
285+
const dirs: Set<string> = new Set();
283286

284287
return {
285288
readFile: async (options) => {
@@ -293,6 +296,13 @@ export const create_mock_fs_ops = (): FsOperations & {
293296
files.set(options.path, options.content);
294297
return {ok: true};
295298
},
299+
mkdir: async (options) => {
300+
dirs.add(options.path);
301+
return {ok: true};
302+
},
303+
exists: (options) => {
304+
return files.has(options.path) || dirs.has(options.path);
305+
},
296306
get: (path: string): string | undefined => files.get(path),
297307
set: (path: string, content: string): void => {
298308
files.set(path, content);

0 commit comments

Comments
 (0)