@pilatos/bitbucket-cli 1.10.0 → 1.11.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/dist/index.js +1308 -79
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -26,6 +26,7 @@ var __export = (target, all) => {
|
|
|
26
26
|
set: (newValue) => all[name] = () => newValue
|
|
27
27
|
});
|
|
28
28
|
};
|
|
29
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
29
30
|
var __require = import.meta.require;
|
|
30
31
|
|
|
31
32
|
// node_modules/commander/lib/error.js
|
|
@@ -13522,6 +13523,660 @@ var require_follow_redirects = __commonJS((exports, module) => {
|
|
|
13522
13523
|
module.exports.wrap = wrap;
|
|
13523
13524
|
});
|
|
13524
13525
|
|
|
13526
|
+
// node_modules/is-docker/index.js
|
|
13527
|
+
import fs from "fs";
|
|
13528
|
+
function hasDockerEnv() {
|
|
13529
|
+
try {
|
|
13530
|
+
fs.statSync("/.dockerenv");
|
|
13531
|
+
return true;
|
|
13532
|
+
} catch {
|
|
13533
|
+
return false;
|
|
13534
|
+
}
|
|
13535
|
+
}
|
|
13536
|
+
function hasDockerCGroup() {
|
|
13537
|
+
try {
|
|
13538
|
+
return fs.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
|
|
13539
|
+
} catch {
|
|
13540
|
+
return false;
|
|
13541
|
+
}
|
|
13542
|
+
}
|
|
13543
|
+
function isDocker() {
|
|
13544
|
+
if (isDockerCached === undefined) {
|
|
13545
|
+
isDockerCached = hasDockerEnv() || hasDockerCGroup();
|
|
13546
|
+
}
|
|
13547
|
+
return isDockerCached;
|
|
13548
|
+
}
|
|
13549
|
+
var isDockerCached;
|
|
13550
|
+
var init_is_docker = () => {};
|
|
13551
|
+
|
|
13552
|
+
// node_modules/is-inside-container/index.js
|
|
13553
|
+
import fs2 from "fs";
|
|
13554
|
+
function isInsideContainer() {
|
|
13555
|
+
if (cachedResult === undefined) {
|
|
13556
|
+
cachedResult = hasContainerEnv() || isDocker();
|
|
13557
|
+
}
|
|
13558
|
+
return cachedResult;
|
|
13559
|
+
}
|
|
13560
|
+
var cachedResult, hasContainerEnv = () => {
|
|
13561
|
+
try {
|
|
13562
|
+
fs2.statSync("/run/.containerenv");
|
|
13563
|
+
return true;
|
|
13564
|
+
} catch {
|
|
13565
|
+
return false;
|
|
13566
|
+
}
|
|
13567
|
+
};
|
|
13568
|
+
var init_is_inside_container = __esm(() => {
|
|
13569
|
+
init_is_docker();
|
|
13570
|
+
});
|
|
13571
|
+
|
|
13572
|
+
// node_modules/is-wsl/index.js
|
|
13573
|
+
import process3 from "process";
|
|
13574
|
+
import os2 from "os";
|
|
13575
|
+
import fs3 from "fs";
|
|
13576
|
+
var isWsl = () => {
|
|
13577
|
+
if (process3.platform !== "linux") {
|
|
13578
|
+
return false;
|
|
13579
|
+
}
|
|
13580
|
+
if (os2.release().toLowerCase().includes("microsoft")) {
|
|
13581
|
+
if (isInsideContainer()) {
|
|
13582
|
+
return false;
|
|
13583
|
+
}
|
|
13584
|
+
return true;
|
|
13585
|
+
}
|
|
13586
|
+
try {
|
|
13587
|
+
if (fs3.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft")) {
|
|
13588
|
+
return !isInsideContainer();
|
|
13589
|
+
}
|
|
13590
|
+
} catch {}
|
|
13591
|
+
if (fs3.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop") || fs3.existsSync("/run/WSL")) {
|
|
13592
|
+
return !isInsideContainer();
|
|
13593
|
+
}
|
|
13594
|
+
return false;
|
|
13595
|
+
}, is_wsl_default;
|
|
13596
|
+
var init_is_wsl = __esm(() => {
|
|
13597
|
+
init_is_inside_container();
|
|
13598
|
+
is_wsl_default = process3.env.__IS_WSL_TEST__ ? isWsl : isWsl();
|
|
13599
|
+
});
|
|
13600
|
+
|
|
13601
|
+
// node_modules/powershell-utils/index.js
|
|
13602
|
+
import process4 from "process";
|
|
13603
|
+
import { Buffer as Buffer2 } from "buffer";
|
|
13604
|
+
import { promisify } from "util";
|
|
13605
|
+
import childProcess from "child_process";
|
|
13606
|
+
var execFile, powerShellPath = () => `${process4.env.SYSTEMROOT || process4.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`, executePowerShell = async (command, options = {}) => {
|
|
13607
|
+
const {
|
|
13608
|
+
powerShellPath: psPath,
|
|
13609
|
+
...execFileOptions
|
|
13610
|
+
} = options;
|
|
13611
|
+
const encodedCommand = executePowerShell.encodeCommand(command);
|
|
13612
|
+
return execFile(psPath ?? powerShellPath(), [
|
|
13613
|
+
...executePowerShell.argumentsPrefix,
|
|
13614
|
+
encodedCommand
|
|
13615
|
+
], {
|
|
13616
|
+
encoding: "utf8",
|
|
13617
|
+
...execFileOptions
|
|
13618
|
+
});
|
|
13619
|
+
};
|
|
13620
|
+
var init_powershell_utils = __esm(() => {
|
|
13621
|
+
execFile = promisify(childProcess.execFile);
|
|
13622
|
+
executePowerShell.argumentsPrefix = [
|
|
13623
|
+
"-NoProfile",
|
|
13624
|
+
"-NonInteractive",
|
|
13625
|
+
"-ExecutionPolicy",
|
|
13626
|
+
"Bypass",
|
|
13627
|
+
"-EncodedCommand"
|
|
13628
|
+
];
|
|
13629
|
+
executePowerShell.encodeCommand = (command) => Buffer2.from(command, "utf16le").toString("base64");
|
|
13630
|
+
executePowerShell.escapeArgument = (value) => `'${String(value).replaceAll("'", "''")}'`;
|
|
13631
|
+
});
|
|
13632
|
+
|
|
13633
|
+
// node_modules/wsl-utils/utilities.js
|
|
13634
|
+
function parseMountPointFromConfig(content) {
|
|
13635
|
+
for (const line of content.split(`
|
|
13636
|
+
`)) {
|
|
13637
|
+
if (/^\s*#/.test(line)) {
|
|
13638
|
+
continue;
|
|
13639
|
+
}
|
|
13640
|
+
const match = /^\s*root\s*=\s*(?<mountPoint>"[^"]*"|'[^']*'|[^#]*)/.exec(line);
|
|
13641
|
+
if (!match) {
|
|
13642
|
+
continue;
|
|
13643
|
+
}
|
|
13644
|
+
return match.groups.mountPoint.trim().replaceAll(/^["']|["']$/g, "");
|
|
13645
|
+
}
|
|
13646
|
+
}
|
|
13647
|
+
|
|
13648
|
+
// node_modules/wsl-utils/index.js
|
|
13649
|
+
import { promisify as promisify2 } from "util";
|
|
13650
|
+
import childProcess2 from "child_process";
|
|
13651
|
+
import fs4, { constants as fsConstants } from "fs/promises";
|
|
13652
|
+
var execFile2, wslDrivesMountPoint, powerShellPathFromWsl = async () => {
|
|
13653
|
+
const mountPoint = await wslDrivesMountPoint();
|
|
13654
|
+
return `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`;
|
|
13655
|
+
}, powerShellPath2, canAccessPowerShellPromise, canAccessPowerShell = async () => {
|
|
13656
|
+
canAccessPowerShellPromise ??= (async () => {
|
|
13657
|
+
try {
|
|
13658
|
+
const psPath = await powerShellPath2();
|
|
13659
|
+
await fs4.access(psPath, fsConstants.X_OK);
|
|
13660
|
+
return true;
|
|
13661
|
+
} catch {
|
|
13662
|
+
return false;
|
|
13663
|
+
}
|
|
13664
|
+
})();
|
|
13665
|
+
return canAccessPowerShellPromise;
|
|
13666
|
+
}, wslDefaultBrowser = async () => {
|
|
13667
|
+
const psPath = await powerShellPath2();
|
|
13668
|
+
const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
|
|
13669
|
+
const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
|
|
13670
|
+
return stdout.trim();
|
|
13671
|
+
}, convertWslPathToWindows = async (path) => {
|
|
13672
|
+
if (/^[a-z]+:\/\//i.test(path)) {
|
|
13673
|
+
return path;
|
|
13674
|
+
}
|
|
13675
|
+
try {
|
|
13676
|
+
const { stdout } = await execFile2("wslpath", ["-aw", path], { encoding: "utf8" });
|
|
13677
|
+
return stdout.trim();
|
|
13678
|
+
} catch {
|
|
13679
|
+
return path;
|
|
13680
|
+
}
|
|
13681
|
+
};
|
|
13682
|
+
var init_wsl_utils = __esm(() => {
|
|
13683
|
+
init_is_wsl();
|
|
13684
|
+
init_powershell_utils();
|
|
13685
|
+
init_is_wsl();
|
|
13686
|
+
execFile2 = promisify2(childProcess2.execFile);
|
|
13687
|
+
wslDrivesMountPoint = (() => {
|
|
13688
|
+
const defaultMountPoint = "/mnt/";
|
|
13689
|
+
let mountPoint;
|
|
13690
|
+
return async function() {
|
|
13691
|
+
if (mountPoint) {
|
|
13692
|
+
return mountPoint;
|
|
13693
|
+
}
|
|
13694
|
+
const configFilePath = "/etc/wsl.conf";
|
|
13695
|
+
let isConfigFileExists = false;
|
|
13696
|
+
try {
|
|
13697
|
+
await fs4.access(configFilePath, fsConstants.F_OK);
|
|
13698
|
+
isConfigFileExists = true;
|
|
13699
|
+
} catch {}
|
|
13700
|
+
if (!isConfigFileExists) {
|
|
13701
|
+
return defaultMountPoint;
|
|
13702
|
+
}
|
|
13703
|
+
const configContent = await fs4.readFile(configFilePath, { encoding: "utf8" });
|
|
13704
|
+
const parsedMountPoint = parseMountPointFromConfig(configContent);
|
|
13705
|
+
if (parsedMountPoint === undefined) {
|
|
13706
|
+
return defaultMountPoint;
|
|
13707
|
+
}
|
|
13708
|
+
mountPoint = parsedMountPoint;
|
|
13709
|
+
mountPoint = mountPoint.endsWith("/") ? mountPoint : `${mountPoint}/`;
|
|
13710
|
+
return mountPoint;
|
|
13711
|
+
};
|
|
13712
|
+
})();
|
|
13713
|
+
powerShellPath2 = is_wsl_default ? powerShellPathFromWsl : powerShellPath;
|
|
13714
|
+
});
|
|
13715
|
+
|
|
13716
|
+
// node_modules/define-lazy-prop/index.js
|
|
13717
|
+
function defineLazyProperty(object, propertyName, valueGetter) {
|
|
13718
|
+
const define = (value) => Object.defineProperty(object, propertyName, { value, enumerable: true, writable: true });
|
|
13719
|
+
Object.defineProperty(object, propertyName, {
|
|
13720
|
+
configurable: true,
|
|
13721
|
+
enumerable: true,
|
|
13722
|
+
get() {
|
|
13723
|
+
const result = valueGetter();
|
|
13724
|
+
define(result);
|
|
13725
|
+
return result;
|
|
13726
|
+
},
|
|
13727
|
+
set(value) {
|
|
13728
|
+
define(value);
|
|
13729
|
+
}
|
|
13730
|
+
});
|
|
13731
|
+
return object;
|
|
13732
|
+
}
|
|
13733
|
+
|
|
13734
|
+
// node_modules/default-browser-id/index.js
|
|
13735
|
+
import { promisify as promisify3 } from "util";
|
|
13736
|
+
import process5 from "process";
|
|
13737
|
+
import { execFile as execFile3 } from "child_process";
|
|
13738
|
+
async function defaultBrowserId() {
|
|
13739
|
+
if (process5.platform !== "darwin") {
|
|
13740
|
+
throw new Error("macOS only");
|
|
13741
|
+
}
|
|
13742
|
+
const { stdout } = await execFileAsync("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
|
|
13743
|
+
const match = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
|
|
13744
|
+
const browserId = match?.groups.id ?? "com.apple.Safari";
|
|
13745
|
+
if (browserId === "com.apple.safari") {
|
|
13746
|
+
return "com.apple.Safari";
|
|
13747
|
+
}
|
|
13748
|
+
return browserId;
|
|
13749
|
+
}
|
|
13750
|
+
var execFileAsync;
|
|
13751
|
+
var init_default_browser_id = __esm(() => {
|
|
13752
|
+
execFileAsync = promisify3(execFile3);
|
|
13753
|
+
});
|
|
13754
|
+
|
|
13755
|
+
// node_modules/run-applescript/index.js
|
|
13756
|
+
import process6 from "process";
|
|
13757
|
+
import { promisify as promisify4 } from "util";
|
|
13758
|
+
import { execFile as execFile4, execFileSync } from "child_process";
|
|
13759
|
+
async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
|
|
13760
|
+
if (process6.platform !== "darwin") {
|
|
13761
|
+
throw new Error("macOS only");
|
|
13762
|
+
}
|
|
13763
|
+
const outputArguments = humanReadableOutput ? [] : ["-ss"];
|
|
13764
|
+
const execOptions = {};
|
|
13765
|
+
if (signal) {
|
|
13766
|
+
execOptions.signal = signal;
|
|
13767
|
+
}
|
|
13768
|
+
const { stdout } = await execFileAsync2("osascript", ["-e", script, outputArguments], execOptions);
|
|
13769
|
+
return stdout.trim();
|
|
13770
|
+
}
|
|
13771
|
+
var execFileAsync2;
|
|
13772
|
+
var init_run_applescript = __esm(() => {
|
|
13773
|
+
execFileAsync2 = promisify4(execFile4);
|
|
13774
|
+
});
|
|
13775
|
+
|
|
13776
|
+
// node_modules/bundle-name/index.js
|
|
13777
|
+
async function bundleName(bundleId) {
|
|
13778
|
+
return runAppleScript(`tell application "Finder" to set app_path to application file id "${bundleId}" as string
|
|
13779
|
+
tell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`);
|
|
13780
|
+
}
|
|
13781
|
+
var init_bundle_name = __esm(() => {
|
|
13782
|
+
init_run_applescript();
|
|
13783
|
+
});
|
|
13784
|
+
|
|
13785
|
+
// node_modules/default-browser/windows.js
|
|
13786
|
+
import { promisify as promisify5 } from "util";
|
|
13787
|
+
import { execFile as execFile5 } from "child_process";
|
|
13788
|
+
async function defaultBrowser(_execFileAsync = execFileAsync3) {
|
|
13789
|
+
const { stdout } = await _execFileAsync("reg", [
|
|
13790
|
+
"QUERY",
|
|
13791
|
+
" HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
|
|
13792
|
+
"/v",
|
|
13793
|
+
"ProgId"
|
|
13794
|
+
]);
|
|
13795
|
+
const match = /ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(stdout);
|
|
13796
|
+
if (!match) {
|
|
13797
|
+
throw new UnknownBrowserError(`Cannot find Windows browser in stdout: ${JSON.stringify(stdout)}`);
|
|
13798
|
+
}
|
|
13799
|
+
const { id } = match.groups;
|
|
13800
|
+
const dotIndex = id.lastIndexOf(".");
|
|
13801
|
+
const hyphenIndex = id.lastIndexOf("-");
|
|
13802
|
+
const baseIdByDot = dotIndex === -1 ? undefined : id.slice(0, dotIndex);
|
|
13803
|
+
const baseIdByHyphen = hyphenIndex === -1 ? undefined : id.slice(0, hyphenIndex);
|
|
13804
|
+
return windowsBrowserProgIds[id] ?? windowsBrowserProgIds[baseIdByDot] ?? windowsBrowserProgIds[baseIdByHyphen] ?? { name: id, id };
|
|
13805
|
+
}
|
|
13806
|
+
var execFileAsync3, windowsBrowserProgIds, _windowsBrowserProgIdMap, UnknownBrowserError;
|
|
13807
|
+
var init_windows = __esm(() => {
|
|
13808
|
+
execFileAsync3 = promisify5(execFile5);
|
|
13809
|
+
windowsBrowserProgIds = {
|
|
13810
|
+
MSEdgeHTM: { name: "Edge", id: "com.microsoft.edge" },
|
|
13811
|
+
MSEdgeBHTML: { name: "Edge Beta", id: "com.microsoft.edge.beta" },
|
|
13812
|
+
MSEdgeDHTML: { name: "Edge Dev", id: "com.microsoft.edge.dev" },
|
|
13813
|
+
AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
|
|
13814
|
+
ChromeHTML: { name: "Chrome", id: "com.google.chrome" },
|
|
13815
|
+
ChromeBHTML: { name: "Chrome Beta", id: "com.google.chrome.beta" },
|
|
13816
|
+
ChromeDHTML: { name: "Chrome Dev", id: "com.google.chrome.dev" },
|
|
13817
|
+
ChromiumHTM: { name: "Chromium", id: "org.chromium.Chromium" },
|
|
13818
|
+
BraveHTML: { name: "Brave", id: "com.brave.Browser" },
|
|
13819
|
+
BraveBHTML: { name: "Brave Beta", id: "com.brave.Browser.beta" },
|
|
13820
|
+
BraveDHTML: { name: "Brave Dev", id: "com.brave.Browser.dev" },
|
|
13821
|
+
BraveSSHTM: { name: "Brave Nightly", id: "com.brave.Browser.nightly" },
|
|
13822
|
+
FirefoxURL: { name: "Firefox", id: "org.mozilla.firefox" },
|
|
13823
|
+
OperaStable: { name: "Opera", id: "com.operasoftware.Opera" },
|
|
13824
|
+
VivaldiHTM: { name: "Vivaldi", id: "com.vivaldi.Vivaldi" },
|
|
13825
|
+
"IE.HTTP": { name: "Internet Explorer", id: "com.microsoft.ie" }
|
|
13826
|
+
};
|
|
13827
|
+
_windowsBrowserProgIdMap = new Map(Object.entries(windowsBrowserProgIds));
|
|
13828
|
+
UnknownBrowserError = class UnknownBrowserError extends Error {
|
|
13829
|
+
};
|
|
13830
|
+
});
|
|
13831
|
+
|
|
13832
|
+
// node_modules/default-browser/index.js
|
|
13833
|
+
import { promisify as promisify6 } from "util";
|
|
13834
|
+
import process7 from "process";
|
|
13835
|
+
import { execFile as execFile6 } from "child_process";
|
|
13836
|
+
async function defaultBrowser2() {
|
|
13837
|
+
if (process7.platform === "darwin") {
|
|
13838
|
+
const id = await defaultBrowserId();
|
|
13839
|
+
const name = await bundleName(id);
|
|
13840
|
+
return { name, id };
|
|
13841
|
+
}
|
|
13842
|
+
if (process7.platform === "linux") {
|
|
13843
|
+
const { stdout } = await execFileAsync4("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
|
|
13844
|
+
const id = stdout.trim();
|
|
13845
|
+
const name = titleize(id.replace(/.desktop$/, "").replace("-", " "));
|
|
13846
|
+
return { name, id };
|
|
13847
|
+
}
|
|
13848
|
+
if (process7.platform === "win32") {
|
|
13849
|
+
return defaultBrowser();
|
|
13850
|
+
}
|
|
13851
|
+
throw new Error("Only macOS, Linux, and Windows are supported");
|
|
13852
|
+
}
|
|
13853
|
+
var execFileAsync4, titleize = (string) => string.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
|
|
13854
|
+
var init_default_browser = __esm(() => {
|
|
13855
|
+
init_default_browser_id();
|
|
13856
|
+
init_bundle_name();
|
|
13857
|
+
init_windows();
|
|
13858
|
+
init_windows();
|
|
13859
|
+
execFileAsync4 = promisify6(execFile6);
|
|
13860
|
+
});
|
|
13861
|
+
|
|
13862
|
+
// node_modules/is-in-ssh/index.js
|
|
13863
|
+
import process8 from "process";
|
|
13864
|
+
var isInSsh, is_in_ssh_default;
|
|
13865
|
+
var init_is_in_ssh = __esm(() => {
|
|
13866
|
+
isInSsh = Boolean(process8.env.SSH_CONNECTION || process8.env.SSH_CLIENT || process8.env.SSH_TTY);
|
|
13867
|
+
is_in_ssh_default = isInSsh;
|
|
13868
|
+
});
|
|
13869
|
+
|
|
13870
|
+
// node_modules/open/index.js
|
|
13871
|
+
var exports_open = {};
|
|
13872
|
+
__export(exports_open, {
|
|
13873
|
+
openApp: () => openApp,
|
|
13874
|
+
default: () => open_default,
|
|
13875
|
+
apps: () => apps
|
|
13876
|
+
});
|
|
13877
|
+
import process9 from "process";
|
|
13878
|
+
import path from "path";
|
|
13879
|
+
import { fileURLToPath } from "url";
|
|
13880
|
+
import childProcess3 from "child_process";
|
|
13881
|
+
import fs5, { constants as fsConstants2 } from "fs/promises";
|
|
13882
|
+
function detectArchBinary(binary) {
|
|
13883
|
+
if (typeof binary === "string" || Array.isArray(binary)) {
|
|
13884
|
+
return binary;
|
|
13885
|
+
}
|
|
13886
|
+
const { [arch]: archBinary } = binary;
|
|
13887
|
+
if (!archBinary) {
|
|
13888
|
+
throw new Error(`${arch} is not supported`);
|
|
13889
|
+
}
|
|
13890
|
+
return archBinary;
|
|
13891
|
+
}
|
|
13892
|
+
function detectPlatformBinary({ [platform]: platformBinary }, { wsl } = {}) {
|
|
13893
|
+
if (wsl && is_wsl_default) {
|
|
13894
|
+
return detectArchBinary(wsl);
|
|
13895
|
+
}
|
|
13896
|
+
if (!platformBinary) {
|
|
13897
|
+
throw new Error(`${platform} is not supported`);
|
|
13898
|
+
}
|
|
13899
|
+
return detectArchBinary(platformBinary);
|
|
13900
|
+
}
|
|
13901
|
+
var fallbackAttemptSymbol, __dirname2, localXdgOpenPath, platform, arch, tryEachApp = async (apps, opener) => {
|
|
13902
|
+
if (apps.length === 0) {
|
|
13903
|
+
return;
|
|
13904
|
+
}
|
|
13905
|
+
const errors = [];
|
|
13906
|
+
for (const app of apps) {
|
|
13907
|
+
try {
|
|
13908
|
+
return await opener(app);
|
|
13909
|
+
} catch (error) {
|
|
13910
|
+
errors.push(error);
|
|
13911
|
+
}
|
|
13912
|
+
}
|
|
13913
|
+
throw new AggregateError(errors, "Failed to open in all supported apps");
|
|
13914
|
+
}, baseOpen = async (options) => {
|
|
13915
|
+
options = {
|
|
13916
|
+
wait: false,
|
|
13917
|
+
background: false,
|
|
13918
|
+
newInstance: false,
|
|
13919
|
+
allowNonzeroExitCode: false,
|
|
13920
|
+
...options
|
|
13921
|
+
};
|
|
13922
|
+
const isFallbackAttempt = options[fallbackAttemptSymbol] === true;
|
|
13923
|
+
delete options[fallbackAttemptSymbol];
|
|
13924
|
+
if (Array.isArray(options.app)) {
|
|
13925
|
+
return tryEachApp(options.app, (singleApp) => baseOpen({
|
|
13926
|
+
...options,
|
|
13927
|
+
app: singleApp,
|
|
13928
|
+
[fallbackAttemptSymbol]: true
|
|
13929
|
+
}));
|
|
13930
|
+
}
|
|
13931
|
+
let { name: app, arguments: appArguments = [] } = options.app ?? {};
|
|
13932
|
+
appArguments = [...appArguments];
|
|
13933
|
+
if (Array.isArray(app)) {
|
|
13934
|
+
return tryEachApp(app, (appName) => baseOpen({
|
|
13935
|
+
...options,
|
|
13936
|
+
app: {
|
|
13937
|
+
name: appName,
|
|
13938
|
+
arguments: appArguments
|
|
13939
|
+
},
|
|
13940
|
+
[fallbackAttemptSymbol]: true
|
|
13941
|
+
}));
|
|
13942
|
+
}
|
|
13943
|
+
if (app === "browser" || app === "browserPrivate") {
|
|
13944
|
+
const ids = {
|
|
13945
|
+
"com.google.chrome": "chrome",
|
|
13946
|
+
"google-chrome.desktop": "chrome",
|
|
13947
|
+
"com.brave.browser": "brave",
|
|
13948
|
+
"org.mozilla.firefox": "firefox",
|
|
13949
|
+
"firefox.desktop": "firefox",
|
|
13950
|
+
"com.microsoft.msedge": "edge",
|
|
13951
|
+
"com.microsoft.edge": "edge",
|
|
13952
|
+
"com.microsoft.edgemac": "edge",
|
|
13953
|
+
"microsoft-edge.desktop": "edge",
|
|
13954
|
+
"com.apple.safari": "safari"
|
|
13955
|
+
};
|
|
13956
|
+
const flags = {
|
|
13957
|
+
chrome: "--incognito",
|
|
13958
|
+
brave: "--incognito",
|
|
13959
|
+
firefox: "--private-window",
|
|
13960
|
+
edge: "--inPrivate"
|
|
13961
|
+
};
|
|
13962
|
+
let browser;
|
|
13963
|
+
if (is_wsl_default) {
|
|
13964
|
+
const progId = await wslDefaultBrowser();
|
|
13965
|
+
const browserInfo = _windowsBrowserProgIdMap.get(progId);
|
|
13966
|
+
browser = browserInfo ?? {};
|
|
13967
|
+
} else {
|
|
13968
|
+
browser = await defaultBrowser2();
|
|
13969
|
+
}
|
|
13970
|
+
if (browser.id in ids) {
|
|
13971
|
+
const browserName = ids[browser.id.toLowerCase()];
|
|
13972
|
+
if (app === "browserPrivate") {
|
|
13973
|
+
if (browserName === "safari") {
|
|
13974
|
+
throw new Error("Safari doesn't support opening in private mode via command line");
|
|
13975
|
+
}
|
|
13976
|
+
appArguments.push(flags[browserName]);
|
|
13977
|
+
}
|
|
13978
|
+
return baseOpen({
|
|
13979
|
+
...options,
|
|
13980
|
+
app: {
|
|
13981
|
+
name: apps[browserName],
|
|
13982
|
+
arguments: appArguments
|
|
13983
|
+
}
|
|
13984
|
+
});
|
|
13985
|
+
}
|
|
13986
|
+
throw new Error(`${browser.name} is not supported as a default browser`);
|
|
13987
|
+
}
|
|
13988
|
+
let command;
|
|
13989
|
+
const cliArguments = [];
|
|
13990
|
+
const childProcessOptions = {};
|
|
13991
|
+
let shouldUseWindowsInWsl = false;
|
|
13992
|
+
if (is_wsl_default && !isInsideContainer() && !is_in_ssh_default && !app) {
|
|
13993
|
+
shouldUseWindowsInWsl = await canAccessPowerShell();
|
|
13994
|
+
}
|
|
13995
|
+
if (platform === "darwin") {
|
|
13996
|
+
command = "open";
|
|
13997
|
+
if (options.wait) {
|
|
13998
|
+
cliArguments.push("--wait-apps");
|
|
13999
|
+
}
|
|
14000
|
+
if (options.background) {
|
|
14001
|
+
cliArguments.push("--background");
|
|
14002
|
+
}
|
|
14003
|
+
if (options.newInstance) {
|
|
14004
|
+
cliArguments.push("--new");
|
|
14005
|
+
}
|
|
14006
|
+
if (app) {
|
|
14007
|
+
cliArguments.push("-a", app);
|
|
14008
|
+
}
|
|
14009
|
+
} else if (platform === "win32" || shouldUseWindowsInWsl) {
|
|
14010
|
+
command = await powerShellPath2();
|
|
14011
|
+
cliArguments.push(...executePowerShell.argumentsPrefix);
|
|
14012
|
+
if (!is_wsl_default) {
|
|
14013
|
+
childProcessOptions.windowsVerbatimArguments = true;
|
|
14014
|
+
}
|
|
14015
|
+
if (is_wsl_default && options.target) {
|
|
14016
|
+
options.target = await convertWslPathToWindows(options.target);
|
|
14017
|
+
}
|
|
14018
|
+
const encodedArguments = ["$ProgressPreference = 'SilentlyContinue';", "Start"];
|
|
14019
|
+
if (options.wait) {
|
|
14020
|
+
encodedArguments.push("-Wait");
|
|
14021
|
+
}
|
|
14022
|
+
if (app) {
|
|
14023
|
+
encodedArguments.push(executePowerShell.escapeArgument(app));
|
|
14024
|
+
if (options.target) {
|
|
14025
|
+
appArguments.push(options.target);
|
|
14026
|
+
}
|
|
14027
|
+
} else if (options.target) {
|
|
14028
|
+
encodedArguments.push(executePowerShell.escapeArgument(options.target));
|
|
14029
|
+
}
|
|
14030
|
+
if (appArguments.length > 0) {
|
|
14031
|
+
appArguments = appArguments.map((argument) => executePowerShell.escapeArgument(argument));
|
|
14032
|
+
encodedArguments.push("-ArgumentList", appArguments.join(","));
|
|
14033
|
+
}
|
|
14034
|
+
options.target = executePowerShell.encodeCommand(encodedArguments.join(" "));
|
|
14035
|
+
if (!options.wait) {
|
|
14036
|
+
childProcessOptions.stdio = "ignore";
|
|
14037
|
+
}
|
|
14038
|
+
} else {
|
|
14039
|
+
if (app) {
|
|
14040
|
+
command = app;
|
|
14041
|
+
} else {
|
|
14042
|
+
const isBundled = !__dirname2 || __dirname2 === "/";
|
|
14043
|
+
let exeLocalXdgOpen = false;
|
|
14044
|
+
try {
|
|
14045
|
+
await fs5.access(localXdgOpenPath, fsConstants2.X_OK);
|
|
14046
|
+
exeLocalXdgOpen = true;
|
|
14047
|
+
} catch {}
|
|
14048
|
+
const useSystemXdgOpen = process9.versions.electron ?? (platform === "android" || isBundled || !exeLocalXdgOpen);
|
|
14049
|
+
command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
|
|
14050
|
+
}
|
|
14051
|
+
if (appArguments.length > 0) {
|
|
14052
|
+
cliArguments.push(...appArguments);
|
|
14053
|
+
}
|
|
14054
|
+
if (!options.wait) {
|
|
14055
|
+
childProcessOptions.stdio = "ignore";
|
|
14056
|
+
childProcessOptions.detached = true;
|
|
14057
|
+
}
|
|
14058
|
+
}
|
|
14059
|
+
if (platform === "darwin" && appArguments.length > 0) {
|
|
14060
|
+
cliArguments.push("--args", ...appArguments);
|
|
14061
|
+
}
|
|
14062
|
+
if (options.target) {
|
|
14063
|
+
cliArguments.push(options.target);
|
|
14064
|
+
}
|
|
14065
|
+
const subprocess = childProcess3.spawn(command, cliArguments, childProcessOptions);
|
|
14066
|
+
if (options.wait) {
|
|
14067
|
+
return new Promise((resolve, reject) => {
|
|
14068
|
+
subprocess.once("error", reject);
|
|
14069
|
+
subprocess.once("close", (exitCode) => {
|
|
14070
|
+
if (!options.allowNonzeroExitCode && exitCode !== 0) {
|
|
14071
|
+
reject(new Error(`Exited with code ${exitCode}`));
|
|
14072
|
+
return;
|
|
14073
|
+
}
|
|
14074
|
+
resolve(subprocess);
|
|
14075
|
+
});
|
|
14076
|
+
});
|
|
14077
|
+
}
|
|
14078
|
+
if (isFallbackAttempt) {
|
|
14079
|
+
return new Promise((resolve, reject) => {
|
|
14080
|
+
subprocess.once("error", reject);
|
|
14081
|
+
subprocess.once("spawn", () => {
|
|
14082
|
+
subprocess.once("close", (exitCode) => {
|
|
14083
|
+
subprocess.off("error", reject);
|
|
14084
|
+
if (exitCode !== 0) {
|
|
14085
|
+
reject(new Error(`Exited with code ${exitCode}`));
|
|
14086
|
+
return;
|
|
14087
|
+
}
|
|
14088
|
+
subprocess.unref();
|
|
14089
|
+
resolve(subprocess);
|
|
14090
|
+
});
|
|
14091
|
+
});
|
|
14092
|
+
});
|
|
14093
|
+
}
|
|
14094
|
+
subprocess.unref();
|
|
14095
|
+
return new Promise((resolve, reject) => {
|
|
14096
|
+
subprocess.once("error", reject);
|
|
14097
|
+
subprocess.once("spawn", () => {
|
|
14098
|
+
subprocess.off("error", reject);
|
|
14099
|
+
resolve(subprocess);
|
|
14100
|
+
});
|
|
14101
|
+
});
|
|
14102
|
+
}, open = (target, options) => {
|
|
14103
|
+
if (typeof target !== "string") {
|
|
14104
|
+
throw new TypeError("Expected a `target`");
|
|
14105
|
+
}
|
|
14106
|
+
return baseOpen({
|
|
14107
|
+
...options,
|
|
14108
|
+
target
|
|
14109
|
+
});
|
|
14110
|
+
}, openApp = (name, options) => {
|
|
14111
|
+
if (typeof name !== "string" && !Array.isArray(name)) {
|
|
14112
|
+
throw new TypeError("Expected a valid `name`");
|
|
14113
|
+
}
|
|
14114
|
+
const { arguments: appArguments = [] } = options ?? {};
|
|
14115
|
+
if (appArguments !== undefined && appArguments !== null && !Array.isArray(appArguments)) {
|
|
14116
|
+
throw new TypeError("Expected `appArguments` as Array type");
|
|
14117
|
+
}
|
|
14118
|
+
return baseOpen({
|
|
14119
|
+
...options,
|
|
14120
|
+
app: {
|
|
14121
|
+
name,
|
|
14122
|
+
arguments: appArguments
|
|
14123
|
+
}
|
|
14124
|
+
});
|
|
14125
|
+
}, apps, open_default;
|
|
14126
|
+
var init_open = __esm(() => {
|
|
14127
|
+
init_wsl_utils();
|
|
14128
|
+
init_powershell_utils();
|
|
14129
|
+
init_default_browser();
|
|
14130
|
+
init_is_inside_container();
|
|
14131
|
+
init_is_in_ssh();
|
|
14132
|
+
fallbackAttemptSymbol = Symbol("fallbackAttempt");
|
|
14133
|
+
__dirname2 = import.meta.url ? path.dirname(fileURLToPath(import.meta.url)) : "";
|
|
14134
|
+
localXdgOpenPath = path.join(__dirname2, "xdg-open");
|
|
14135
|
+
({ platform, arch } = process9);
|
|
14136
|
+
apps = {
|
|
14137
|
+
browser: "browser",
|
|
14138
|
+
browserPrivate: "browserPrivate"
|
|
14139
|
+
};
|
|
14140
|
+
defineLazyProperty(apps, "chrome", () => detectPlatformBinary({
|
|
14141
|
+
darwin: "google chrome",
|
|
14142
|
+
win32: "chrome",
|
|
14143
|
+
linux: ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"]
|
|
14144
|
+
}, {
|
|
14145
|
+
wsl: {
|
|
14146
|
+
ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
|
|
14147
|
+
x64: ["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe", "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"]
|
|
14148
|
+
}
|
|
14149
|
+
}));
|
|
14150
|
+
defineLazyProperty(apps, "brave", () => detectPlatformBinary({
|
|
14151
|
+
darwin: "brave browser",
|
|
14152
|
+
win32: "brave",
|
|
14153
|
+
linux: ["brave-browser", "brave"]
|
|
14154
|
+
}, {
|
|
14155
|
+
wsl: {
|
|
14156
|
+
ia32: "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe",
|
|
14157
|
+
x64: ["/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe", "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe"]
|
|
14158
|
+
}
|
|
14159
|
+
}));
|
|
14160
|
+
defineLazyProperty(apps, "firefox", () => detectPlatformBinary({
|
|
14161
|
+
darwin: "firefox",
|
|
14162
|
+
win32: String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`,
|
|
14163
|
+
linux: "firefox"
|
|
14164
|
+
}, {
|
|
14165
|
+
wsl: "/mnt/c/Program Files/Mozilla Firefox/firefox.exe"
|
|
14166
|
+
}));
|
|
14167
|
+
defineLazyProperty(apps, "edge", () => detectPlatformBinary({
|
|
14168
|
+
darwin: "microsoft edge",
|
|
14169
|
+
win32: "msedge",
|
|
14170
|
+
linux: ["microsoft-edge", "microsoft-edge-dev"]
|
|
14171
|
+
}, {
|
|
14172
|
+
wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"
|
|
14173
|
+
}));
|
|
14174
|
+
defineLazyProperty(apps, "safari", () => detectPlatformBinary({
|
|
14175
|
+
darwin: "Safari"
|
|
14176
|
+
}));
|
|
14177
|
+
open_default = open;
|
|
14178
|
+
});
|
|
14179
|
+
|
|
13525
14180
|
// node_modules/commander/esm.mjs
|
|
13526
14181
|
var import__ = __toESM(require_commander(), 1);
|
|
13527
14182
|
var {
|
|
@@ -13606,6 +14261,7 @@ var ServiceTokens = {
|
|
|
13606
14261
|
ContextService: "ContextService",
|
|
13607
14262
|
OutputService: "OutputService",
|
|
13608
14263
|
HttpClient: "HttpClient",
|
|
14264
|
+
OAuthService: "OAuthService",
|
|
13609
14265
|
VersionService: "VersionService",
|
|
13610
14266
|
PullrequestsApi: "PullrequestsApi",
|
|
13611
14267
|
RepositoriesApi: "RepositoriesApi",
|
|
@@ -13801,6 +14457,7 @@ class ConfigService {
|
|
|
13801
14457
|
const config = await this.getConfig();
|
|
13802
14458
|
await this.setConfig({
|
|
13803
14459
|
...config,
|
|
14460
|
+
authMethod: "basic",
|
|
13804
14461
|
username: credentials.username,
|
|
13805
14462
|
apiToken: credentials.apiToken
|
|
13806
14463
|
});
|
|
@@ -13828,6 +14485,56 @@ class ConfigService {
|
|
|
13828
14485
|
getConfigPath() {
|
|
13829
14486
|
return this.configFile;
|
|
13830
14487
|
}
|
|
14488
|
+
async getAuthMethod() {
|
|
14489
|
+
const config = await this.getConfig();
|
|
14490
|
+
return config.authMethod ?? "basic";
|
|
14491
|
+
}
|
|
14492
|
+
async getOAuthCredentials() {
|
|
14493
|
+
const config = await this.getConfig();
|
|
14494
|
+
const { oauthAccessToken, oauthRefreshToken, oauthExpiresAt } = config;
|
|
14495
|
+
if (!oauthAccessToken || !oauthRefreshToken || !oauthExpiresAt) {
|
|
14496
|
+
throw new BBError({
|
|
14497
|
+
code: 1001 /* AUTH_REQUIRED */,
|
|
14498
|
+
message: "OAuth authentication required. Run 'bb auth login' to authenticate."
|
|
14499
|
+
});
|
|
14500
|
+
}
|
|
14501
|
+
return {
|
|
14502
|
+
accessToken: oauthAccessToken,
|
|
14503
|
+
refreshToken: oauthRefreshToken,
|
|
14504
|
+
expiresAt: oauthExpiresAt
|
|
14505
|
+
};
|
|
14506
|
+
}
|
|
14507
|
+
async setOAuthCredentials(credentials) {
|
|
14508
|
+
const config = await this.getConfig();
|
|
14509
|
+
const { username: _u, apiToken: _t, ...rest } = config;
|
|
14510
|
+
await this.setConfig({
|
|
14511
|
+
...rest,
|
|
14512
|
+
authMethod: "oauth",
|
|
14513
|
+
oauthAccessToken: credentials.accessToken,
|
|
14514
|
+
oauthRefreshToken: credentials.refreshToken,
|
|
14515
|
+
oauthExpiresAt: credentials.expiresAt
|
|
14516
|
+
});
|
|
14517
|
+
}
|
|
14518
|
+
async clearOAuthCredentials() {
|
|
14519
|
+
const config = await this.getConfig();
|
|
14520
|
+
const {
|
|
14521
|
+
authMethod: _am,
|
|
14522
|
+
oauthAccessToken: _at,
|
|
14523
|
+
oauthRefreshToken: _rt,
|
|
14524
|
+
oauthExpiresAt: _ea,
|
|
14525
|
+
oauthClientId: _ci,
|
|
14526
|
+
oauthClientSecret: _cs,
|
|
14527
|
+
...rest
|
|
14528
|
+
} = config;
|
|
14529
|
+
await this.setConfig(rest);
|
|
14530
|
+
}
|
|
14531
|
+
async isOAuthTokenExpired() {
|
|
14532
|
+
const config = await this.getConfig();
|
|
14533
|
+
if (!config.oauthExpiresAt) {
|
|
14534
|
+
return true;
|
|
14535
|
+
}
|
|
14536
|
+
return Date.now() >= (config.oauthExpiresAt - 60) * 1000;
|
|
14537
|
+
}
|
|
13831
14538
|
clearCache() {
|
|
13832
14539
|
this.configCache = null;
|
|
13833
14540
|
}
|
|
@@ -18205,7 +18912,7 @@ function getRetryDelay(error, attempt) {
|
|
|
18205
18912
|
function sleep(ms) {
|
|
18206
18913
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
18207
18914
|
}
|
|
18208
|
-
function createApiClient(configService) {
|
|
18915
|
+
function createApiClient(configService, oauthService) {
|
|
18209
18916
|
const instance = axios_default.create({
|
|
18210
18917
|
baseURL: BASE_URL,
|
|
18211
18918
|
headers: {
|
|
@@ -18217,9 +18924,15 @@ function createApiClient(configService) {
|
|
|
18217
18924
|
if (process.env.DEBUG === "true") {
|
|
18218
18925
|
console.debug(`[HTTP] ${config.method?.toUpperCase()} ${config.url}`);
|
|
18219
18926
|
}
|
|
18220
|
-
const
|
|
18221
|
-
|
|
18222
|
-
|
|
18927
|
+
const authMethod = await configService.getAuthMethod();
|
|
18928
|
+
if (authMethod === "oauth" && oauthService) {
|
|
18929
|
+
const accessToken = await oauthService.getValidAccessToken();
|
|
18930
|
+
config.headers.Authorization = `Bearer ${accessToken}`;
|
|
18931
|
+
} else {
|
|
18932
|
+
const credentials = await configService.getCredentials();
|
|
18933
|
+
const authString = Buffer.from(`${credentials.username}:${credentials.apiToken}`).toString("base64");
|
|
18934
|
+
config.headers.Authorization = `Basic ${authString}`;
|
|
18935
|
+
}
|
|
18223
18936
|
return config;
|
|
18224
18937
|
}, (error) => Promise.reject(error));
|
|
18225
18938
|
instance.interceptors.response.use((response) => {
|
|
@@ -18235,6 +18948,25 @@ function createApiClient(configService) {
|
|
|
18235
18948
|
console.debug(`[HTTP] Error Response Body:`, JSON.stringify(error.response.data, null, 2));
|
|
18236
18949
|
}
|
|
18237
18950
|
}
|
|
18951
|
+
if (error.response?.status === 401 && oauthService) {
|
|
18952
|
+
const config = error.config;
|
|
18953
|
+
if (config && !config.__tokenRefreshed) {
|
|
18954
|
+
const authMethod = await configService.getAuthMethod();
|
|
18955
|
+
if (authMethod === "oauth") {
|
|
18956
|
+
try {
|
|
18957
|
+
config.__tokenRefreshed = true;
|
|
18958
|
+
const newToken = await oauthService.refreshAccessToken();
|
|
18959
|
+
config.headers.Authorization = `Bearer ${newToken}`;
|
|
18960
|
+
return instance(config);
|
|
18961
|
+
} catch {
|
|
18962
|
+
throw new BBError({
|
|
18963
|
+
code: 1003 /* AUTH_EXPIRED */,
|
|
18964
|
+
message: `OAuth token expired. Run 'bb auth login' to re-authenticate.`
|
|
18965
|
+
});
|
|
18966
|
+
}
|
|
18967
|
+
}
|
|
18968
|
+
}
|
|
18969
|
+
}
|
|
18238
18970
|
if (error.response && RETRYABLE_STATUS_CODES.has(error.response.status)) {
|
|
18239
18971
|
const config = error.config;
|
|
18240
18972
|
if (config) {
|
|
@@ -18285,6 +19017,444 @@ function extractErrorMessage(data) {
|
|
|
18285
19017
|
}
|
|
18286
19018
|
return;
|
|
18287
19019
|
}
|
|
19020
|
+
// src/services/oauth.service.ts
|
|
19021
|
+
import { createServer } from "http";
|
|
19022
|
+
import { randomBytes } from "crypto";
|
|
19023
|
+
var BITBUCKET_AUTHORIZE_URL = "https://bitbucket.org/site/oauth2/authorize";
|
|
19024
|
+
var BITBUCKET_TOKEN_URL = "https://bitbucket.org/site/oauth2/access_token";
|
|
19025
|
+
var CALLBACK_PORT = 19872;
|
|
19026
|
+
var CALLBACK_PATH = "/callback";
|
|
19027
|
+
var CALLBACK_URL = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
|
|
19028
|
+
var AUTH_TIMEOUT_MS = 5 * 60 * 1000;
|
|
19029
|
+
var DEFAULT_CLIENT_ID = "ErUBvNmdYtfVHgW6J4";
|
|
19030
|
+
var DEFAULT_CLIENT_SECRET = "QnrWypuKXv7YvU7WJwQRza2n2QfHCEw5";
|
|
19031
|
+
var OAUTH_SCOPES = [
|
|
19032
|
+
"account",
|
|
19033
|
+
"repository",
|
|
19034
|
+
"repository:admin",
|
|
19035
|
+
"pullrequest",
|
|
19036
|
+
"pullrequest:write"
|
|
19037
|
+
].join(" ");
|
|
19038
|
+
function generateState() {
|
|
19039
|
+
return randomBytes(16).toString("hex");
|
|
19040
|
+
}
|
|
19041
|
+
|
|
19042
|
+
class OAuthService {
|
|
19043
|
+
configService;
|
|
19044
|
+
constructor(configService) {
|
|
19045
|
+
this.configService = configService;
|
|
19046
|
+
}
|
|
19047
|
+
async authorize(clientId, clientSecret) {
|
|
19048
|
+
const resolvedClientId = clientId ?? await this.getClientId();
|
|
19049
|
+
const state = generateState();
|
|
19050
|
+
const authUrl = this.buildAuthUrl(resolvedClientId, state);
|
|
19051
|
+
const { code } = await this.waitForCallback(authUrl, state);
|
|
19052
|
+
const tokenResponse = await this.exchangeCode(code, resolvedClientId, clientSecret);
|
|
19053
|
+
const expiresAt = Math.floor(Date.now() / 1000) + tokenResponse.expires_in;
|
|
19054
|
+
await this.configService.setOAuthCredentials({
|
|
19055
|
+
accessToken: tokenResponse.access_token,
|
|
19056
|
+
refreshToken: tokenResponse.refresh_token,
|
|
19057
|
+
expiresAt
|
|
19058
|
+
});
|
|
19059
|
+
if (clientId) {
|
|
19060
|
+
await this.configService.setValue("oauthClientId", clientId);
|
|
19061
|
+
}
|
|
19062
|
+
if (clientSecret) {
|
|
19063
|
+
await this.configService.setValue("oauthClientSecret", clientSecret);
|
|
19064
|
+
}
|
|
19065
|
+
const userInfo = await this.fetchUserInfo(tokenResponse.access_token);
|
|
19066
|
+
return userInfo;
|
|
19067
|
+
}
|
|
19068
|
+
async refreshAccessToken() {
|
|
19069
|
+
const credentials = await this.configService.getOAuthCredentials();
|
|
19070
|
+
const clientId = await this.getClientId();
|
|
19071
|
+
const clientSecret = await this.getClientSecret();
|
|
19072
|
+
const params = new URLSearchParams({
|
|
19073
|
+
grant_type: "refresh_token",
|
|
19074
|
+
refresh_token: credentials.refreshToken
|
|
19075
|
+
});
|
|
19076
|
+
const response = await fetch(BITBUCKET_TOKEN_URL, {
|
|
19077
|
+
method: "POST",
|
|
19078
|
+
headers: {
|
|
19079
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
19080
|
+
Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`
|
|
19081
|
+
},
|
|
19082
|
+
body: params.toString()
|
|
19083
|
+
});
|
|
19084
|
+
if (!response.ok) {
|
|
19085
|
+
const errorBody = await response.text();
|
|
19086
|
+
throw new BBError({
|
|
19087
|
+
code: 1003 /* AUTH_EXPIRED */,
|
|
19088
|
+
message: `Failed to refresh OAuth token. Run 'bb auth login' to re-authenticate.`,
|
|
19089
|
+
context: { status: response.status, body: errorBody }
|
|
19090
|
+
});
|
|
19091
|
+
}
|
|
19092
|
+
const tokenResponse = await response.json();
|
|
19093
|
+
const expiresAt = Math.floor(Date.now() / 1000) + tokenResponse.expires_in;
|
|
19094
|
+
await this.configService.setOAuthCredentials({
|
|
19095
|
+
accessToken: tokenResponse.access_token,
|
|
19096
|
+
refreshToken: tokenResponse.refresh_token,
|
|
19097
|
+
expiresAt
|
|
19098
|
+
});
|
|
19099
|
+
return tokenResponse.access_token;
|
|
19100
|
+
}
|
|
19101
|
+
async revokeToken() {
|
|
19102
|
+
try {
|
|
19103
|
+
const credentials = await this.configService.getOAuthCredentials();
|
|
19104
|
+
const clientId = await this.getClientId();
|
|
19105
|
+
const clientSecret = await this.getClientSecret();
|
|
19106
|
+
const params = new URLSearchParams({
|
|
19107
|
+
token: credentials.accessToken
|
|
19108
|
+
});
|
|
19109
|
+
await fetch("https://bitbucket.org/site/oauth2/revoke", {
|
|
19110
|
+
method: "POST",
|
|
19111
|
+
headers: {
|
|
19112
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
19113
|
+
Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`
|
|
19114
|
+
},
|
|
19115
|
+
body: params.toString()
|
|
19116
|
+
});
|
|
19117
|
+
} catch {}
|
|
19118
|
+
}
|
|
19119
|
+
async getValidAccessToken() {
|
|
19120
|
+
const isExpired = await this.configService.isOAuthTokenExpired();
|
|
19121
|
+
if (isExpired) {
|
|
19122
|
+
return this.refreshAccessToken();
|
|
19123
|
+
}
|
|
19124
|
+
const credentials = await this.configService.getOAuthCredentials();
|
|
19125
|
+
return credentials.accessToken;
|
|
19126
|
+
}
|
|
19127
|
+
async getClientId() {
|
|
19128
|
+
const customClientId = await this.configService.getValue("oauthClientId");
|
|
19129
|
+
return customClientId ?? DEFAULT_CLIENT_ID;
|
|
19130
|
+
}
|
|
19131
|
+
async getClientSecret() {
|
|
19132
|
+
const customSecret = await this.configService.getValue("oauthClientSecret");
|
|
19133
|
+
return customSecret ?? DEFAULT_CLIENT_SECRET;
|
|
19134
|
+
}
|
|
19135
|
+
buildAuthUrl(clientId, state) {
|
|
19136
|
+
const params = new URLSearchParams({
|
|
19137
|
+
client_id: clientId,
|
|
19138
|
+
response_type: "code",
|
|
19139
|
+
redirect_uri: CALLBACK_URL,
|
|
19140
|
+
scope: OAUTH_SCOPES,
|
|
19141
|
+
state
|
|
19142
|
+
});
|
|
19143
|
+
return `${BITBUCKET_AUTHORIZE_URL}?${params.toString()}`;
|
|
19144
|
+
}
|
|
19145
|
+
async waitForCallback(authUrl, expectedState) {
|
|
19146
|
+
return new Promise((resolve, reject) => {
|
|
19147
|
+
let server;
|
|
19148
|
+
let timeout;
|
|
19149
|
+
const cleanup = () => {
|
|
19150
|
+
clearTimeout(timeout);
|
|
19151
|
+
server?.close();
|
|
19152
|
+
};
|
|
19153
|
+
timeout = setTimeout(() => {
|
|
19154
|
+
cleanup();
|
|
19155
|
+
reject(new BBError({
|
|
19156
|
+
code: 1002 /* AUTH_INVALID */,
|
|
19157
|
+
message: "Authorization timed out. Please try again."
|
|
19158
|
+
}));
|
|
19159
|
+
}, AUTH_TIMEOUT_MS);
|
|
19160
|
+
server = createServer((req, res) => {
|
|
19161
|
+
const url2 = new URL(req.url ?? "/", `http://localhost:${CALLBACK_PORT}`);
|
|
19162
|
+
if (url2.pathname !== CALLBACK_PATH) {
|
|
19163
|
+
res.writeHead(404);
|
|
19164
|
+
res.end("Not found");
|
|
19165
|
+
return;
|
|
19166
|
+
}
|
|
19167
|
+
const code = url2.searchParams.get("code");
|
|
19168
|
+
const state = url2.searchParams.get("state");
|
|
19169
|
+
const error = url2.searchParams.get("error");
|
|
19170
|
+
const errorDescription = url2.searchParams.get("error_description");
|
|
19171
|
+
if (error) {
|
|
19172
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
19173
|
+
res.end(this.buildErrorPage(errorDescription ?? error));
|
|
19174
|
+
cleanup();
|
|
19175
|
+
reject(new BBError({
|
|
19176
|
+
code: 1002 /* AUTH_INVALID */,
|
|
19177
|
+
message: `Authorization was denied: ${errorDescription ?? error}. Run "bb auth login --app-password" to use an API token instead.`
|
|
19178
|
+
}));
|
|
19179
|
+
return;
|
|
19180
|
+
}
|
|
19181
|
+
if (!code || state !== expectedState) {
|
|
19182
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
19183
|
+
res.end(this.buildErrorPage("Invalid callback parameters"));
|
|
19184
|
+
cleanup();
|
|
19185
|
+
reject(new BBError({
|
|
19186
|
+
code: 1002 /* AUTH_INVALID */,
|
|
19187
|
+
message: "Invalid authorization callback. Please try again."
|
|
19188
|
+
}));
|
|
19189
|
+
return;
|
|
19190
|
+
}
|
|
19191
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
19192
|
+
res.end(this.buildSuccessPage());
|
|
19193
|
+
cleanup();
|
|
19194
|
+
resolve({ code });
|
|
19195
|
+
});
|
|
19196
|
+
server.on("error", (err) => {
|
|
19197
|
+
cleanup();
|
|
19198
|
+
if (err.code === "EADDRINUSE") {
|
|
19199
|
+
reject(new BBError({
|
|
19200
|
+
code: 1002 /* AUTH_INVALID */,
|
|
19201
|
+
message: `Port ${CALLBACK_PORT} is already in use. Close the application using it and try again.`
|
|
19202
|
+
}));
|
|
19203
|
+
} else {
|
|
19204
|
+
reject(new BBError({
|
|
19205
|
+
code: 7001 /* NETWORK_ERROR */,
|
|
19206
|
+
message: `Failed to start callback server: ${err.message}`,
|
|
19207
|
+
cause: err
|
|
19208
|
+
}));
|
|
19209
|
+
}
|
|
19210
|
+
});
|
|
19211
|
+
server.listen(CALLBACK_PORT, async () => {
|
|
19212
|
+
try {
|
|
19213
|
+
const open2 = (await Promise.resolve().then(() => (init_open(), exports_open))).default;
|
|
19214
|
+
await open2(authUrl);
|
|
19215
|
+
} catch {}
|
|
19216
|
+
console.error(`If the browser doesn't open, visit:
|
|
19217
|
+
${authUrl}
|
|
19218
|
+
`);
|
|
19219
|
+
});
|
|
19220
|
+
});
|
|
19221
|
+
}
|
|
19222
|
+
async exchangeCode(code, clientId, clientSecretOverride) {
|
|
19223
|
+
const clientSecret = clientSecretOverride ?? await this.getClientSecret();
|
|
19224
|
+
const params = new URLSearchParams({
|
|
19225
|
+
grant_type: "authorization_code",
|
|
19226
|
+
code,
|
|
19227
|
+
redirect_uri: CALLBACK_URL
|
|
19228
|
+
});
|
|
19229
|
+
const response = await fetch(BITBUCKET_TOKEN_URL, {
|
|
19230
|
+
method: "POST",
|
|
19231
|
+
headers: {
|
|
19232
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
19233
|
+
Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`
|
|
19234
|
+
},
|
|
19235
|
+
body: params.toString()
|
|
19236
|
+
});
|
|
19237
|
+
if (!response.ok) {
|
|
19238
|
+
const errorBody = await response.text();
|
|
19239
|
+
throw new BBError({
|
|
19240
|
+
code: 1002 /* AUTH_INVALID */,
|
|
19241
|
+
message: `Failed to exchange authorization code. Please try again.`,
|
|
19242
|
+
context: { status: response.status, body: errorBody }
|
|
19243
|
+
});
|
|
19244
|
+
}
|
|
19245
|
+
return await response.json();
|
|
19246
|
+
}
|
|
19247
|
+
async fetchUserInfo(accessToken) {
|
|
19248
|
+
const response = await fetch("https://api.bitbucket.org/2.0/user", {
|
|
19249
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
19250
|
+
});
|
|
19251
|
+
if (!response.ok) {
|
|
19252
|
+
throw new BBError({
|
|
19253
|
+
code: 1002 /* AUTH_INVALID */,
|
|
19254
|
+
message: "Failed to verify OAuth credentials."
|
|
19255
|
+
});
|
|
19256
|
+
}
|
|
19257
|
+
const user = await response.json();
|
|
19258
|
+
return {
|
|
19259
|
+
username: user.username,
|
|
19260
|
+
displayName: user.display_name,
|
|
19261
|
+
accountId: user.account_id
|
|
19262
|
+
};
|
|
19263
|
+
}
|
|
19264
|
+
buildPageShell(content) {
|
|
19265
|
+
return `<!DOCTYPE html>
|
|
19266
|
+
<html lang="en"><head>
|
|
19267
|
+
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
19268
|
+
<title>Bitbucket CLI</title>
|
|
19269
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
19270
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
19271
|
+
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=Space+Grotesk:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
19272
|
+
<style>
|
|
19273
|
+
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
|
19274
|
+
:root{
|
|
19275
|
+
--bg:#181c24;
|
|
19276
|
+
--surface:#1e2330;
|
|
19277
|
+
--border:hsl(216,24%,27%);
|
|
19278
|
+
--text:#e0e4ec;
|
|
19279
|
+
--text-dim:#8892a4;
|
|
19280
|
+
--accent:hsl(216,100%,50%);
|
|
19281
|
+
--accent-glow:hsla(216,100%,52%,0.2);
|
|
19282
|
+
--accent-soft:hsla(216,100%,52%,0.09);
|
|
19283
|
+
--font:'Space Grotesk',sans-serif;
|
|
19284
|
+
--mono:'IBM Plex Mono',monospace;
|
|
19285
|
+
}
|
|
19286
|
+
body{
|
|
19287
|
+
font-family:var(--font);
|
|
19288
|
+
background:var(--bg);
|
|
19289
|
+
color:var(--text);
|
|
19290
|
+
min-height:100vh;
|
|
19291
|
+
display:flex;
|
|
19292
|
+
align-items:center;
|
|
19293
|
+
justify-content:center;
|
|
19294
|
+
background-image:
|
|
19295
|
+
radial-gradient(ellipse 80% 60% at 50% 0%,var(--accent-glow),transparent),
|
|
19296
|
+
radial-gradient(circle at 100% 100%,var(--accent-soft),transparent 50%);
|
|
19297
|
+
}
|
|
19298
|
+
.scene{
|
|
19299
|
+
display:flex;
|
|
19300
|
+
flex-direction:column;
|
|
19301
|
+
align-items:center;
|
|
19302
|
+
gap:2rem;
|
|
19303
|
+
animation:enter 600ms cubic-bezier(.16,1,.3,1) both;
|
|
19304
|
+
}
|
|
19305
|
+
@keyframes enter{
|
|
19306
|
+
from{opacity:0;transform:translateY(16px) scale(.97)}
|
|
19307
|
+
to{opacity:1;transform:translateY(0) scale(1)}
|
|
19308
|
+
}
|
|
19309
|
+
.logo{
|
|
19310
|
+
width:56px;height:56px;
|
|
19311
|
+
background:var(--accent);
|
|
19312
|
+
border-radius:14px;
|
|
19313
|
+
display:flex;align-items:center;justify-content:center;
|
|
19314
|
+
font-family:var(--mono);font-weight:700;font-size:24px;
|
|
19315
|
+
color:#fff;
|
|
19316
|
+
box-shadow:0 0 0 1px hsla(216,100%,70%,0.15),0 8px 32px hsla(216,100%,40%,0.25);
|
|
19317
|
+
animation:logo-in 700ms cubic-bezier(.16,1,.3,1) both;
|
|
19318
|
+
animation-delay:100ms;
|
|
19319
|
+
}
|
|
19320
|
+
@keyframes logo-in{
|
|
19321
|
+
from{opacity:0;transform:scale(.6) rotate(-8deg)}
|
|
19322
|
+
to{opacity:1;transform:scale(1) rotate(0)}
|
|
19323
|
+
}
|
|
19324
|
+
.card{
|
|
19325
|
+
background:var(--surface);
|
|
19326
|
+
border:1px solid var(--border);
|
|
19327
|
+
border-radius:16px;
|
|
19328
|
+
padding:2.5rem 3rem;
|
|
19329
|
+
text-align:center;
|
|
19330
|
+
max-width:420px;
|
|
19331
|
+
width:100%;
|
|
19332
|
+
box-shadow:0 1px 2px rgba(0,0,0,0.2),0 16px 48px rgba(0,0,0,0.15);
|
|
19333
|
+
animation:card-in 600ms cubic-bezier(.16,1,.3,1) both;
|
|
19334
|
+
animation-delay:200ms;
|
|
19335
|
+
}
|
|
19336
|
+
@keyframes card-in{
|
|
19337
|
+
from{opacity:0;transform:translateY(12px)}
|
|
19338
|
+
to{opacity:1;transform:translateY(0)}
|
|
19339
|
+
}
|
|
19340
|
+
.icon-ring{
|
|
19341
|
+
width:52px;height:52px;
|
|
19342
|
+
border-radius:50%;
|
|
19343
|
+
display:flex;align-items:center;justify-content:center;
|
|
19344
|
+
margin:0 auto 1.25rem;
|
|
19345
|
+
animation:ring-pop 500ms cubic-bezier(.16,1,.3,1) both;
|
|
19346
|
+
animation-delay:450ms;
|
|
19347
|
+
}
|
|
19348
|
+
@keyframes ring-pop{
|
|
19349
|
+
from{opacity:0;transform:scale(.5)}
|
|
19350
|
+
to{opacity:1;transform:scale(1)}
|
|
19351
|
+
}
|
|
19352
|
+
.icon-ring svg{width:28px;height:28px}
|
|
19353
|
+
.icon-ring.success{background:hsla(152,68%,46%,0.12);color:hsl(152,68%,46%)}
|
|
19354
|
+
.icon-ring.error{background:hsla(0,72%,56%,0.12);color:hsl(0,72%,56%)}
|
|
19355
|
+
h1{
|
|
19356
|
+
font-size:1.35rem;font-weight:700;
|
|
19357
|
+
letter-spacing:-0.02em;
|
|
19358
|
+
margin-bottom:0.5rem;
|
|
19359
|
+
animation:text-in 500ms ease both;animation-delay:500ms;
|
|
19360
|
+
}
|
|
19361
|
+
.subtitle{
|
|
19362
|
+
font-size:0.9rem;color:var(--text-dim);
|
|
19363
|
+
line-height:1.5;
|
|
19364
|
+
animation:text-in 500ms ease both;animation-delay:580ms;
|
|
19365
|
+
}
|
|
19366
|
+
@keyframes text-in{
|
|
19367
|
+
from{opacity:0;transform:translateY(6px)}
|
|
19368
|
+
to{opacity:1;transform:translateY(0)}
|
|
19369
|
+
}
|
|
19370
|
+
.hint{
|
|
19371
|
+
font-family:var(--mono);font-size:0.72rem;
|
|
19372
|
+
color:var(--text-dim);letter-spacing:0.02em;
|
|
19373
|
+
opacity:0;animation:text-in 500ms ease forwards;animation-delay:700ms;
|
|
19374
|
+
}
|
|
19375
|
+
.hint a{
|
|
19376
|
+
color:var(--accent);text-decoration:none;
|
|
19377
|
+
text-underline-offset:0.2em;
|
|
19378
|
+
}
|
|
19379
|
+
.hint a:hover{text-decoration:underline}
|
|
19380
|
+
.hint kbd{
|
|
19381
|
+
background:var(--surface);border:1px solid var(--border);
|
|
19382
|
+
border-radius:4px;padding:0.15em 0.45em;
|
|
19383
|
+
font-family:var(--mono);font-size:0.72rem;
|
|
19384
|
+
}
|
|
19385
|
+
</style>
|
|
19386
|
+
</head><body>
|
|
19387
|
+
<div class="scene">
|
|
19388
|
+
<div class="logo">bb</div>
|
|
19389
|
+
<div class="card">${content}</div>
|
|
19390
|
+
</div>
|
|
19391
|
+
</body></html>`;
|
|
19392
|
+
}
|
|
19393
|
+
buildSuccessPage() {
|
|
19394
|
+
return this.buildPageShell(`
|
|
19395
|
+
<div class="icon-ring success">
|
|
19396
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
19397
|
+
<polyline points="20 6 9 17 4 12"/>
|
|
19398
|
+
</svg>
|
|
19399
|
+
</div>
|
|
19400
|
+
<h1>Authenticated</h1>
|
|
19401
|
+
<p class="subtitle">You're all set. Close this tab and return to your terminal.</p>
|
|
19402
|
+
<p class="hint"><a href="https://bitbucket-cli.paulvanderlei.com" target="_blank" rel="noopener">View documentation</a></p>
|
|
19403
|
+
`);
|
|
19404
|
+
}
|
|
19405
|
+
buildErrorPage(message) {
|
|
19406
|
+
const escaped = message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
19407
|
+
return this.buildPageShell(`
|
|
19408
|
+
<div class="icon-ring error">
|
|
19409
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
19410
|
+
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
|
|
19411
|
+
</svg>
|
|
19412
|
+
</div>
|
|
19413
|
+
<h1>Authentication Failed</h1>
|
|
19414
|
+
<p class="subtitle">${escaped}</p>
|
|
19415
|
+
<p class="hint"><a href="https://bitbucket-cli.paulvanderlei.com/help/troubleshooting/" target="_blank" rel="noopener">Troubleshooting guide</a></p>
|
|
19416
|
+
`);
|
|
19417
|
+
}
|
|
19418
|
+
}
|
|
19419
|
+
// src/services/reviewer.service.ts
|
|
19420
|
+
function extractReviewerUuids(reviewers) {
|
|
19421
|
+
if (!reviewers) {
|
|
19422
|
+
return [];
|
|
19423
|
+
}
|
|
19424
|
+
const list = Array.from(reviewers);
|
|
19425
|
+
const uuids = [];
|
|
19426
|
+
for (const reviewer of list) {
|
|
19427
|
+
if (reviewer.uuid) {
|
|
19428
|
+
uuids.push(reviewer.uuid);
|
|
19429
|
+
}
|
|
19430
|
+
}
|
|
19431
|
+
return uuids;
|
|
19432
|
+
}
|
|
19433
|
+
function buildReviewersUpdateBody(uuids) {
|
|
19434
|
+
const body = {
|
|
19435
|
+
type: "pullrequest",
|
|
19436
|
+
reviewers: uuids.map((uuid) => ({ type: "user", uuid }))
|
|
19437
|
+
};
|
|
19438
|
+
return body;
|
|
19439
|
+
}
|
|
19440
|
+
async function updatePullRequestReviewers(pullrequestsApi, repoContext, prId, transformUuids) {
|
|
19441
|
+
const prResponse = await pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdGet({
|
|
19442
|
+
workspace: repoContext.workspace,
|
|
19443
|
+
repoSlug: repoContext.repoSlug,
|
|
19444
|
+
pullRequestId: prId
|
|
19445
|
+
});
|
|
19446
|
+
const pr = prResponse.data;
|
|
19447
|
+
const currentUuids = extractReviewerUuids(pr.reviewers);
|
|
19448
|
+
const updatedUuids = transformUuids(currentUuids);
|
|
19449
|
+
const body = buildReviewersUpdateBody(updatedUuids);
|
|
19450
|
+
const response = await pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdPut({
|
|
19451
|
+
workspace: repoContext.workspace,
|
|
19452
|
+
repoSlug: repoContext.repoSlug,
|
|
19453
|
+
pullRequestId: prId,
|
|
19454
|
+
body
|
|
19455
|
+
});
|
|
19456
|
+
return response.data;
|
|
19457
|
+
}
|
|
18288
19458
|
// src/bootstrap.ts
|
|
18289
19459
|
import { createRequire } from "module";
|
|
18290
19460
|
|
|
@@ -19996,12 +21166,12 @@ var RepositoriesApiAxiosParamCreator = function(configuration) {
|
|
|
19996
21166
|
options: localVarRequestOptions
|
|
19997
21167
|
};
|
|
19998
21168
|
},
|
|
19999
|
-
repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet: async (commit,
|
|
21169
|
+
repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet: async (commit, path2, repoSlug, workspace, renames, q, sort, options = {}) => {
|
|
20000
21170
|
assertParamExists("repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet", "commit", commit);
|
|
20001
|
-
assertParamExists("repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet", "path",
|
|
21171
|
+
assertParamExists("repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet", "path", path2);
|
|
20002
21172
|
assertParamExists("repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet", "repoSlug", repoSlug);
|
|
20003
21173
|
assertParamExists("repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet", "workspace", workspace);
|
|
20004
|
-
const localVarPath = `/repositories/{workspace}/{repo_slug}/filehistory/{commit}/{path}`.replace(`{${"commit"}}`, encodeURIComponent(String(commit))).replace(`{${"path"}}`, encodeURIComponent(String(
|
|
21174
|
+
const localVarPath = `/repositories/{workspace}/{repo_slug}/filehistory/{commit}/{path}`.replace(`{${"commit"}}`, encodeURIComponent(String(commit))).replace(`{${"path"}}`, encodeURIComponent(String(path2))).replace(`{${"repo_slug"}}`, encodeURIComponent(String(repoSlug))).replace(`{${"workspace"}}`, encodeURIComponent(String(workspace)));
|
|
20005
21175
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
20006
21176
|
let baseOptions;
|
|
20007
21177
|
if (configuration) {
|
|
@@ -20541,12 +21711,12 @@ var RepositoriesApiAxiosParamCreator = function(configuration) {
|
|
|
20541
21711
|
options: localVarRequestOptions
|
|
20542
21712
|
};
|
|
20543
21713
|
},
|
|
20544
|
-
repositoriesWorkspaceRepoSlugSrcCommitPathGet: async (commit,
|
|
21714
|
+
repositoriesWorkspaceRepoSlugSrcCommitPathGet: async (commit, path2, repoSlug, workspace, format, q, sort, maxDepth, options = {}) => {
|
|
20545
21715
|
assertParamExists("repositoriesWorkspaceRepoSlugSrcCommitPathGet", "commit", commit);
|
|
20546
|
-
assertParamExists("repositoriesWorkspaceRepoSlugSrcCommitPathGet", "path",
|
|
21716
|
+
assertParamExists("repositoriesWorkspaceRepoSlugSrcCommitPathGet", "path", path2);
|
|
20547
21717
|
assertParamExists("repositoriesWorkspaceRepoSlugSrcCommitPathGet", "repoSlug", repoSlug);
|
|
20548
21718
|
assertParamExists("repositoriesWorkspaceRepoSlugSrcCommitPathGet", "workspace", workspace);
|
|
20549
|
-
const localVarPath = `/repositories/{workspace}/{repo_slug}/src/{commit}/{path}`.replace(`{${"commit"}}`, encodeURIComponent(String(commit))).replace(`{${"path"}}`, encodeURIComponent(String(
|
|
21719
|
+
const localVarPath = `/repositories/{workspace}/{repo_slug}/src/{commit}/{path}`.replace(`{${"commit"}}`, encodeURIComponent(String(commit))).replace(`{${"path"}}`, encodeURIComponent(String(path2))).replace(`{${"repo_slug"}}`, encodeURIComponent(String(repoSlug))).replace(`{${"workspace"}}`, encodeURIComponent(String(workspace)));
|
|
20550
21720
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
20551
21721
|
let baseOptions;
|
|
20552
21722
|
if (configuration) {
|
|
@@ -20720,8 +21890,8 @@ var RepositoriesApiFp = function(configuration) {
|
|
|
20720
21890
|
const localVarOperationServerBasePath = operationServerMap["RepositoriesApi.repositoriesWorkspaceRepoSlugDelete"]?.[localVarOperationServerIndex]?.url;
|
|
20721
21891
|
return (axios2, basePath) => createRequestFunction(localVarAxiosArgs, axios_default, BASE_PATH, configuration)(axios2, localVarOperationServerBasePath || basePath);
|
|
20722
21892
|
},
|
|
20723
|
-
async repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet(commit,
|
|
20724
|
-
const localVarAxiosArgs = await localVarAxiosParamCreator.repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet(commit,
|
|
21893
|
+
async repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet(commit, path2, repoSlug, workspace, renames, q, sort, options) {
|
|
21894
|
+
const localVarAxiosArgs = await localVarAxiosParamCreator.repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet(commit, path2, repoSlug, workspace, renames, q, sort, options);
|
|
20725
21895
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
|
20726
21896
|
const localVarOperationServerBasePath = operationServerMap["RepositoriesApi.repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet"]?.[localVarOperationServerIndex]?.url;
|
|
20727
21897
|
return (axios2, basePath) => createRequestFunction(localVarAxiosArgs, axios_default, BASE_PATH, configuration)(axios2, localVarOperationServerBasePath || basePath);
|
|
@@ -20846,8 +22016,8 @@ var RepositoriesApiFp = function(configuration) {
|
|
|
20846
22016
|
const localVarOperationServerBasePath = operationServerMap["RepositoriesApi.repositoriesWorkspaceRepoSlugPut"]?.[localVarOperationServerIndex]?.url;
|
|
20847
22017
|
return (axios2, basePath) => createRequestFunction(localVarAxiosArgs, axios_default, BASE_PATH, configuration)(axios2, localVarOperationServerBasePath || basePath);
|
|
20848
22018
|
},
|
|
20849
|
-
async repositoriesWorkspaceRepoSlugSrcCommitPathGet(commit,
|
|
20850
|
-
const localVarAxiosArgs = await localVarAxiosParamCreator.repositoriesWorkspaceRepoSlugSrcCommitPathGet(commit,
|
|
22019
|
+
async repositoriesWorkspaceRepoSlugSrcCommitPathGet(commit, path2, repoSlug, workspace, format, q, sort, maxDepth, options) {
|
|
22020
|
+
const localVarAxiosArgs = await localVarAxiosParamCreator.repositoriesWorkspaceRepoSlugSrcCommitPathGet(commit, path2, repoSlug, workspace, format, q, sort, maxDepth, options);
|
|
20851
22021
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
|
20852
22022
|
const localVarOperationServerBasePath = operationServerMap["RepositoriesApi.repositoriesWorkspaceRepoSlugSrcCommitPathGet"]?.[localVarOperationServerIndex]?.url;
|
|
20853
22023
|
return (axios2, basePath) => createRequestFunction(localVarAxiosArgs, axios_default, BASE_PATH, configuration)(axios2, localVarOperationServerBasePath || basePath);
|
|
@@ -21184,14 +22354,45 @@ class BaseCommand {
|
|
|
21184
22354
|
class LoginCommand extends BaseCommand {
|
|
21185
22355
|
configService;
|
|
21186
22356
|
usersApi;
|
|
22357
|
+
oauthService;
|
|
21187
22358
|
name = "login";
|
|
21188
|
-
description = "Authenticate with Bitbucket
|
|
21189
|
-
constructor(configService, usersApi, output) {
|
|
22359
|
+
description = "Authenticate with Bitbucket";
|
|
22360
|
+
constructor(configService, usersApi, oauthService, output) {
|
|
21190
22361
|
super(output);
|
|
21191
22362
|
this.configService = configService;
|
|
21192
22363
|
this.usersApi = usersApi;
|
|
22364
|
+
this.oauthService = oauthService;
|
|
21193
22365
|
}
|
|
21194
22366
|
async execute(options, context) {
|
|
22367
|
+
const useAppPassword = options.appPassword || options.username !== undefined || options.password !== undefined || process.env.BB_API_TOKEN !== undefined;
|
|
22368
|
+
if (useAppPassword) {
|
|
22369
|
+
return this.loginWithApiToken(options, context);
|
|
22370
|
+
}
|
|
22371
|
+
return this.loginWithOAuth(options, context);
|
|
22372
|
+
}
|
|
22373
|
+
async loginWithOAuth(options, context) {
|
|
22374
|
+
this.output.info("Opening browser to authenticate with Bitbucket...");
|
|
22375
|
+
try {
|
|
22376
|
+
const userInfo = await this.oauthService.authorize(options.clientId, options.clientSecret);
|
|
22377
|
+
if (context.globalOptions.json) {
|
|
22378
|
+
this.output.json({
|
|
22379
|
+
authenticated: true,
|
|
22380
|
+
method: "oauth",
|
|
22381
|
+
user: {
|
|
22382
|
+
username: userInfo.username,
|
|
22383
|
+
displayName: userInfo.displayName,
|
|
22384
|
+
accountId: userInfo.accountId
|
|
22385
|
+
}
|
|
22386
|
+
});
|
|
22387
|
+
return;
|
|
22388
|
+
}
|
|
22389
|
+
this.output.success(`Logged in as ${userInfo.displayName} (${userInfo.username})`);
|
|
22390
|
+
} catch (error) {
|
|
22391
|
+
await this.configService.clearOAuthCredentials();
|
|
22392
|
+
throw error;
|
|
22393
|
+
}
|
|
22394
|
+
}
|
|
22395
|
+
async loginWithApiToken(options, context) {
|
|
21195
22396
|
const username = options.username || process.env.BB_USERNAME;
|
|
21196
22397
|
const apiToken = options.password || process.env.BB_API_TOKEN;
|
|
21197
22398
|
if (!username) {
|
|
@@ -21206,6 +22407,7 @@ class LoginCommand extends BaseCommand {
|
|
|
21206
22407
|
message: "API token is required. Use --password option or set BB_API_TOKEN environment variable."
|
|
21207
22408
|
});
|
|
21208
22409
|
}
|
|
22410
|
+
await this.configService.clearOAuthCredentials();
|
|
21209
22411
|
await this.configService.setCredentials({ username, apiToken });
|
|
21210
22412
|
try {
|
|
21211
22413
|
const response = await this.usersApi.userGet();
|
|
@@ -21213,6 +22415,7 @@ class LoginCommand extends BaseCommand {
|
|
|
21213
22415
|
if (context.globalOptions.json) {
|
|
21214
22416
|
this.output.json({
|
|
21215
22417
|
authenticated: true,
|
|
22418
|
+
method: "api_token",
|
|
21216
22419
|
user: {
|
|
21217
22420
|
username: user.username,
|
|
21218
22421
|
displayName: user.display_name,
|
|
@@ -21235,14 +22438,22 @@ class LoginCommand extends BaseCommand {
|
|
|
21235
22438
|
// src/commands/auth/logout.command.ts
|
|
21236
22439
|
class LogoutCommand extends BaseCommand {
|
|
21237
22440
|
configService;
|
|
22441
|
+
oauthService;
|
|
21238
22442
|
name = "logout";
|
|
21239
22443
|
description = "Log out of Bitbucket";
|
|
21240
|
-
constructor(configService, output) {
|
|
22444
|
+
constructor(configService, oauthService, output) {
|
|
21241
22445
|
super(output);
|
|
21242
22446
|
this.configService = configService;
|
|
22447
|
+
this.oauthService = oauthService;
|
|
21243
22448
|
}
|
|
21244
22449
|
async execute(_options, context) {
|
|
21245
|
-
await this.configService.
|
|
22450
|
+
const authMethod = await this.configService.getAuthMethod();
|
|
22451
|
+
if (authMethod === "oauth") {
|
|
22452
|
+
await this.oauthService.revokeToken();
|
|
22453
|
+
await this.configService.clearOAuthCredentials();
|
|
22454
|
+
} else {
|
|
22455
|
+
await this.configService.clearCredentials();
|
|
22456
|
+
}
|
|
21246
22457
|
if (context.globalOptions.json) {
|
|
21247
22458
|
this.output.json({ authenticated: false, success: true });
|
|
21248
22459
|
return;
|
|
@@ -21264,7 +22475,10 @@ class StatusCommand extends BaseCommand {
|
|
|
21264
22475
|
}
|
|
21265
22476
|
async execute(_options, context) {
|
|
21266
22477
|
const config = await this.configService.getConfig();
|
|
21267
|
-
|
|
22478
|
+
const authMethod = await this.configService.getAuthMethod();
|
|
22479
|
+
const hasBasicAuth = config.username && config.apiToken;
|
|
22480
|
+
const hasOAuth = config.oauthAccessToken && config.oauthRefreshToken;
|
|
22481
|
+
if (!hasBasicAuth && !hasOAuth) {
|
|
21268
22482
|
if (context.globalOptions.json) {
|
|
21269
22483
|
this.output.json({ authenticated: false });
|
|
21270
22484
|
return;
|
|
@@ -21277,21 +22491,41 @@ class StatusCommand extends BaseCommand {
|
|
|
21277
22491
|
const response = await this.usersApi.userGet();
|
|
21278
22492
|
const user = response.data;
|
|
21279
22493
|
if (context.globalOptions.json) {
|
|
21280
|
-
|
|
22494
|
+
const jsonOutput = {
|
|
21281
22495
|
authenticated: true,
|
|
22496
|
+
method: authMethod,
|
|
21282
22497
|
user: {
|
|
21283
22498
|
username: user.username,
|
|
21284
22499
|
displayName: user.display_name,
|
|
21285
22500
|
accountId: user.account_id
|
|
21286
22501
|
},
|
|
21287
22502
|
defaultWorkspace: config.defaultWorkspace
|
|
21288
|
-
}
|
|
22503
|
+
};
|
|
22504
|
+
if (authMethod === "oauth" && config.oauthExpiresAt) {
|
|
22505
|
+
jsonOutput.tokenExpiresAt = config.oauthExpiresAt;
|
|
22506
|
+
}
|
|
22507
|
+
this.output.json(jsonOutput);
|
|
21289
22508
|
return;
|
|
21290
22509
|
}
|
|
21291
22510
|
this.output.success("Logged in to Bitbucket");
|
|
22511
|
+
this.output.text(` Authentication: ${this.output.highlight(authMethod === "oauth" ? "OAuth" : "API Token")}`);
|
|
21292
22512
|
this.output.text(` Username: ${this.output.highlight(user.username ?? "")}`);
|
|
21293
22513
|
this.output.text(` Display name: ${user.display_name}`);
|
|
21294
22514
|
this.output.text(` Account ID: ${user.account_id}`);
|
|
22515
|
+
if (authMethod === "oauth" && config.oauthExpiresAt) {
|
|
22516
|
+
const expiresIn = config.oauthExpiresAt - Math.floor(Date.now() / 1000);
|
|
22517
|
+
if (expiresIn > 0) {
|
|
22518
|
+
const hours = Math.floor(expiresIn / 3600);
|
|
22519
|
+
const minutes = Math.floor(expiresIn % 3600 / 60);
|
|
22520
|
+
const parts = [];
|
|
22521
|
+
if (hours > 0)
|
|
22522
|
+
parts.push(`${hours}h`);
|
|
22523
|
+
parts.push(`${minutes}m`);
|
|
22524
|
+
this.output.text(` Token expires: in ${parts.join(" ")}`);
|
|
22525
|
+
} else {
|
|
22526
|
+
this.output.text(` Token expires: ${this.output.yellow("expired (will refresh automatically)")}`);
|
|
22527
|
+
}
|
|
22528
|
+
}
|
|
21295
22529
|
if (config.defaultWorkspace) {
|
|
21296
22530
|
this.output.text(` Default workspace: ${this.output.highlight(config.defaultWorkspace)}`);
|
|
21297
22531
|
}
|
|
@@ -21308,13 +22542,25 @@ class StatusCommand extends BaseCommand {
|
|
|
21308
22542
|
// src/commands/auth/token.command.ts
|
|
21309
22543
|
class TokenCommand extends BaseCommand {
|
|
21310
22544
|
configService;
|
|
22545
|
+
oauthService;
|
|
21311
22546
|
name = "token";
|
|
21312
22547
|
description = "Print the current access token";
|
|
21313
|
-
constructor(configService, output) {
|
|
22548
|
+
constructor(configService, oauthService, output) {
|
|
21314
22549
|
super(output);
|
|
21315
22550
|
this.configService = configService;
|
|
22551
|
+
this.oauthService = oauthService;
|
|
21316
22552
|
}
|
|
21317
22553
|
async execute(_options, context) {
|
|
22554
|
+
const authMethod = await this.configService.getAuthMethod();
|
|
22555
|
+
if (authMethod === "oauth") {
|
|
22556
|
+
const accessToken = await this.oauthService.getValidAccessToken();
|
|
22557
|
+
if (context.globalOptions.json) {
|
|
22558
|
+
this.output.json({ token: accessToken, type: "bearer" });
|
|
22559
|
+
return;
|
|
22560
|
+
}
|
|
22561
|
+
this.output.text(accessToken);
|
|
22562
|
+
return;
|
|
22563
|
+
}
|
|
21318
22564
|
const credentials = await this.configService.getCredentials();
|
|
21319
22565
|
if (!credentials.username || !credentials.apiToken) {
|
|
21320
22566
|
throw new BBError({
|
|
@@ -21324,7 +22570,7 @@ class TokenCommand extends BaseCommand {
|
|
|
21324
22570
|
}
|
|
21325
22571
|
const token = Buffer.from(`${credentials.username}:${credentials.apiToken}`).toString("base64");
|
|
21326
22572
|
if (context.globalOptions.json) {
|
|
21327
|
-
this.output.json({ token });
|
|
22573
|
+
this.output.json({ token, type: "basic" });
|
|
21328
22574
|
return;
|
|
21329
22575
|
}
|
|
21330
22576
|
this.output.text(token);
|
|
@@ -21449,8 +22695,8 @@ function getCommitFilePath(file) {
|
|
|
21449
22695
|
if (!isRecord(file)) {
|
|
21450
22696
|
return;
|
|
21451
22697
|
}
|
|
21452
|
-
const
|
|
21453
|
-
return typeof
|
|
22698
|
+
const path2 = file.path;
|
|
22699
|
+
return typeof path2 === "string" && path2.length > 0 ? path2 : undefined;
|
|
21454
22700
|
}
|
|
21455
22701
|
function parseDiffstatFile(value) {
|
|
21456
22702
|
if (!isRecord(value)) {
|
|
@@ -22231,7 +23477,7 @@ class ViewPRCommand extends BaseCommand {
|
|
|
22231
23477
|
}
|
|
22232
23478
|
|
|
22233
23479
|
// src/commands/pr/edit.command.ts
|
|
22234
|
-
import * as
|
|
23480
|
+
import * as fs6 from "fs";
|
|
22235
23481
|
class EditPRCommand extends BaseCommand {
|
|
22236
23482
|
pullrequestsApi;
|
|
22237
23483
|
contextService;
|
|
@@ -22285,7 +23531,7 @@ class EditPRCommand extends BaseCommand {
|
|
|
22285
23531
|
let body = options.body;
|
|
22286
23532
|
if (options.bodyFile) {
|
|
22287
23533
|
try {
|
|
22288
|
-
body =
|
|
23534
|
+
body = fs6.readFileSync(options.bodyFile, "utf-8");
|
|
22289
23535
|
} catch (err) {
|
|
22290
23536
|
throw new BBError({
|
|
22291
23537
|
code: 9999 /* UNKNOWN */,
|
|
@@ -22557,8 +23803,8 @@ class CheckoutPRCommand extends BaseCommand {
|
|
|
22557
23803
|
|
|
22558
23804
|
// src/commands/pr/diff.command.ts
|
|
22559
23805
|
import { exec } from "child_process";
|
|
22560
|
-
import { promisify } from "util";
|
|
22561
|
-
var execAsync =
|
|
23806
|
+
import { promisify as promisify7 } from "util";
|
|
23807
|
+
var execAsync = promisify7(exec);
|
|
22562
23808
|
|
|
22563
23809
|
class DiffPRCommand extends BaseCommand {
|
|
22564
23810
|
pullrequestsApi;
|
|
@@ -22670,11 +23916,11 @@ class DiffPRCommand extends BaseCommand {
|
|
|
22670
23916
|
}
|
|
22671
23917
|
async openInBrowser(url2) {
|
|
22672
23918
|
this.output.info(`Opening ${url2} in your browser...`);
|
|
22673
|
-
const
|
|
23919
|
+
const platform2 = process.platform;
|
|
22674
23920
|
let command;
|
|
22675
|
-
if (
|
|
23921
|
+
if (platform2 === "darwin") {
|
|
22676
23922
|
command = `open "${url2}"`;
|
|
22677
|
-
} else if (
|
|
23923
|
+
} else if (platform2 === "win32") {
|
|
22678
23924
|
command = `start "" "${url2}"`;
|
|
22679
23925
|
} else {
|
|
22680
23926
|
command = `xdg-open "${url2}"`;
|
|
@@ -23197,25 +24443,11 @@ class AddReviewerPRCommand extends BaseCommand {
|
|
|
23197
24443
|
selectedUser: options.username
|
|
23198
24444
|
});
|
|
23199
24445
|
const user = userResponse.data;
|
|
23200
|
-
const
|
|
23201
|
-
|
|
23202
|
-
|
|
23203
|
-
pullRequestId: prId
|
|
23204
|
-
});
|
|
23205
|
-
const pr = prResponse.data;
|
|
23206
|
-
const existingReviewers = pr.reviewers ? Array.from(pr.reviewers) : [];
|
|
23207
|
-
const reviewerUuids = existingReviewers.map((r) => r.uuid).filter(Boolean);
|
|
23208
|
-
if (!reviewerUuids.includes(user.uuid)) {
|
|
23209
|
-
reviewerUuids.push(user.uuid);
|
|
23210
|
-
}
|
|
23211
|
-
const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdPut({
|
|
23212
|
-
workspace: repoContext.workspace,
|
|
23213
|
-
repoSlug: repoContext.repoSlug,
|
|
23214
|
-
pullRequestId: prId,
|
|
23215
|
-
body: {
|
|
23216
|
-
type: "pullrequest",
|
|
23217
|
-
reviewers: reviewerUuids.map((uuid) => ({ uuid }))
|
|
24446
|
+
const updatedPr = await updatePullRequestReviewers(this.pullrequestsApi, repoContext, prId, (uuids) => {
|
|
24447
|
+
if (!uuids.includes(user.uuid)) {
|
|
24448
|
+
return [...uuids, user.uuid];
|
|
23218
24449
|
}
|
|
24450
|
+
return uuids;
|
|
23219
24451
|
});
|
|
23220
24452
|
if (context.globalOptions.json) {
|
|
23221
24453
|
this.output.json({
|
|
@@ -23225,7 +24457,7 @@ class AddReviewerPRCommand extends BaseCommand {
|
|
|
23225
24457
|
username: options.username,
|
|
23226
24458
|
uuid: user.uuid
|
|
23227
24459
|
},
|
|
23228
|
-
pullRequest:
|
|
24460
|
+
pullRequest: updatedPr
|
|
23229
24461
|
});
|
|
23230
24462
|
return;
|
|
23231
24463
|
}
|
|
@@ -23256,23 +24488,7 @@ class RemoveReviewerPRCommand extends BaseCommand {
|
|
|
23256
24488
|
selectedUser: options.username
|
|
23257
24489
|
});
|
|
23258
24490
|
const user = userResponse.data;
|
|
23259
|
-
const
|
|
23260
|
-
workspace: repoContext.workspace,
|
|
23261
|
-
repoSlug: repoContext.repoSlug,
|
|
23262
|
-
pullRequestId: prId
|
|
23263
|
-
});
|
|
23264
|
-
const pr = prResponse.data;
|
|
23265
|
-
const existingReviewers = pr.reviewers ? Array.from(pr.reviewers) : [];
|
|
23266
|
-
const reviewerUuids = existingReviewers.map((r) => r.uuid).filter((uuid) => uuid && uuid !== user.uuid);
|
|
23267
|
-
const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdPut({
|
|
23268
|
-
workspace: repoContext.workspace,
|
|
23269
|
-
repoSlug: repoContext.repoSlug,
|
|
23270
|
-
pullRequestId: prId,
|
|
23271
|
-
body: {
|
|
23272
|
-
type: "pullrequest",
|
|
23273
|
-
reviewers: reviewerUuids.map((uuid) => ({ uuid }))
|
|
23274
|
-
}
|
|
23275
|
-
});
|
|
24491
|
+
const updatedPr = await updatePullRequestReviewers(this.pullrequestsApi, repoContext, prId, (uuids) => uuids.filter((uuid) => uuid !== user.uuid));
|
|
23276
24492
|
if (context.globalOptions.json) {
|
|
23277
24493
|
this.output.json({
|
|
23278
24494
|
success: true,
|
|
@@ -23281,7 +24497,7 @@ class RemoveReviewerPRCommand extends BaseCommand {
|
|
|
23281
24497
|
username: options.username,
|
|
23282
24498
|
uuid: user.uuid
|
|
23283
24499
|
},
|
|
23284
|
-
pullRequest:
|
|
24500
|
+
pullRequest: updatedPr
|
|
23285
24501
|
});
|
|
23286
24502
|
return;
|
|
23287
24503
|
}
|
|
@@ -23667,24 +24883,32 @@ function bootstrap(options = {}) {
|
|
|
23667
24883
|
container.register(ServiceTokens.ConfigService, () => new ConfigService);
|
|
23668
24884
|
container.register(ServiceTokens.GitService, () => new GitService);
|
|
23669
24885
|
container.register(ServiceTokens.OutputService, () => new OutputService({ noColor: options.noColor }));
|
|
24886
|
+
container.register(ServiceTokens.OAuthService, () => {
|
|
24887
|
+
const configService = container.resolve(ServiceTokens.ConfigService);
|
|
24888
|
+
return new OAuthService(configService);
|
|
24889
|
+
});
|
|
23670
24890
|
container.register(ServiceTokens.PullrequestsApi, () => {
|
|
23671
24891
|
const configService = container.resolve(ServiceTokens.ConfigService);
|
|
23672
|
-
const
|
|
24892
|
+
const oauthService = container.resolve(ServiceTokens.OAuthService);
|
|
24893
|
+
const axiosInstance = createApiClient(configService, oauthService);
|
|
23673
24894
|
return new PullrequestsApi(undefined, undefined, axiosInstance);
|
|
23674
24895
|
});
|
|
23675
24896
|
container.register(ServiceTokens.RepositoriesApi, () => {
|
|
23676
24897
|
const configService = container.resolve(ServiceTokens.ConfigService);
|
|
23677
|
-
const
|
|
24898
|
+
const oauthService = container.resolve(ServiceTokens.OAuthService);
|
|
24899
|
+
const axiosInstance = createApiClient(configService, oauthService);
|
|
23678
24900
|
return new RepositoriesApi(undefined, undefined, axiosInstance);
|
|
23679
24901
|
});
|
|
23680
24902
|
container.register(ServiceTokens.UsersApi, () => {
|
|
23681
24903
|
const configService = container.resolve(ServiceTokens.ConfigService);
|
|
23682
|
-
const
|
|
24904
|
+
const oauthService = container.resolve(ServiceTokens.OAuthService);
|
|
24905
|
+
const axiosInstance = createApiClient(configService, oauthService);
|
|
23683
24906
|
return new UsersApi(undefined, undefined, axiosInstance);
|
|
23684
24907
|
});
|
|
23685
24908
|
container.register(ServiceTokens.CommitStatusesApi, () => {
|
|
23686
24909
|
const configService = container.resolve(ServiceTokens.ConfigService);
|
|
23687
|
-
const
|
|
24910
|
+
const oauthService = container.resolve(ServiceTokens.OAuthService);
|
|
24911
|
+
const axiosInstance = createApiClient(configService, oauthService);
|
|
23688
24912
|
return new CommitStatusesApi(undefined, undefined, axiosInstance);
|
|
23689
24913
|
});
|
|
23690
24914
|
container.register(ServiceTokens.ContextService, () => {
|
|
@@ -23695,13 +24919,15 @@ function bootstrap(options = {}) {
|
|
|
23695
24919
|
container.register(ServiceTokens.LoginCommand, () => {
|
|
23696
24920
|
const configService = container.resolve(ServiceTokens.ConfigService);
|
|
23697
24921
|
const usersApi = container.resolve(ServiceTokens.UsersApi);
|
|
24922
|
+
const oauthService = container.resolve(ServiceTokens.OAuthService);
|
|
23698
24923
|
const output = container.resolve(ServiceTokens.OutputService);
|
|
23699
|
-
return new LoginCommand(configService, usersApi, output);
|
|
24924
|
+
return new LoginCommand(configService, usersApi, oauthService, output);
|
|
23700
24925
|
});
|
|
23701
24926
|
container.register(ServiceTokens.LogoutCommand, () => {
|
|
23702
24927
|
const configService = container.resolve(ServiceTokens.ConfigService);
|
|
24928
|
+
const oauthService = container.resolve(ServiceTokens.OAuthService);
|
|
23703
24929
|
const output = container.resolve(ServiceTokens.OutputService);
|
|
23704
|
-
return new LogoutCommand(configService, output);
|
|
24930
|
+
return new LogoutCommand(configService, oauthService, output);
|
|
23705
24931
|
});
|
|
23706
24932
|
container.register(ServiceTokens.StatusCommand, () => {
|
|
23707
24933
|
const configService = container.resolve(ServiceTokens.ConfigService);
|
|
@@ -23711,8 +24937,9 @@ function bootstrap(options = {}) {
|
|
|
23711
24937
|
});
|
|
23712
24938
|
container.register(ServiceTokens.TokenCommand, () => {
|
|
23713
24939
|
const configService = container.resolve(ServiceTokens.ConfigService);
|
|
24940
|
+
const oauthService = container.resolve(ServiceTokens.OAuthService);
|
|
23714
24941
|
const output = container.resolve(ServiceTokens.OutputService);
|
|
23715
|
-
return new TokenCommand(configService, output);
|
|
24942
|
+
return new TokenCommand(configService, oauthService, output);
|
|
23716
24943
|
});
|
|
23717
24944
|
container.register(ServiceTokens.CloneCommand, () => {
|
|
23718
24945
|
const gitService = container.resolve(ServiceTokens.GitService);
|
|
@@ -24055,14 +25282,16 @@ cli.name("bb").description("A command-line interface for Bitbucket Cloud").versi
|
|
|
24055
25282
|
} catch {}
|
|
24056
25283
|
});
|
|
24057
25284
|
var authCmd = new Command("auth").description("Authenticate with Bitbucket");
|
|
24058
|
-
authCmd.command("login").description("Authenticate with Bitbucket
|
|
25285
|
+
authCmd.command("login").description("Authenticate with Bitbucket (OAuth or API token)").option("-u, --username <username>", "Bitbucket username (implies API token auth)").option("-p, --password <password>", "Bitbucket API token (implies API token auth)").option("--app-password", "Use API token authentication instead of OAuth").option("--client-id <clientId>", "Custom OAuth consumer client ID").option("--client-secret <clientSecret>", "Custom OAuth consumer client secret").addHelpText("after", buildHelpText({
|
|
24059
25286
|
examples: [
|
|
24060
|
-
"bb auth login
|
|
25287
|
+
"bb auth login",
|
|
25288
|
+
"bb auth login --app-password -u myuser -p mytoken",
|
|
25289
|
+
"bb auth login --client-id <id>",
|
|
24061
25290
|
"BB_USERNAME=myuser BB_API_TOKEN=mytoken bb auth login"
|
|
24062
25291
|
],
|
|
24063
25292
|
envVars: {
|
|
24064
25293
|
BB_USERNAME: "Used when --username is not provided",
|
|
24065
|
-
BB_API_TOKEN: "Used when --password is not provided"
|
|
25294
|
+
BB_API_TOKEN: "Used when --password is not provided (implies API token auth)"
|
|
24066
25295
|
}
|
|
24067
25296
|
})).action(async (options) => {
|
|
24068
25297
|
await runCommand(ServiceTokens.LoginCommand, options, cli);
|