Created
March 19, 2024 20:18
-
-
Save slaughtr/14e3e69c8c1eba17a8576390ddc71f56 to your computer and use it in GitHub Desktop.
Find if a specific action is present in the workflows of all repos in an org. Outputs CSV for review. Not perfect, Github API doesn't like some things.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { Octokit } = require("@octokit/rest"); | |
const createCsvWriter = require('csv-writer').createObjectCsvWriter; | |
// Initialize Octokit with your GitHub token from environment variable | |
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN }); | |
// CSV setup | |
const csvWriter = createCsvWriter({ | |
path: 'compliance_check_result.csv', | |
header: [ | |
{id: 'repo_name', title: 'Repo Name'}, | |
{id: 'action_present', title: 'Action Present'}, | |
{id: 'repo_status', title: 'Repo Status'} | |
] | |
}); | |
// Delay function to avoid hitting rate limits | |
function delay(ms) { | |
return new Promise(resolve => setTimeout(resolve, ms)); | |
} | |
async function fetchFileContent(owner, repo, path) { | |
try { | |
await delay(3000); // Delay added before fetching content to reduce rate limit hits | |
const { data } = await octokit.repos.getContent({ | |
owner, | |
repo, | |
path, | |
}); | |
console.log(`Fetched ${owner}/${repo}/${path} successfully.`) | |
return Buffer.from(data.content, 'base64').toString(); | |
} catch (error) { | |
console.error(`Error fetching ${owner}/${repo}/${path} content: ${error}`); | |
return null; | |
} | |
} | |
async function checkWorkflowForAction(org, actionToFind) { | |
let results = []; | |
const repos = await octokit.paginate(octokit.repos.listForOrg, { | |
org, | |
type: 'all' | |
}); | |
for (const repo of repos) { | |
let actionPresent = 'no'; | |
await delay(1000); // Delay added between repository checks | |
const workflows = await octokit.paginate(octokit.actions.listRepoWorkflows, { | |
owner: org, | |
repo: repo.name | |
}); | |
for (const workflow of workflows) { | |
await delay(2000); // Delay added between workflow checks | |
const content = await fetchFileContent(org, repo.name, workflow.path); | |
if (content && content.includes(actionToFind)) { | |
actionPresent = 'yes'; | |
break; | |
} | |
} | |
const pullRequests = await octokit.paginate(octokit.pulls.list, { | |
owner: org, | |
repo: repo.name, | |
state: 'open' | |
}); | |
for (const pr of pullRequests) { | |
await delay(2000); // Delay added between pull request checks | |
const files = await octokit.paginate(octokit.pulls.listFiles, { | |
owner: org, | |
repo: repo.name, | |
pull_number: pr.number | |
}); | |
for (const file of files) { | |
if (file.filename.endsWith('.yml')) { | |
const content = await fetchFileContent(org, repo.name, file.filename); | |
if (content && content.includes(actionToFind)) { | |
actionPresent = 'pull request'; | |
break; | |
} | |
} | |
} | |
if (actionPresent === 'pull request') { | |
break; | |
} | |
} | |
results.push({ | |
repo_name: repo.name, | |
action_present: actionPresent, | |
repo_status: repo.private ? 'private' : repo.is_template ? 'template' : repo.archived ? 'archived' : 'public' | |
}); | |
} | |
await csvWriter.writeRecords(results) | |
.then(() => console.log('The CSV file was written successfully')); | |
} | |
// Use environment variables for org name and action name | |
const orgName = process.env.ORG_NAME; | |
const actionName = process.env.ACTION_NAME; | |
if (!orgName || !actionName || !process.env.GITHUB_TOKEN) { | |
console.log('Please set the GITHUB_TOKEN, ACTION_NAME, and ORG_NAME environment variables.'); | |
} else { | |
checkWorkflowForAction(orgName, actionName).catch(console.error); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment