@formigio/fazemos-cli 0.10.14 → 0.10.15
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/connectionErrorCopy.d.ts +27 -4
- package/dist/connectionErrorCopy.js +67 -9
- package/dist/connectionErrorCopy.js.map +1 -1
- package/dist/dispatch.d.ts +96 -0
- package/dist/dispatch.js +169 -0
- package/dist/dispatch.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +199 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1390,27 +1390,34 @@ const connections = program.command('connections').alias('conn').description('Gi
|
|
|
1390
1390
|
*/
|
|
1391
1391
|
connections
|
|
1392
1392
|
.command('list')
|
|
1393
|
-
.description('List
|
|
1393
|
+
.description('List VCS Connections (GitHub + BitBucket) in the active organization')
|
|
1394
1394
|
.option('-s, --status <status>', 'Filter: active (default), all, pending, suspended, revoked, uninstalled', 'active')
|
|
1395
1395
|
.action(async (opts) => {
|
|
1396
1396
|
try {
|
|
1397
1397
|
const orgId = requireActiveOrgOrExit();
|
|
1398
|
-
|
|
1399
|
-
|
|
1398
|
+
// F22 — call the provider-agnostic /vcs/connections endpoint.
|
|
1399
|
+
// The legacy /github/connections alias still works during the
|
|
1400
|
+
// dual-write phase, but `vcs/` returns BOTH providers' rows so
|
|
1401
|
+
// the user sees their full Org Connection list.
|
|
1402
|
+
const data = await api('GET', `/api/organizations/${orgId}/vcs/connections?status=${encodeURIComponent(opts.status)}`, undefined, { noProjectHeader: true });
|
|
1403
|
+
const list = (data.connections ?? []).map(normalizeConnection);
|
|
1400
1404
|
if (list.length === 0) {
|
|
1401
1405
|
const orgName = findOrgById(orgId)?.name ?? orgId;
|
|
1402
|
-
console.log(chalk.yellow(`No
|
|
1406
|
+
console.log(chalk.yellow(`No code platform connections in ${orgName}.`));
|
|
1403
1407
|
console.log(chalk.gray('Add one with: fazemos connections install'));
|
|
1404
1408
|
return;
|
|
1405
1409
|
}
|
|
1406
1410
|
const orgName = findOrgById(orgId)?.name ?? orgId;
|
|
1407
|
-
console.log(chalk.cyan(`
|
|
1411
|
+
console.log(chalk.cyan(`Code platform connections in ${orgName}:`));
|
|
1408
1412
|
console.log('');
|
|
1409
1413
|
for (const c of list) {
|
|
1410
1414
|
const statusColor = pickStatusColor(c.status);
|
|
1411
1415
|
const projects = c.projectCount == null ? '—' : `${c.projectCount} ${c.projectCount === 1 ? 'project' : 'projects'}`;
|
|
1412
|
-
const login = c.
|
|
1413
|
-
|
|
1416
|
+
const login = c.accountLogin ?? chalk.gray('—');
|
|
1417
|
+
const providerLabel = formatProviderLabel(c.provider);
|
|
1418
|
+
// F22 §8.3 item 1: provider column. Renders as a prefix tag so
|
|
1419
|
+
// mixed-provider lists are scannable at a glance.
|
|
1420
|
+
console.log(` ${chalk.magenta(providerLabel)} ${chalk.cyan(c.name)} ${chalk.gray(login)} ${statusColor(c.status)} ${chalk.gray(projects)}`);
|
|
1414
1421
|
console.log(chalk.gray(` ID: ${c.id}`));
|
|
1415
1422
|
}
|
|
1416
1423
|
}
|
|
@@ -1425,40 +1432,56 @@ connections
|
|
|
1425
1432
|
*/
|
|
1426
1433
|
connections
|
|
1427
1434
|
.command('show')
|
|
1428
|
-
.description('Show a
|
|
1435
|
+
.description('Show a VCS Connection in detail')
|
|
1429
1436
|
.argument('<id>', 'Connection ID')
|
|
1430
1437
|
.action(async (id) => {
|
|
1431
1438
|
try {
|
|
1432
1439
|
const orgId = requireActiveOrgOrExit();
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1440
|
+
// F22 — provider-agnostic detail endpoint. The serialized shape
|
|
1441
|
+
// includes `provider`, `account_login`, `supports_contents_api`
|
|
1442
|
+
// and (for GitHub) `installation_id` / (BitBucket) `workspace_uuid`.
|
|
1443
|
+
const data = await api('GET', `/api/organizations/${orgId}/vcs/connections/${id}`, undefined, { noProjectHeader: true });
|
|
1444
|
+
const raw = data.connection ?? data;
|
|
1445
|
+
const c = normalizeConnection(raw);
|
|
1446
|
+
console.log(chalk.cyan(c.name ?? '(unnamed connection)'));
|
|
1436
1447
|
console.log(` ID: ${c.id}`);
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1448
|
+
// F22 §8.3 item 2 — provider line above account info.
|
|
1449
|
+
console.log(` Provider: ${formatProviderLabel(c.provider)}`);
|
|
1450
|
+
console.log(` Account: ${c.accountLogin ?? chalk.gray('— (pending)')}`);
|
|
1451
|
+
if (c.accountType)
|
|
1452
|
+
console.log(` Account type: ${c.accountType}`);
|
|
1440
1453
|
const statusColor = pickStatusColor(c.status);
|
|
1441
1454
|
console.log(` Status: ${statusColor(c.status)}`);
|
|
1442
|
-
|
|
1455
|
+
if (c.installedAt) {
|
|
1456
|
+
console.log(` Installed: ${new Date(c.installedAt).toLocaleString()}`);
|
|
1457
|
+
}
|
|
1443
1458
|
if (c.lastHealthCheckAt) {
|
|
1444
1459
|
console.log(` Last checked: ${new Date(c.lastHealthCheckAt).toLocaleString()}`);
|
|
1445
1460
|
}
|
|
1446
1461
|
if (c.lastUsedAt) {
|
|
1447
1462
|
console.log(` Last used: ${new Date(c.lastUsedAt).toLocaleString()}`);
|
|
1448
1463
|
}
|
|
1449
|
-
|
|
1450
|
-
|
|
1464
|
+
// F22 §6.4 — supports_contents_api is the canonical signal for
|
|
1465
|
+
// "can this Connection back F18 docs surfaces?" Surface it so
|
|
1466
|
+
// users understand why docs may be unavailable on BitBucket.
|
|
1467
|
+
if (typeof c.supportsContentsApi === 'boolean') {
|
|
1468
|
+
const docs = c.supportsContentsApi ? 'yes' : chalk.yellow('no');
|
|
1469
|
+
console.log(` Docs API: ${docs}`);
|
|
1470
|
+
}
|
|
1471
|
+
if (raw.repositorySelection === 'all') {
|
|
1472
|
+
console.log(` Repos: All repositories${c.accountLogin ? ` in ${c.accountLogin}` : ''}`);
|
|
1451
1473
|
}
|
|
1452
|
-
else if (Array.isArray(
|
|
1453
|
-
console.log(` Repos: ${
|
|
1454
|
-
for (const r of
|
|
1455
|
-
console.log(chalk.gray(` · ${r.fullName}`));
|
|
1474
|
+
else if (Array.isArray(raw.repositories)) {
|
|
1475
|
+
console.log(` Repos: ${raw.repositories.length}${raw.repositoriesTruncated ? ' (showing 100)' : ''}`);
|
|
1476
|
+
for (const r of raw.repositories) {
|
|
1477
|
+
console.log(chalk.gray(` · ${r.fullName ?? r.full_name ?? r.name}`));
|
|
1456
1478
|
}
|
|
1457
1479
|
}
|
|
1458
|
-
|
|
1480
|
+
const boundProjects = raw.boundProjects ?? raw.bound_projects ?? [];
|
|
1481
|
+
if (Array.isArray(boundProjects) && boundProjects.length > 0) {
|
|
1459
1482
|
console.log('');
|
|
1460
1483
|
console.log(chalk.cyan('Projects using this connection:'));
|
|
1461
|
-
for (const p of
|
|
1484
|
+
for (const p of boundProjects) {
|
|
1462
1485
|
console.log(` · ${p.name} (${p.slug})`);
|
|
1463
1486
|
}
|
|
1464
1487
|
}
|
|
@@ -1479,12 +1502,55 @@ connections
|
|
|
1479
1502
|
*/
|
|
1480
1503
|
connections
|
|
1481
1504
|
.command('install')
|
|
1482
|
-
.description('Add a GitHub
|
|
1483
|
-
.
|
|
1505
|
+
.description('Add a VCS Connection (GitHub or BitBucket). Prints an install URL and (for GitHub) waits for a confirmation code.')
|
|
1506
|
+
.option('--provider <provider>', 'VCS provider: github | bitbucket')
|
|
1507
|
+
.action(async (opts) => {
|
|
1484
1508
|
try {
|
|
1485
1509
|
const orgId = requireActiveOrgOrExit();
|
|
1486
1510
|
const orgName = findOrgById(orgId)?.name ?? orgId;
|
|
1487
|
-
|
|
1511
|
+
// F22 §8.3 item 3 — provider selection matrix.
|
|
1512
|
+
// 1) `--provider github|bitbucket` supplied: use directly.
|
|
1513
|
+
// 2) No flag: prompt the user interactively (provider-picker).
|
|
1514
|
+
// The CLI cannot probe server-side provider configuration, so the
|
|
1515
|
+
// "exactly one provider configured" auto-select branch of the spec
|
|
1516
|
+
// is implemented as "user always confirms" — narrower than the
|
|
1517
|
+
// spec wording but strictly safer (no silent provider choice).
|
|
1518
|
+
let provider = opts.provider?.toLowerCase();
|
|
1519
|
+
if (!provider) {
|
|
1520
|
+
provider = await promptProviderChoice();
|
|
1521
|
+
}
|
|
1522
|
+
if (provider !== 'github' && provider !== 'bitbucket') {
|
|
1523
|
+
console.error(chalk.red(`Invalid --provider: ${provider}. Use 'github' or 'bitbucket'.`));
|
|
1524
|
+
process.exit(1);
|
|
1525
|
+
}
|
|
1526
|
+
// F22 prefers the new provider-agnostic /vcs/connections route, which
|
|
1527
|
+
// expects `provider` in the body. The github-only endpoint is kept
|
|
1528
|
+
// alive but not used here so all new connections flow through one path.
|
|
1529
|
+
const mintData = await api('POST', `/api/organizations/${orgId}/vcs/connections/install-url`, { provider, source: 'cli', returnTo: null }, { noProjectHeader: true });
|
|
1530
|
+
// F22 §8.3 item 8 — BitBucket install is browser-only in v1 (no CLI
|
|
1531
|
+
// confirmation-code exchange counterpart). Print the literal copy
|
|
1532
|
+
// block specified in the spec verbatim, then exit successfully.
|
|
1533
|
+
// The user completes consent in the browser and the /api/bitbucket/
|
|
1534
|
+
// oauth/callback handler finishes the Connection server-side.
|
|
1535
|
+
//
|
|
1536
|
+
// Dex nit N4 — output literal MUST match the spec block exactly so
|
|
1537
|
+
// the acceptance test can assert it.
|
|
1538
|
+
if (provider === 'bitbucket') {
|
|
1539
|
+
console.log('');
|
|
1540
|
+
console.log('BitBucket Connection install — browser required');
|
|
1541
|
+
console.log('');
|
|
1542
|
+
console.log('Open this URL in your browser to authorize Fazemos:');
|
|
1543
|
+
console.log('');
|
|
1544
|
+
console.log(` ${mintData.url}`);
|
|
1545
|
+
console.log('');
|
|
1546
|
+
console.log('After you authorize, BitBucket will redirect to Fazemos and complete the Connection.');
|
|
1547
|
+
console.log('You can then list your connections with:');
|
|
1548
|
+
console.log('');
|
|
1549
|
+
console.log(' fazemos connections list');
|
|
1550
|
+
console.log('');
|
|
1551
|
+
console.log('This URL expires in 10 minutes.');
|
|
1552
|
+
return;
|
|
1553
|
+
}
|
|
1488
1554
|
console.log('');
|
|
1489
1555
|
console.log(`To add a GitHub connection to ${chalk.cyan(orgName)}:`);
|
|
1490
1556
|
console.log('');
|
|
@@ -1573,18 +1639,20 @@ connections
|
|
|
1573
1639
|
connections
|
|
1574
1640
|
.command('revoke')
|
|
1575
1641
|
.alias('disconnect')
|
|
1576
|
-
.description('Disconnect a
|
|
1642
|
+
.description('Disconnect a VCS Connection (Fazemos-side; does not uninstall the App from GitHub / revoke the OAuth grant on BitBucket).')
|
|
1577
1643
|
.argument('<id>', 'Connection ID')
|
|
1578
1644
|
.option('-f, --force', 'Skip the confirmation prompt', false)
|
|
1579
1645
|
.action(async (id, opts) => {
|
|
1580
1646
|
try {
|
|
1581
1647
|
const orgId = requireActiveOrgOrExit();
|
|
1582
1648
|
// Fetch the Connection so we can show what we're about to revoke
|
|
1583
|
-
// and how many projects it affects (
|
|
1584
|
-
|
|
1649
|
+
// and how many projects it affects (UX §8.3 confirmation copy).
|
|
1650
|
+
// F22 — use the provider-agnostic /vcs/ endpoint so both provider
|
|
1651
|
+
// rows are reachable.
|
|
1652
|
+
let raw;
|
|
1585
1653
|
try {
|
|
1586
|
-
const detail = await api('GET', `/api/organizations/${orgId}/
|
|
1587
|
-
|
|
1654
|
+
const detail = await api('GET', `/api/organizations/${orgId}/vcs/connections/${id}`, undefined, { noProjectHeader: true });
|
|
1655
|
+
raw = detail.connection ?? detail;
|
|
1588
1656
|
}
|
|
1589
1657
|
catch (err) {
|
|
1590
1658
|
if (err instanceof ApiError && err.code === 'CONNECTION_NOT_FOUND') {
|
|
@@ -1593,15 +1661,17 @@ connections
|
|
|
1593
1661
|
}
|
|
1594
1662
|
throw err;
|
|
1595
1663
|
}
|
|
1596
|
-
const
|
|
1664
|
+
const connection = normalizeConnection(raw);
|
|
1665
|
+
const boundProjects = raw.boundProjects ?? raw.bound_projects ?? [];
|
|
1666
|
+
const providerLabelStr = formatProviderLabel(connection.provider);
|
|
1597
1667
|
if (!opts.force) {
|
|
1598
1668
|
console.log('');
|
|
1599
|
-
console.log(`Disconnect ${chalk.cyan(connection.name)}?`);
|
|
1669
|
+
console.log(`Disconnect ${chalk.magenta(providerLabelStr)} ${chalk.cyan(connection.name ?? id)}?`);
|
|
1600
1670
|
console.log('');
|
|
1601
1671
|
if (boundProjects.length > 0) {
|
|
1602
1672
|
const projectList = boundProjects.map(p => p.name).join(', ');
|
|
1603
1673
|
console.log(` This connection is used by ${boundProjects.length} ${boundProjects.length === 1 ? 'project' : 'projects'}: ${projectList}.`);
|
|
1604
|
-
console.log(
|
|
1674
|
+
console.log(` Pipelines in those projects will fail on ${providerLabelStr} steps until`);
|
|
1605
1675
|
console.log(' they are bound to a different connection.');
|
|
1606
1676
|
console.log('');
|
|
1607
1677
|
}
|
|
@@ -1609,7 +1679,13 @@ connections
|
|
|
1609
1679
|
console.log(' No projects are using this connection.');
|
|
1610
1680
|
console.log('');
|
|
1611
1681
|
}
|
|
1612
|
-
|
|
1682
|
+
// Provider-aware caveat: GitHub App vs BitBucket OAuth grant.
|
|
1683
|
+
if (connection.provider === 'bitbucket') {
|
|
1684
|
+
console.log(chalk.gray(' This does not revoke the OAuth grant on BitBucket.'));
|
|
1685
|
+
}
|
|
1686
|
+
else {
|
|
1687
|
+
console.log(chalk.gray(' This does not uninstall the Fazemos App from GitHub.'));
|
|
1688
|
+
}
|
|
1613
1689
|
console.log('');
|
|
1614
1690
|
const answer = await promptLine('Disconnect? [y/N]: ');
|
|
1615
1691
|
if (!answer || !/^y/i.test(answer.trim())) {
|
|
@@ -1617,11 +1693,14 @@ connections
|
|
|
1617
1693
|
return;
|
|
1618
1694
|
}
|
|
1619
1695
|
}
|
|
1620
|
-
const data = await api('DELETE', `/api/organizations/${orgId}/
|
|
1621
|
-
console.log(chalk.green(`Disconnected: ${connection.name}`));
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1696
|
+
const data = await api('DELETE', `/api/organizations/${orgId}/vcs/connections/${id}`, undefined, { noProjectHeader: true });
|
|
1697
|
+
console.log(chalk.green(`Disconnected: ${providerLabelStr} ${connection.name ?? id}`));
|
|
1698
|
+
// F22 response shape: { revoked, secrets_deleted, projects_unbound }.
|
|
1699
|
+
// F16 legacy shape: { affectedProjects: [...] }. Handle both during
|
|
1700
|
+
// the dual-write rollout.
|
|
1701
|
+
const unbound = data.projects_unbound ?? (data.affectedProjects ?? []).length ?? 0;
|
|
1702
|
+
if (unbound > 0) {
|
|
1703
|
+
console.log(chalk.gray(` ${unbound} project${unbound === 1 ? '' : 's'} unbound.`));
|
|
1625
1704
|
}
|
|
1626
1705
|
invalidateAuthMeCache();
|
|
1627
1706
|
}
|
|
@@ -1636,19 +1715,23 @@ connections
|
|
|
1636
1715
|
*/
|
|
1637
1716
|
connections
|
|
1638
1717
|
.command('health-check')
|
|
1639
|
-
.description('Verify a Connection is still healthy on GitHub')
|
|
1718
|
+
.description('Verify a Connection is still healthy on its code platform (GitHub or BitBucket)')
|
|
1640
1719
|
.argument('<id>', 'Connection ID')
|
|
1641
1720
|
.action(async (id) => {
|
|
1642
1721
|
try {
|
|
1643
1722
|
const orgId = requireActiveOrgOrExit();
|
|
1644
|
-
|
|
1645
|
-
|
|
1723
|
+
// F22 — provider-aware health-check route on the /vcs/ alias.
|
|
1724
|
+
// The handler dispatches to the right provider (GitHub installation
|
|
1725
|
+
// probe / BitBucket OAuth-refresh + workspace probe).
|
|
1726
|
+
const data = await api('POST', `/api/organizations/${orgId}/vcs/connections/${id}/health-check`, {}, { noProjectHeader: true });
|
|
1727
|
+
const c = normalizeConnection(data.connection ?? data);
|
|
1646
1728
|
const statusColor = pickStatusColor(c.status);
|
|
1729
|
+
const label = `${formatProviderLabel(c.provider)} ${c.name ?? id}`;
|
|
1647
1730
|
if (data.changed) {
|
|
1648
|
-
console.log(chalk.yellow(`Status changed: ${
|
|
1731
|
+
console.log(chalk.yellow(`Status changed: ${label} → ${statusColor(c.status)}`));
|
|
1649
1732
|
}
|
|
1650
1733
|
else {
|
|
1651
|
-
console.log(chalk.green(`✓ ${
|
|
1734
|
+
console.log(chalk.green(`✓ ${label} — ${statusColor(c.status)}`));
|
|
1652
1735
|
}
|
|
1653
1736
|
}
|
|
1654
1737
|
catch (err) {
|
|
@@ -1660,6 +1743,53 @@ connections
|
|
|
1660
1743
|
process.exit(1);
|
|
1661
1744
|
}
|
|
1662
1745
|
});
|
|
1746
|
+
export function normalizeConnection(raw) {
|
|
1747
|
+
if (!raw || typeof raw !== 'object') {
|
|
1748
|
+
return {
|
|
1749
|
+
id: '',
|
|
1750
|
+
provider: null,
|
|
1751
|
+
name: null,
|
|
1752
|
+
accountLogin: null,
|
|
1753
|
+
accountType: null,
|
|
1754
|
+
status: 'unknown',
|
|
1755
|
+
installedAt: null,
|
|
1756
|
+
lastHealthCheckAt: null,
|
|
1757
|
+
lastUsedAt: null,
|
|
1758
|
+
supportsContentsApi: null,
|
|
1759
|
+
projectCount: null,
|
|
1760
|
+
};
|
|
1761
|
+
}
|
|
1762
|
+
// Provider — F22 new field. Older /github/ rows always meant github;
|
|
1763
|
+
// default there for back-compat.
|
|
1764
|
+
const provider = raw.provider ?? (raw.githubAccountLogin !== undefined ? 'github' : null);
|
|
1765
|
+
return {
|
|
1766
|
+
id: String(raw.id ?? ''),
|
|
1767
|
+
provider,
|
|
1768
|
+
name: raw.name ?? null,
|
|
1769
|
+
accountLogin: raw.accountLogin ?? raw.account_login ?? raw.githubAccountLogin ?? null,
|
|
1770
|
+
accountType: raw.accountType ?? raw.account_type ?? raw.githubAccountType ?? null,
|
|
1771
|
+
status: raw.status ?? 'unknown',
|
|
1772
|
+
installedAt: raw.installedAt ?? raw.installed_at ?? raw.created_at ?? null,
|
|
1773
|
+
lastHealthCheckAt: raw.lastHealthCheckAt ?? raw.last_health_check_at ?? null,
|
|
1774
|
+
lastUsedAt: raw.lastUsedAt ?? raw.last_used_at ?? null,
|
|
1775
|
+
supportsContentsApi: typeof raw.supportsContentsApi === 'boolean'
|
|
1776
|
+
? raw.supportsContentsApi
|
|
1777
|
+
: typeof raw.supports_contents_api === 'boolean'
|
|
1778
|
+
? raw.supports_contents_api
|
|
1779
|
+
: null,
|
|
1780
|
+
projectCount: raw.projectCount ?? raw.project_count ?? null,
|
|
1781
|
+
};
|
|
1782
|
+
}
|
|
1783
|
+
/**
|
|
1784
|
+
* F22 — Human-friendly provider label used in CLI columns and lines.
|
|
1785
|
+
*/
|
|
1786
|
+
export function formatProviderLabel(provider) {
|
|
1787
|
+
if (provider === 'github')
|
|
1788
|
+
return 'GitHub';
|
|
1789
|
+
if (provider === 'bitbucket')
|
|
1790
|
+
return 'BitBucket';
|
|
1791
|
+
return '—';
|
|
1792
|
+
}
|
|
1663
1793
|
/**
|
|
1664
1794
|
* Helper — color a status string per the Sage §2.2 taxonomy.
|
|
1665
1795
|
*/
|
|
@@ -1679,6 +1809,30 @@ function pickStatusColor(status) {
|
|
|
1679
1809
|
return chalk.white;
|
|
1680
1810
|
}
|
|
1681
1811
|
}
|
|
1812
|
+
/**
|
|
1813
|
+
* F22 §8.3 item 3 — interactive provider picker. Used by
|
|
1814
|
+
* `fazemos connections install` when no `--provider` flag is supplied
|
|
1815
|
+
* so the user explicitly chooses GitHub or BitBucket before the URL
|
|
1816
|
+
* mint hits the API. Mirrors the web `ProviderPickerModal` choice
|
|
1817
|
+
* without the modal chrome.
|
|
1818
|
+
*
|
|
1819
|
+
* Returns 'github' or 'bitbucket'. Repeats on invalid input.
|
|
1820
|
+
*/
|
|
1821
|
+
export async function promptProviderChoice() {
|
|
1822
|
+
console.log('');
|
|
1823
|
+
console.log('Which code platform do you want to connect?');
|
|
1824
|
+
console.log(' 1. GitHub');
|
|
1825
|
+
console.log(' 2. BitBucket');
|
|
1826
|
+
console.log('');
|
|
1827
|
+
while (true) {
|
|
1828
|
+
const ans = (await promptLine(' Choose [1=GitHub / 2=BitBucket]: ')).trim().toLowerCase();
|
|
1829
|
+
if (ans === '1' || ans === 'github' || ans === 'gh')
|
|
1830
|
+
return 'github';
|
|
1831
|
+
if (ans === '2' || ans === 'bitbucket' || ans === 'bb')
|
|
1832
|
+
return 'bitbucket';
|
|
1833
|
+
console.log(chalk.yellow(' Please answer 1 (GitHub) or 2 (BitBucket).'));
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1682
1836
|
/**
|
|
1683
1837
|
* Read a single line of input from stdin. No fancy framing — `readline`
|
|
1684
1838
|
* is sufficient for the install confirmation-code prompt and the
|