Skip to main content

One post tagged with "costs"

View All Tags

GitHub β†’ AWS: Show infrastructure costs

See last 30‑day AWS cost for resources tagged to this repo
πŸ”’
https://github.com/mycompany/webshop
preload

How does this help you?​

  • See the last 30 days AWS cost for infra tagged with this repository
  • Jump directly to AWS Cost Explorer pre-filtered by the repo tag

Preview​

How it looks in the extension

ToolJumpβ€’costCosts 30d: $2950β€’ ... Other items ...

High level approach​

We assume AWS resources are tagged with the repository name (tag key repository, value matching the GitHub repo, e.g. company/webshop). We then query AWS Cost Explorer for the past 30 days, filtered by that tag across all services, and sum the total cost.

Prerequisites​

For the code below to work, please follow the guide on Connecting to AWS. Provide AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY as secrets.

In addition, the AWS identity used by the integration must allow querying the Cost Explorer API. At minimum, grant ce:GetCostAndUsage:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ce:GetCostAndUsage"],
"Resource": "*"
}
]
}

Code​

github.aws.costs.integration.example.js
module.exports = {
metadata: {
name: 'github-aws-costs',
description: 'Show last 30 days AWS cost for resources tagged with this GitHub repository and link to Cost Explorer',
match: {
contextType: 'github',
context: {
'page.repository': { startsWith: 'my-org/' }
}
},
requiredSecrets: ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY'],
cache: 300
},
run: async function (context, secrets = {}) {
// Import AWS SDK v3 Cost Explorer client only at runtime
const { CostExplorerClient, GetCostAndUsageCommand } = require('@aws-sdk/client-cost-explorer');

// Tag key and value derived from GitHub context
const tagKey = 'repository';
const tagValue = context.page.repository; // e.g. "company/webshop"

// Cost Explorer is in us-east-1
const client = new CostExplorerClient({
region: 'us-east-1',
credentials: {
accessKeyId: secrets.AWS_ACCESS_KEY_ID,
secretAccessKey: secrets.AWS_SECRET_ACCESS_KEY,
},
});

// Build a 30-day window (End is exclusive per AWS API)
function toYMD(d) {
const y = d.getUTCFullYear();
const m = String(d.getUTCMonth() + 1).padStart(2, '0');
const day = String(d.getUTCDate()).padStart(2, '0');
return `${y}-${m}-${day}`;
}
const endDate = new Date(); // today (exclusive)
const startDate = new Date();
startDate.setUTCDate(endDate.getUTCDate() - 30);

const params = {
TimePeriod: { Start: toYMD(startDate), End: toYMD(endDate) },
Granularity: 'DAILY',
Metrics: ['UnblendedCost'],
Filter: {
Tags: { Key: tagKey, Values: [tagValue] }
}
};

let total = 0;
let unit = 'USD';
let nextToken;
do {
const resp = await client.send(new GetCostAndUsageCommand({ ...params, NextPageToken: nextToken }));
if (Array.isArray(resp.ResultsByTime)) {
for (const p of resp.ResultsByTime) {
const metric = p.Total && p.Total.UnblendedCost;
if (metric && metric.Amount) {
total += parseFloat(metric.Amount);
unit = metric.Unit || unit;
}
}
}
nextToken = resp.NextPageToken;
} while (nextToken);

// Build a deep link to AWS Cost Explorer filtered by the tag and last 30 days
const ceFilter = { Tags: { Key: tagKey, Values: [tagValue] } };
const ceUrl = 'https://us-east-1.console.aws.amazon.com/cost-management/home' +
'?region=us-east-1#/cost-explorer' +
`?timeRange=LAST_30_DAYS&granularity=DAILY&costMetric=UnblendedCost&filter=${encodeURIComponent(JSON.stringify(ceFilter))}`;

// Format amount (simple two-decimal string)
const currencySymbol = unit === 'USD' ? '$' : `${unit} `;
const pretty = `${currencySymbol}${total.toFixed(2)}`;

const results = [
{ type: 'link', content: `Costs 30d: ${pretty}`, href: ceUrl }
];

return results;
}
};