@geneverse/workctl 0.2.5
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 +340 -0
- package/dist/packages/capabilities/assistant/src/commands.d.ts +10 -0
- package/dist/packages/capabilities/assistant/src/commands.js +33 -0
- package/dist/packages/capabilities/assistant/src/commands.js.map +1 -0
- package/dist/packages/capabilities/assistant/src/index.d.ts +2 -0
- package/dist/packages/capabilities/assistant/src/index.js +3 -0
- package/dist/packages/capabilities/assistant/src/index.js.map +1 -0
- package/dist/packages/capabilities/assistant/src/status.d.ts +18 -0
- package/dist/packages/capabilities/assistant/src/status.js +48 -0
- package/dist/packages/capabilities/assistant/src/status.js.map +1 -0
- package/dist/packages/capabilities/jenkins/src/commands.d.ts +9 -0
- package/dist/packages/capabilities/jenkins/src/commands.js +43 -0
- package/dist/packages/capabilities/jenkins/src/commands.js.map +1 -0
- package/dist/packages/capabilities/jenkins/src/definition.d.ts +10 -0
- package/dist/packages/capabilities/jenkins/src/definition.js +59 -0
- package/dist/packages/capabilities/jenkins/src/definition.js.map +1 -0
- package/dist/packages/capabilities/jenkins/src/index.d.ts +2 -0
- package/dist/packages/capabilities/jenkins/src/index.js +3 -0
- package/dist/packages/capabilities/jenkins/src/index.js.map +1 -0
- package/dist/packages/capabilities/jira/src/adapters/filesystem/config.store.d.ts +2 -0
- package/dist/packages/capabilities/jira/src/adapters/filesystem/config.store.js +43 -0
- package/dist/packages/capabilities/jira/src/adapters/filesystem/config.store.js.map +1 -0
- package/dist/packages/capabilities/jira/src/adapters/filesystem/local.paths.d.ts +16 -0
- package/dist/packages/capabilities/jira/src/adapters/filesystem/local.paths.js +46 -0
- package/dist/packages/capabilities/jira/src/adapters/filesystem/local.paths.js.map +1 -0
- package/dist/packages/capabilities/jira/src/adapters/filesystem/sync-lock.d.ts +2 -0
- package/dist/packages/capabilities/jira/src/adapters/filesystem/sync-lock.js +120 -0
- package/dist/packages/capabilities/jira/src/adapters/filesystem/sync-lock.js.map +1 -0
- package/dist/packages/capabilities/jira/src/adapters/jira/jira.client.d.ts +31 -0
- package/dist/packages/capabilities/jira/src/adapters/jira/jira.client.js +344 -0
- package/dist/packages/capabilities/jira/src/adapters/jira/jira.client.js.map +1 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/catalog.d.ts +9 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/catalog.js +17 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/catalog.js.map +1 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/orchestrator.d.ts +14 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/orchestrator.js +116 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/orchestrator.js.map +1 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/scraper.d.ts +32 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/scraper.js +2 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/scraper.js.map +1 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/detect.d.ts +2 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/detect.js +45 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/detect.js.map +1 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/extract.d.ts +3 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/extract.js +115 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/extract.js.map +1 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/index.d.ts +2 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/index.js +27 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/index.js.map +1 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/navigation.d.ts +3 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/navigation.js +104 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/navigation.js.map +1 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/ready.d.ts +2 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/ready.js +47 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/ready.js.map +1 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/shared.d.ts +4 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/shared.js +5 -0
- package/dist/packages/capabilities/jira/src/adapters/kawari/v1/shared.js.map +1 -0
- package/dist/packages/capabilities/jira/src/adapters/terminal/node-cli.io.d.ts +2 -0
- package/dist/packages/capabilities/jira/src/adapters/terminal/node-cli.io.js +40 -0
- package/dist/packages/capabilities/jira/src/adapters/terminal/node-cli.io.js.map +1 -0
- package/dist/packages/capabilities/jira/src/batch-interaction.d.ts +53 -0
- package/dist/packages/capabilities/jira/src/batch-interaction.js +201 -0
- package/dist/packages/capabilities/jira/src/batch-interaction.js.map +1 -0
- package/dist/packages/capabilities/jira/src/capability.d.ts +16 -0
- package/dist/packages/capabilities/jira/src/capability.js +56 -0
- package/dist/packages/capabilities/jira/src/capability.js.map +1 -0
- package/dist/packages/capabilities/jira/src/cli/contracts.d.ts +42 -0
- package/dist/packages/capabilities/jira/src/cli/contracts.js +2 -0
- package/dist/packages/capabilities/jira/src/cli/contracts.js.map +1 -0
- package/dist/packages/capabilities/jira/src/cli/errors.d.ts +3 -0
- package/dist/packages/capabilities/jira/src/cli/errors.js +7 -0
- package/dist/packages/capabilities/jira/src/cli/errors.js.map +1 -0
- package/dist/packages/capabilities/jira/src/cli/program.d.ts +6 -0
- package/dist/packages/capabilities/jira/src/cli/program.js +48 -0
- package/dist/packages/capabilities/jira/src/cli/program.js.map +1 -0
- package/dist/packages/capabilities/jira/src/cli/run-cli.d.ts +2 -0
- package/dist/packages/capabilities/jira/src/cli/run-cli.js +72 -0
- package/dist/packages/capabilities/jira/src/cli/run-cli.js.map +1 -0
- package/dist/packages/capabilities/jira/src/commands/audit-links/audit-links.command.d.ts +2 -0
- package/dist/packages/capabilities/jira/src/commands/audit-links/audit-links.command.js +165 -0
- package/dist/packages/capabilities/jira/src/commands/audit-links/audit-links.command.js.map +1 -0
- package/dist/packages/capabilities/jira/src/commands/audit-links/audit-links.service.d.ts +30 -0
- package/dist/packages/capabilities/jira/src/commands/audit-links/audit-links.service.js +174 -0
- package/dist/packages/capabilities/jira/src/commands/audit-links/audit-links.service.js.map +1 -0
- package/dist/packages/capabilities/jira/src/commands/command-context.d.ts +10 -0
- package/dist/packages/capabilities/jira/src/commands/command-context.js +2 -0
- package/dist/packages/capabilities/jira/src/commands/command-context.js.map +1 -0
- package/dist/packages/capabilities/jira/src/commands/config-show/config-show.command.d.ts +2 -0
- package/dist/packages/capabilities/jira/src/commands/config-show/config-show.command.js +26 -0
- package/dist/packages/capabilities/jira/src/commands/config-show/config-show.command.js.map +1 -0
- package/dist/packages/capabilities/jira/src/commands/configure/configure.command.d.ts +2 -0
- package/dist/packages/capabilities/jira/src/commands/configure/configure.command.js +26 -0
- package/dist/packages/capabilities/jira/src/commands/configure/configure.command.js.map +1 -0
- package/dist/packages/capabilities/jira/src/commands/configure/configure.service.d.ts +42 -0
- package/dist/packages/capabilities/jira/src/commands/configure/configure.service.js +205 -0
- package/dist/packages/capabilities/jira/src/commands/configure/configure.service.js.map +1 -0
- package/dist/packages/capabilities/jira/src/commands/doctor/doctor.command.d.ts +2 -0
- package/dist/packages/capabilities/jira/src/commands/doctor/doctor.command.js +17 -0
- package/dist/packages/capabilities/jira/src/commands/doctor/doctor.command.js.map +1 -0
- package/dist/packages/capabilities/jira/src/commands/doctor/doctor.service.d.ts +18 -0
- package/dist/packages/capabilities/jira/src/commands/doctor/doctor.service.js +84 -0
- package/dist/packages/capabilities/jira/src/commands/doctor/doctor.service.js.map +1 -0
- package/dist/packages/capabilities/jira/src/commands/rollback/rollback.command.d.ts +2 -0
- package/dist/packages/capabilities/jira/src/commands/rollback/rollback.command.js +198 -0
- package/dist/packages/capabilities/jira/src/commands/rollback/rollback.command.js.map +1 -0
- package/dist/packages/capabilities/jira/src/commands/rollback/rollback.service.d.ts +37 -0
- package/dist/packages/capabilities/jira/src/commands/rollback/rollback.service.js +112 -0
- package/dist/packages/capabilities/jira/src/commands/rollback/rollback.service.js.map +1 -0
- package/dist/packages/capabilities/jira/src/commands/sync/audit-export.service.d.ts +18 -0
- package/dist/packages/capabilities/jira/src/commands/sync/audit-export.service.js +96 -0
- package/dist/packages/capabilities/jira/src/commands/sync/audit-export.service.js.map +1 -0
- package/dist/packages/capabilities/jira/src/commands/sync/preview.service.d.ts +23 -0
- package/dist/packages/capabilities/jira/src/commands/sync/preview.service.js +201 -0
- package/dist/packages/capabilities/jira/src/commands/sync/preview.service.js.map +1 -0
- package/dist/packages/capabilities/jira/src/commands/sync/sync.command.d.ts +2 -0
- package/dist/packages/capabilities/jira/src/commands/sync/sync.command.js +537 -0
- package/dist/packages/capabilities/jira/src/commands/sync/sync.command.js.map +1 -0
- package/dist/packages/capabilities/jira/src/commands/sync/verification.service.d.ts +34 -0
- package/dist/packages/capabilities/jira/src/commands/sync/verification.service.js +164 -0
- package/dist/packages/capabilities/jira/src/commands/sync/verification.service.js.map +1 -0
- package/dist/packages/capabilities/jira/src/config.d.ts +37 -0
- package/dist/packages/capabilities/jira/src/config.js +217 -0
- package/dist/packages/capabilities/jira/src/config.js.map +1 -0
- package/dist/packages/capabilities/jira/src/dependencies.d.ts +2 -0
- package/dist/packages/capabilities/jira/src/dependencies.js +92 -0
- package/dist/packages/capabilities/jira/src/dependencies.js.map +1 -0
- package/dist/packages/capabilities/jira/src/domain/date-range.d.ts +10 -0
- package/dist/packages/capabilities/jira/src/domain/date-range.js +63 -0
- package/dist/packages/capabilities/jira/src/domain/date-range.js.map +1 -0
- package/dist/packages/capabilities/jira/src/domain/marker.d.ts +20 -0
- package/dist/packages/capabilities/jira/src/domain/marker.js +100 -0
- package/dist/packages/capabilities/jira/src/domain/marker.js.map +1 -0
- package/dist/packages/capabilities/jira/src/domain/timesheet-entry.d.ts +45 -0
- package/dist/packages/capabilities/jira/src/domain/timesheet-entry.js +117 -0
- package/dist/packages/capabilities/jira/src/domain/timesheet-entry.js.map +1 -0
- package/dist/packages/capabilities/jira/src/index.d.ts +5 -0
- package/dist/packages/capabilities/jira/src/index.js +4 -0
- package/dist/packages/capabilities/jira/src/index.js.map +1 -0
- package/dist/packages/capabilities/jira/src/ports/jira.d.ts +49 -0
- package/dist/packages/capabilities/jira/src/ports/jira.js +11 -0
- package/dist/packages/capabilities/jira/src/ports/jira.js.map +1 -0
- package/dist/packages/capabilities/jira/src/ports/sync-lock.d.ts +6 -0
- package/dist/packages/capabilities/jira/src/ports/sync-lock.js +7 -0
- package/dist/packages/capabilities/jira/src/ports/sync-lock.js.map +1 -0
- package/dist/packages/capabilities/jira/src/ports/timesheet.d.ts +11 -0
- package/dist/packages/capabilities/jira/src/ports/timesheet.js +7 -0
- package/dist/packages/capabilities/jira/src/ports/timesheet.js.map +1 -0
- package/dist/packages/capabilities/jira/src/presentation.d.ts +37 -0
- package/dist/packages/capabilities/jira/src/presentation.js +111 -0
- package/dist/packages/capabilities/jira/src/presentation.js.map +1 -0
- package/dist/packages/cli/src/bin.d.ts +2 -0
- package/dist/packages/cli/src/bin.js +4 -0
- package/dist/packages/cli/src/bin.js.map +1 -0
- package/dist/packages/cli/src/commands/browsers/browsers.command.d.ts +7 -0
- package/dist/packages/cli/src/commands/browsers/browsers.command.js +22 -0
- package/dist/packages/cli/src/commands/browsers/browsers.command.js.map +1 -0
- package/dist/packages/cli/src/commands/browsers/browsers.service.d.ts +16 -0
- package/dist/packages/cli/src/commands/browsers/browsers.service.js +37 -0
- package/dist/packages/cli/src/commands/browsers/browsers.service.js.map +1 -0
- package/dist/packages/cli/src/commands/setup/setup.command.d.ts +4 -0
- package/dist/packages/cli/src/commands/setup/setup.command.js +41 -0
- package/dist/packages/cli/src/commands/setup/setup.command.js.map +1 -0
- package/dist/packages/cli/src/commands/setup/setup.service.d.ts +23 -0
- package/dist/packages/cli/src/commands/setup/setup.service.js +32 -0
- package/dist/packages/cli/src/commands/setup/setup.service.js.map +1 -0
- package/dist/packages/cli/src/commands/update/update.command.d.ts +7 -0
- package/dist/packages/cli/src/commands/update/update.command.js +34 -0
- package/dist/packages/cli/src/commands/update/update.command.js.map +1 -0
- package/dist/packages/cli/src/commands/update/update.service.d.ts +35 -0
- package/dist/packages/cli/src/commands/update/update.service.js +134 -0
- package/dist/packages/cli/src/commands/update/update.service.js.map +1 -0
- package/dist/packages/cli/src/index.d.ts +1 -0
- package/dist/packages/cli/src/index.js +2 -0
- package/dist/packages/cli/src/index.js.map +1 -0
- package/dist/packages/cli/src/program.d.ts +21 -0
- package/dist/packages/cli/src/program.js +74 -0
- package/dist/packages/cli/src/program.js.map +1 -0
- package/dist/packages/cli/src/release-version.d.ts +1 -0
- package/dist/packages/cli/src/release-version.js +2 -0
- package/package.json +57 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { chmod, mkdir, open, readFile, rename, rm } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
export async function writeConfigAtomic(configPath, config) {
|
|
4
|
+
const directory = path.dirname(configPath);
|
|
5
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
6
|
+
if (process.platform !== "win32")
|
|
7
|
+
await chmod(directory, 0o700);
|
|
8
|
+
const temporary = path.join(directory, `.config.json.${process.pid}.${Date.now()}.tmp`);
|
|
9
|
+
let capabilities = {};
|
|
10
|
+
try {
|
|
11
|
+
const existing = JSON.parse(await readFile(configPath, "utf8"));
|
|
12
|
+
if (existing.version === 1 &&
|
|
13
|
+
typeof existing.capabilities === "object" &&
|
|
14
|
+
existing.capabilities !== null &&
|
|
15
|
+
!Array.isArray(existing.capabilities)) {
|
|
16
|
+
capabilities = existing.capabilities;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// A missing or malformed file is replaced after setup confirmation.
|
|
21
|
+
}
|
|
22
|
+
delete capabilities.jlog;
|
|
23
|
+
const serialized = `${JSON.stringify({
|
|
24
|
+
version: 1,
|
|
25
|
+
capabilities: { ...capabilities, jira: config },
|
|
26
|
+
}, null, 2)}\n`;
|
|
27
|
+
let handle;
|
|
28
|
+
try {
|
|
29
|
+
handle = await open(temporary, "wx", 0o600);
|
|
30
|
+
await handle.writeFile(serialized, "utf8");
|
|
31
|
+
await handle.sync();
|
|
32
|
+
await handle.close();
|
|
33
|
+
handle = undefined;
|
|
34
|
+
await rename(temporary, configPath);
|
|
35
|
+
if (process.platform !== "win32")
|
|
36
|
+
await chmod(configPath, 0o600);
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
await handle?.close().catch(() => undefined);
|
|
40
|
+
await rm(temporary, { force: true }).catch(() => undefined);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=config.store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.store.js","sourceRoot":"","sources":["../../../../../../../packages/capabilities/jira/src/adapters/filesystem/config.store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,UAAkB,EAAE,MAAiB;IAC3E,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACzD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,MAAM,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAEhE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CACzB,SAAS,EACT,gBAAgB,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,MAAM,CAChD,CAAC;IACF,IAAI,YAAY,GAA4B,EAAE,CAAC;IAC/C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAG7D,CAAC;QACF,IACE,QAAQ,CAAC,OAAO,KAAK,CAAC;YACtB,OAAO,QAAQ,CAAC,YAAY,KAAK,QAAQ;YACzC,QAAQ,CAAC,YAAY,KAAK,IAAI;YAC9B,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EACrC,CAAC;YACD,YAAY,GAAG,QAAQ,CAAC,YAAuC,CAAC;QAClE,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,oEAAoE;IACtE,CAAC;IAED,OAAO,YAAY,CAAC,IAAI,CAAC;IACzB,MAAM,UAAU,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC;QACnC,OAAO,EAAE,CAAC;QACV,YAAY,EAAE,EAAE,GAAG,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE;KAChD,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;IAChB,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QAC5C,MAAM,MAAM,CAAC,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC3C,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,MAAM,GAAG,SAAS,CAAC;QACnB,MAAM,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QACpC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;YAAE,MAAM,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACnE,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC7C,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface LocalPaths {
|
|
2
|
+
root: string;
|
|
3
|
+
configRoot: string;
|
|
4
|
+
configFile: string;
|
|
5
|
+
browserProfile: string;
|
|
6
|
+
snapshots: string;
|
|
7
|
+
auditExports: string;
|
|
8
|
+
syncState: string;
|
|
9
|
+
syncLock: string;
|
|
10
|
+
}
|
|
11
|
+
export interface LocalPathOptions {
|
|
12
|
+
platform?: NodeJS.Platform;
|
|
13
|
+
env?: NodeJS.ProcessEnv;
|
|
14
|
+
}
|
|
15
|
+
export declare function localPaths(home?: string, options?: LocalPathOptions): LocalPaths;
|
|
16
|
+
export declare function migrateLegacyLocalData(home?: string): Promise<void>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { rename } from "node:fs/promises";
|
|
4
|
+
function windowsRoot(home, env, variable, fallback) {
|
|
5
|
+
const value = env[variable];
|
|
6
|
+
return value && value.trim() !== ""
|
|
7
|
+
? path.win32.join(value, "workctl")
|
|
8
|
+
: path.win32.join(home, ...fallback, "workctl");
|
|
9
|
+
}
|
|
10
|
+
export function localPaths(home = os.homedir(), options = {}) {
|
|
11
|
+
const platform = options.platform ?? process.platform;
|
|
12
|
+
const env = options.env ?? process.env;
|
|
13
|
+
const pathApi = platform === "win32" ? path.win32 : path;
|
|
14
|
+
const configRoot = platform === "win32"
|
|
15
|
+
? windowsRoot(home, env, "APPDATA", ["AppData", "Roaming"])
|
|
16
|
+
: pathApi.join(home, ".config", "workctl");
|
|
17
|
+
const dataRoot = platform === "win32"
|
|
18
|
+
? windowsRoot(home, env, "LOCALAPPDATA", ["AppData", "Local"])
|
|
19
|
+
: pathApi.join(home, ".local", "share", "workctl");
|
|
20
|
+
const root = pathApi.join(dataRoot, "jira");
|
|
21
|
+
return {
|
|
22
|
+
root,
|
|
23
|
+
configRoot,
|
|
24
|
+
configFile: pathApi.join(configRoot, "config.json"),
|
|
25
|
+
browserProfile: pathApi.join(root, "browser-profile"),
|
|
26
|
+
snapshots: pathApi.join(root, "snapshots"),
|
|
27
|
+
auditExports: pathApi.join(root, "audit-exports"),
|
|
28
|
+
syncState: pathApi.join(root, "state"),
|
|
29
|
+
syncLock: pathApi.join(root, "sync.lock"),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export async function migrateLegacyLocalData(home = os.homedir()) {
|
|
33
|
+
const dataRoot = path.join(home, ".local", "share", "workctl");
|
|
34
|
+
const legacyRoot = path.join(dataRoot, "jlog");
|
|
35
|
+
const jiraRoot = path.join(dataRoot, "jira");
|
|
36
|
+
try {
|
|
37
|
+
await rename(legacyRoot, jiraRoot);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
const code = error.code;
|
|
41
|
+
if (code === "ENOENT" || code === "EEXIST" || code === "ENOTEMPTY")
|
|
42
|
+
return;
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=local.paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.paths.js","sourceRoot":"","sources":["../../../../../../../packages/capabilities/jira/src/adapters/filesystem/local.paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { mkdir, readFile, rename, rm, stat, writeFile, } from "node:fs/promises";
|
|
5
|
+
import { SyncLockError, } from "../../ports/sync-lock.js";
|
|
6
|
+
const OWNER_FILE = "owner.json";
|
|
7
|
+
const INITIALIZATION_GRACE_MS = 30_000;
|
|
8
|
+
function isNodeError(error, code) {
|
|
9
|
+
return error.code === code;
|
|
10
|
+
}
|
|
11
|
+
function parseOwner(value) {
|
|
12
|
+
try {
|
|
13
|
+
const owner = JSON.parse(value);
|
|
14
|
+
if (owner.version !== 1 ||
|
|
15
|
+
!Number.isSafeInteger(owner.pid) ||
|
|
16
|
+
owner.pid <= 0 ||
|
|
17
|
+
typeof owner.createdAt !== "string" ||
|
|
18
|
+
Number.isNaN(Date.parse(owner.createdAt)) ||
|
|
19
|
+
typeof owner.token !== "string" ||
|
|
20
|
+
owner.token.length === 0) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
return owner;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function ownerIsAlive(pid) {
|
|
30
|
+
try {
|
|
31
|
+
process.kill(pid, 0);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (isNodeError(error, "ESRCH"))
|
|
36
|
+
return false;
|
|
37
|
+
if (isNodeError(error, "EPERM"))
|
|
38
|
+
return true;
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function readOwner(lockPath) {
|
|
43
|
+
try {
|
|
44
|
+
return parseOwner(await readFile(path.join(lockPath, OWNER_FILE), "utf8"));
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (isNodeError(error, "ENOENT"))
|
|
48
|
+
return undefined;
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async function incompleteLockIsInitializing(lockPath) {
|
|
53
|
+
try {
|
|
54
|
+
const lockStat = await stat(lockPath);
|
|
55
|
+
return Date.now() - lockStat.mtimeMs < INITIALIZATION_GRACE_MS;
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (isNodeError(error, "ENOENT"))
|
|
59
|
+
return false;
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function reclaim(lockPath, token) {
|
|
64
|
+
const quarantinePath = `${lockPath}.stale-${token}`;
|
|
65
|
+
try {
|
|
66
|
+
await rename(lockPath, quarantinePath);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (isNodeError(error, "ENOENT"))
|
|
70
|
+
return false;
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
await rm(quarantinePath, { recursive: true, force: true });
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
export async function acquireSyncLock(lockPath) {
|
|
77
|
+
const token = randomUUID();
|
|
78
|
+
const owner = {
|
|
79
|
+
version: 1,
|
|
80
|
+
pid: process.pid,
|
|
81
|
+
createdAt: new Date().toISOString(),
|
|
82
|
+
token,
|
|
83
|
+
};
|
|
84
|
+
await mkdir(path.dirname(lockPath), { recursive: true, mode: 0o700 });
|
|
85
|
+
for (;;) {
|
|
86
|
+
try {
|
|
87
|
+
await mkdir(lockPath, { recursive: false, mode: 0o700 });
|
|
88
|
+
try {
|
|
89
|
+
await writeFile(path.join(lockPath, OWNER_FILE), `${JSON.stringify(owner)}\n`, { encoding: "utf8", flag: "wx", mode: 0o600 });
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
await rm(lockPath, { recursive: true, force: true });
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
async release() {
|
|
97
|
+
const currentOwner = await readOwner(lockPath);
|
|
98
|
+
if (currentOwner?.token !== token)
|
|
99
|
+
return;
|
|
100
|
+
await rm(lockPath, { recursive: true, force: true });
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
if (!isNodeError(error, "EEXIST"))
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
const currentOwner = await readOwner(lockPath);
|
|
109
|
+
if (currentOwner) {
|
|
110
|
+
if (ownerIsAlive(currentOwner.pid)) {
|
|
111
|
+
throw new SyncLockError("Another Jira sync is already running. Wait for it to finish, then try again.");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else if (await incompleteLockIsInitializing(lockPath)) {
|
|
115
|
+
throw new SyncLockError("Another Jira sync is starting. Wait for it to finish, then try again.");
|
|
116
|
+
}
|
|
117
|
+
await reclaim(lockPath, token);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=sync-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-lock.js","sourceRoot":"","sources":["../../../../../../../packages/capabilities/jira/src/adapters/filesystem/sync-lock.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { AppConfig } from "../../config.js";
|
|
2
|
+
import type { TimesheetEntry } from "../../domain/timesheet-entry.js";
|
|
3
|
+
import { type CreatedJiraWorklog, type JiraAccount, type JiraIssueSnapshot, type JiraLinkIssueSnapshot, type JiraProject, type JiraProjectStatus } from "../../ports/jira.js";
|
|
4
|
+
type Fetch = typeof fetch;
|
|
5
|
+
export interface JiraClientOptions {
|
|
6
|
+
getTimeoutMs?: number;
|
|
7
|
+
getRetries?: number;
|
|
8
|
+
onGetRetry?: (issueKey: string, attempt: number, totalAttempts: number, reason: "timeout" | "network") => void;
|
|
9
|
+
}
|
|
10
|
+
export declare class JiraClient {
|
|
11
|
+
private readonly baseUrl;
|
|
12
|
+
private readonly fetchImpl;
|
|
13
|
+
private readonly authorization;
|
|
14
|
+
private readonly getTimeoutMs;
|
|
15
|
+
private readonly getRetries;
|
|
16
|
+
private readonly onGetRetry;
|
|
17
|
+
constructor(baseUrl: string, email: string, apiToken: string, fetchImpl?: Fetch, options?: JiraClientOptions);
|
|
18
|
+
static fromConfig(config: AppConfig, fetchImpl?: Fetch): JiraClient;
|
|
19
|
+
private get;
|
|
20
|
+
private post;
|
|
21
|
+
private delete;
|
|
22
|
+
readIssue(issueKey: string): Promise<JiraIssueSnapshot>;
|
|
23
|
+
readLinkIssue(issueKey: string): Promise<JiraLinkIssueSnapshot>;
|
|
24
|
+
listProjects(): Promise<JiraProject[]>;
|
|
25
|
+
listProjectStatuses(projectKey: string): Promise<JiraProjectStatus[]>;
|
|
26
|
+
authenticate(): Promise<void>;
|
|
27
|
+
readCurrentAccount(): Promise<JiraAccount>;
|
|
28
|
+
createWorklog(entry: TimesheetEntry): Promise<CreatedJiraWorklog>;
|
|
29
|
+
deleteWorklog(issueKey: string, worklogId: string): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { encodeMarker } from "../../domain/marker.js";
|
|
2
|
+
import { JiraClientError, } from "../../ports/jira.js";
|
|
3
|
+
function isRecord(value) {
|
|
4
|
+
return typeof value === "object" && value !== null;
|
|
5
|
+
}
|
|
6
|
+
function parseIssue(value, expectedKey) {
|
|
7
|
+
if (!isRecord(value) ||
|
|
8
|
+
typeof value.key !== "string" ||
|
|
9
|
+
!isRecord(value.fields) ||
|
|
10
|
+
typeof value.fields.summary !== "string") {
|
|
11
|
+
throw new JiraClientError(`Jira returned an invalid issue response for ${expectedKey}.`);
|
|
12
|
+
}
|
|
13
|
+
const assignee = value.fields.assignee;
|
|
14
|
+
if (assignee === null) {
|
|
15
|
+
return { key: value.key, summary: value.fields.summary, assigneeStatus: "unassigned" };
|
|
16
|
+
}
|
|
17
|
+
if (isRecord(assignee) &&
|
|
18
|
+
typeof assignee.accountId === "string" &&
|
|
19
|
+
assignee.accountId.length > 0) {
|
|
20
|
+
return {
|
|
21
|
+
key: value.key,
|
|
22
|
+
summary: value.fields.summary,
|
|
23
|
+
assigneeAccountId: assignee.accountId,
|
|
24
|
+
...(typeof assignee.displayName === "string" && assignee.displayName.length > 0
|
|
25
|
+
? { assigneeDisplayName: assignee.displayName }
|
|
26
|
+
: {}),
|
|
27
|
+
assigneeStatus: "assigned",
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return { key: value.key, summary: value.fields.summary, assigneeStatus: "unverifiable" };
|
|
31
|
+
}
|
|
32
|
+
function parseWorklogPage(value, issueKey) {
|
|
33
|
+
if (!isRecord(value) ||
|
|
34
|
+
!Number.isInteger(value.startAt) ||
|
|
35
|
+
!Number.isInteger(value.maxResults) ||
|
|
36
|
+
!Number.isInteger(value.total) ||
|
|
37
|
+
!Array.isArray(value.worklogs)) {
|
|
38
|
+
throw new JiraClientError(`Jira returned an invalid worklog response for ${issueKey}.`);
|
|
39
|
+
}
|
|
40
|
+
const worklogs = value.worklogs.map((worklog) => {
|
|
41
|
+
if (!isRecord(worklog) ||
|
|
42
|
+
typeof worklog.id !== "string" ||
|
|
43
|
+
typeof worklog.timeSpentSeconds !== "number" ||
|
|
44
|
+
!Number.isFinite(worklog.timeSpentSeconds) ||
|
|
45
|
+
typeof worklog.started !== "string") {
|
|
46
|
+
throw new JiraClientError(`Jira returned an invalid worklog response for ${issueKey}.`);
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
id: worklog.id,
|
|
50
|
+
timeSpentSeconds: worklog.timeSpentSeconds,
|
|
51
|
+
started: worklog.started,
|
|
52
|
+
...("comment" in worklog ? { comment: worklog.comment } : {}),
|
|
53
|
+
...(isRecord(worklog.author) && typeof worklog.author.accountId === "string"
|
|
54
|
+
? { authorAccountId: worklog.author.accountId }
|
|
55
|
+
: {}),
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
return {
|
|
59
|
+
startAt: value.startAt,
|
|
60
|
+
maxResults: value.maxResults,
|
|
61
|
+
total: value.total,
|
|
62
|
+
worklogs,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function parseCreatedWorklog(value, issueKey) {
|
|
66
|
+
if (!isRecord(value) || typeof value.id !== "string" || value.id.length === 0) {
|
|
67
|
+
throw new JiraClientError(`Jira returned an invalid created worklog response for ${issueKey}.`);
|
|
68
|
+
}
|
|
69
|
+
return { id: value.id };
|
|
70
|
+
}
|
|
71
|
+
function parseLinkedIssue(value, issueKey) {
|
|
72
|
+
if (!isRecord(value) ||
|
|
73
|
+
typeof value.key !== "string" ||
|
|
74
|
+
!isRecord(value.fields) ||
|
|
75
|
+
typeof value.fields.summary !== "string" ||
|
|
76
|
+
!isRecord(value.fields.status) ||
|
|
77
|
+
typeof value.fields.status.name !== "string") {
|
|
78
|
+
throw new JiraClientError(`Jira returned an invalid issue-link response for ${issueKey}.`);
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
key: value.key,
|
|
82
|
+
summary: value.fields.summary,
|
|
83
|
+
status: value.fields.status.name,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function parseLinkIssue(value, expectedKey) {
|
|
87
|
+
const issue = parseLinkedIssue(value, expectedKey);
|
|
88
|
+
if (!isRecord(value) || !isRecord(value.fields) || !Array.isArray(value.fields.issuelinks)) {
|
|
89
|
+
throw new JiraClientError(`Jira returned an invalid issue-link response for ${expectedKey}.`);
|
|
90
|
+
}
|
|
91
|
+
const links = value.fields.issuelinks.map((link) => {
|
|
92
|
+
if (!isRecord(link) ||
|
|
93
|
+
typeof link.id !== "string" ||
|
|
94
|
+
!isRecord(link.type) ||
|
|
95
|
+
typeof link.type.name !== "string" ||
|
|
96
|
+
typeof link.type.inward !== "string" ||
|
|
97
|
+
typeof link.type.outward !== "string") {
|
|
98
|
+
throw new JiraClientError(`Jira returned an invalid issue-link response for ${expectedKey}.`);
|
|
99
|
+
}
|
|
100
|
+
if ("outwardIssue" in link) {
|
|
101
|
+
return {
|
|
102
|
+
id: link.id,
|
|
103
|
+
type: link.type.name,
|
|
104
|
+
relationship: link.type.outward,
|
|
105
|
+
direction: "outward",
|
|
106
|
+
issue: parseLinkedIssue(link.outwardIssue, expectedKey),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if ("inwardIssue" in link) {
|
|
110
|
+
return {
|
|
111
|
+
id: link.id,
|
|
112
|
+
type: link.type.name,
|
|
113
|
+
relationship: link.type.inward,
|
|
114
|
+
direction: "inward",
|
|
115
|
+
issue: parseLinkedIssue(link.inwardIssue, expectedKey),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
throw new JiraClientError(`Jira returned an invalid issue-link response for ${expectedKey}.`);
|
|
119
|
+
});
|
|
120
|
+
return { ...issue, links };
|
|
121
|
+
}
|
|
122
|
+
function parseProjects(value) {
|
|
123
|
+
if (!isRecord(value) || !Array.isArray(value.values)) {
|
|
124
|
+
throw new JiraClientError("Jira returned an invalid project-search response.");
|
|
125
|
+
}
|
|
126
|
+
return value.values.map((project) => {
|
|
127
|
+
if (!isRecord(project) || typeof project.key !== "string" || typeof project.name !== "string") {
|
|
128
|
+
throw new JiraClientError("Jira returned an invalid project-search response.");
|
|
129
|
+
}
|
|
130
|
+
return { key: project.key.toUpperCase(), name: project.name };
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function parseProjectStatuses(value, projectKey) {
|
|
134
|
+
if (!Array.isArray(value)) {
|
|
135
|
+
throw new JiraClientError(`Jira returned an invalid status response for ${projectKey}.`);
|
|
136
|
+
}
|
|
137
|
+
const statuses = new Map();
|
|
138
|
+
for (const issueType of value) {
|
|
139
|
+
if (!isRecord(issueType) || !Array.isArray(issueType.statuses)) {
|
|
140
|
+
throw new JiraClientError(`Jira returned an invalid status response for ${projectKey}.`);
|
|
141
|
+
}
|
|
142
|
+
for (const status of issueType.statuses) {
|
|
143
|
+
if (!isRecord(status) || typeof status.id !== "string" || typeof status.name !== "string") {
|
|
144
|
+
throw new JiraClientError(`Jira returned an invalid status response for ${projectKey}.`);
|
|
145
|
+
}
|
|
146
|
+
statuses.set(status.id, { id: status.id, name: status.name });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return [...statuses.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
150
|
+
}
|
|
151
|
+
function statusMessage(status, issueKey) {
|
|
152
|
+
if (status === 401)
|
|
153
|
+
return "Jira authentication failed.";
|
|
154
|
+
if (status === 403)
|
|
155
|
+
return `Jira access was denied for ${issueKey}.`;
|
|
156
|
+
if (status === 404)
|
|
157
|
+
return `Jira issue ${issueKey} was not found.`;
|
|
158
|
+
if (status === 429)
|
|
159
|
+
return "Jira rate limit was reached; retry later.";
|
|
160
|
+
return `Jira request for ${issueKey} failed with HTTP ${status}.`;
|
|
161
|
+
}
|
|
162
|
+
export class JiraClient {
|
|
163
|
+
baseUrl;
|
|
164
|
+
fetchImpl;
|
|
165
|
+
authorization;
|
|
166
|
+
getTimeoutMs;
|
|
167
|
+
getRetries;
|
|
168
|
+
onGetRetry;
|
|
169
|
+
constructor(baseUrl, email, apiToken, fetchImpl = fetch, options = {}) {
|
|
170
|
+
this.baseUrl = baseUrl;
|
|
171
|
+
this.fetchImpl = fetchImpl;
|
|
172
|
+
this.authorization = `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`;
|
|
173
|
+
this.getTimeoutMs = options.getTimeoutMs ?? 30_000;
|
|
174
|
+
this.getRetries = options.getRetries ?? 1;
|
|
175
|
+
this.onGetRetry = options.onGetRetry;
|
|
176
|
+
}
|
|
177
|
+
static fromConfig(config, fetchImpl = fetch) {
|
|
178
|
+
return new JiraClient(config.jiraBaseUrl, config.jiraEmail, config.jiraApiToken, fetchImpl);
|
|
179
|
+
}
|
|
180
|
+
async get(path, issueKey) {
|
|
181
|
+
let response;
|
|
182
|
+
for (let attempt = 0; attempt <= this.getRetries; attempt += 1) {
|
|
183
|
+
const controller = new AbortController();
|
|
184
|
+
let timedOut = false;
|
|
185
|
+
const timeout = setTimeout(() => {
|
|
186
|
+
timedOut = true;
|
|
187
|
+
controller.abort();
|
|
188
|
+
}, this.getTimeoutMs);
|
|
189
|
+
try {
|
|
190
|
+
response = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
191
|
+
method: "GET",
|
|
192
|
+
headers: {
|
|
193
|
+
Accept: "application/json",
|
|
194
|
+
Authorization: this.authorization,
|
|
195
|
+
},
|
|
196
|
+
signal: controller.signal,
|
|
197
|
+
});
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
if (attempt < this.getRetries) {
|
|
202
|
+
this.onGetRetry?.(issueKey, attempt + 2, this.getRetries + 1, timedOut ? "timeout" : "network");
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
throw new JiraClientError(timedOut
|
|
206
|
+
? `Jira timed out after ${this.getTimeoutMs / 1000}s while reading ${issueKey}.`
|
|
207
|
+
: `Could not connect to Jira while reading ${issueKey}.`);
|
|
208
|
+
}
|
|
209
|
+
finally {
|
|
210
|
+
clearTimeout(timeout);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (!response) {
|
|
214
|
+
throw new JiraClientError(`Could not connect to Jira while reading ${issueKey}.`);
|
|
215
|
+
}
|
|
216
|
+
if (!response.ok) {
|
|
217
|
+
throw new JiraClientError(statusMessage(response.status, issueKey), response.status, issueKey);
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
return await response.json();
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
throw new JiraClientError(`Jira returned malformed JSON for ${issueKey}.`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async post(path, issueKey, body) {
|
|
227
|
+
let response;
|
|
228
|
+
try {
|
|
229
|
+
response = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
230
|
+
method: "POST",
|
|
231
|
+
headers: {
|
|
232
|
+
Accept: "application/json",
|
|
233
|
+
Authorization: this.authorization,
|
|
234
|
+
"Content-Type": "application/json",
|
|
235
|
+
},
|
|
236
|
+
body: JSON.stringify(body),
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
throw new JiraClientError(`Could not connect to Jira while creating a worklog for ${issueKey}.`);
|
|
241
|
+
}
|
|
242
|
+
if (!response.ok) {
|
|
243
|
+
throw new JiraClientError(statusMessage(response.status, issueKey), response.status, issueKey);
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
return await response.json();
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
throw new JiraClientError(`Jira returned malformed JSON for ${issueKey}.`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async delete(path, issueKey) {
|
|
253
|
+
let response;
|
|
254
|
+
try {
|
|
255
|
+
response = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
256
|
+
method: "DELETE",
|
|
257
|
+
headers: {
|
|
258
|
+
Accept: "application/json",
|
|
259
|
+
Authorization: this.authorization,
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
throw new JiraClientError(`Could not connect to Jira while deleting a worklog for ${issueKey}.`);
|
|
265
|
+
}
|
|
266
|
+
if (!response.ok) {
|
|
267
|
+
throw new JiraClientError(statusMessage(response.status, issueKey), response.status, issueKey);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
async readIssue(issueKey) {
|
|
271
|
+
const encodedKey = encodeURIComponent(issueKey);
|
|
272
|
+
const issue = parseIssue(await this.get(`/rest/api/3/issue/${encodedKey}?fields=summary,assignee`, issueKey), issueKey);
|
|
273
|
+
const worklogs = [];
|
|
274
|
+
let startAt = 0;
|
|
275
|
+
for (;;) {
|
|
276
|
+
const page = parseWorklogPage(await this.get(`/rest/api/3/issue/${encodedKey}/worklog?startAt=${startAt}&maxResults=100`, issueKey), issueKey);
|
|
277
|
+
if (page.startAt !== startAt || page.total < worklogs.length + page.worklogs.length) {
|
|
278
|
+
throw new JiraClientError(`Jira returned inconsistent worklog pagination for ${issueKey}.`);
|
|
279
|
+
}
|
|
280
|
+
worklogs.push(...page.worklogs);
|
|
281
|
+
if (worklogs.length >= page.total)
|
|
282
|
+
break;
|
|
283
|
+
if (page.worklogs.length === 0) {
|
|
284
|
+
throw new JiraClientError(`Jira returned incomplete worklog pagination for ${issueKey}.`);
|
|
285
|
+
}
|
|
286
|
+
startAt += page.worklogs.length;
|
|
287
|
+
}
|
|
288
|
+
return { ...issue, worklogs };
|
|
289
|
+
}
|
|
290
|
+
async readLinkIssue(issueKey) {
|
|
291
|
+
const encodedKey = encodeURIComponent(issueKey);
|
|
292
|
+
return parseLinkIssue(await this.get(`/rest/api/3/issue/${encodedKey}?fields=summary,status,issuelinks`, issueKey), issueKey);
|
|
293
|
+
}
|
|
294
|
+
async listProjects() {
|
|
295
|
+
return parseProjects(await this.get("/rest/api/3/project/search?orderBy=name&maxResults=100", "accessible projects"));
|
|
296
|
+
}
|
|
297
|
+
async listProjectStatuses(projectKey) {
|
|
298
|
+
const key = projectKey.toUpperCase();
|
|
299
|
+
return parseProjectStatuses(await this.get(`/rest/api/3/project/${encodeURIComponent(key)}/statuses`, key), key);
|
|
300
|
+
}
|
|
301
|
+
async authenticate() {
|
|
302
|
+
await this.get("/rest/api/3/myself", "the current user");
|
|
303
|
+
}
|
|
304
|
+
async readCurrentAccount() {
|
|
305
|
+
const value = await this.get("/rest/api/3/myself", "the current user");
|
|
306
|
+
if (!isRecord(value) || typeof value.accountId !== "string" || value.accountId.length === 0) {
|
|
307
|
+
throw new JiraClientError("Jira returned an invalid current-user response.");
|
|
308
|
+
}
|
|
309
|
+
return { accountId: value.accountId };
|
|
310
|
+
}
|
|
311
|
+
async createWorklog(entry) {
|
|
312
|
+
if (!entry.jiraKey) {
|
|
313
|
+
throw new JiraClientError("Cannot create a Jira worklog for an unmapped entry.");
|
|
314
|
+
}
|
|
315
|
+
const timeSpentSeconds = entry.duration * 60 * 60;
|
|
316
|
+
if (!Number.isSafeInteger(timeSpentSeconds) || timeSpentSeconds <= 0) {
|
|
317
|
+
throw new JiraClientError(`Duration for ${entry.jiraKey} must convert to a positive whole number of seconds.`);
|
|
318
|
+
}
|
|
319
|
+
const marker = encodeMarker(entry);
|
|
320
|
+
const comment = {
|
|
321
|
+
type: "doc",
|
|
322
|
+
version: 1,
|
|
323
|
+
content: [{
|
|
324
|
+
type: "paragraph",
|
|
325
|
+
content: [{ type: "text", text: entry.description }],
|
|
326
|
+
}, {
|
|
327
|
+
type: "paragraph",
|
|
328
|
+
content: [{ type: "text", text: marker }],
|
|
329
|
+
}],
|
|
330
|
+
};
|
|
331
|
+
const encodedKey = encodeURIComponent(entry.jiraKey);
|
|
332
|
+
return parseCreatedWorklog(await this.post(`/rest/api/3/issue/${encodedKey}/worklog`, entry.jiraKey, {
|
|
333
|
+
timeSpentSeconds,
|
|
334
|
+
started: `${entry.date}T12:00:00.000+0700`,
|
|
335
|
+
comment,
|
|
336
|
+
}), entry.jiraKey);
|
|
337
|
+
}
|
|
338
|
+
async deleteWorklog(issueKey, worklogId) {
|
|
339
|
+
const encodedKey = encodeURIComponent(issueKey);
|
|
340
|
+
const encodedId = encodeURIComponent(worklogId);
|
|
341
|
+
await this.delete(`/rest/api/3/issue/${encodedKey}/worklog/${encodedId}?adjustEstimate=auto`, issueKey);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
//# sourceMappingURL=jira.client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jira.client.js","sourceRoot":"","sources":["../../../../../../../packages/capabilities/jira/src/adapters/jira/jira.client.ts"],"names":[],"mappings":"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"}
|