confluence-cli 1.18.0 → 1.19.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.
- package/.github/workflows/ci.yml +3 -2
- package/CHANGELOG.md +7 -0
- package/bin/confluence.js +2 -1
- package/lib/confluence-client.js +3 -2
- package/package.json +1 -1
- package/tests/confluence-client.test.js +62 -0
package/.github/workflows/ci.yml
CHANGED
|
@@ -31,8 +31,9 @@ jobs:
|
|
|
31
31
|
runs-on: ubuntu-latest
|
|
32
32
|
steps:
|
|
33
33
|
- uses: actions/checkout@v3
|
|
34
|
-
-
|
|
35
|
-
|
|
34
|
+
- run: npm ci
|
|
35
|
+
- name: Run npm audit (production only)
|
|
36
|
+
run: npm audit --audit-level moderate --omit=dev
|
|
36
37
|
|
|
37
38
|
publish:
|
|
38
39
|
needs: [test, security]
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [1.19.0](https://github.com/pchuri/confluence-cli/compare/v1.18.0...v1.19.0) (2026-02-20)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* add --cql flag to search command for raw CQL queries ([#40](https://github.com/pchuri/confluence-cli/issues/40)) ([311f5a9](https://github.com/pchuri/confluence-cli/commit/311f5a98bfd175c6b7902c55b4dd0687b2a0d8c0)), closes [#39](https://github.com/pchuri/confluence-cli/issues/39)
|
|
7
|
+
|
|
1
8
|
# [1.18.0](https://github.com/pchuri/confluence-cli/compare/v1.17.0...v1.18.0) (2026-02-15)
|
|
2
9
|
|
|
3
10
|
|
package/bin/confluence.js
CHANGED
|
@@ -75,11 +75,12 @@ program
|
|
|
75
75
|
.command('search <query>')
|
|
76
76
|
.description('Search for Confluence pages')
|
|
77
77
|
.option('-l, --limit <limit>', 'Limit number of results', '10')
|
|
78
|
+
.option('--cql', 'Pass query as raw CQL instead of text search')
|
|
78
79
|
.action(async (query, options) => {
|
|
79
80
|
const analytics = new Analytics();
|
|
80
81
|
try {
|
|
81
82
|
const client = new ConfluenceClient(getConfig());
|
|
82
|
-
const results = await client.search(query, parseInt(options.limit));
|
|
83
|
+
const results = await client.search(query, parseInt(options.limit), options.cql);
|
|
83
84
|
|
|
84
85
|
if (results.length === 0) {
|
|
85
86
|
console.log(chalk.yellow('No results found.'));
|
package/lib/confluence-client.js
CHANGED
|
@@ -221,10 +221,11 @@ class ConfluenceClient {
|
|
|
221
221
|
/**
|
|
222
222
|
* Search for pages
|
|
223
223
|
*/
|
|
224
|
-
async search(query, limit = 10) {
|
|
224
|
+
async search(query, limit = 10, rawCql = false) {
|
|
225
|
+
const cql = rawCql ? query : `text ~ "${String(query).replace(/"/g, '\\"')}"`;
|
|
225
226
|
const response = await this.client.get('/search', {
|
|
226
227
|
params: {
|
|
227
|
-
cql
|
|
228
|
+
cql,
|
|
228
229
|
limit: limit
|
|
229
230
|
}
|
|
230
231
|
});
|
package/package.json
CHANGED
|
@@ -303,6 +303,68 @@ describe('ConfluenceClient', () => {
|
|
|
303
303
|
});
|
|
304
304
|
});
|
|
305
305
|
|
|
306
|
+
describe('search', () => {
|
|
307
|
+
test('should wrap query in text search by default', async () => {
|
|
308
|
+
const mock = new MockAdapter(client.client);
|
|
309
|
+
mock.onGet('/search').reply((config) => {
|
|
310
|
+
expect(config.params.cql).toBe('text ~ "architecture decisions"');
|
|
311
|
+
expect(config.params.limit).toBe(10);
|
|
312
|
+
return [200, { results: [] }];
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
const results = await client.search('architecture decisions');
|
|
316
|
+
expect(results).toEqual([]);
|
|
317
|
+
|
|
318
|
+
mock.restore();
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
test('should pass raw CQL when rawCql is true', async () => {
|
|
322
|
+
const mock = new MockAdapter(client.client);
|
|
323
|
+
const rawQuery = 'contributor = currentUser() order by lastmodified desc';
|
|
324
|
+
mock.onGet('/search').reply((config) => {
|
|
325
|
+
expect(config.params.cql).toBe(rawQuery);
|
|
326
|
+
return [200, {
|
|
327
|
+
results: [{
|
|
328
|
+
content: { id: '123', title: 'Test Page', type: 'page' },
|
|
329
|
+
excerpt: 'test excerpt'
|
|
330
|
+
}]
|
|
331
|
+
}];
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
const results = await client.search(rawQuery, 10, true);
|
|
335
|
+
expect(results).toHaveLength(1);
|
|
336
|
+
expect(results[0].id).toBe('123');
|
|
337
|
+
expect(results[0].title).toBe('Test Page');
|
|
338
|
+
|
|
339
|
+
mock.restore();
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
test('should escape double quotes in text search query', async () => {
|
|
343
|
+
const mock = new MockAdapter(client.client);
|
|
344
|
+
mock.onGet('/search').reply((config) => {
|
|
345
|
+
expect(config.params.cql).toBe('text ~ "test \\"quoted\\" term"');
|
|
346
|
+
return [200, { results: [] }];
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
const results = await client.search('test "quoted" term');
|
|
350
|
+
expect(results).toEqual([]);
|
|
351
|
+
|
|
352
|
+
mock.restore();
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
test('should respect limit parameter', async () => {
|
|
356
|
+
const mock = new MockAdapter(client.client);
|
|
357
|
+
mock.onGet('/search').reply((config) => {
|
|
358
|
+
expect(config.params.limit).toBe(5);
|
|
359
|
+
return [200, { results: [] }];
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
await client.search('test', 5);
|
|
363
|
+
|
|
364
|
+
mock.restore();
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
306
368
|
describe('page creation and updates', () => {
|
|
307
369
|
test('should have required methods for page management', () => {
|
|
308
370
|
expect(typeof client.createPage).toBe('function');
|