Skip to main content

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