Skip to main content

11 posts tagged with "github"

View All Tags

AWS Lambda β†’ GitHub: Browse deployed code

Jump to the exact Git commit deployed to this Lambda
πŸ”’
https://eu-central-1.console.aws.amazon.com/lambda/home?region=eu-central-1#/functions/shop-order-processing?tab=code
preload

How does this help you?​

  • You can quickly navigate to the exact code version that's currently deployed to your Lambda function
  • No need to manually search for the repository or figure out which commit is deployed

Preview​

How it looks in the extension

ToolJumpβ€’githubBrowse code @ a1b2c3dβ€’ ... Other items ...

High level approach​

We read the repository and version tags from the Lambda function using the AWS Lambda API, then construct a GitHub URL to browse the code at that specific version/commit.

Prerequisites​

For the code below to work, please ensure you have:

  1. AWS credentials configured in your secrets
  2. Lambda functions tagged with:
    • repository tag containing your GitHub repository in org/repo format
    • version tag containing the commit SHA or version identifier

Code​

aws-lambda-browse-github-code.integration.example.js
module.exports = {
metadata: {
name: 'aws-lambda-browse-github-code',
description: 'Browse the deployed code for AWS Lambda functions by linking to the GitHub repository at the specific version',
match: {
contextType: 'aws',
context: {
'service.name': { equals: 'lambda' },
'service.arn': { exists: true },
'scope.region': { exists: true },
'service.resourceName': { exists: true }
}
},
requiredSecrets: ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY'],
cache: 900
},
run: async function (context, secrets = {}) {
// Get AWS region from context
const awsRegion = context.scope.region;
const functionName = context.service.resourceName;

try {
// Query AWS Lambda to get function tags
const { LambdaClient, ListTagsCommand } = require('@aws-sdk/client-lambda');

const lambdaClient = new LambdaClient({
credentials: {
accessKeyId: secrets.AWS_ACCESS_KEY_ID,
secretAccessKey: secrets.AWS_SECRET_ACCESS_KEY,
},
region: awsRegion
});

const command = new ListTagsCommand({ Resource: context.service.arn });
const tagsResponse = await lambdaClient.send(command);

// Look for repository and version tags
const repository = tagsResponse.Tags?.repository;
const version = tagsResponse.Tags?.version;

if (!repository) {
logger.warn({
operation: 'aws-lambda-browse-github-code',
step: 'no-repository-tag',
functionName: functionName
}, 'No repository tag found on Lambda function');
return [];
}

if (!version) {
logger.warn({
operation: 'aws-lambda-browse-github-code',
step: 'no-version-tag',
functionName: functionName,
repository: repository
}, 'No version tag found on Lambda function');
return [];
}

// Construct GitHub URL
const githubUrl = `https://github.com/${repository}/tree/${version}`;

const results = [
{
type: 'link',
content: `Browse code @ ${version.substring(0, 7)}`,
href: githubUrl,
icon: 'github'
}
];

logger.info({
operation: 'aws-lambda-browse-github-code',
step: 'success',
functionName: functionName,
repository: repository,
version: version,
githubUrl: githubUrl
}, 'Successfully generated GitHub code browse link');

return results;

} catch (error) {
logger.error({
operation: 'aws-lambda-browse-github-code',
step: 'aws-lambda-error',
functionName: functionName,
error: error.message
}, 'Error querying AWS Lambda tags');
return [];
}
}
};

GitHub β†’ AWS: Show infrastructure (Lambdas) for this repo

View Lambda functions belonging to this repo
πŸ”’
https://github.com/mycompany/webshop
preload

How does this help you?​

  • See your AWS infrastructure (Lambda functions) directly from your Github repositories
  • Jump directly to each function in the AWS Console
tip

You can easily modify this integration to return other tagged resources, including EC2s, ECS, EKS, SQS, etc

Preview​

How it looks in the extension

ToolJumpβ€’
lambdaAWS Infra (4 lambdas)
β€’ ... Other items ...

High level approach​

We assume Lambda functions are tagged with the repository name (tag key repository, value matching the GitHub repo, e.g. company/webshop). We use the AWS Resource Groups Tagging API to query lambda:function resources in us-east-1 filtered by that tag, then render a dropdown of the first 10 functions. If there are more, a final "More…" item links to the Lambda console filtered by the repository tag.

Notes:

  • Only the us-east-1 region is scanned to keep things simple and fast.
  • Each item links to the function details page in the AWS console.

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 Resource Groups Tagging API. At minimum, grant tag:GetResources:

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

No lambda:ListFunctions permission is required for this example.

Code​

github.aws.infrastructure.integration.example.js
module.exports = {
metadata: {
name: 'github-aws-infrastructure',
description: 'Show Lambda functions in us-east-1 tagged with this repository as a dropdown',
match: {
contextType: 'github',
context: {
'page.repository': { startsWith: 'my-org/' }
}
},
requiredSecrets: ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY'],
cache: 1800
},
run: async function (context, secrets = {}) {
const { ResourceGroupsTaggingAPIClient, GetResourcesCommand } = require('@aws-sdk/client-resource-groups-tagging-api');

const region = 'us-east-1';
const tagKey = 'repository';
const tagValue = context.page.repository; // e.g., "company/webshop"

const tagging = new ResourceGroupsTaggingAPIClient({
region,
credentials: {
accessKeyId: secrets.AWS_ACCESS_KEY_ID,
secretAccessKey: secrets.AWS_SECRET_ACCESS_KEY,
},
});

const matched = [];
let token;
do {
const out = await tagging.send(new GetResourcesCommand({
ResourceTypeFilters: ['lambda:function'],
TagFilters: [{ Key: tagKey, Values: [tagValue] }],
PaginationToken: token,
}));

const list = out.ResourceTagMappingList || [];
for (const m of list) {
if (matched.length > 10) break; // collect up to 11 to know if there are more
const arn = m.ResourceARN || '';
const name = arn.split(':').pop();
if (name) {
matched.push({ name, arn });
}
}

token = out.PaginationToken;
if (matched.length > 10) break;
} while (token);

if (matched.length === 0) {
return [];
}

// First 10 items
const items = matched.slice(0, 10).map(m => ({
content: m.name,
href: `https://${region}.console.aws.amazon.com/lambda/home?region=${region}#/functions/${encodeURIComponent(m.name)}?tab=configuration`
}));

// If more than 10, add a More… item linking to Lambda list filtered by tag
if (matched.length > 10) {
const moreUrl = `https://${region}.console.aws.amazon.com/lambda/home?region=${region}#/functions?search=${encodeURIComponent('tag:repository=' + tagValue)}`;
items.push({ content: 'More…', href: moreUrl, status: 'relevant' });
}

return [{
type: 'dropdown',
content: `AWS Infra (${matched.length} Lambdas)`,
items
}];
}
};

GitHub β†’ Datadog: Show active alerts & logs

See active alerts for this repo at a glance
πŸ”’
https://github.com/mycompany/webshop
preload

How does this help you?​

  • You will notice any active alerts on the repo, which can help you fix issues faster
  • You will be able to navigate directly to the logs for the repo

Preview​

How it looks in the extension

ToolJumpβ€’datadog3 active alertsβ€’datadogLogsβ€’ ... Other items ...

High level approach​

We assume the alerts and logs are tagged with the repository name. We then query alerts in Datadog by the tag with the repo name, and filter the active alerts.

Prerequisites​

For the code below to work, please follow the guide on Connecting to Datadog.

Code​

github.datadog.logs-alerts.integration.example.js
module.exports = {
metadata: {
name: 'github-datadog-logs-alerts',
description: 'Show any active alerts from Datadog in Github, and jump from Github to Logs and Alerts for this repository',
match: {
contextType: 'github',
context: {
'page.repository': { startsWith: 'my-org/' }
}
},
requiredSecrets: ['DATADOG_API_KEY', 'DATADOG_APP_KEY'],
cache: 300
},
run: async function (context, secrets = {}) {

// adjust this to your Datadog instance
const DATADOG_HOST = 'https://api.datadoghq.com';

// assume the alerts for services belonging to this repository are tagged using the repository tag
const repoTag = `repository:${context.page.repository}`;

// if using Datadog EU instance, please change the url accordingly
const url = `${DATADOG_HOST}/api/v1/monitor?group_states=alert&monitor_tags=${encodeURIComponent(repoTag)}`;
const response = await fetch(url, {
method: 'GET',
headers: {
'DD-API-KEY': secrets.DATADOG_API_KEY,
'DD-APPLICATION-KEY': secrets.DATADOG_APP_KEY,
'Content-Type': 'application/json'
}
});

if (!response.ok) {
throw new Error(`Datadog API error: ${response.status} ${response.statusText}`);
}

monitorList = await response.json();
// Filter monitorList to only include monitors with overall_state === "Alert"
monitorList = Array.isArray(monitorList)
? monitorList.filter(monitor => monitor.overall_state === "Alert")
: [];
const activeAlertsCount = monitorList.length || 0;

// Build Datadog logs and alerts URLs for this repository
const logsUrl = `${DATADOG_HOST}/logs?query=${encodeURIComponent(repoTag)}`;
const alertsUrl = `${DATADOG_HOST}/monitors/manage?q=tag%3A"${encodeURIComponent(repoTag)}`;

const results = [
{
type: 'link',
content: `${activeAlertsCount} alert${activeAlertsCount === 1 ? '' : 's'}`,
href: alertsUrl,
status: activeAlertsCount > 0 ? 'important' : 'success',
icon: 'datadog'
},
{ type: 'link', content: 'Logs', href: logsUrl, icon: 'datadog' }
];

return results;
}
};

Github: Show deployed service URLs

Open staging and production URLs for this service instantly
πŸ”’
https://github.com/mycompany/webshop
preload

How does this help you?​

  • Quickly access the staging and production URLs for repositories

Preview​

How it looks in the extension

ToolJumpβ€’
Deployed URLs
β€’ ... Other items ...

High level approach​

There are two common ways to map a repository to its deployed URLs:

  1. Data file (simple): Keep a small mapping file alongside your integrations that lists, for each repo, the staging and production URLs. This is easy to start with and version‑controlled.
  2. Service catalog (scalable): Query your source of truth (e.g., Backstage, Datadog Service Catalog) to resolve environment endpoints dynamically. This is preferable when you already maintain a catalog.

Below, we implement approach number 1 (the simple data file approach) and render a dropdown with links to staging and production.

Example data file (deployed-urls.data.json)​

{
"mappings": {
"company/webshop": {
"production": "https://webshop.company.com",
"staging": "https://staging.webshop.company.com"
},
"company/notifier": {
"production": "https://notifier.company.com",
"staging": "https://staging.notifier.company.com"
}
}
}

Prerequisites​

No external auth required. Add the data file (e.g., deployed-urls.data.json) to your data directory in your Github repository. Learn more about data files in Data.

Code​

github.deployed-urls.integration.example.js
module.exports = {
metadata: {
name: 'github-show-deployed-service-urls',
description: 'Show staging and production URLs for this repository as a dropdown, using a data file mapping',
match: {
contextType: 'github',
context: {
'page.repository': { startsWith: 'my-org/' }
}
},
requiredSecrets: [],
cache: 300
},
run: async function (context, secrets = {}, dataFiles = []) {
const repo = context.page.repository; // e.g., "company/webshop"

// Expect a data file like deployed-urls.data.json with shape:
// { "mappings": { "org/repo": { "production": "https://...", "staging": "https://..." } } }
const df = dataFiles.find(f => f.id === 'deployed-urls');
if (!df || !df.data) {
return [];
}

const mappings = df.data.mappings || {};
const envs = mappings[repo];
if (!envs || (typeof envs !== 'object')) {
return [];
}

const items = [];
if (envs.production) {
items.push({ content: 'Production', href: envs.production, status: 'important', icon: 'link' });
}
if (envs.staging) {
items.push({ content: 'Staging', href: envs.staging, icon: 'link' });
}

if (items.length === 0) {
return [];
}

return [
{
type: 'dropdown',
content: 'Deployed URLs',
items
}
];
}
};

GitHub β†’ LaunchDarkly: Show feature flags for this repo

See feature flags tagged to this repo
πŸ”’
https://github.com/mycompany/webshop
preload

How does this help you?​

  • See your LaunchDarkly feature flags directly from your GitHub repositories
  • Jump directly to each feature flag in the LaunchDarkly dashboard
  • Quickly identify which flags are associated with specific repositories
tip

You can easily modify this integration to return other tagged resources or use different tag formats

Preview​

How it looks in the extension

ToolJumpβ€’
launchdarklyFeature Flags (3 flags)
β€’ ... Other items ...

High level approach​

We query LaunchDarkly's API for feature flags tagged with the repository name (tag key repository, value matching the GitHub repo name, e.g. my-repo). We extract the last part of the repository path (after the final /) and use that as the tag value. We then render a dropdown of the first 10 flags. If there are more, a final "More…" item links to the LaunchDarkly flags page filtered by the repository tag.

Notes:

  • Only the first 10 flags are shown to keep the dropdown manageable
  • Each item links to the specific feature flag page in LaunchDarkly
  • The "More…" link goes to the LaunchDarkly flags list with the tag filter applied

Prerequisites​

For the code below to work, you need a LaunchDarkly access token with read permissions for feature flags. Provide LAUNCHDARKLY_ACCESS_TOKEN as a secret.

The LaunchDarkly access token must have the following permissions:

  • read:flag - to read feature flags
  • read:project - to access project information

Code​

github.launchdarkly.integration.example.js
module.exports = {
metadata: {
name: 'github-launchdarkly',
description: 'Show LaunchDarkly feature flags tagged with this repository as a dropdown',
match: {
contextType: 'github',
context: {
'page.repository': { startsWith: 'my-org/' }
}
},
requiredSecrets: ['LAUNCHDARKLY_ACCESS_TOKEN'],
cache: 1800
},
run: async function (context, secrets = {}) {
// Extract repository name (last part after /)
const repository = context.page.repository; // e.g., "company/webshop"
const repoName = repository.split('/').pop(); // e.g., "webshop"

const projectKey = 'your-project-key'; // Replace with your LaunchDarkly project key
const tagKey = 'repository';
const tagValue = repoName;

const apiUrl = `https://app.launchdarkly.com/api/v2/flags/${projectKey}?filter=tags:${tagKey}:${tagValue}`;

const response = await fetch(apiUrl, {
method: 'GET',
headers: {
'Authorization': `Bearer ${secrets.LAUNCHDARKLY_ACCESS_TOKEN}`,
'Content-Type': 'application/json'
}
});

if (!response.ok) {
throw new Error(`LaunchDarkly API request failed: ${response.status} ${response.statusText}`);
}

const data = await response.json();
const flags = data.items || [];

if (flags.length === 0) {
return [];
}

// First 10 items
const items = flags.slice(0, 10).map(flag => ({
content: flag.key,
href: `https://app.launchdarkly.com/${projectKey}/flags/${flag.key}`,
icon: 'launchdarkly'
}));

// If more than 10, add a More… item linking to LaunchDarkly flags list filtered by tag
if (flags.length > 10) {
const moreUrl = `https://app.launchdarkly.com/${projectKey}/flags?filter=tags:${tagKey}:${tagValue}`;
items.push({
content: 'More…',
href: moreUrl,
status: 'relevant',
icon: 'launchdarkly'
});
}

return [{
type: 'dropdown',
content: `Feature Flags (${flags.length} flags)`,
icon: 'launchdarkly',
items
}];
}
};

GitHub: Next deploy time

Next deploy countdown β€” know when changes go live
πŸ”’
https://github.com/mycompany/webshop
preload

How does this help you?​

  • Quick, readable countdown for the next production deploy

Preview​

How it looks in the extension

ToolJumpβ€’Next deploy in 2hβ€’ ... Other items ...

High level approach​

Hardcode your organization’s deployment schedule (or read it via an API call from your CI/CD system) and compute the next matching slot relative to the current time. This example uses:

  • Days: Tuesday, Wednesday, Thursday
  • Times: 09:00, 15:00, 20:00 (local time)

It returns a simple text item like Next deploy: 1d 3h

Prerequisites​

No external auth or data files required.

Code​

github.next-deploy.integration.example.js
module.exports = {
metadata: {
name: 'github-next-deploy',
description: 'Show when the repository will be deployed next based on a hardcoded schedule',
match: {
contextType: 'github',
context: {
'page.repository': { startsWith: 'my-org/' }
}
},
requiredSecrets: [],
cache: 60
},
run: async function (context, secrets = {}, dataFiles = []) {
// Hardcoded deployment schedule:
// Days: Tuesday, Wednesday, Thursday
// Times (local time): 09:00, 15:00, 20:00
const allowedDays = new Set([2, 3, 4]); // 0=Sun ... 6=Sat
const allowedHours = [9, 15, 20];

const now = new Date();

function nextScheduled(nowDate) {
const candidates = [];
for (let d = 0; d <= 7; d++) { // look up to one week ahead
const probe = new Date(nowDate);
probe.setDate(nowDate.getDate() + d);
const day = probe.getDay();
if (!allowedDays.has(day)) continue;
for (const h of allowedHours) {
const slot = new Date(probe);
slot.setHours(h, 0, 0, 0);
if (slot > nowDate) {
candidates.push(slot.getTime());
}
}
}
if (candidates.length === 0) return null;
const ts = Math.min(...candidates);
return new Date(ts);
}

function formatDiff(from, to) {
const ms = Math.max(0, to.getTime() - from.getTime());
const HOUR = 60 * 60 * 1000;
const DAY = 24 * HOUR;
const days = Math.floor(ms / DAY);
const hours = Math.floor((ms - days * DAY) / HOUR);
if (days > 0) return `Next deploy: ${days}d ${hours}h`;
return `Next deploy: ${hours}h`;
}

const next = nextScheduled(now);
if (!next) return [];

return [
{ type: 'text', status: 'relevant', content: formatDiff(now, next) }
];
}
};

tip

You can also change the status to values like important or relevant (or do not set status) depending on how soon the next deploy is. For example, if the next deploy is in 1h, it should be important and show with red. If it is in 3 hours, it can be shown wih yellow as relevant.

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;
}
};

GitHub β†’ CircleCI: Browse deployment

How does this help you?​

  • One-click to browse the exact Git commit deployed to each environment
  • Reduces guesswork when debugging differences between environments

Preview​

How it looks in the extension

ToolJumpβ€’β€’ ... Other items ...

Approaches​

  • Insights by workflow name (implemented): Use CircleCI Insights for conventional workflow names (e.g., deploy-staging, deploy-prod) on branch main, find the latest successful run, resolve the pipeline to get the commit SHA, and link to the GitHub tree. Simple and widely applicable.
  • Pipelines + workflows traversal: List recent pipelines for the repo/branch, then fetch workflows per pipeline to find the most recent successful deploy job per environment. More API calls, similar outcome.
  • Artifact or metadata lookup: Emit an artifact or store metadata (e.g., commit SHA, release tag, URL) during deploy jobs and fetch it via the Artifacts API. More setup, flexible if your org already publishes metadata.

Assumptions​

  • Branch: main. Adjust in the example if your default deploy branch differs.
  • Workflows: deploy-staging and deploy-prod. Rename to match your pipeline.
  • Output: a dropdown labeled Browse deployment with Staging and Prod items linking to https://github.com/<org>/<repo>/tree/<sha>.

Prerequisites​

For the code below to work, please follow the guide on Connecting to CircleCI. Provide CIRCLECI_API_TOKEN as a secret.

Code​

github.circleci.browse.deployment.integration.example.js
module.exports = {
metadata: {
name: 'github-circleci-browse-deployment',
description: 'Dropdown to browse the deployed revisions (staging, QA) on GitHub using CircleCI workflows',
match: {
contextType: 'github',
context: {
'page.repository': { startsWith: 'my-org/' }
}
},
requiredSecrets: ['CIRCLECI_API_TOKEN'],
cache: 300
},
run: async function (context, secrets = {}) {
const CIRCLE_HOST = 'https://circleci.com/api/v2';
const repo = context.page.repository; // e.g., "org/repo"
const projectSlug = `gh/${repo}`;
const branch = 'main';

// Conventional workflow names used by many teams; customize if needed
const WORKFLOWS = {
staging: 'deploy-staging',
prod: 'deploy-prod'
};

const headers = {
'Circle-Token': secrets.CIRCLECI_API_TOKEN,
'Accept': 'application/json'
};

async function getDeployedShaForWorkflow(workflowName) {
// Use Insights to find the most recent successful run for the workflow on the target branch
const insightsUrl = `${CIRCLE_HOST}/insights/${encodeURIComponent(projectSlug)}/workflows/${encodeURIComponent(workflowName)}?branch=${encodeURIComponent(branch)}`;
const r1 = await fetch(insightsUrl, { headers });
if (!r1.ok) throw new Error(`CircleCI insights error (${workflowName}): ${r1.status} ${r1.statusText}`);
const j1 = await r1.json();
const items = Array.isArray(j1.items) ? j1.items : [];
const success = items.find(i => i.status === 'success');
if (!success) return null;

// Resolve pipeline id from pipeline number so we can get VCS revision (commit SHA)
const byNumberUrl = `${CIRCLE_HOST}/project/${encodeURIComponent(projectSlug)}/pipeline/${success.pipeline_number}`;
const r2 = await fetch(byNumberUrl, { headers });
if (!r2.ok) throw new Error(`CircleCI pipeline lookup error: ${r2.status} ${r2.statusText}`);
const j2 = await r2.json();
const pipelineId = j2.id;
if (!pipelineId) return null;

const pipelineUrl = `${CIRCLE_HOST}/pipeline/${pipelineId}`;
const r3 = await fetch(pipelineUrl, { headers });
if (!r3.ok) throw new Error(`CircleCI pipeline fetch error: ${r3.status} ${r3.statusText}`);
const j3 = await r3.json();
const sha = j3.vcs && j3.vcs.revision;
return sha || null;
}

const [stagingSha, prodSha] = await Promise.all([
getDeployedShaForWorkflow(WORKFLOWS.staging),
getDeployedShaForWorkflow(WORKFLOWS.prod)
]);

const items = [];
if (stagingSha) {
items.push({ content: 'Staging', href: `https://github.com/${repo}/tree/${stagingSha}` });
}
if (prodSha) {
items.push({ content: 'Prod', href: `https://github.com/${repo}/tree/${prodSha}` });
}

if (items.length === 0) return [];

return [{
type: 'dropdown',
content: 'Browse deployment',
icon: 'github',
items
}];
}
};

GitHub β†’ CircleCI: Last production deploy

See time of last production deploy without leaving GitHub
πŸ”’
https://github.com/mycompany/webshop
preload

How does this help you?​

  • See when this repo was last deployed to production
  • Jump directly to the corresponding successful workflow run in CircleCI

Preview​

How it looks in the extension

ToolJumpβ€’circleciDeployed 5m agoβ€’ ... Other items ...

High level approach​

There are multiple ways to determine the last production deploy for a repository:

  1. Insights API by workflow name (simple): Query GET /insights/{project-slug}/workflows/{workflow_name} for the deploy-prod workflow on main and pick the most recent successful run.
  2. Pipelines β†’ Workflows traversal: List pipelines for main via GET /project/{project-slug}/pipeline?branch=main, then for each pipeline call GET /pipeline/{id}/workflow and find the latest successful deploy-prod workflow.
  3. Job-level heuristics: If workflow names vary, filter workflow runs whose names contain both β€œdeploy” and β€œprod”, or use a job name convention inside workflows.

The implementation below uses the Insights API (option 1) for simplicity.

Prerequisites​

For the code below to work, please follow the guide on Connecting to CircleCI. Provide CIRCLECI_API_TOKEN as a secret.

Code​

github.circleci.last-deploy.integration.example.js
module.exports = {
metadata: {
name: 'github-circleci-last-deploy',
description: 'Show when main was last deployed to production (deploy-prod workflow) and link to the workflow run',
match: {
contextType: 'github',
context: {
'url': { exists: true },
'page.repository': { startsWith: 'my-org/' }
}
},
requiredSecrets: ['CIRCLECI_API_TOKEN'],
cache: 300
},
run: async function (context, secrets = {}) {
const CIRCLE_HOST = 'https://circleci.com/api/v2';
const repo = context.page.repository; // e.g., "org/repo"
const projectSlug = `gh/${repo}`;
const workflowName = 'deploy-prod';
const branch = 'main';

// Helper to format "Deployed 3d ago" / "Deployed 3h ago"
function formatRelativeDuration(thenIso) {
const then = new Date(thenIso).getTime();
const now = Date.now();
const diffMs = Math.max(0, now - then);
const diffMin = Math.floor(diffMs / 60000);
const diffHr = Math.floor(diffMin / 60);
const diffDay = Math.floor(diffHr / 24);
if (diffDay >= 1) return `Deployed ${diffDay}d ago`;
if (diffHr >= 1) return `Deployed ${diffHr}h ago`;
return `Deployed ${Math.max(1, diffMin)}m ago`;
}

const headers = {
'Circle-Token': secrets.CIRCLECI_API_TOKEN,
'Accept': 'application/json'
};

// Insights API: latest runs for a workflow on a branch
const url = `${CIRCLE_HOST}/insights/${encodeURIComponent(projectSlug)}/workflows/${encodeURIComponent(workflowName)}?branch=${encodeURIComponent(branch)}`;
const resp = await fetch(url, { headers });
if (!resp.ok) {
throw new Error(`CircleCI API error: ${resp.status} ${resp.statusText}`);
}

const json = await resp.json();
const items = Array.isArray(json.items) ? json.items : [];
const success = items.find(i => i.status === 'success');
if (!success) {
return [];
}

const workflowId = success.id; // workflow UUID
const pipelineNumber = success.pipeline_number; // for deep link
const stoppedAt = success.stopped_at || success.created_at;

const relative = formatRelativeDuration(stoppedAt);
const link = `https://app.circleci.com/pipelines/gh/${repo}/${pipelineNumber}/workflows/${workflowId}`;

return [
{ type: 'link', content: relative, href: link, icon: 'circleci' }
];
}
};

GitHub β†’ PagerDuty: Show who's on‑call

See who’s on‑call for this repo’s service right now
πŸ”’
https://github.com/mycompany/webshop
preload

How does this help you?​

  • See who is currently on‑call for this repository
  • Jump directly to PagerDuty’s On‑Call view filtered to the service

Preview​

How it looks in the extension

ToolJumpβ€’pagerdutyOncall: Johnβ€’ ... Other items ...

High level approach​

We assume PagerDuty services are tagged with the repository name (tag key repository, value matching the GitHub repo, e.g. company/webshop). We locate the first matching service, resolve its escalation policy, fetch the current L1 on‑call user, and show their first name.

Prerequisites​

For the code below to work, please follow the guide on Connecting to PagerDuty. Provide PAGERDUTY_API_TOKEN as a secret.

Code​

github.pagerduty.oncall.integration.example.js
module.exports = {
metadata: {
name: 'github-pagerduty-oncall',
description: 'Show current L1 on-call for the first PagerDuty service tagged with this repository, with link to the On-Call view',
match: {
contextType: 'github',
context: {
'page.repository': { startsWith: 'my-org/' }
}
},
requiredSecrets: ['PAGERDUTY_API_TOKEN'],
cache: 900
},
run: async function (context, secrets = {}) {
const PD_HOST = 'https://api.pagerduty.com'; // US API

const repoTag = `repository:${context.page.repository}`;
const headers = {
'Authorization': `Token token=${secrets.PAGERDUTY_API_TOKEN}`,
'Accept': 'application/vnd.pagerduty+json;version=2',
'Content-Type': 'application/json'
};

// 1) Resolve the tag ID by label (exact match)
const tagsResp = await fetch(`${PD_HOST}/tags?query=${encodeURIComponent(repoTag)}&limit=25`, { headers });
if (!tagsResp.ok) {
throw new Error(`PagerDuty API error (tags): ${tagsResp.status} ${tagsResp.statusText}`);
}
const tagsJson = await tagsResp.json();
const tag = (tagsJson.tags || []).find(t => t.label === repoTag);
if (!tag) {
return [];
}

// 2) Find first service entity with this tag
const entitiesResp = await fetch(`${PD_HOST}/tags/${encodeURIComponent(tag.id)}/entities?type=service&limit=25`, { headers });
if (!entitiesResp.ok) {
throw new Error(`PagerDuty API error (tag entities): ${entitiesResp.status} ${entitiesResp.statusText}`);
}
const entitiesJson = await entitiesResp.json();
const service = (entitiesJson.entities || []).find(e => e.type === 'service');
if (!service) {
return [];
}

// 3) Fetch service to get escalation policy
const serviceResp = await fetch(`${PD_HOST}/services/${encodeURIComponent(service.id)}?include[]=escalation_policy`, { headers });
if (!serviceResp.ok) {
throw new Error(`PagerDuty API error (service): ${serviceResp.status} ${serviceResp.statusText}`);
}
const serviceJson = await serviceResp.json();
const ep = serviceJson.service && serviceJson.service.escalation_policy;
if (!ep || !ep.id) {
return [];
}

// 4) Query on-calls for this escalation policy and pick L1
const oncallsResp = await fetch(`${PD_HOST}/oncalls?limit=25&escalation_policy_ids[]=${encodeURIComponent(ep.id)}`, { headers });
if (!oncallsResp.ok) {
throw new Error(`PagerDuty API error (oncalls): ${oncallsResp.status} ${oncallsResp.statusText}`);
}
const oncallsJson = await oncallsResp.json();
const l1 = (oncallsJson.oncalls || []).find(o => o.escalation_level === 1);
if (!l1 || !l1.user) {
return [];
}

// Extract first name
const fullName = l1.user.name || l1.user.summary || '';
const firstName = fullName.split(' ')[0] || fullName;

// 5) Build deep link to On-Call view filtered by service
const oncallUrl = `https://app.pagerduty.com/oncalls?service_ids[]=${encodeURIComponent(service.id)}`;

const results = [
{ type: 'link', content: `On-call: ${firstName}`, icon: 'pagerduty', href: oncallUrl },
];

return results;
}
};

GitHub β†’ Slack: Show service channel

How does this help you?​

  • Quickly find the Slack channel associated with this repository
  • Jump straight into Slack via a deep link

High level approach​

We assume a local data file maps repositories to Slack channels. The integration reads the mapping, finds the channel for the current repo (tag key repository, value from the GitHub page), and renders a link to Slack.

Example data file (slack-channels.data.json):

{
"mappings": {
"company/webshop": "#webshop",
"company/notifier": "#alerts-notifier"
}
}
tip

The prefered way of obtaining this information is if you use a Service/Inventory Catalog solution, which you can read this information from via API access.

Prerequisites​

No external auth required. Add a data file (e.g., slack-channels.data.json) to your data directory. Learn more in Data files.

Code​

github.slack.channel.integration.example.js
module.exports = {
metadata: {
name: 'github-slack-channel',
description: 'Show the Slack channel mapped to this repository via data files',
match: {
contextType: 'github',
context: {
'page.repository': { startsWith: 'my-org/' }
}
},
requiredSecrets: [],
cache: 300
},
run: async function (context, secrets = {}, dataFiles = []) {
const repo = context.page.repository; // e.g., "company/webshop"

// Expect a data file like slack-channels.data.json with shape:
// { "mappings": { "company/webshop": "#webshop" } }
const df = dataFiles.find(f => f.id === 'slack-channels');
if (!df || !df.data || !df.data.mappings) {
return [];
}

let channel = df.data.mappings[repo];
if (!channel || typeof channel !== 'string') {
return [];
}

// Normalize channel value (accepts "#name", "name", or channel ID)
const normalized = channel.startsWith('#') ? channel.slice(1) : channel;

// Slack app redirect supports channel by name or ID
const slackUrl = `https://slack.com/app_redirect?channel=${encodeURIComponent(normalized)}`;

return [
{ type: 'link', content: `#${normalized}`, icon: 'slack', href: slackUrl },
];
}
};