Skip to content

Commit

Permalink
Merge pull request #89 from mediumroast/alpha_2_actions
Browse files Browse the repository at this point in the history
Alpha 2 actions - completed actions plus some others
  • Loading branch information
miha42-github authored Feb 13, 2024
2 parents 444c97a + a7ae0c6 commit 940daa2
Show file tree
Hide file tree
Showing 27 changed files with 1,529 additions and 567 deletions.
9 changes: 9 additions & 0 deletions cli/actions/actions/basic-reporting/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: 'Basic Reporting'
description: 'Generates basic reports for companies plus wrapping README.md files in the repository'
inputs:
github-token:
description: 'GitHub token'
required: true
runs:
using: 'node20'
main: 'index.js'
200 changes: 200 additions & 0 deletions cli/actions/actions/basic-reporting/github.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
const github = require('@actions/github')
const core = require('@actions/core')

async function readObjects (fileName) {
const token = core.getInput('github-token', { required: true })
const octokit = github.getOctokit(token)

const { data: file } = await octokit.rest.repos.getContent({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
path: fileName,
ref: 'main'
})

// check to see if the file is empty and if it is return an empty object
if (file.size === 0) {
return []
}

// Return the file content as an object
return JSON.parse(Buffer.from(file.content, 'base64').toString())
}

async function readWorkflows () {
const token = core.getInput('github-token', { required: true })
const octokit = github.getOctokit(token)

const workflows = await octokit.rest.actions.listWorkflowRunsForRepo({
owner: github.context.repo.owner,
repo: github.context.repo.repo
})

const workflowList = []
let totalRunTimeThisMonth = 0
for (const workflow of workflows.data.workflow_runs) {
// Get the current month
const currentMonth = new Date().getMonth()

// Compute the runtime and if the time is less than 60s round it to 1m
const runTime = Math.ceil((new Date(workflow.updated_at) - new Date(workflow.created_at)) / 1000 / 60) < 1 ? 1 : Math.ceil((new Date(workflow.updated_at) - new Date(workflow.created_at)) / 1000 / 60)

// If the month of the workflow is not the current month, then skip it
if (new Date(workflow.updated_at).getMonth() !== currentMonth) {
continue
}
totalRunTimeThisMonth += runTime

// Add the workflow to the workflowList
workflowList.push({
run_time_minutes: runTime,
path: workflow.path,
name: workflow.path.replace('.github/workflows/', '').replace('.yml', ''),
run_time_name: workflow.name,
conclusion: workflow.conclusion,
created_at: workflow.created_at,
updated_at: workflow.updated_at,
html_url: workflow.html_url
})
}

// Sort the worflowList to put the most recent workflows first
workflowList.sort((a, b) => new Date(b.updated_at) - new Date(a.updated_at))

// log the length of the workflowList
console.log(`Number of workflows: ${workflowList.length}`)

return {allWorkFlows: workflowList, runTime: totalRunTimeThisMonth}
}

async function readBranches () {
const token = core.getInput('github-token', { required: true })
const octokit = github.getOctokit(token)

let { data: branches } = await octokit.rest.repos.listBranches({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
})

// Loop through the branches to obtain the latest commit comment, author, and date added to the branch, and then add them to the branches array
for (const branch of branches) {
const { data: commit } = await octokit.rest.repos.getBranch({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
branch: branch.name
})
branch.commit = commit.commit.sha
branch.author = commit.commit.author.name
branch.date = commit.commit.author.date
}

return branches
}

// Create a function that compares the current list of companies and the associated markdown files for each company present in the repository. Should there be a markdown file for a company that is not in the current list of companies, then the file should be deleted.
async function reconcileCompanyFiles (companies) {
const token = core.getInput('github-token', { required: true })
const octokit = github.getOctokit(token)

// Get the list of company files
const { data: companyFiles } = await octokit.rest.repos.getContent({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
path: 'Companies',
ref: 'main'
})
// Filter in only the markdown files that aren't the README.md
const companyFilesFiltered = companyFiles.filter(file => file.name.endsWith('.md') && file.name !== 'README.md')

// Using the supplied companies create a new object with the key being the company markdown and the value being the company name
let markdownToCompanies = companies.reduce((acc, company) => {
const markdown = company.name.replace(/[\s,.\?!]/g, '')
acc[`${markdown}.md`] = company.name
return acc
} , {})

// Check to see if if each companyFilesFiltered is in the markdownToCompanies object, if it isn't then delete the file
const deleteFiles = []
for (const file of companyFilesFiltered) {
if (!markdownToCompanies[file.name]) {
await octokit.rest.repos.deleteFile({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
path: `Companies/${file.name}`,
message: `Delete ${file.name} report`,
branch: 'main'
})
// Add the file to the deleteFiles array
deleteFiles.push(file.name)
}
}
// Return the deleteFiles array
return deleteFiles
}

async function saveReports (reports, inputs) {
// Reconile the company files
const prunedMarkdowns = await reconcileCompanyFiles(inputs.companies)

const token = core.getInput('github-token', { required: true })
const octokit = github.getOctokit(token)

// Create or update each file in a single commit
for (const report of reports) {
// Get the sha of the file if it exists
try {
const { data: file } = await octokit.rest.repos.getContent({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
path: report.path,
ref: 'main'
})
// If the file exists then get the sha
if (file) {
report.sha = file.sha
}
} catch (error) {
// If the file doesn't exist then set the sha to null
report.sha = null
}

// Create or update the file
// NOTE: The file must be encoded as a base64 string
// NOTE: Unsure how to handle the case where the file exists vs doesn't exist

// If the file doesn't exist then create then report.sha will be null, so create the object to create the file without the sha
let octokitContent = {
owner: github.context.repo.owner,
repo: github.context.repo.repo,
// If the file exists then update it, otherwise create it
path: report.path,
message: `Update ${report.name} report`,
content: Buffer.from(report.content).toString('base64'),
sha: report.sha, // The blob SHA of the file being replaced
branch: 'main',
committer: {
name: github.context.actor,
email: `${github.context.actor}@users.noreply.github.com`
},
author: {
name: github.context.actor,
email: `${github.context.actor}@users.noreply.github.com`
}
}

// if report.sha is null delete the sha property from the object
if (!report.sha) {
delete octokitContent.sha
}

await octokit.rest.repos.createOrUpdateFileContents(octokitContent)
}
}


module.exports = {
readObjects,
readWorkflows,
readBranches,
saveReports
}
53 changes: 53 additions & 0 deletions cli/actions/actions/basic-reporting/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Load the modules
const { readObjects, readBranches, readWorkflows, saveReports } = require('./github.js')
const { createCompaniesReport, createCompanyReports, createMainReport } = require('./reports.js')


// Create the run function that creates the reports
async function run () {
// Define inputs
const inputs = {
companies: await readObjects('/Companies/Companies.json'),
interactions: await readObjects('/Interactions/Interactions.json'),
branches: await readBranches(),
workflows: await readWorkflows()
}

// If there are no companies then return
if (inputs.companies.length === 0) {
return
}

// Define reports
const reports = {
companies: `Companies/README.md`,
company: `Companies/`,
main: `README.md`,
}

// Create the company files
const companyFiles = await createCompanyReports(inputs.companies, inputs.interactions, reports)
// Create the companies file
const companiesFile = createCompaniesReport(inputs.companies)
// Create the main file
const mainFile = createMainReport(inputs)
// Create the reports array
const markdownReports = [
{
name: 'Companies',
path: reports.companies,
content: companiesFile
},
{
name: 'Main',
path: reports.main,
content: mainFile
},
...companyFiles
]

// Write the reports
await saveReports(markdownReports, inputs)
}

run()
Loading

0 comments on commit 940daa2

Please sign in to comment.