atlass 1.3.0 → 1.4.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/README.md +13 -0
- package/dist/cli.mjs +51 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -163,6 +163,19 @@ filters. Prints one issue per line (`KEY status summary`); use `--json` for
|
|
|
163
163
|
machine output. Only the first `--limit` results are shown (default 25, max
|
|
164
164
|
100).
|
|
165
165
|
|
|
166
|
+
### List Jira projects
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
atlass jira projects # every project you can browse
|
|
170
|
+
atlass jira projects pay # filter by key or name
|
|
171
|
+
atlass jira projects --json # machine output
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
A discovery aid for the `--project` filter above: it fetches every project
|
|
175
|
+
(paginated, ordered by key) and prints one per line as an aligned `KEY Name`
|
|
176
|
+
list. An optional query filters by key or name server-side. `--json` emits
|
|
177
|
+
`{ key, name, id, type, url }` per project.
|
|
178
|
+
|
|
166
179
|
### Search Confluence pages
|
|
167
180
|
|
|
168
181
|
```bash
|
package/dist/cli.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import { Entry } from "@napi-rs/keyring";
|
|
|
8
8
|
import { marked } from "marked";
|
|
9
9
|
import { randomUUID } from "node:crypto";
|
|
10
10
|
//#region package.json
|
|
11
|
-
var version = "1.
|
|
11
|
+
var version = "1.4.0";
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region src/api/client.ts
|
|
14
14
|
var AtlassianClient = class {
|
|
@@ -1254,13 +1254,16 @@ const FIELDS = [
|
|
|
1254
1254
|
"updated",
|
|
1255
1255
|
"attachment"
|
|
1256
1256
|
].join(",");
|
|
1257
|
+
function browseUrl(site, key) {
|
|
1258
|
+
return `${site}/browse/${key}`;
|
|
1259
|
+
}
|
|
1257
1260
|
async function fetchIssue(client, site, key) {
|
|
1258
1261
|
const issue = await client.getJson(`/rest/api/3/issue/${encodeURIComponent(key)}?fields=${FIELDS}`);
|
|
1259
1262
|
const comments = await fetchComments(client, key);
|
|
1260
1263
|
const f = issue.fields;
|
|
1261
1264
|
return {
|
|
1262
1265
|
key: issue.key,
|
|
1263
|
-
url:
|
|
1266
|
+
url: browseUrl(site, issue.key),
|
|
1264
1267
|
summary: f.summary ?? "",
|
|
1265
1268
|
type: f.issuetype?.name ?? "",
|
|
1266
1269
|
status: f.status?.name ?? "",
|
|
@@ -1295,7 +1298,7 @@ async function searchIssues(client, site, params) {
|
|
|
1295
1298
|
key: i.key,
|
|
1296
1299
|
status: i.fields?.status?.name ?? "",
|
|
1297
1300
|
summary: decodeEntities(i.fields?.summary ?? ""),
|
|
1298
|
-
url:
|
|
1301
|
+
url: browseUrl(site, i.key)
|
|
1299
1302
|
}));
|
|
1300
1303
|
}
|
|
1301
1304
|
function buildJql(params) {
|
|
@@ -1308,6 +1311,33 @@ function buildJql(params) {
|
|
|
1308
1311
|
if (clauses.length === 0) clauses.push("updated >= -30d");
|
|
1309
1312
|
return `${clauses.join(" AND ")} ORDER BY updated DESC`;
|
|
1310
1313
|
}
|
|
1314
|
+
const PROJECT_PAGE_SIZE = 50;
|
|
1315
|
+
async function listProjects(client, site, query) {
|
|
1316
|
+
const projects = [];
|
|
1317
|
+
for (let startAt = 0;;) {
|
|
1318
|
+
const res = await client.getJson(`/rest/api/3/project/search?${projectSearchQuery(query, startAt)}`);
|
|
1319
|
+
const values = res.values ?? [];
|
|
1320
|
+
for (const p of values) projects.push({
|
|
1321
|
+
key: p.key,
|
|
1322
|
+
name: p.name,
|
|
1323
|
+
id: p.id,
|
|
1324
|
+
type: p.projectTypeKey ?? "",
|
|
1325
|
+
url: browseUrl(site, p.key)
|
|
1326
|
+
});
|
|
1327
|
+
if (res.isLast || values.length === 0) break;
|
|
1328
|
+
startAt += values.length;
|
|
1329
|
+
}
|
|
1330
|
+
return projects;
|
|
1331
|
+
}
|
|
1332
|
+
function projectSearchQuery(query, startAt) {
|
|
1333
|
+
const params = new URLSearchParams({
|
|
1334
|
+
orderBy: "key",
|
|
1335
|
+
maxResults: String(PROJECT_PAGE_SIZE),
|
|
1336
|
+
startAt: String(startAt)
|
|
1337
|
+
});
|
|
1338
|
+
if (query) params.set("query", query);
|
|
1339
|
+
return params.toString();
|
|
1340
|
+
}
|
|
1311
1341
|
function jqlValue(value) {
|
|
1312
1342
|
return `"${value.replace(/(["\\])/g, "\\$1")}"`;
|
|
1313
1343
|
}
|
|
@@ -1320,6 +1350,23 @@ async function fetchComments(client, key) {
|
|
|
1320
1350
|
}
|
|
1321
1351
|
//#endregion
|
|
1322
1352
|
//#region src/commands/jira.ts
|
|
1353
|
+
async function jiraProjects(query, options) {
|
|
1354
|
+
const auth = await requireAuth();
|
|
1355
|
+
const projects = await listProjects(new AtlassianClient(auth), auth.site, query);
|
|
1356
|
+
if (options.json) {
|
|
1357
|
+
console.log(JSON.stringify(projects, null, 2));
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
if (projects.length === 0) {
|
|
1361
|
+
console.log("No matching projects.");
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
for (const line of formatProjectRows(projects)) console.log(line);
|
|
1365
|
+
}
|
|
1366
|
+
function formatProjectRows(projects) {
|
|
1367
|
+
const width = Math.max(...projects.map((p) => p.key.length));
|
|
1368
|
+
return projects.map((p) => `${p.key.padEnd(width)} ${p.name}`);
|
|
1369
|
+
}
|
|
1323
1370
|
async function jiraCopy(arg, options) {
|
|
1324
1371
|
const auth = await requireAuth();
|
|
1325
1372
|
const key = await resolveKey(arg);
|
|
@@ -1470,6 +1517,7 @@ auth.command("login").description("Store site, email, and API token").action(run
|
|
|
1470
1517
|
auth.command("logout").description("Remove stored credentials").action(run(logout));
|
|
1471
1518
|
auth.command("status").description("Show the current login").action(run(status));
|
|
1472
1519
|
const jira = program.command("jira").description("Jira commands");
|
|
1520
|
+
jira.command("projects [query]").description("List projects (optionally filtered by key or name)").option("--json", "output results as JSON").action(run(jiraProjects));
|
|
1473
1521
|
jira.command("copy [issue]").description("Copy a Jira issue (key or URL) to a Markdown file").option("-o, --out <path>", "output file or directory").action(run(jiraCopy));
|
|
1474
1522
|
jira.command("update [file]").description("Update a Jira issue description from an edited Markdown file").option("--summary", "also push the H1 as the issue summary").option("-f, --force", "skip the stale-issue and data-loss checks").option("--dry-run", "show what would change without writing").action(run(jiraUpdate));
|
|
1475
1523
|
jira.command("search [query]").description("Search Jira issues (text query, filters, or --jql)").option("-p, --project <key>", "limit to a project").option("-a, --assignee <who>", "limit to an assignee (or 'me')").option("-s, --status <status>", "limit to a status").option("--jql <jql>", "raw JQL query (ignores other filters)").option("-l, --limit <n>", "max results (default 25, max 100)").option("--json", "output results as JSON").option("-c, --copy", "pick results to copy to Markdown").option("-o, --out <dir>", "output directory for --copy").action(run(jiraSearch));
|