infra-cost 0.1.0 → 0.2.1

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,9 +1,13 @@
1
1
  {
2
2
  "name": "infra-cost",
3
- "version": "0.1.0",
4
- "description": "A CLI tool to perform cost analysis on your infra account's cost",
3
+ "version": "0.2.1",
4
+ "description": "Multi-cloud FinOps CLI tool for comprehensive cost analysis and infrastructure optimization across AWS, GCP, Azure, Alibaba Cloud, and Oracle Cloud",
5
5
  "type": "module",
6
- "author": "Code Collab <codecollab.co@gmail.com> (https://github.com/codecollab-co/infra-cost)",
6
+ "author": {
7
+ "name": "Code Collab",
8
+ "email": "codecollab.co@gmail.com",
9
+ "url": "https://github.com/codecollab-co/infra-cost"
10
+ },
7
11
  "files": [
8
12
  "!tests/**/*",
9
13
  "dist/**/*",
@@ -11,7 +15,8 @@
11
15
  "bin/**/*"
12
16
  ],
13
17
  "bin": {
14
- "aws-cost": "bin/index.js"
18
+ "infra-cost": "./bin/index.js",
19
+ "aws-cost": "./bin/index.js"
15
20
  },
16
21
  "scripts": {
17
22
  "build": "tsup",
@@ -20,22 +25,40 @@
20
25
  "predev": "run-s clean",
21
26
  "clean": "rm -rf dist",
22
27
  "typecheck": "tsc --noEmit",
23
- "test": "echo \"Error: no test specified\" && exit 1"
28
+ "test": "echo \"Error: no test specified\" && exit 1",
29
+ "version:check": "node scripts/version-manager.js check",
30
+ "version:next": "node scripts/version-manager.js next",
31
+ "version:bump:patch": "node scripts/version-manager.js bump patch",
32
+ "version:bump:minor": "node scripts/version-manager.js bump minor",
33
+ "version:bump:major": "node scripts/version-manager.js bump major",
34
+ "version:bump:prerelease": "node scripts/version-manager.js bump prerelease",
35
+ "version:set": "node scripts/version-manager.js set",
36
+ "publish:dry": "npm publish --dry-run",
37
+ "publish:beta": "npm publish --tag beta",
38
+ "publish:latest": "npm publish --tag latest",
39
+ "prepare-release": "./scripts/prepare-release.sh",
40
+ "prepublishOnly": "npm run build",
41
+ "postversion": "echo \"Don't forget to push the tag: git push origin v$npm_package_version\"",
42
+ "postpublish": "echo \"🎉 Published $(npm pkg get name)@$(npm pkg get version) to npm!\""
24
43
  },
25
44
  "keywords": [
26
45
  "aws",
46
+ "gcp",
47
+ "azure",
48
+ "alibaba-cloud",
49
+ "oracle-cloud",
50
+ "multi-cloud",
27
51
  "cost",
28
52
  "cli",
29
- "aws-cost",
30
- "aws-cost-cli",
31
- "aws-costs",
32
- "typescript",
33
- "aws cli"
53
+ "infra-cost",
54
+ "cloud-cost",
55
+ "cost-analysis",
56
+ "typescript"
34
57
  ],
35
58
  "license": "MIT",
36
59
  "repository": {
37
60
  "type": "git",
38
- "url": "git+https://github.com/codecollab-co/infra-cost.git"
61
+ "url": "https://github.com/codecollab-co/infra-cost.git"
39
62
  },
40
63
  "engines": {
41
64
  "node": ">=12.0"
@@ -45,23 +68,75 @@
45
68
  },
46
69
  "homepage": "https://github.com/codecollab-co/infra-cost.git#readme",
47
70
  "dependencies": {
48
- "@aws-sdk/shared-ini-file-loader": "^3.254.0",
49
- "aws-sdk": "^2.1299.0",
71
+ "@aws-sdk/client-budgets": "^3.908.0",
72
+ "@aws-sdk/client-cost-explorer": "^3.370.0",
73
+ "@aws-sdk/client-ec2": "^3.909.0",
74
+ "@aws-sdk/client-iam": "^3.370.0",
75
+ "@aws-sdk/client-lambda": "^3.908.0",
76
+ "@aws-sdk/client-rds": "^3.908.0",
77
+ "@aws-sdk/client-s3": "^3.908.0",
78
+ "@aws-sdk/client-sts": "^3.370.0",
79
+ "@aws-sdk/credential-providers": "^3.370.0",
80
+ "@aws-sdk/shared-ini-file-loader": "^3.370.0",
81
+ "axios": "^1.12.2",
50
82
  "chalk": "^5.2.0",
83
+ "cli-progress": "^3.12.0",
84
+ "cli-table3": "^0.6.5",
51
85
  "commander": "^10.0.0",
52
86
  "dayjs": "^1.11.7",
53
87
  "dotenv": "^16.0.3",
88
+ "exceljs": "^4.4.0",
89
+ "express": "^5.1.0",
90
+ "moment": "^2.30.1",
54
91
  "node-fetch": "^3.3.0",
55
- "ora": "^6.1.2"
92
+ "ora": "^6.1.2",
93
+ "puppeteer": "^24.24.1",
94
+ "xlsx": "^0.18.5"
56
95
  },
57
96
  "devDependencies": {
97
+ "@types/cli-progress": "^3.11.6",
98
+ "@types/express": "^5.0.3",
99
+ "@types/jest": "^30.0.0",
58
100
  "@types/node": "^18.11.18",
101
+ "@types/supertest": "^6.0.3",
102
+ "jest": "^30.2.0",
59
103
  "npm-run-all": "^4.1.5",
60
- "react": "^19.0.0",
104
+ "supertest": "^7.1.4",
105
+ "ts-jest": "^29.4.5",
61
106
  "ts-node": "^10.9.1",
62
- "tslib": "^2.8.1",
63
- "tsup": "^8.4.0",
64
- "typescript": "^4.9.5"
107
+ "tsup": "^6.5.0",
108
+ "typescript": "^4.9.4"
109
+ },
110
+ "peerDependencies": {
111
+ "@alicloud/pop-core": "^1.7.12",
112
+ "@azure/arm-costmanagement": "^1.0.0",
113
+ "@azure/arm-subscriptions": "^5.1.0",
114
+ "@azure/identity": "^3.1.0",
115
+ "@google-cloud/billing": "^4.1.0",
116
+ "@google-cloud/resource-manager": "^5.1.0",
117
+ "oci-sdk": "^2.69.0"
65
118
  },
66
- "main": "index.js"
119
+ "peerDependenciesMeta": {
120
+ "@google-cloud/billing": {
121
+ "optional": true
122
+ },
123
+ "@google-cloud/resource-manager": {
124
+ "optional": true
125
+ },
126
+ "@azure/arm-costmanagement": {
127
+ "optional": true
128
+ },
129
+ "@azure/arm-subscriptions": {
130
+ "optional": true
131
+ },
132
+ "@azure/identity": {
133
+ "optional": true
134
+ },
135
+ "@alicloud/pop-core": {
136
+ "optional": true
137
+ },
138
+ "oci-sdk": {
139
+ "optional": true
140
+ }
141
+ }
67
142
  }
package/dist/index.js DELETED
@@ -1,487 +0,0 @@
1
- // src/index.ts
2
- import { Command } from "commander";
3
-
4
- // package.json
5
- var package_default = {
6
- name: "infra-cost",
7
- version: "0.1.0",
8
- description: "A CLI tool to perform cost analysis on your infra account's cost",
9
- type: "module",
10
- author: {
11
- name: "Code Collab",
12
- email: "codecollab.co@gmail.com",
13
- url: "https://github.com/codecollab-co/infra-cost"
14
- },
15
- files: [
16
- "!tests/**/*",
17
- "dist/**/*",
18
- "!dist/**/*.js.map",
19
- "bin/**/*"
20
- ],
21
- bin: {
22
- "aws-cost": "./bin/index.js"
23
- },
24
- scripts: {
25
- build: "tsup",
26
- dev: "tsup --watch",
27
- prebuild: "run-s clean",
28
- predev: "run-s clean",
29
- clean: "rm -rf dist",
30
- typecheck: "tsc --noEmit",
31
- test: 'echo "Error: no test specified" && exit 1'
32
- },
33
- keywords: [
34
- "aws",
35
- "cost",
36
- "cli",
37
- "aws-cost",
38
- "aws-cost-cli",
39
- "aws-costs",
40
- "typescript",
41
- "aws cli"
42
- ],
43
- license: "MIT",
44
- repository: {
45
- type: "git",
46
- url: "https://github.com/codecollab-co/infra-cost.git"
47
- },
48
- engines: {
49
- node: ">=12.0"
50
- },
51
- bugs: {
52
- url: "https://github.com/codecollab-co/infra-cost/issues"
53
- },
54
- homepage: "https://github.com/codecollab-co/infra-cost.git#readme",
55
- dependencies: {
56
- "@aws-sdk/shared-ini-file-loader": "^3.254.0",
57
- "aws-sdk": "^2.1299.0",
58
- chalk: "^5.2.0",
59
- commander: "^10.0.0",
60
- dayjs: "^1.11.7",
61
- dotenv: "^16.0.3",
62
- "node-fetch": "^3.3.0",
63
- ora: "^6.1.2"
64
- },
65
- devDependencies: {
66
- "@types/node": "^18.11.18",
67
- "npm-run-all": "^4.1.5",
68
- "ts-node": "^10.9.1",
69
- tsup: "^8.4.0",
70
- typescript: "^4.9.4"
71
- }
72
- };
73
-
74
- // src/account.ts
75
- import AWS from "aws-sdk";
76
-
77
- // src/logger.ts
78
- import chalk from "chalk";
79
- import ora from "ora";
80
- function printFatalError(error) {
81
- console.error(`
82
- ${chalk.bold.redBright.underline(`Error:`)}
83
- ${chalk.redBright(`${error}`)}
84
- `);
85
- process.exit(1);
86
- }
87
- var spinner;
88
- function showSpinner(text) {
89
- if (!spinner) {
90
- spinner = ora({ text: "" }).start();
91
- }
92
- spinner.text = text;
93
- }
94
- function hideSpinner() {
95
- if (!spinner) {
96
- return;
97
- }
98
- spinner.stop();
99
- }
100
-
101
- // src/account.ts
102
- async function getAccountAlias(awsConfig2) {
103
- var _a;
104
- showSpinner("Getting account alias");
105
- const iam = new AWS.IAM(awsConfig2);
106
- const accountAliases = await iam.listAccountAliases().promise();
107
- const foundAlias = (_a = accountAliases == null ? void 0 : accountAliases["AccountAliases"]) == null ? void 0 : _a[0];
108
- if (foundAlias) {
109
- return foundAlias;
110
- }
111
- const sts = new AWS.STS(awsConfig2);
112
- const accountInfo = await sts.getCallerIdentity().promise();
113
- return (accountInfo == null ? void 0 : accountInfo.Account) || "";
114
- }
115
-
116
- // src/config.ts
117
- import { loadSharedConfigFiles } from "@aws-sdk/shared-ini-file-loader";
118
- import chalk2 from "chalk";
119
- async function getAwsConfigFromOptionsOrFile(options2) {
120
- const { profile, accessKey, secretKey, sessionToken, region } = options2;
121
- if (accessKey || secretKey) {
122
- if (!accessKey || !secretKey) {
123
- printFatalError(`
124
- You need to provide both of the following options:
125
- ${chalk2.bold("--access-key")}
126
- ${chalk2.bold("--secret-key")}
127
- `);
128
- }
129
- return {
130
- credentials: {
131
- accessKeyId: accessKey,
132
- secretAccessKey: secretKey,
133
- sessionToken
134
- },
135
- region
136
- };
137
- }
138
- return {
139
- credentials: await loadAwsCredentials(profile),
140
- region
141
- };
142
- }
143
- async function loadAwsCredentials(profile = "default") {
144
- var _a, _b, _c;
145
- const configFiles = await loadSharedConfigFiles();
146
- const credentialsFile = configFiles.credentialsFile;
147
- const accessKey = (_a = credentialsFile == null ? void 0 : credentialsFile[profile]) == null ? void 0 : _a.aws_access_key_id;
148
- const secretKey = (_b = credentialsFile == null ? void 0 : credentialsFile[profile]) == null ? void 0 : _b.aws_secret_access_key;
149
- const sessionToken = (_c = credentialsFile == null ? void 0 : credentialsFile[profile]) == null ? void 0 : _c.aws_session_token;
150
- if (!accessKey || !secretKey) {
151
- const sharedCredentialsFile = process.env.AWS_SHARED_CREDENTIALS_FILE || "~/.aws/credentials";
152
- const sharedConfigFile = process.env.AWS_CONFIG_FILE || "~/.aws/config";
153
- printFatalError(`
154
- Could not find the AWS credentials in the following files for the profile "${profile}":
155
- ${chalk2.bold(sharedCredentialsFile)}
156
- ${chalk2.bold(sharedConfigFile)}
157
-
158
- If the config files exist at different locations, set the following environment variables:
159
- ${chalk2.bold(`AWS_SHARED_CREDENTIALS_FILE`)}
160
- ${chalk2.bold(`AWS_CONFIG_FILE`)}
161
-
162
- You can also configure the credentials via the following command:
163
- ${chalk2.bold(`aws configure --profile ${profile}`)}
164
-
165
- You can also provide the credentials via the following options:
166
- ${chalk2.bold(`--access-key`)}
167
- ${chalk2.bold(`--secret-key`)}
168
- ${chalk2.bold(`--region`)}
169
- `);
170
- }
171
- return {
172
- accessKeyId: accessKey,
173
- secretAccessKey: secretKey,
174
- sessionToken
175
- };
176
- }
177
-
178
- // src/cost.ts
179
- import AWS2 from "aws-sdk";
180
- import dayjs from "dayjs";
181
- async function getRawCostByService(awsConfig2) {
182
- showSpinner("Getting pricing data");
183
- const costExplorer = new AWS2.CostExplorer(awsConfig2);
184
- const endDate = dayjs().subtract(1, "day");
185
- const startDate = endDate.subtract(65, "day");
186
- const pricingData = await costExplorer.getCostAndUsage({
187
- TimePeriod: {
188
- Start: startDate.format("YYYY-MM-DD"),
189
- End: endDate.format("YYYY-MM-DD")
190
- },
191
- Granularity: "DAILY",
192
- Filter: {
193
- Not: {
194
- Dimensions: {
195
- Key: "RECORD_TYPE",
196
- Values: ["Credit", "Refund", "Upfront", "Support"]
197
- }
198
- }
199
- },
200
- Metrics: ["UnblendedCost"],
201
- GroupBy: [
202
- {
203
- Type: "DIMENSION",
204
- Key: "SERVICE"
205
- }
206
- ]
207
- }).promise();
208
- const costByService = {};
209
- for (const day of pricingData.ResultsByTime) {
210
- for (const group of day.Groups) {
211
- const serviceName = group.Keys[0];
212
- const cost = group.Metrics.UnblendedCost.Amount;
213
- const costDate = day.TimePeriod.End;
214
- costByService[serviceName] = costByService[serviceName] || {};
215
- costByService[serviceName][costDate] = parseFloat(cost);
216
- }
217
- }
218
- return costByService;
219
- }
220
- function calculateServiceTotals(rawCostByService) {
221
- const totals = {
222
- lastMonth: 0,
223
- thisMonth: 0,
224
- last7Days: 0,
225
- yesterday: 0
226
- };
227
- const totalsByService = {
228
- lastMonth: {},
229
- thisMonth: {},
230
- last7Days: {},
231
- yesterday: {}
232
- };
233
- const startOfLastMonth = dayjs().subtract(1, "month").startOf("month");
234
- const startOfThisMonth = dayjs().startOf("month");
235
- const startOfLast7Days = dayjs().subtract(7, "day");
236
- const startOfYesterday = dayjs().subtract(1, "day");
237
- for (const service of Object.keys(rawCostByService)) {
238
- const servicePrices = rawCostByService[service];
239
- let lastMonthServiceTotal = 0;
240
- let thisMonthServiceTotal = 0;
241
- let last7DaysServiceTotal = 0;
242
- let yesterdayServiceTotal = 0;
243
- for (const date of Object.keys(servicePrices)) {
244
- const price = servicePrices[date];
245
- const dateObj = dayjs(date);
246
- if (dateObj.isSame(startOfLastMonth, "month")) {
247
- lastMonthServiceTotal += price;
248
- }
249
- if (dateObj.isSame(startOfThisMonth, "month")) {
250
- thisMonthServiceTotal += price;
251
- }
252
- if (dateObj.isSame(startOfLast7Days, "week") && !dateObj.isSame(startOfYesterday, "day")) {
253
- last7DaysServiceTotal += price;
254
- }
255
- if (dateObj.isSame(startOfYesterday, "day")) {
256
- yesterdayServiceTotal += price;
257
- }
258
- }
259
- totalsByService.lastMonth[service] = lastMonthServiceTotal;
260
- totalsByService.thisMonth[service] = thisMonthServiceTotal;
261
- totalsByService.last7Days[service] = last7DaysServiceTotal;
262
- totalsByService.yesterday[service] = yesterdayServiceTotal;
263
- totals.lastMonth += lastMonthServiceTotal;
264
- totals.thisMonth += thisMonthServiceTotal;
265
- totals.last7Days += last7DaysServiceTotal;
266
- totals.yesterday += yesterdayServiceTotal;
267
- }
268
- return {
269
- totals,
270
- totalsByService
271
- };
272
- }
273
- async function getTotalCosts(awsConfig2) {
274
- const rawCosts = await getRawCostByService(awsConfig2);
275
- const totals = calculateServiceTotals(rawCosts);
276
- return totals;
277
- }
278
-
279
- // src/printers/fancy.ts
280
- import chalk3 from "chalk";
281
- function printFancy(accountAlias, totals, isSummary = false) {
282
- hideSpinner();
283
- console.clear();
284
- const totalCosts = totals.totals;
285
- const serviceCosts = totals.totalsByService;
286
- const allServices = Object.keys(serviceCosts.yesterday);
287
- const sortedServiceNames = allServices.sort((a, b) => b.length - a.length);
288
- const maxServiceLength = sortedServiceNames.reduce((max, service) => {
289
- return Math.max(max, service.length);
290
- }, 0) + 1;
291
- const totalLastMonth = chalk3.green(`$${totalCosts.lastMonth.toFixed(2)}`);
292
- const totalThisMonth = chalk3.green(`$${totalCosts.thisMonth.toFixed(2)}`);
293
- const totalLast7Days = chalk3.green(`$${totalCosts.last7Days.toFixed(2)}`);
294
- const totalYesterday = chalk3.bold.yellowBright(`$${totalCosts.yesterday.toFixed(2)}`);
295
- console.log("");
296
- console.log(`${"AWS Cost Report:".padStart(maxServiceLength + 1)} ${chalk3.bold.yellow(accountAlias)}`);
297
- console.log("");
298
- console.log(`${"Last Month".padStart(maxServiceLength)}: ${totalLastMonth}`);
299
- console.log(`${"This Month".padStart(maxServiceLength)}: ${totalThisMonth}`);
300
- console.log(`${"Last 7 days".padStart(maxServiceLength)}: ${totalLast7Days}`);
301
- console.log(`${chalk3.bold("Yesterday".padStart(maxServiceLength))}: ${totalYesterday}`);
302
- console.log("");
303
- if (isSummary) {
304
- return;
305
- }
306
- const headerPadLength = 11;
307
- const serviceHeader = chalk3.white("Service".padStart(maxServiceLength));
308
- const lastMonthHeader = chalk3.white(`Last Month`.padEnd(headerPadLength));
309
- const thisMonthHeader = chalk3.white(`This Month`.padEnd(headerPadLength));
310
- const last7DaysHeader = chalk3.white(`Last 7 Days`.padEnd(headerPadLength));
311
- const yesterdayHeader = chalk3.bold.white("Yesterday".padEnd(headerPadLength));
312
- console.log(`${serviceHeader} ${lastMonthHeader} ${thisMonthHeader} ${last7DaysHeader} ${yesterdayHeader}`);
313
- for (let service of sortedServiceNames) {
314
- const serviceLabel = chalk3.cyan(service.padStart(maxServiceLength));
315
- const lastMonthTotal = chalk3.green(`$${serviceCosts.lastMonth[service].toFixed(2)}`.padEnd(headerPadLength));
316
- const thisMonthTotal = chalk3.green(`$${serviceCosts.thisMonth[service].toFixed(2)}`.padEnd(headerPadLength));
317
- const last7DaysTotal = chalk3.green(`$${serviceCosts.last7Days[service].toFixed(2)}`.padEnd(headerPadLength));
318
- const yesterdayTotal = chalk3.bold.yellowBright(
319
- `$${serviceCosts.yesterday[service].toFixed(2)}`.padEnd(headerPadLength)
320
- );
321
- console.log(`${serviceLabel} ${lastMonthTotal} ${thisMonthTotal} ${last7DaysTotal} ${yesterdayTotal}`);
322
- }
323
- }
324
-
325
- // src/printers/json.ts
326
- function printJson(accountAlias, totalCosts, isSummary = false) {
327
- hideSpinner();
328
- if (isSummary) {
329
- console.log(
330
- JSON.stringify(
331
- {
332
- account: accountAlias,
333
- totals: totalCosts.totals
334
- },
335
- null,
336
- 2
337
- )
338
- );
339
- return;
340
- }
341
- console.log(
342
- JSON.stringify(
343
- {
344
- account: accountAlias,
345
- ...totalCosts
346
- },
347
- null,
348
- 2
349
- )
350
- );
351
- }
352
-
353
- // src/printers/slack.ts
354
- import fetch from "node-fetch";
355
- function formatServiceBreakdown(costs2) {
356
- const serviceCosts = costs2.totalsByService;
357
- const sortedServices = Object.keys(serviceCosts.yesterday).filter((service) => serviceCosts.yesterday[service] > 0).sort((a, b) => serviceCosts.yesterday[b] - serviceCosts.yesterday[a]);
358
- const serviceCostsYesterday = sortedServices.map((service) => {
359
- return `> ${service}: \`$${serviceCosts.yesterday[service].toFixed(2)}\``;
360
- });
361
- return serviceCostsYesterday.join("\n");
362
- }
363
- async function notifySlack(accountAlias, costs2, isSummary, slackToken, slackChannel) {
364
- const channel = slackChannel;
365
- const totals = costs2.totals;
366
- const serviceCosts = costs2.totalsByService;
367
- let serviceCostsYesterday = [];
368
- Object.keys(serviceCosts.yesterday).forEach((service) => {
369
- serviceCosts.yesterday[service].toFixed(2);
370
- serviceCostsYesterday.push(`${service}: $${serviceCosts.yesterday[service].toFixed(2)}`);
371
- });
372
- const summary = `> *Account: ${accountAlias}*
373
-
374
- > *Summary *
375
- > Total Yesterday: \`$${totals.yesterday.toFixed(2)}\`
376
- > Total This Month: \`$${totals.thisMonth.toFixed(2)}\`
377
- > Total Last Month: \`$${totals.lastMonth.toFixed(2)}\`
378
- `;
379
- const breakdown = `
380
- > *Breakdown by Service:*
381
- ${formatServiceBreakdown(costs2)}
382
- `;
383
- let message = `${summary}`;
384
- if (!isSummary) {
385
- message += `${breakdown}`;
386
- }
387
- const response = await fetch("https://slack.com/api/chat.postMessage", {
388
- method: "post",
389
- body: JSON.stringify({
390
- channel,
391
- blocks: [
392
- {
393
- type: "section",
394
- text: {
395
- type: "mrkdwn",
396
- text: message
397
- }
398
- }
399
- ]
400
- }),
401
- headers: {
402
- "Content-Type": "application/json; charset=utf-8",
403
- Authorization: `Bearer ${slackToken}`
404
- }
405
- });
406
- const data = await response.json();
407
- if (!data.ok) {
408
- const message2 = data.error || "Unknown error";
409
- console.error(`
410
- Failed to send message to Slack: ${message2}`);
411
- process.exit(1);
412
- }
413
- console.log("\nSuccessfully sent message to Slack");
414
- }
415
-
416
- // src/printers/text.ts
417
- function printPlainSummary(accountAlias, costs2) {
418
- hideSpinner();
419
- console.clear();
420
- console.log("");
421
- console.log(`Account: ${accountAlias}`);
422
- console.log("");
423
- console.log("Totals:");
424
- console.log(` Last Month: $${costs2.totals.lastMonth.toFixed(2)}`);
425
- console.log(` This Month: $${costs2.totals.thisMonth.toFixed(2)}`);
426
- console.log(` Last 7 Days: $${costs2.totals.last7Days.toFixed(2)}`);
427
- console.log(` Yesterday: $${costs2.totals.yesterday.toFixed(2)}`);
428
- }
429
- function printPlainText(accountAlias, totals, isSummary = false) {
430
- printPlainSummary(accountAlias, totals);
431
- if (isSummary) {
432
- return;
433
- }
434
- const serviceTotals = totals.totalsByService;
435
- const allServices = Object.keys(serviceTotals.yesterday).sort((a, b) => b.length - a.length);
436
- console.log("");
437
- console.log("Totals by Service:");
438
- console.log(" Last Month:");
439
- allServices.forEach((service) => {
440
- console.log(` ${service}: $${serviceTotals.lastMonth[service].toFixed(2)}`);
441
- });
442
- console.log("");
443
- console.log(" This Month:");
444
- allServices.forEach((service) => {
445
- console.log(` ${service}: $${serviceTotals.thisMonth[service].toFixed(2)}`);
446
- });
447
- console.log("");
448
- console.log(" Last 7 Days:");
449
- allServices.forEach((service) => {
450
- console.log(` ${service}: $${serviceTotals.last7Days[service].toFixed(2)}`);
451
- });
452
- console.log("");
453
- console.log(" Yesterday:");
454
- allServices.forEach((service) => {
455
- console.log(` ${service}: $${serviceTotals.yesterday[service].toFixed(2)}`);
456
- });
457
- }
458
-
459
- // src/index.ts
460
- process.env.AWS_SDK_JS_SUPPRESS_MAINTENANCE_MODE_MESSAGE = "1";
461
- var program = new Command();
462
- program.version(package_default.version).name("aws-cost").description(package_default.description).option("-p, --profile [profile]", "AWS profile to use", "default").option("-k, --access-key [key]", "AWS access key").option("-s, --secret-key [key]", "AWS secret key").option("-T, --session-token [key]", "AWS session Token").option("-r, --region [region]", "AWS region", "us-east-1").option("-j, --json", "Get the output as JSON").option("-u, --summary", "Get only the summary without service breakdown").option("-t, --text", "Get the output as plain text (no colors / tables)").option("-S, --slack-token [token]", "Token for the slack integration").option("-C, --slack-channel [channel]", "Channel to which the slack integration should post").option("-h, --help", "Get the help of the CLI").parse(process.argv);
463
- var options = program.opts();
464
- if (options.help) {
465
- program.help();
466
- process.exit(0);
467
- }
468
- var awsConfig = await getAwsConfigFromOptionsOrFile({
469
- profile: options.profile,
470
- accessKey: options.accessKey,
471
- secretKey: options.secretKey,
472
- sessionToken: options.sessionToken,
473
- region: options.region
474
- });
475
- var alias = await getAccountAlias(awsConfig);
476
- var costs = await getTotalCosts(awsConfig);
477
- if (options.json) {
478
- printJson(alias, costs, options.summary);
479
- } else if (options.text) {
480
- printPlainText(alias, costs, options.summary);
481
- } else {
482
- printFancy(alias, costs, options.summary);
483
- }
484
- if (options.slackToken && options.slackChannel) {
485
- await notifySlack(alias, costs, options.summary, options.slackToken, options.slackChannel);
486
- }
487
- //# sourceMappingURL=index.js.map