@intecoag/inteco-cli 1.8.0 → 1.9.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intecoag/inteco-cli",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "CLI-Tools for Inteco",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/index.js CHANGED
@@ -22,6 +22,7 @@ import configMutation from './modules/configMutation.js';
22
22
  import bundleProduct from './modules/bundleProduct.js';
23
23
  import { azureCreateSyncConfig, azurePush, azurePull } from './modules/azureSync.js';
24
24
  import githubSecurityAdvisories from './modules/githubSecurityAdvisories.js';
25
+ import listGithubDeploymentKeys from './modules/githubDeploymentKeysList.js';
25
26
 
26
27
  import updateNotifier from 'update-notifier';
27
28
  import { addGithubDeploymentKey } from './modules/githubDeploymentKey.js';
@@ -115,6 +116,9 @@ switch (cli.input[0]) {
115
116
  case "github_add_deploy_key":
116
117
  addGithubDeploymentKey();
117
118
  break;
119
+ case "github_list_deploy_keys":
120
+ listGithubDeploymentKeys();
121
+ break;
118
122
  default:
119
123
  cli.showHelp()
120
124
  break;
@@ -0,0 +1,199 @@
1
+ import prompts from 'prompts';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import Table from 'cli-table3';
5
+ import { getGithubToken, fetchPaginatedGithubAPI, fetchGithubAPI } from '../utils/github/github.js';
6
+
7
+ /**
8
+ * Format a date string to a readable format, or show "Never" if null
9
+ * @param {string|null} dateString - ISO date string or null
10
+ * @returns {string} Formatted date or "Never"
11
+ */
12
+ function formatDate(dateString) {
13
+ if (!dateString) return chalk.gray('Never');
14
+
15
+ const date = new Date(dateString);
16
+ const now = new Date();
17
+ const diffMs = now - date;
18
+ const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
19
+
20
+ if (diffDays === 0) return chalk.green('Today');
21
+ if (diffDays === 1) return chalk.green('Yesterday');
22
+ if (diffDays < 7) return chalk.green(`${diffDays} days ago`);
23
+ if (diffDays < 30) return chalk.yellow(`${Math.floor(diffDays / 7)} weeks ago`);
24
+ if (diffDays < 365) return chalk.yellow(`${Math.floor(diffDays / 30)} months ago`);
25
+
26
+ return chalk.red(`${Math.floor(diffDays / 365)} years ago`);
27
+ }
28
+
29
+ /**
30
+ * Fetch all deployment keys for a repository
31
+ * @param {string} baseUrl - Base API URL for the repository keys
32
+ * @param {string} token - GitHub authentication token
33
+ * @returns {Promise<Array>} Array of deployment keys
34
+ */
35
+ async function fetchDeploymentKeys(baseUrl, token) {
36
+ try {
37
+ return await fetchPaginatedGithubAPI(baseUrl, token);
38
+ } catch (error) {
39
+ // Return empty array if there's an error fetching keys for this repo
40
+ return [];
41
+ }
42
+ }
43
+
44
+ /**
45
+ * List all deployment keys across all repositories in an organization
46
+ */
47
+ export async function listGithubDeploymentKeys() {
48
+ console.log();
49
+
50
+ // Get GitHub authentication token
51
+ let token;
52
+ let authMethod;
53
+
54
+ try {
55
+ ({ token, authMethod } = await getGithubToken());
56
+ } catch (error) {
57
+ console.log();
58
+ console.error(chalk.red(`✗ ${error.message}`));
59
+ console.log(chalk.yellow('\nAuthentication setup:'));
60
+ console.log(chalk.gray(' Option 1: Install GitHub CLI and run: gh auth login'));
61
+ console.log(chalk.gray(' Option 2: Set GITHUB_TOKEN environment variable'));
62
+ console.log();
63
+ process.exit(1);
64
+ }
65
+
66
+ console.log(chalk.green(`✓ Authenticated via: ${authMethod}`));
67
+ console.log();
68
+
69
+ // Get organization name
70
+ const orgResponse = await prompts([
71
+ {
72
+ type: 'text',
73
+ name: 'organization',
74
+ message: 'GitHub Organization Name?',
75
+ initial: 'intecoag',
76
+ validate: (value) => value.length > 0 || 'Organization name is required'
77
+ }
78
+ ], {
79
+ onCancel: () => {
80
+ console.log();
81
+ console.log(chalk.red('Cancelled deployment keys listing!'));
82
+ console.log();
83
+ process.exit(0);
84
+ }
85
+ });
86
+
87
+ const { organization } = orgResponse;
88
+
89
+ let mainSpinner = ora('Fetching repositories...').start();
90
+
91
+ try {
92
+ // Fetch all repositories for the organization
93
+ const baseReposUrl = `https://api.github.com/orgs/${organization}/repos`;
94
+ const repos = await fetchPaginatedGithubAPI(baseReposUrl, token);
95
+
96
+ if (repos.length === 0) {
97
+ mainSpinner.warn(`No repositories found in organization "${organization}"`);
98
+ console.log();
99
+ return;
100
+ }
101
+
102
+ // Fetch deployment keys for all repositories
103
+ const allKeys = [];
104
+ for (let i = 0; i < repos.length; i++) {
105
+ const repo = repos[i];
106
+ const progress = `[${i + 1}/${repos.length}]`;
107
+ mainSpinner.text = `${progress} Fetching deployment keys from: ${chalk.blue(repo.name)}...`;
108
+
109
+ const keysUrl = `https://api.github.com/repos/${organization}/${repo.name}/keys`;
110
+ const keys = await fetchDeploymentKeys(keysUrl, token);
111
+
112
+ keys.forEach(key => {
113
+ allKeys.push({
114
+ repository: repo.name,
115
+ keyId: key.id,
116
+ title: key.title,
117
+ createdAt: key.created_at,
118
+ lastUsedAt: key.last_used,
119
+ readOnly: key.read_only
120
+ });
121
+ });
122
+ }
123
+
124
+ mainSpinner.succeed(`Found ${allKeys.length} deployment keys across ${repos.length} repositories`);
125
+ console.log();
126
+
127
+ if (allKeys.length === 0) {
128
+ console.log(chalk.yellow('No deployment keys found in this organization.'));
129
+ console.log();
130
+ return;
131
+ }
132
+
133
+ // Display keys in a table
134
+ const table = new Table({
135
+ head: [
136
+ chalk.cyan('Repository'),
137
+ chalk.cyan('Key Title'),
138
+ chalk.cyan('Created'),
139
+ chalk.cyan('Last Used'),
140
+ chalk.cyan('Read-Only')
141
+ ].map(h => h),
142
+ style: { head: [], border: ['cyan'] },
143
+ colWidths: [25, 30, 20, 20, 12],
144
+ wordWrap: true
145
+ });
146
+
147
+ // Sort by repository name and then by last used date (newest first)
148
+ allKeys.sort((a, b) => {
149
+ if (a.repository !== b.repository) {
150
+ return a.repository.localeCompare(b.repository);
151
+ }
152
+ return new Date(b.lastUsedAt || 0) - new Date(a.lastUsedAt || 0);
153
+ });
154
+
155
+ allKeys.forEach(key => {
156
+ table.push([
157
+ chalk.blue(key.repository),
158
+ key.title,
159
+ new Date(key.createdAt).toLocaleDateString(),
160
+ formatDate(key.lastUsedAt),
161
+ key.readOnly ? chalk.green('Yes') : chalk.yellow('No')
162
+ ]);
163
+ });
164
+
165
+ console.log(table.toString());
166
+ console.log();
167
+
168
+ // Show statistics
169
+ const keysNeverUsed = allKeys.filter(k => !k.lastUsedAt).length;
170
+ const readOnlyKeys = allKeys.filter(k => k.readOnly).length;
171
+ const readWriteKeys = allKeys.filter(k => !k.readOnly).length;
172
+
173
+ console.log(chalk.bold('Summary:'));
174
+ console.log(` Total deployment keys: ${chalk.cyan(allKeys.length)}`);
175
+ console.log(` Never used: ${chalk.yellow(keysNeverUsed)}`);
176
+ console.log(` Read-only keys: ${chalk.green(readOnlyKeys)}`);
177
+ console.log(` Read-write keys: ${chalk.yellow(readWriteKeys)}`);
178
+ console.log();
179
+
180
+ } catch (error) {
181
+ console.log();
182
+ mainSpinner.fail('Error fetching deployment keys');
183
+
184
+ if (error.message.startsWith('401')) {
185
+ console.error(chalk.red(`✗ ${error.message}`));
186
+ console.log(chalk.yellow('\nAuthentication setup:'));
187
+ console.log(chalk.gray(' Option 1: Install GitHub CLI and run: gh auth login'));
188
+ console.log(chalk.gray(' Option 2: Set GITHUB_TOKEN environment variable'));
189
+ } else if (error.message.startsWith('404')) {
190
+ console.error(chalk.red(`✗ ${error.message} - Organization not found`));
191
+ } else {
192
+ console.error(chalk.red(`Error: ${error.message}`));
193
+ }
194
+ console.log();
195
+ process.exit(1);
196
+ }
197
+ }
198
+
199
+ export default listGithubDeploymentKeys;
@@ -64,5 +64,8 @@
64
64
  },
65
65
  "github_add_deploy_key": {
66
66
  "desc": "Workflow to add a deployment key to a GitHub repository for a remote server (requires GitHub CLI)"
67
+ },
68
+ "github_list_deploy_keys": {
69
+ "desc": "Lists all deployment keys across all repositories in a GitHub organization with their last used dates (requires GitHub CLI or GITHUB_TOKEN)"
67
70
  }
68
71
  }