@hyperdrive.bot/cli 1.0.5 ā 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +169 -63
- package/dist/commands/account/add.d.ts +6 -6
- package/dist/commands/account/remove.d.ts +3 -3
- package/dist/commands/auth/login.d.ts +4 -4
- package/dist/commands/auth/login.js +1 -0
- package/dist/commands/ci/account/create.d.ts +7 -6
- package/dist/commands/ci/account/create.js +49 -3
- package/dist/commands/ci/account/delete.d.ts +3 -3
- package/dist/commands/ci/account/list.d.ts +2 -2
- package/dist/commands/config/get.d.ts +1 -1
- package/dist/commands/config/set.d.ts +2 -2
- package/dist/commands/deployment/create.d.ts +10 -10
- package/dist/commands/deployment/get.d.ts +4 -4
- package/dist/commands/deployment/launch.d.ts +6 -6
- package/dist/commands/deployment/list.d.ts +3 -3
- package/dist/commands/deployment/list.js +17 -17
- package/dist/commands/domain/switch.d.ts +1 -1
- package/dist/commands/example.d.ts +3 -3
- package/dist/commands/git/connect.d.ts +2 -2
- package/dist/commands/git/disconnect.d.ts +3 -3
- package/dist/commands/git/list.d.ts +2 -2
- package/dist/commands/git/sync.d.ts +7 -7
- package/dist/commands/git/sync.js +24 -23
- package/dist/commands/jira/connect.d.ts +1 -1
- package/dist/commands/jira/status.d.ts +1 -1
- package/dist/commands/module/analyze.d.ts +5 -5
- package/dist/commands/module/create.d.ts +17 -17
- package/dist/commands/module/create.js +9 -1
- package/dist/commands/module/destroy.d.ts +3 -3
- package/dist/commands/module/get.d.ts +2 -2
- package/dist/commands/module/link.d.ts +4 -4
- package/dist/commands/module/list.d.ts +1 -1
- package/dist/commands/module/list.js +12 -11
- package/dist/commands/module/reanalyze.d.ts +6 -6
- package/dist/commands/module/update.d.ts +19 -19
- package/dist/commands/parameter/add.d.ts +7 -7
- package/dist/commands/parameter/backfill.d.ts +4 -4
- package/dist/commands/parameter/backfill.js +4 -3
- package/dist/commands/parameter/clear.d.ts +6 -6
- package/dist/commands/parameter/list.d.ts +6 -6
- package/dist/commands/parameter/list.js +4 -3
- package/dist/commands/parameter/pull.d.ts +6 -6
- package/dist/commands/parameter/remove.d.ts +7 -7
- package/dist/commands/parameter/sync.d.ts +6 -6
- package/dist/commands/parameter/update.d.ts +7 -7
- package/dist/commands/stage/access.d.ts +15 -0
- package/dist/commands/stage/access.js +130 -0
- package/dist/commands/stage/create.d.ts +11 -11
- package/dist/commands/stage/list.d.ts +1 -1
- package/dist/commands/stage/list.js +21 -20
- package/dist/commands/stage/revoke.d.ts +18 -0
- package/dist/commands/stage/revoke.js +171 -0
- package/dist/commands/stage/share.d.ts +23 -0
- package/dist/commands/stage/share.js +292 -0
- package/dist/commands/test-api.d.ts +1 -1
- package/dist/services/auth-service.d.ts +15 -82
- package/dist/services/auth-service.js +24 -237
- package/dist/services/hyperdrive-sigv4.d.ts +37 -24
- package/dist/services/hyperdrive-sigv4.js +62 -193
- package/dist/services/tenant-service.d.ts +6 -0
- package/dist/services/tenant-service.js +13 -0
- package/dist/utils/auth-flow.d.ts +1 -0
- package/dist/utils/auth-flow.js +2 -0
- package/dist/utils/table.d.ts +17 -0
- package/dist/utils/table.js +41 -0
- package/oclif.manifest.json +309 -81
- package/package.json +55 -15
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import { HyperdriveSigV4Service } from '../../services/hyperdrive-sigv4.js';
|
|
5
|
+
import { printTable } from '../../utils/table.js';
|
|
6
|
+
export default class StageAccess extends Command {
|
|
7
|
+
static args = {
|
|
8
|
+
stage: Args.string({
|
|
9
|
+
description: 'Stage name to view access for',
|
|
10
|
+
required: false,
|
|
11
|
+
}),
|
|
12
|
+
};
|
|
13
|
+
static description = 'View who has access to a stage';
|
|
14
|
+
static examples = [
|
|
15
|
+
'<%= config.bin %> <%= command.id %>',
|
|
16
|
+
'<%= config.bin %> <%= command.id %> develop',
|
|
17
|
+
'<%= config.bin %> <%= command.id %> develop --format json',
|
|
18
|
+
];
|
|
19
|
+
static flags = {
|
|
20
|
+
domain: Flags.string({
|
|
21
|
+
char: 'd',
|
|
22
|
+
description: 'Tenant domain (for multi-domain setups)',
|
|
23
|
+
}),
|
|
24
|
+
format: Flags.string({
|
|
25
|
+
char: 'f',
|
|
26
|
+
default: 'table',
|
|
27
|
+
description: 'Output format',
|
|
28
|
+
options: ['table', 'json'],
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
async run() {
|
|
32
|
+
const { args, flags } = await this.parse(StageAccess);
|
|
33
|
+
const service = new HyperdriveSigV4Service(flags.domain);
|
|
34
|
+
// Resolve stage
|
|
35
|
+
let stageName;
|
|
36
|
+
if (args.stage) {
|
|
37
|
+
stageName = args.stage;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
stageName = await this.promptForStage(service);
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
this.log(chalk.blue(`\nš Fetching access for stage '${stageName}'...\n`));
|
|
44
|
+
const result = await service.stageAccessGet(stageName);
|
|
45
|
+
if (flags.format === 'json') {
|
|
46
|
+
this.log(JSON.stringify(result, null, 2));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
// Display header
|
|
50
|
+
this.log(chalk.cyan('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
51
|
+
this.log(chalk.cyan(`š Access for stage: ${result.stageName}`));
|
|
52
|
+
this.log(chalk.cyan('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
53
|
+
this.log('');
|
|
54
|
+
if (!result.access || result.access.length === 0) {
|
|
55
|
+
this.log(chalk.yellow('ā ļø No access entries found (only the owner has access)'));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Group by type
|
|
59
|
+
const users = result.access.filter((a) => a.targetType === 'user');
|
|
60
|
+
const groups = result.access.filter((a) => a.targetType === 'group');
|
|
61
|
+
if (users.length > 0) {
|
|
62
|
+
this.log(chalk.white(`Users (${users.length}):`));
|
|
63
|
+
printTable(users, {
|
|
64
|
+
targetId: {
|
|
65
|
+
header: 'User ID / Email',
|
|
66
|
+
minWidth: 30,
|
|
67
|
+
},
|
|
68
|
+
role: {
|
|
69
|
+
header: 'Role',
|
|
70
|
+
get: (row) => this.formatRole(row.role),
|
|
71
|
+
},
|
|
72
|
+
}, (msg) => this.log(msg));
|
|
73
|
+
this.log('');
|
|
74
|
+
}
|
|
75
|
+
if (groups.length > 0) {
|
|
76
|
+
this.log(chalk.white(`Groups (${groups.length}):`));
|
|
77
|
+
printTable(groups, {
|
|
78
|
+
targetId: {
|
|
79
|
+
header: 'Group ID',
|
|
80
|
+
minWidth: 30,
|
|
81
|
+
},
|
|
82
|
+
role: {
|
|
83
|
+
header: 'Role',
|
|
84
|
+
get: (row) => this.formatRole(row.role),
|
|
85
|
+
},
|
|
86
|
+
}, (msg) => this.log(msg));
|
|
87
|
+
this.log('');
|
|
88
|
+
}
|
|
89
|
+
// Summary
|
|
90
|
+
this.log(chalk.gray(`Total: ${result.access.length} access entries`));
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
const err = error;
|
|
94
|
+
const message = err.response?.data?.message || err.message;
|
|
95
|
+
this.error(`Failed to get stage access: ${message}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
formatRole(role) {
|
|
99
|
+
switch (role) {
|
|
100
|
+
case 'manager':
|
|
101
|
+
return chalk.red('Manager');
|
|
102
|
+
case 'deployer':
|
|
103
|
+
return chalk.yellow('Deployer');
|
|
104
|
+
case 'viewer':
|
|
105
|
+
return chalk.blue('Viewer');
|
|
106
|
+
default:
|
|
107
|
+
return role;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async promptForStage(service) {
|
|
111
|
+
this.log(chalk.gray(' Fetching stages...'));
|
|
112
|
+
const stages = await service.stageList();
|
|
113
|
+
if (!stages || stages.length === 0) {
|
|
114
|
+
this.error('No stages found');
|
|
115
|
+
}
|
|
116
|
+
const stageChoices = stages.map(s => ({
|
|
117
|
+
name: s.production
|
|
118
|
+
? `${s.name} ${chalk.red('(PROD)')}`
|
|
119
|
+
: `${s.name} ${chalk.blue('(dev)')}`,
|
|
120
|
+
value: s.slug || s.name,
|
|
121
|
+
}));
|
|
122
|
+
const { stage } = await inquirer.prompt([{
|
|
123
|
+
choices: stageChoices,
|
|
124
|
+
message: chalk.yellow('Select a stage:'),
|
|
125
|
+
name: 'stage',
|
|
126
|
+
type: 'list',
|
|
127
|
+
}]);
|
|
128
|
+
return stage;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -2,17 +2,17 @@ import { Command } from '@oclif/core';
|
|
|
2
2
|
export default class StageCreate extends Command {
|
|
3
3
|
static description: string;
|
|
4
4
|
static flags: {
|
|
5
|
-
accountId: import("@oclif/core/
|
|
6
|
-
autoLaunch: import("@oclif/core/
|
|
7
|
-
branchName: import("@oclif/core/
|
|
8
|
-
defaultStage: import("@oclif/core/
|
|
9
|
-
deletionProtection: import("@oclif/core/
|
|
10
|
-
domain: import("@oclif/core/
|
|
11
|
-
name: import("@oclif/core/
|
|
12
|
-
production: import("@oclif/core/
|
|
13
|
-
project: import("@oclif/core/
|
|
14
|
-
provider: import("@oclif/core/
|
|
15
|
-
region: import("@oclif/core/
|
|
5
|
+
accountId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
autoLaunch: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
branchName: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
defaultStage: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
deletionProtection: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
domain: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
production: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
project: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
provider: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
region: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
16
|
};
|
|
17
17
|
run(): Promise<void>;
|
|
18
18
|
/**
|
|
@@ -3,7 +3,7 @@ export default class StageList extends Command {
|
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
6
|
-
domain: import("@oclif/core/
|
|
6
|
+
domain: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
7
|
};
|
|
8
8
|
run(): Promise<void>;
|
|
9
9
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Command, Flags
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { HyperdriveSigV4Service } from '../../services/hyperdrive-sigv4.js';
|
|
4
|
+
import { printTable } from '../../utils/table.js';
|
|
4
5
|
export default class StageList extends Command {
|
|
5
6
|
static description = 'List all stages';
|
|
6
7
|
static examples = [
|
|
@@ -24,36 +25,36 @@ export default class StageList extends Command {
|
|
|
24
25
|
}
|
|
25
26
|
this.log(chalk.green(`ā
Found ${stages.length} stage(s)\n`));
|
|
26
27
|
// Display stages in a table
|
|
27
|
-
|
|
28
|
-
branchName: {
|
|
29
|
-
header: 'Branch',
|
|
30
|
-
},
|
|
31
|
-
createdAt: {
|
|
32
|
-
get: (row) => new Date(row.createdAt).toLocaleDateString(),
|
|
33
|
-
header: 'Created',
|
|
34
|
-
},
|
|
35
|
-
defaultStage: {
|
|
36
|
-
get: (row) => row.defaultStage ? chalk.green('ā') : '',
|
|
37
|
-
header: 'Default',
|
|
38
|
-
},
|
|
28
|
+
printTable(stages, {
|
|
39
29
|
name: {
|
|
40
30
|
header: 'Name',
|
|
41
31
|
minWidth: 15,
|
|
42
32
|
},
|
|
33
|
+
slug: {
|
|
34
|
+
header: 'Slug',
|
|
35
|
+
minWidth: 15,
|
|
36
|
+
get: (row) => chalk.cyan(row.slug),
|
|
37
|
+
},
|
|
43
38
|
production: {
|
|
44
|
-
get: (row) => row.production ? chalk.red('PROD') : chalk.blue('DEV'),
|
|
45
39
|
header: 'Type',
|
|
40
|
+
get: (row) => row.production ? chalk.red('PROD') : chalk.blue('DEV'),
|
|
41
|
+
},
|
|
42
|
+
branchName: {
|
|
43
|
+
header: 'Branch',
|
|
46
44
|
},
|
|
47
45
|
regions: {
|
|
48
|
-
get: (row) => (row.regions || []).join(', '),
|
|
49
46
|
header: 'Regions',
|
|
47
|
+
get: (row) => (row.regions || []).join(', '),
|
|
50
48
|
},
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
defaultStage: {
|
|
50
|
+
header: 'Default',
|
|
51
|
+
get: (row) => row.defaultStage ? chalk.green('ā') : '',
|
|
52
|
+
},
|
|
53
|
+
createdAt: {
|
|
54
|
+
header: 'Created',
|
|
55
|
+
get: (row) => new Date(row.createdAt).toLocaleDateString(),
|
|
55
56
|
},
|
|
56
|
-
});
|
|
57
|
+
}, (msg) => this.log(msg));
|
|
57
58
|
}
|
|
58
59
|
catch (error) {
|
|
59
60
|
console.error('Error:', error);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class StageRevoke extends Command {
|
|
3
|
+
static args: {
|
|
4
|
+
stage: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
static examples: string[];
|
|
8
|
+
static flags: {
|
|
9
|
+
ci: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
domain: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
user: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
};
|
|
14
|
+
run(): Promise<void>;
|
|
15
|
+
private findCIAccount;
|
|
16
|
+
private promptForStage;
|
|
17
|
+
private promptForTarget;
|
|
18
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import { HyperdriveSigV4Service } from '../../services/hyperdrive-sigv4.js';
|
|
5
|
+
export default class StageRevoke extends Command {
|
|
6
|
+
static args = {
|
|
7
|
+
stage: Args.string({
|
|
8
|
+
description: 'Stage name to revoke access from',
|
|
9
|
+
required: false,
|
|
10
|
+
}),
|
|
11
|
+
};
|
|
12
|
+
static description = 'Revoke access from a stage for a user or CI account';
|
|
13
|
+
static examples = [
|
|
14
|
+
// Interactive
|
|
15
|
+
'<%= config.bin %> <%= command.id %>',
|
|
16
|
+
'<%= config.bin %> <%= command.id %> develop',
|
|
17
|
+
// Non-interactive
|
|
18
|
+
'<%= config.bin %> <%= command.id %> develop --user maria@company.com',
|
|
19
|
+
'<%= config.bin %> <%= command.id %> develop --ci github-actions',
|
|
20
|
+
];
|
|
21
|
+
static flags = {
|
|
22
|
+
ci: Flags.string({
|
|
23
|
+
char: 'c',
|
|
24
|
+
description: 'CI account name or ID to revoke access from',
|
|
25
|
+
exclusive: ['user'],
|
|
26
|
+
}),
|
|
27
|
+
domain: Flags.string({
|
|
28
|
+
char: 'd',
|
|
29
|
+
description: 'Tenant domain (for multi-domain setups)',
|
|
30
|
+
}),
|
|
31
|
+
user: Flags.string({
|
|
32
|
+
char: 'u',
|
|
33
|
+
description: 'User email to revoke access from',
|
|
34
|
+
exclusive: ['ci'],
|
|
35
|
+
}),
|
|
36
|
+
yes: Flags.boolean({
|
|
37
|
+
char: 'y',
|
|
38
|
+
default: false,
|
|
39
|
+
description: 'Skip confirmation',
|
|
40
|
+
}),
|
|
41
|
+
};
|
|
42
|
+
async run() {
|
|
43
|
+
const { args, flags } = await this.parse(StageRevoke);
|
|
44
|
+
this.log(chalk.cyan('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
45
|
+
this.log(chalk.cyan('š Revoke Stage Access'));
|
|
46
|
+
this.log(chalk.cyan('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
47
|
+
this.log('');
|
|
48
|
+
const service = new HyperdriveSigV4Service(flags.domain);
|
|
49
|
+
// Step 1: Resolve stage
|
|
50
|
+
let stageName;
|
|
51
|
+
if (args.stage) {
|
|
52
|
+
stageName = args.stage;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
stageName = await this.promptForStage(service);
|
|
56
|
+
}
|
|
57
|
+
// Step 2: Resolve target
|
|
58
|
+
let targetType;
|
|
59
|
+
let targetId;
|
|
60
|
+
let displayName;
|
|
61
|
+
if (flags.user) {
|
|
62
|
+
targetType = 'user';
|
|
63
|
+
targetId = flags.user;
|
|
64
|
+
displayName = flags.user;
|
|
65
|
+
}
|
|
66
|
+
else if (flags.ci) {
|
|
67
|
+
const ciAccount = await this.findCIAccount(service, flags.ci);
|
|
68
|
+
if (!ciAccount) {
|
|
69
|
+
this.error(`CI account '${flags.ci}' not found`);
|
|
70
|
+
}
|
|
71
|
+
targetType = 'user';
|
|
72
|
+
targetId = ciAccount.cognitoUsername;
|
|
73
|
+
displayName = `CI: ${ciAccount.name}`;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
// Interactive: show current access and let user select
|
|
77
|
+
const target = await this.promptForTarget(service, stageName);
|
|
78
|
+
if (!target) {
|
|
79
|
+
this.log(chalk.yellow('No access entries to revoke.'));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
targetType = target.type;
|
|
83
|
+
targetId = target.id;
|
|
84
|
+
displayName = target.displayName;
|
|
85
|
+
}
|
|
86
|
+
// Step 3: Confirm
|
|
87
|
+
if (!flags.yes) {
|
|
88
|
+
const { confirmed } = await inquirer.prompt([{
|
|
89
|
+
default: false,
|
|
90
|
+
message: chalk.yellow(`Revoke all access from ${displayName} on stage '${stageName}'?`),
|
|
91
|
+
name: 'confirmed',
|
|
92
|
+
type: 'confirm',
|
|
93
|
+
}]);
|
|
94
|
+
if (!confirmed) {
|
|
95
|
+
this.log(chalk.gray('Cancelled.'));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Step 4: Revoke
|
|
100
|
+
try {
|
|
101
|
+
this.log(chalk.blue(`\nš Revoking access from '${stageName}' for ${displayName}...`));
|
|
102
|
+
await service.stageAccessRevoke(stageName, targetType, targetId);
|
|
103
|
+
this.log(chalk.green(`ā
Access revoked for ${displayName} from '${stageName}'`));
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
const err = error;
|
|
107
|
+
const message = err.response?.data?.message || err.message;
|
|
108
|
+
this.error(`Failed to revoke access: ${message}`);
|
|
109
|
+
}
|
|
110
|
+
this.log('');
|
|
111
|
+
}
|
|
112
|
+
async findCIAccount(service, nameOrId) {
|
|
113
|
+
try {
|
|
114
|
+
const accounts = await service.ciAccountList();
|
|
115
|
+
return accounts.find(a => a.name.toLowerCase() === nameOrId.toLowerCase() ||
|
|
116
|
+
a.accountId === nameOrId ||
|
|
117
|
+
a.cognitoUsername.includes(nameOrId)) || null;
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async promptForStage(service) {
|
|
124
|
+
this.log(chalk.gray(' Fetching stages...'));
|
|
125
|
+
const stages = await service.stageList();
|
|
126
|
+
if (!stages || stages.length === 0) {
|
|
127
|
+
this.error('No stages found');
|
|
128
|
+
}
|
|
129
|
+
const stageChoices = stages.map(s => ({
|
|
130
|
+
name: s.production
|
|
131
|
+
? `${s.name} ${chalk.red('(PROD)')}`
|
|
132
|
+
: `${s.name} ${chalk.blue('(dev)')}`,
|
|
133
|
+
value: s.slug || s.name,
|
|
134
|
+
}));
|
|
135
|
+
const { stage } = await inquirer.prompt([{
|
|
136
|
+
choices: stageChoices,
|
|
137
|
+
message: chalk.yellow('Select a stage:'),
|
|
138
|
+
name: 'stage',
|
|
139
|
+
type: 'list',
|
|
140
|
+
}]);
|
|
141
|
+
return stage;
|
|
142
|
+
}
|
|
143
|
+
async promptForTarget(service, stageName) {
|
|
144
|
+
this.log(chalk.gray(' Fetching current access...'));
|
|
145
|
+
try {
|
|
146
|
+
const accessData = await service.stageAccessGet(stageName);
|
|
147
|
+
if (!accessData.access || accessData.access.length === 0) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
// Build choices from current access
|
|
151
|
+
const choices = accessData.access.map(entry => ({
|
|
152
|
+
name: `${entry.targetId} (${entry.role})`,
|
|
153
|
+
value: {
|
|
154
|
+
displayName: entry.targetId,
|
|
155
|
+
id: entry.targetId,
|
|
156
|
+
type: entry.targetType,
|
|
157
|
+
},
|
|
158
|
+
}));
|
|
159
|
+
const { target } = await inquirer.prompt([{
|
|
160
|
+
choices,
|
|
161
|
+
message: chalk.yellow('Select who to revoke access from:'),
|
|
162
|
+
name: 'target',
|
|
163
|
+
type: 'list',
|
|
164
|
+
}]);
|
|
165
|
+
return target;
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class StageShare extends Command {
|
|
3
|
+
static args: {
|
|
4
|
+
stage: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
static examples: string[];
|
|
8
|
+
static flags: {
|
|
9
|
+
ci: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
domain: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
group: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
role: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
user: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
};
|
|
16
|
+
static strict: boolean;
|
|
17
|
+
run(): Promise<void>;
|
|
18
|
+
private findCIAccount;
|
|
19
|
+
private findGroup;
|
|
20
|
+
private promptForRole;
|
|
21
|
+
private promptForStages;
|
|
22
|
+
private promptForTarget;
|
|
23
|
+
}
|