@aaronshaf/confluence-cli 0.1.15
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.
- package/LICENSE +21 -0
- package/README.md +69 -0
- package/package.json +73 -0
- package/src/cli/commands/attachments.ts +113 -0
- package/src/cli/commands/clone.ts +188 -0
- package/src/cli/commands/comments.ts +56 -0
- package/src/cli/commands/create.ts +58 -0
- package/src/cli/commands/delete.ts +46 -0
- package/src/cli/commands/doctor.ts +161 -0
- package/src/cli/commands/duplicate-check.ts +89 -0
- package/src/cli/commands/file-rename.ts +113 -0
- package/src/cli/commands/folder-hierarchy.ts +241 -0
- package/src/cli/commands/info.ts +56 -0
- package/src/cli/commands/labels.ts +53 -0
- package/src/cli/commands/move.ts +23 -0
- package/src/cli/commands/open.ts +145 -0
- package/src/cli/commands/pull.ts +241 -0
- package/src/cli/commands/push-errors.ts +40 -0
- package/src/cli/commands/push.ts +699 -0
- package/src/cli/commands/search.ts +62 -0
- package/src/cli/commands/setup.ts +124 -0
- package/src/cli/commands/spaces.ts +42 -0
- package/src/cli/commands/status.ts +88 -0
- package/src/cli/commands/tree.ts +190 -0
- package/src/cli/help.ts +425 -0
- package/src/cli/index.ts +413 -0
- package/src/cli/utils/browser.ts +34 -0
- package/src/cli/utils/progress-reporter.ts +49 -0
- package/src/cli.ts +6 -0
- package/src/lib/config.ts +156 -0
- package/src/lib/confluence-client/attachment-operations.ts +221 -0
- package/src/lib/confluence-client/client.ts +653 -0
- package/src/lib/confluence-client/comment-operations.ts +60 -0
- package/src/lib/confluence-client/folder-operations.ts +203 -0
- package/src/lib/confluence-client/index.ts +47 -0
- package/src/lib/confluence-client/label-operations.ts +102 -0
- package/src/lib/confluence-client/page-operations.ts +270 -0
- package/src/lib/confluence-client/search-operations.ts +60 -0
- package/src/lib/confluence-client/types.ts +329 -0
- package/src/lib/confluence-client/user-operations.ts +58 -0
- package/src/lib/dependency-sorter.ts +233 -0
- package/src/lib/errors.ts +237 -0
- package/src/lib/file-scanner.ts +195 -0
- package/src/lib/formatters.ts +314 -0
- package/src/lib/health-check.ts +204 -0
- package/src/lib/markdown/converter.ts +427 -0
- package/src/lib/markdown/frontmatter.ts +116 -0
- package/src/lib/markdown/html-converter.ts +398 -0
- package/src/lib/markdown/index.ts +21 -0
- package/src/lib/markdown/link-converter.ts +189 -0
- package/src/lib/markdown/reference-updater.ts +251 -0
- package/src/lib/markdown/slugify.ts +32 -0
- package/src/lib/page-state.ts +195 -0
- package/src/lib/resolve-page-target.ts +33 -0
- package/src/lib/space-config.ts +264 -0
- package/src/lib/sync/cleanup.ts +50 -0
- package/src/lib/sync/folder-path.ts +61 -0
- package/src/lib/sync/index.ts +2 -0
- package/src/lib/sync/link-resolution-pass.ts +139 -0
- package/src/lib/sync/sync-engine.ts +681 -0
- package/src/lib/sync/sync-specific.ts +221 -0
- package/src/lib/sync/types.ts +42 -0
- package/src/test/attachments.test.ts +68 -0
- package/src/test/clone.test.ts +373 -0
- package/src/test/comments.test.ts +53 -0
- package/src/test/config.test.ts +209 -0
- package/src/test/confluence-client.test.ts +535 -0
- package/src/test/delete.test.ts +39 -0
- package/src/test/dependency-sorter.test.ts +384 -0
- package/src/test/errors.test.ts +199 -0
- package/src/test/file-rename.test.ts +305 -0
- package/src/test/file-scanner.test.ts +331 -0
- package/src/test/folder-hierarchy.test.ts +337 -0
- package/src/test/formatters.test.ts +213 -0
- package/src/test/html-converter.test.ts +399 -0
- package/src/test/info.test.ts +56 -0
- package/src/test/labels.test.ts +70 -0
- package/src/test/link-conversion-integration.test.ts +189 -0
- package/src/test/link-converter.test.ts +413 -0
- package/src/test/link-resolution-pass.test.ts +368 -0
- package/src/test/markdown.test.ts +443 -0
- package/src/test/mocks/handlers.ts +228 -0
- package/src/test/move.test.ts +53 -0
- package/src/test/msw-schema-validation.ts +151 -0
- package/src/test/page-state.test.ts +542 -0
- package/src/test/push.test.ts +551 -0
- package/src/test/reference-updater.test.ts +293 -0
- package/src/test/resolve-page-target.test.ts +55 -0
- package/src/test/search.test.ts +64 -0
- package/src/test/setup-msw.ts +75 -0
- package/src/test/space-config.test.ts +516 -0
- package/src/test/spaces.test.ts +53 -0
- package/src/test/sync-engine.test.ts +486 -0
- package/src/types/turndown-plugin-gfm.d.ts +9 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import { HttpResponse, http } from 'msw';
|
|
3
|
+
import { ConfluenceClient } from '../lib/confluence-client/client.js';
|
|
4
|
+
import { server } from './setup-msw.js';
|
|
5
|
+
|
|
6
|
+
const testConfig = {
|
|
7
|
+
confluenceUrl: 'https://test.atlassian.net',
|
|
8
|
+
email: 'test@example.com',
|
|
9
|
+
apiToken: 'test-token',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
describe('ConfluenceClient - movePage', () => {
|
|
13
|
+
test('moves page successfully', async () => {
|
|
14
|
+
const client = new ConfluenceClient(testConfig);
|
|
15
|
+
await client.movePage('page-123', 'page-456', 'append');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('uses append position by default', async () => {
|
|
19
|
+
let capturedPosition = '';
|
|
20
|
+
server.use(
|
|
21
|
+
http.put('*/wiki/rest/api/content/:pageId/move/:position/:targetId', ({ params }) => {
|
|
22
|
+
capturedPosition = params.position as string;
|
|
23
|
+
return HttpResponse.json({});
|
|
24
|
+
}),
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const client = new ConfluenceClient(testConfig);
|
|
28
|
+
await client.movePage('page-123', 'page-456');
|
|
29
|
+
expect(capturedPosition).toBe('append');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('throws on 404', async () => {
|
|
33
|
+
server.use(
|
|
34
|
+
http.put('*/wiki/rest/api/content/:pageId/move/:position/:targetId', () => {
|
|
35
|
+
return HttpResponse.json({ error: 'Not found' }, { status: 404 });
|
|
36
|
+
}),
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const client = new ConfluenceClient(testConfig);
|
|
40
|
+
await expect(client.movePage('nonexistent', 'page-456')).rejects.toThrow();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('throws on 401', async () => {
|
|
44
|
+
server.use(
|
|
45
|
+
http.put('*/wiki/rest/api/content/:pageId/move/:position/:targetId', () => {
|
|
46
|
+
return HttpResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
47
|
+
}),
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const client = new ConfluenceClient(testConfig);
|
|
51
|
+
await expect(client.movePage('page-123', 'page-456')).rejects.toThrow();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { Schema } from 'effect';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Validate mock data against a schema and return it
|
|
5
|
+
* Throws an error if validation fails, helping catch mock data issues early
|
|
6
|
+
*/
|
|
7
|
+
export function validateAndReturn<A, I>(schema: Schema.Schema<A, I>, data: unknown, description: string): A {
|
|
8
|
+
try {
|
|
9
|
+
return Schema.decodeUnknownSync(schema)(data);
|
|
10
|
+
} catch (error) {
|
|
11
|
+
console.error(`Schema validation failed for ${description}:`, error);
|
|
12
|
+
throw error;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create a valid user object for mocking
|
|
18
|
+
*/
|
|
19
|
+
export function createValidUser(overrides: Partial<{ accountId: string; displayName: string; email: string }> = {}): {
|
|
20
|
+
accountId: string;
|
|
21
|
+
displayName?: string;
|
|
22
|
+
email?: string;
|
|
23
|
+
} {
|
|
24
|
+
return {
|
|
25
|
+
accountId: overrides.accountId || 'test-account-id',
|
|
26
|
+
displayName: overrides.displayName || 'Test User',
|
|
27
|
+
email: overrides.email || 'test@example.com',
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Create a valid space object for mocking
|
|
33
|
+
*/
|
|
34
|
+
export function createValidSpace(
|
|
35
|
+
overrides: Partial<{ id: string; key: string; name: string; homepageId: string }> = {},
|
|
36
|
+
): {
|
|
37
|
+
id: string;
|
|
38
|
+
key: string;
|
|
39
|
+
name: string;
|
|
40
|
+
homepageId?: string;
|
|
41
|
+
} {
|
|
42
|
+
return {
|
|
43
|
+
id: overrides.id || 'space-123',
|
|
44
|
+
key: overrides.key || 'TEST',
|
|
45
|
+
name: overrides.name || 'Test Space',
|
|
46
|
+
homepageId: overrides.homepageId,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Create a valid folder object for mocking
|
|
52
|
+
*/
|
|
53
|
+
export function createValidFolder(
|
|
54
|
+
overrides: Partial<{
|
|
55
|
+
id: string;
|
|
56
|
+
title: string;
|
|
57
|
+
parentId: string | null;
|
|
58
|
+
parentType: string | null;
|
|
59
|
+
}> = {},
|
|
60
|
+
): {
|
|
61
|
+
id: string;
|
|
62
|
+
type: 'folder';
|
|
63
|
+
title: string;
|
|
64
|
+
parentId?: string | null;
|
|
65
|
+
parentType?: string | null;
|
|
66
|
+
authorId?: string;
|
|
67
|
+
ownerId?: string;
|
|
68
|
+
status?: string;
|
|
69
|
+
} {
|
|
70
|
+
return {
|
|
71
|
+
id: overrides.id || 'folder-123',
|
|
72
|
+
type: 'folder',
|
|
73
|
+
title: overrides.title || 'Test Folder',
|
|
74
|
+
parentId: overrides.parentId,
|
|
75
|
+
parentType: overrides.parentType,
|
|
76
|
+
authorId: 'user-123',
|
|
77
|
+
ownerId: 'user-123',
|
|
78
|
+
status: 'current',
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Create a valid attachment object for mocking
|
|
84
|
+
*/
|
|
85
|
+
export function createValidAttachment(
|
|
86
|
+
overrides: Partial<{
|
|
87
|
+
id: string;
|
|
88
|
+
title: string;
|
|
89
|
+
mediaType: string;
|
|
90
|
+
fileSize: number;
|
|
91
|
+
}> = {},
|
|
92
|
+
): {
|
|
93
|
+
id: string;
|
|
94
|
+
title: string;
|
|
95
|
+
status?: string;
|
|
96
|
+
mediaType?: string;
|
|
97
|
+
fileSize?: number;
|
|
98
|
+
} {
|
|
99
|
+
return {
|
|
100
|
+
id: overrides.id || 'att-123',
|
|
101
|
+
title: overrides.title || 'test-file.png',
|
|
102
|
+
status: 'current',
|
|
103
|
+
mediaType: overrides.mediaType || 'image/png',
|
|
104
|
+
fileSize: overrides.fileSize || 1024,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Create a valid page object for mocking
|
|
110
|
+
*/
|
|
111
|
+
export function createValidPage(
|
|
112
|
+
overrides: Partial<{
|
|
113
|
+
id: string;
|
|
114
|
+
title: string;
|
|
115
|
+
spaceId: string;
|
|
116
|
+
parentId: string | null;
|
|
117
|
+
authorId: string;
|
|
118
|
+
version: number;
|
|
119
|
+
body: string;
|
|
120
|
+
}> = {},
|
|
121
|
+
): {
|
|
122
|
+
id: string;
|
|
123
|
+
title: string;
|
|
124
|
+
spaceId: string;
|
|
125
|
+
status: string;
|
|
126
|
+
parentId?: string | null;
|
|
127
|
+
authorId?: string;
|
|
128
|
+
version?: { number: number; createdAt?: string };
|
|
129
|
+
body?: { storage?: { value: string; representation?: string } };
|
|
130
|
+
} {
|
|
131
|
+
return {
|
|
132
|
+
id: overrides.id || 'page-123',
|
|
133
|
+
title: overrides.title || 'Test Page',
|
|
134
|
+
spaceId: overrides.spaceId || 'space-123',
|
|
135
|
+
status: 'current',
|
|
136
|
+
parentId: overrides.parentId,
|
|
137
|
+
authorId: overrides.authorId || 'user-123',
|
|
138
|
+
version: {
|
|
139
|
+
number: overrides.version || 1,
|
|
140
|
+
createdAt: new Date().toISOString(),
|
|
141
|
+
},
|
|
142
|
+
body: overrides.body
|
|
143
|
+
? {
|
|
144
|
+
storage: {
|
|
145
|
+
value: overrides.body,
|
|
146
|
+
representation: 'storage',
|
|
147
|
+
},
|
|
148
|
+
}
|
|
149
|
+
: undefined,
|
|
150
|
+
};
|
|
151
|
+
}
|