@gitkraken/core-gitlens 0.20.1 → 0.21.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/CHANGELOG.md +19 -1
- package/dist/git/models/issue.d.ts +30 -1
- package/dist/git/models/issue.js +3 -1
- package/dist/git/models/issue.js.map +1 -1
- package/dist/git/providers/config.d.ts +4 -1
- package/dist/git/providers/remotes.d.ts +18 -0
- package/dist/git/utils/issue.utils.js +2 -1
- package/dist/git/utils/issue.utils.js.map +1 -1
- package/dist/git-cli/exec/git.js +1 -1
- package/dist/git-cli/exec/git.js.map +1 -1
- package/dist/git-cli/providers/config.d.ts +6 -2
- package/dist/git-cli/providers/config.js +47 -7
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/remotes.d.ts +9 -1
- package/dist/git-cli/providers/remotes.js +79 -4
- package/dist/git-cli/providers/remotes.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +13 -1
- package/dist/plus/integrations/models/integration.js +8 -1
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/providers/issueSorts.d.ts +1 -0
- package/dist/plus/integrations/providers/linearIssuesEtag.d.ts +20 -4
- package/dist/plus/integrations/providers/linearIssuesEtag.js +42 -6
- package/dist/plus/integrations/providers/linearIssuesEtag.js.map +1 -1
- package/dist/plus/integrations/providers/models.js +25 -13
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/providers/providerErrors.d.ts +2 -0
- package/dist/plus/integrations/providers/providerErrors.js +5 -2
- package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
- package/dist/plus/integrations/reads/drains.d.ts +1 -0
- package/dist/plus/integrations/reads/etag.js +3 -1
- package/dist/plus/integrations/reads/etag.js.map +1 -1
- package/docs/integrations.md +12 -1
- package/package.json +2 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CancellationError } from "../../utils/cancellation.js";
|
|
1
2
|
import { getScopedLogger } from "../../utils/logger.scoped.js";
|
|
2
3
|
import { debug } from "../../utils/decorators/log.js";
|
|
3
4
|
import __decorate from "../../_virtual/@oxc-project+runtime/helpers/esm/decorate.js";
|
|
@@ -7,6 +8,40 @@ import { RemotesGitProviderBase } from "../../git/providers/shared/remotes.js";
|
|
|
7
8
|
import { createRemoteProviderMatcher } from "../../git/remotes/matcher.js";
|
|
8
9
|
import { parseGitRemotes } from "../parsers/remoteParser.js";
|
|
9
10
|
//#region ../git-cli/src/providers/remotes.ts
|
|
11
|
+
/** Long enough for a slow host to answer, short enough that a blackholed one doesn't stall the wizard */
|
|
12
|
+
const probeRemoteTimeoutMs = 5e3;
|
|
13
|
+
/**
|
|
14
|
+
* Keeps the probe from asking anyone for credentials: an empty `GIT_ASKPASS` stops git's askpass lookup
|
|
15
|
+
* outright (it doesn't fall through to `core.askPass` or `SSH_ASKPASS`), so the editor's askpass can't
|
|
16
|
+
* open a credential prompt over the wizard, and `GIT_TERMINAL_PROMPT=0` refuses the tty fallback.
|
|
17
|
+
* Non-interactive credential helpers still run, so a stored credential still authenticates.
|
|
18
|
+
*/
|
|
19
|
+
const probeRemoteEnv = {
|
|
20
|
+
GIT_ASKPASS: "",
|
|
21
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
22
|
+
GCM_INTERACTIVE: "NEVER",
|
|
23
|
+
SSH_ASKPASS: ""
|
|
24
|
+
};
|
|
25
|
+
function getProbeFailureReason(stderr) {
|
|
26
|
+
if (/Could not resolve host|nodename nor servname|Name or service not known|No such host/i.test(stderr)) return "hostNotFound";
|
|
27
|
+
if (/Host key verification failed/i.test(stderr)) return "hostKeyUnverified";
|
|
28
|
+
if (/could not read (?:Username|Password)|terminal prompts disabled|Authentication failed|Permission denied|returned error: 40[13]\b/i.test(stderr)) return "authRequired";
|
|
29
|
+
if (/Repository not found|repository '.*' not found|does not appear to be a git repository|returned error: 404\b/i.test(stderr)) return "notFound";
|
|
30
|
+
return "other";
|
|
31
|
+
}
|
|
32
|
+
/** SSH's generic tail, which follows (and buries) the host's own explanation of the failure */
|
|
33
|
+
const genericProbeFailureLine = /^(?:fatal:\s*)?(?:Could not read from remote repository|Please make sure you have the correct access rights|and the repository exists)/;
|
|
34
|
+
/**
|
|
35
|
+
* The line of stderr that names what went wrong most plainly: SSH's generic trailer is dropped first so the host's
|
|
36
|
+
* message before it (e.g. `ERROR: Repository not found.`) can win; then the last `fatal:` line (prefix stripped),
|
|
37
|
+
* else the last line. If only the generic trailer remains, it is used rather than returning nothing.
|
|
38
|
+
*/
|
|
39
|
+
function getProbeFailureMessage(stderr) {
|
|
40
|
+
const lines = stderr.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length);
|
|
41
|
+
const specific = lines.filter((l) => !genericProbeFailureLine.test(l));
|
|
42
|
+
const candidates = specific.length ? specific : lines;
|
|
43
|
+
return (candidates.findLast((l) => l.startsWith("fatal:")) ?? candidates.at(-1))?.replace(/^fatal:\s*/, "") || void 0;
|
|
44
|
+
}
|
|
10
45
|
var RemotesGitSubProvider = class extends RemotesGitProviderBase {
|
|
11
46
|
git;
|
|
12
47
|
constructor(context, git, cache, provider) {
|
|
@@ -42,11 +77,16 @@ var RemotesGitSubProvider = class extends RemotesGitProviderBase {
|
|
|
42
77
|
return remotes;
|
|
43
78
|
}
|
|
44
79
|
async addRemote(repoPath, name, url, options) {
|
|
80
|
+
if (!options?.fetch) {
|
|
81
|
+
await this.git.run({ cwd: repoPath }, "remote", "add", name, url);
|
|
82
|
+
this.context.hooks?.cache?.onReset?.(repoPath, "remotes");
|
|
83
|
+
this.context.hooks?.repository?.onChanged?.(repoPath, ["config", "remotes"]);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
45
86
|
try {
|
|
46
|
-
await this.git.run({ cwd: repoPath }, "remote", "add",
|
|
87
|
+
await this.git.run({ cwd: repoPath }, "remote", "add", "-f", name, url);
|
|
47
88
|
} finally {
|
|
48
|
-
|
|
49
|
-
else this.context.hooks?.cache?.onReset?.(repoPath, "remotes");
|
|
89
|
+
this.context.hooks?.cache?.onReset?.(repoPath, "remotes", "branches");
|
|
50
90
|
this.context.hooks?.repository?.onChanged?.(repoPath, ["config", "remotes"]);
|
|
51
91
|
}
|
|
52
92
|
}
|
|
@@ -55,6 +95,40 @@ var RemotesGitSubProvider = class extends RemotesGitProviderBase {
|
|
|
55
95
|
const [remote] = await this.getRemotes(repoPath, { filter: (r) => r.url === url });
|
|
56
96
|
return remote;
|
|
57
97
|
}
|
|
98
|
+
async probeRemote(repoPath, url, cancellation) {
|
|
99
|
+
if (url.startsWith("-")) return {
|
|
100
|
+
reachable: false,
|
|
101
|
+
reason: "other"
|
|
102
|
+
};
|
|
103
|
+
const timeoutSignal = AbortSignal.timeout(probeRemoteTimeoutMs);
|
|
104
|
+
const signal = cancellation != null ? AbortSignal.any([cancellation, timeoutSignal]) : timeoutSignal;
|
|
105
|
+
const result = await this.git.run({
|
|
106
|
+
cwd: repoPath,
|
|
107
|
+
cancellation: signal,
|
|
108
|
+
errors: "ignore",
|
|
109
|
+
env: probeRemoteEnv,
|
|
110
|
+
priority: "interactive"
|
|
111
|
+
}, "ls-remote", url, "HEAD");
|
|
112
|
+
const { completion } = result;
|
|
113
|
+
if (completion.status === "exited" && completion.code === 0) return { reachable: true };
|
|
114
|
+
if (completion.status === "cancelled") {
|
|
115
|
+
if (cancellation?.aborted) throw new CancellationError(completion.error, "aborted");
|
|
116
|
+
return {
|
|
117
|
+
reachable: false,
|
|
118
|
+
reason: "timeout"
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
if (completion.status === "failed") {
|
|
122
|
+
if (cancellation?.aborted) throw new CancellationError(completion.error, "aborted");
|
|
123
|
+
throw completion.error;
|
|
124
|
+
}
|
|
125
|
+
const stderr = typeof result.stderr === "string" ? result.stderr : "";
|
|
126
|
+
return {
|
|
127
|
+
reachable: false,
|
|
128
|
+
reason: getProbeFailureReason(stderr),
|
|
129
|
+
message: getProbeFailureMessage(stderr)
|
|
130
|
+
};
|
|
131
|
+
}
|
|
58
132
|
async pruneRemote(repoPath, name) {
|
|
59
133
|
try {
|
|
60
134
|
await this.git.run({ cwd: repoPath }, "remote", "prune", name);
|
|
@@ -78,9 +152,10 @@ __decorate([debug({
|
|
|
78
152
|
})], RemotesGitSubProvider.prototype, "getRemotes", null);
|
|
79
153
|
__decorate([gate(), debug()], RemotesGitSubProvider.prototype, "addRemote", null);
|
|
80
154
|
__decorate([gate(), debug()], RemotesGitSubProvider.prototype, "addRemoteWithResult", null);
|
|
155
|
+
__decorate([debug({ args: (repoPath) => ({ repoPath }) })], RemotesGitSubProvider.prototype, "probeRemote", null);
|
|
81
156
|
__decorate([gate(), debug()], RemotesGitSubProvider.prototype, "pruneRemote", null);
|
|
82
157
|
__decorate([gate(), debug()], RemotesGitSubProvider.prototype, "removeRemote", null);
|
|
83
158
|
//#endregion
|
|
84
|
-
export { RemotesGitSubProvider };
|
|
159
|
+
export { RemotesGitSubProvider, getProbeFailureMessage, getProbeFailureReason };
|
|
85
160
|
|
|
86
161
|
//# sourceMappingURL=remotes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remotes.js","names":[],"sources":["../../../../git-cli/src/providers/remotes.ts"],"sourcesContent":["import type { Cache } from '@gitlens/git/cache.js';\nimport type { GitServiceContext } from '@gitlens/git/context.js';\nimport type { GitRemote } from '@gitlens/git/models/remote.js';\nimport type { GitRemotesSubProvider } from '@gitlens/git/providers/remotes.js';\nimport { RemotesGitProviderBase } from '@gitlens/git/providers/shared/remotes.js';\nimport { createRemoteProviderMatcher } from '@gitlens/git/remotes/matcher.js';\nimport { sortRemotes } from '@gitlens/git/utils/sorting.js';\nimport { gate } from '@gitlens/utils/decorators/gate.js';\nimport { debug } from '@gitlens/utils/decorators/log.js';\nimport { getScopedLogger } from '@gitlens/utils/logger.scoped.js';\nimport type { CliGitProviderInternal } from '../cliGitProvider.js';\nimport type { Git } from '../exec/git.js';\nimport { parseGitRemotes } from '../parsers/remoteParser.js';\n\nexport class RemotesGitSubProvider extends RemotesGitProviderBase implements GitRemotesSubProvider {\n\tconstructor(\n\t\tcontext: GitServiceContext,\n\t\tprivate readonly git: Git,\n\t\tcache: Cache,\n\t\tprovider: CliGitProviderInternal,\n\t) {\n\t\tsuper(context, cache, provider);\n\t}\n\n\t@debug({ quiet: true, args: repoPath => ({ repoPath: repoPath }) })\n\tasync getRemotes(\n\t\trepoPath: string | undefined,\n\t\toptions?: { filter?: (remote: GitRemote) => boolean; sort?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitRemote[]> {\n\t\tif (repoPath == null) return [];\n\n\t\tconst scope = getScopedLogger();\n\n\t\tlet remotes = await this.cache.getRemotes(\n\t\t\trepoPath,\n\t\t\tasync (commonPath, cacheable, signal) => {\n\t\t\t\t// Prefer the aggregate signal from the cache; fall back to the caller's cancellation.\n\t\t\t\tsignal ??= cancellation;\n\t\t\t\tconst configs = await this.context.remotes?.getCustomProviders?.(repoPath);\n\t\t\t\tconst remoteProviderMatcher = createRemoteProviderMatcher(configs, this.context.remotes);\n\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await this.git.run(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcwd: repoPath,\n\t\t\t\t\t\t\tcancellation: signal,\n\t\t\t\t\t\t\tcaching: { cache: this.cache.gitResults, commonPath: commonPath },\n\t\t\t\t\t\t},\n\t\t\t\t\t\t'remote',\n\t\t\t\t\t\t'-v',\n\t\t\t\t\t);\n\n\t\t\t\t\t// Fetch default remote name from GK config before parsing so it's set at construction time\n\t\t\t\t\tconst defaultName = await this.provider.config.getGkConfig?.(repoPath, 'gk.defaultRemote');\n\t\t\t\t\tconst remotes = parseGitRemotes(result.stdout, commonPath, remoteProviderMatcher, defaultName);\n\n\t\t\t\t\treturn remotes;\n\t\t\t\t} catch (ex) {\n\t\t\t\t\tcacheable.invalidate();\n\t\t\t\t\tscope?.error(ex);\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\n\t\tif (options?.filter != null) {\n\t\t\tremotes = remotes.filter(options.filter);\n\t\t}\n\n\t\tif (options?.sort) {\n\t\t\tsortRemotes(remotes);\n\t\t}\n\n\t\treturn remotes;\n\t}\n\n\t@gate()\n\t@debug()\n\tasync addRemote(repoPath: string, name: string, url: string, options?: { fetch?: boolean }): Promise<void> {\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'remote', 'add', options?.fetch ? '-f' : undefined, name, url);\n\t\t} finally {\n\t\t\t// A fetch creates the remote's tracking branches, which the branch, ref and history caches hold. The\n\t\t\t// remote is added before the fetch runs, so a failed `-f` still leaves it behind.\n\t\t\tif (options?.fetch) {\n\t\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'remotes', 'branches');\n\t\t\t} else {\n\t\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'remotes');\n\t\t\t}\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['config', 'remotes']);\n\t\t}\n\t}\n\n\t@gate()\n\t@debug()\n\tasync addRemoteWithResult(\n\t\trepoPath: string,\n\t\tname: string,\n\t\turl: string,\n\t\toptions?: { fetch?: boolean },\n\t): Promise<GitRemote | undefined> {\n\t\tawait this.addRemote(repoPath, name, url, options);\n\t\tconst [remote] = await this.getRemotes(repoPath, { filter: r => r.url === url });\n\t\treturn remote;\n\t}\n\n\t@gate()\n\t@debug()\n\tasync pruneRemote(repoPath: string, name: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'remote', 'prune', name);\n\t\t} finally {\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'remotes', 'branches');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['remotes']);\n\t\t}\n\t}\n\n\t@gate()\n\t@debug()\n\tasync removeRemote(repoPath: string, name: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'remote', 'remove', name);\n\t\t} finally {\n\t\t\t// Removing a remote deletes its tracking branches too\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'remotes', 'branches');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['config', 'remotes']);\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"remotes.js","names":[],"sources":["../../../../git-cli/src/providers/remotes.ts"],"sourcesContent":["import type { Cache } from '@gitlens/git/cache.js';\nimport type { GitServiceContext } from '@gitlens/git/context.js';\nimport type { GitRemote } from '@gitlens/git/models/remote.js';\nimport type {\n\tGitRemoteProbeFailureReason,\n\tGitRemoteProbeResult,\n\tGitRemotesSubProvider,\n} from '@gitlens/git/providers/remotes.js';\nimport { RemotesGitProviderBase } from '@gitlens/git/providers/shared/remotes.js';\nimport { createRemoteProviderMatcher } from '@gitlens/git/remotes/matcher.js';\nimport { sortRemotes } from '@gitlens/git/utils/sorting.js';\nimport { CancellationError } from '@gitlens/utils/cancellation.js';\nimport { gate } from '@gitlens/utils/decorators/gate.js';\nimport { debug } from '@gitlens/utils/decorators/log.js';\nimport { getScopedLogger } from '@gitlens/utils/logger.scoped.js';\nimport type { CliGitProviderInternal } from '../cliGitProvider.js';\nimport type { Git } from '../exec/git.js';\nimport { parseGitRemotes } from '../parsers/remoteParser.js';\n\n/** Long enough for a slow host to answer, short enough that a blackholed one doesn't stall the wizard */\nconst probeRemoteTimeoutMs = 5000;\n\n/**\n * Keeps the probe from asking anyone for credentials: an empty `GIT_ASKPASS` stops git's askpass lookup\n * outright (it doesn't fall through to `core.askPass` or `SSH_ASKPASS`), so the editor's askpass can't\n * open a credential prompt over the wizard, and `GIT_TERMINAL_PROMPT=0` refuses the tty fallback.\n * Non-interactive credential helpers still run, so a stored credential still authenticates.\n */\nconst probeRemoteEnv: Record<string, string> = {\n\tGIT_ASKPASS: '',\n\tGIT_TERMINAL_PROMPT: '0',\n\tGCM_INTERACTIVE: 'NEVER',\n\tSSH_ASKPASS: '',\n};\n\nexport function getProbeFailureReason(stderr: string): GitRemoteProbeFailureReason {\n\tif (/Could not resolve host|nodename nor servname|Name or service not known|No such host/i.test(stderr)) {\n\t\treturn 'hostNotFound';\n\t}\n\t// Checked before auth: the probe forbids ssh's prompt to trust an unknown host, so a correct URL on a host\n\t// not yet in known_hosts fails here, and that isn't an authentication problem\n\tif (/Host key verification failed/i.test(stderr)) {\n\t\treturn 'hostKeyUnverified';\n\t}\n\t// HTTP statuses are matched on git's own wording so digits elsewhere (e.g. a `/403/` URL path) don't count\n\tif (\n\t\t/could not read (?:Username|Password)|terminal prompts disabled|Authentication failed|Permission denied|returned error: 40[13]\\b/i.test(\n\t\t\tstderr,\n\t\t)\n\t) {\n\t\treturn 'authRequired';\n\t}\n\tif (\n\t\t/Repository not found|repository '.*' not found|does not appear to be a git repository|returned error: 404\\b/i.test(\n\t\t\tstderr,\n\t\t)\n\t) {\n\t\treturn 'notFound';\n\t}\n\treturn 'other';\n}\n\n/** SSH's generic tail, which follows (and buries) the host's own explanation of the failure */\nconst genericProbeFailureLine =\n\t/^(?:fatal:\\s*)?(?:Could not read from remote repository|Please make sure you have the correct access rights|and the repository exists)/;\n\n/**\n * The line of stderr that names what went wrong most plainly: SSH's generic trailer is dropped first so the host's\n * message before it (e.g. `ERROR: Repository not found.`) can win; then the last `fatal:` line (prefix stripped),\n * else the last line. If only the generic trailer remains, it is used rather than returning nothing.\n */\nexport function getProbeFailureMessage(stderr: string): string | undefined {\n\tconst lines = stderr\n\t\t.split(/\\r?\\n/)\n\t\t.map(l => l.trim())\n\t\t.filter(l => l.length);\n\tconst specific = lines.filter(l => !genericProbeFailureLine.test(l));\n\tconst candidates = specific.length ? specific : lines;\n\tconst fatal = candidates.findLast(l => l.startsWith('fatal:'));\n\treturn (fatal ?? candidates.at(-1))?.replace(/^fatal:\\s*/, '') || undefined;\n}\n\nexport class RemotesGitSubProvider extends RemotesGitProviderBase implements GitRemotesSubProvider {\n\tconstructor(\n\t\tcontext: GitServiceContext,\n\t\tprivate readonly git: Git,\n\t\tcache: Cache,\n\t\tprovider: CliGitProviderInternal,\n\t) {\n\t\tsuper(context, cache, provider);\n\t}\n\n\t@debug({ quiet: true, args: repoPath => ({ repoPath: repoPath }) })\n\tasync getRemotes(\n\t\trepoPath: string | undefined,\n\t\toptions?: { filter?: (remote: GitRemote) => boolean; sort?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitRemote[]> {\n\t\tif (repoPath == null) return [];\n\n\t\tconst scope = getScopedLogger();\n\n\t\tlet remotes = await this.cache.getRemotes(\n\t\t\trepoPath,\n\t\t\tasync (commonPath, cacheable, signal) => {\n\t\t\t\t// Prefer the aggregate signal from the cache; fall back to the caller's cancellation.\n\t\t\t\tsignal ??= cancellation;\n\t\t\t\tconst configs = await this.context.remotes?.getCustomProviders?.(repoPath);\n\t\t\t\tconst remoteProviderMatcher = createRemoteProviderMatcher(configs, this.context.remotes);\n\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await this.git.run(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcwd: repoPath,\n\t\t\t\t\t\t\tcancellation: signal,\n\t\t\t\t\t\t\tcaching: { cache: this.cache.gitResults, commonPath: commonPath },\n\t\t\t\t\t\t},\n\t\t\t\t\t\t'remote',\n\t\t\t\t\t\t'-v',\n\t\t\t\t\t);\n\n\t\t\t\t\t// Fetch default remote name from GK config before parsing so it's set at construction time\n\t\t\t\t\tconst defaultName = await this.provider.config.getGkConfig?.(repoPath, 'gk.defaultRemote');\n\t\t\t\t\tconst remotes = parseGitRemotes(result.stdout, commonPath, remoteProviderMatcher, defaultName);\n\n\t\t\t\t\treturn remotes;\n\t\t\t\t} catch (ex) {\n\t\t\t\t\tcacheable.invalidate();\n\t\t\t\t\tscope?.error(ex);\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\n\t\tif (options?.filter != null) {\n\t\t\tremotes = remotes.filter(options.filter);\n\t\t}\n\n\t\tif (options?.sort) {\n\t\t\tsortRemotes(remotes);\n\t\t}\n\n\t\treturn remotes;\n\t}\n\n\t@gate()\n\t@debug()\n\tasync addRemote(repoPath: string, name: string, url: string, options?: { fetch?: boolean }): Promise<void> {\n\t\tif (!options?.fetch) {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'remote', 'add', name, url);\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'remotes');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['config', 'remotes']);\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'remote', 'add', '-f', name, url);\n\t\t} finally {\n\t\t\t// Reset even on failure: `remote add -f` keeps the remote when only its fetch fails, and a\n\t\t\t// caller checking whether the remote now exists must not read the pre-add cache.\n\t\t\t// A fetch creates the remote's tracking branches, which the branch, ref and history caches hold\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'remotes', 'branches');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['config', 'remotes']);\n\t\t}\n\t}\n\n\t@gate()\n\t@debug()\n\tasync addRemoteWithResult(\n\t\trepoPath: string,\n\t\tname: string,\n\t\turl: string,\n\t\toptions?: { fetch?: boolean },\n\t): Promise<GitRemote | undefined> {\n\t\tawait this.addRemote(repoPath, name, url, options);\n\t\tconst [remote] = await this.getRemotes(repoPath, { filter: r => r.url === url });\n\t\treturn remote;\n\t}\n\n\t// The URL is left out of the log — it can carry credentials (`https://<token>@host/...`)\n\t@debug({ args: repoPath => ({ repoPath: repoPath }) })\n\tasync probeRemote(repoPath: string, url: string, cancellation?: AbortSignal): Promise<GitRemoteProbeResult> {\n\t\t// A leading `-` would be parsed as an option rather than the repository to query\n\t\tif (url.startsWith('-')) return { reachable: false, reason: 'other' };\n\n\t\tconst timeoutSignal = AbortSignal.timeout(probeRemoteTimeoutMs);\n\t\tconst signal = cancellation != null ? AbortSignal.any([cancellation, timeoutSignal]) : timeoutSignal;\n\n\t\tconst result = await this.git.run(\n\t\t\t{ cwd: repoPath, cancellation: signal, errors: 'ignore', env: probeRemoteEnv, priority: 'interactive' },\n\t\t\t// No `--exit-code`: a freshly created, empty repository advertises no HEAD but is a valid remote\n\t\t\t'ls-remote',\n\t\t\turl,\n\t\t\t'HEAD',\n\t\t);\n\n\t\tconst { completion } = result;\n\t\tif (completion.status === 'exited' && completion.code === 0) return { reachable: true };\n\n\t\tif (completion.status === 'cancelled') {\n\t\t\tif (cancellation?.aborted) throw new CancellationError(completion.error, 'aborted');\n\n\t\t\treturn { reachable: false, reason: 'timeout' };\n\t\t}\n\n\t\t// A run that never exited (spawn failure, missing binary, queue rejection) says nothing about the remote;\n\t\t// throw so callers treat it as unprobed rather than unreachable\n\t\tif (completion.status === 'failed') {\n\t\t\tif (cancellation?.aborted) throw new CancellationError(completion.error, 'aborted');\n\n\t\t\tthrow completion.error;\n\t\t}\n\n\t\t// Under `errors: 'ignore'` a non-zero exit resolves with its stderr; a run that never exited has none\n\t\tconst stderr = typeof result.stderr === 'string' ? result.stderr : '';\n\t\treturn {\n\t\t\treachable: false,\n\t\t\treason: getProbeFailureReason(stderr),\n\t\t\tmessage: getProbeFailureMessage(stderr),\n\t\t};\n\t}\n\n\t@gate()\n\t@debug()\n\tasync pruneRemote(repoPath: string, name: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'remote', 'prune', name);\n\t\t} finally {\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'remotes', 'branches');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['remotes']);\n\t\t}\n\t}\n\n\t@gate()\n\t@debug()\n\tasync removeRemote(repoPath: string, name: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'remote', 'remove', name);\n\t\t} finally {\n\t\t\t// Removing a remote deletes its tracking branches too\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'remotes', 'branches');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['config', 'remotes']);\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import { Emitter, Event } from "../../../utils/event.js";
|
|
|
3
3
|
import { ResourceDescriptor } from "../../../git/models/resourceDescriptor.js";
|
|
4
4
|
import { AutolinkReference, DynamicAutolinkReference } from "../../../git/models/autolink.js";
|
|
5
5
|
import { IssueOrPullRequest, IssueOrPullRequestState, IssueOrPullRequestType } from "../../../git/models/issueOrPullRequest.js";
|
|
6
|
-
import { Issue as Issue$1, IssueShape } from "../../../git/models/issue.js";
|
|
6
|
+
import { Issue as Issue$1, IssueShape, IssueSyncedWith } from "../../../git/models/issue.js";
|
|
7
7
|
import { PullRequest, PullRequestMergeableState, PullRequestReviewDecision, PullRequestReviewState, PullRequestStatusCheckRollupState } from "../../../git/models/pullRequest.js";
|
|
8
8
|
import { ScopedLogger } from "../../../utils/logger.scoped.js";
|
|
9
9
|
import { Account as Account$1 } from "../../../git/models/author.js";
|
|
@@ -135,6 +135,13 @@ export interface IssueEtagFields {
|
|
|
135
135
|
* it never compares unchanged and is read in full again rather than kept without one.
|
|
136
136
|
*/
|
|
137
137
|
viewerRule?: number;
|
|
138
|
+
/**
|
|
139
|
+
* Linear only: the row's `syncedWith` links as {@link linearSyncedWithEtagKeys} spells them, so a link added, removed
|
|
140
|
+
* or moved to other coordinates changes the etag whether or not the issue's update time moves. `null` on a
|
|
141
|
+
* full row without `syncedWith` (held from before it existed, or read while Linear failed to resolve it), which
|
|
142
|
+
* never compares unchanged with a cheap check's list.
|
|
143
|
+
*/
|
|
144
|
+
syncedWithKeys?: readonly string[] | null;
|
|
138
145
|
}
|
|
139
146
|
/**
|
|
140
147
|
* {@link IssueEtagFields.descriptionRule}: the version of the rule an Azure DevOps work item's body is read by, stamped
|
|
@@ -154,6 +161,11 @@ export declare const azureWorkItemDescriptionRule = 1;
|
|
|
154
161
|
* identity in the work item's organization (gitkraken/kepler#4291).
|
|
155
162
|
*/
|
|
156
163
|
export declare const azureWorkItemViewerRule = 1;
|
|
164
|
+
/**
|
|
165
|
+
* A Linear row's sync links in its etag, sorted: each as its GitHub id and, when known, the coordinates a host matches
|
|
166
|
+
* the GitHub row by, so a link whose coordinates Linear fills in or changes later compares changed.
|
|
167
|
+
*/
|
|
168
|
+
export declare function linearSyncedWithEtagKeys(links: readonly IssueSyncedWith[]): string[];
|
|
157
169
|
/** A batch read's target, in the form its provider addresses it by: a repository coordinate, or a tracker's resource. */
|
|
158
170
|
type BatchTarget = {
|
|
159
171
|
owner: string;
|
|
@@ -74,6 +74,13 @@ const azureWorkItemDescriptionRule = 1;
|
|
|
74
74
|
*/
|
|
75
75
|
const azureWorkItemViewerRule = 1;
|
|
76
76
|
/**
|
|
77
|
+
* A Linear row's sync links in its etag, sorted: each as its GitHub id and, when known, the coordinates a host matches
|
|
78
|
+
* the GitHub row by, so a link whose coordinates Linear fills in or changes later compares changed.
|
|
79
|
+
*/
|
|
80
|
+
function linearSyncedWithEtagKeys(links) {
|
|
81
|
+
return links.map((link) => link.owner != null ? `${link.id}:${link.owner}/${link.repo}#${link.number}` : `${link.id}:`).sort();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
77
84
|
* The scope a batch read records a refused target under. It is decided here rather than in the read, which has the
|
|
78
85
|
* same targets, because naming the refusal's cause (`describeRefusal`) needs it too. Azure DevOps: the organization
|
|
79
86
|
* and project, since its refusals come from those (an organization's OAuth policy or tenant, a project's permissions)
|
|
@@ -968,6 +975,6 @@ __decorate([trace()], IntegrationBase.prototype, "getLinkedIssueOrPullRequest",
|
|
|
968
975
|
__decorate([trace()], IntegrationBase.prototype, "getIssueResultCore", null);
|
|
969
976
|
__decorate([trace()], IntegrationBase.prototype, "getPullRequest", null);
|
|
970
977
|
//#endregion
|
|
971
|
-
export { IntegrationBase, ReadSessionFailure, azureWorkItemDescriptionRule, azureWorkItemViewerRule, isReadSessionFailure, issueEtagIncludes, pullRequestEtagIncludes, pullRequestRevision };
|
|
978
|
+
export { IntegrationBase, ReadSessionFailure, azureWorkItemDescriptionRule, azureWorkItemViewerRule, isReadSessionFailure, issueEtagIncludes, linearSyncedWithEtagKeys, pullRequestEtagIncludes, pullRequestRevision };
|
|
972
979
|
|
|
973
980
|
//# sourceMappingURL=integration.js.map
|