Skip to content

Instantly share code, notes, and snippets.

@mikaelvesavuori
Last active April 22, 2024 05:42
Show Gist options
  • Save mikaelvesavuori/82fb8aeb4a9408fdadafe429c98e6f46 to your computer and use it in GitHub Desktop.
Save mikaelvesavuori/82fb8aeb4a9408fdadafe429c98e6f46 to your computer and use it in GitHub Desktop.
Helpful GitHub API functionality for Node.
import { getBlobShaFromGithub } from './getBlobShaFromGithub';
export async function createFileInGithub(input: string, fileName: string, type: string) {
const owner = process.env.OWNER;
const repo = process.env.REPO;
const workflowId = process.env.WORKFLOW_ID;
const token = process.env.GITHUB_TOKEN;
if (!owner || !repo || !workflowId || !token)
throw new Error('Missing required environment variables!');
const folder = 'latest';
const sha = await getBlobShaFromGithub(`${folder}/${fileName}`);
const url = `https://api.github.com/repos/${owner}/${repo}/contents/${folder}/${fileName}`;
const body = JSON.stringify({
message: type,
committer: {
name: 'Something',
email: '[email protected]'
},
content: encode(input),
sha
});
return await fetch(url, {
method: 'PUT',
headers: {
Authorization: `Bearer ${token}`
},
body
});
}
function encode(content: string) {
return Buffer.from(content, 'utf8').toString('base64');
}
export async function getBlobShaFromGithub(path: string) {
const owner = process.env.OWNER;
const repo = process.env.REPO;
const workflowId = process.env.WORKFLOW_ID;
const token = process.env.GITHUB_TOKEN;
if (!owner || !repo || !workflowId || !token)
throw new Error('Missing required environment variables!');
const GITHUB_URL = `https://api.github.com/repos/${owner}/${repo}/contents/${path}`;
return await fetch(GITHUB_URL, {
method: 'GET',
headers: {
Authorization: `Bearer ${token}`
}
})
.then((res: any) => res.json())
.then((res: Record<string, any>) => res.sha);
}
export async function startGitHubWorkflow(
type: string,
timestamp: string,
customerId: string,
systemId: string // Used for App ID or Flow ID
) {
const owner = process.env.OWNER || '';
const repo = process.env.REPO || '';
const token = process.env.GITHUB_TOKEN || '';
if (!owner || !repo || !token)
throw new Error(
'Missing required environment variables when getting blob SHA from GitHub!'
);
const basePath = `https://api.github.com/repos/${owner}/${repo}`;
const workflowFile = 'main.yml';
return await fetch(`${basePath}/actions/workflows/${workflowFile}/dispatches`, {
method: 'POST',
body: JSON.stringify({
ref: 'main',
inputs: { type, timestamp, customer_id: customerId, flow_id: systemId }
}),
headers: headers(token)
})
}
const headers = (token: string, hasBody = true) => ({
Accept: 'application/vnd.github.v3+json',
Authorization: `Bearer ${token}`,
'Content-Type': hasBody ? 'application/json' : 'text/plain'
});
/**
* @description Uploading several files to GitHub is a complicated affair.
* This utility takes care of that orchestration.
*/
export async function uploadFilesToGitHub(files: { name: string; content: string }[]) {
const owner = process.env.OWNER || '';
const repo = process.env.REPO || '';
const token = process.env.GITHUB_TOKEN || '';
if (!owner || !repo || !token)
throw new Error('Missing required environment variables when generating CFN template!');
const basePath = `https://api.github.com/repos/${owner}/${repo}`;
const branch = 'main';
const blobs = await Promise.all(
files.map(async (file) => {
const response = fetch(`${basePath}/git/blobs`, {
method: 'POST',
body: JSON.stringify({
content: file.content,
encoding: 'utf-8'
}),
headers: headers(token)
}) as any;
return { path: file.name, mode: '100644', type: 'blob', sha: response.sha };
})
);
const { baseTreeSha, refData } = await getBaseTreeSha(
`${basePath}/git/ref/heads/${branch}`,
token
);
const treeData = await createNewTree(`${basePath}/git/trees`, token, baseTreeSha, blobs);
const commitData = await createCommit(`${basePath}/git/commits`, token, refData, treeData);
await updateRef(`${basePath}/git/refs/heads/${branch}`, token, commitData);
}
async function getBaseTreeSha(url: string, token: string) {
const response = await fetch(url, {
method: 'GET',
headers: headers(token, false)
}) as any;
return { refData: response, baseTreeSha: response.object.sha };
}
async function createNewTree(url: string, token: string, baseTreeSha: string, blobs: any) {
return await fetch(url, {
method: 'POST',
body: JSON.stringify({
base_tree: baseTreeSha,
tree: blobs
}),
headers: headers(token)
});
}
async function createCommit(url: string, token: string, refData: any, treeData: any) {
return await fetch(url, {
method: 'POST',
body: JSON.stringify({
committer: {
name: 'Popcorn Cloud builder',
email: '[email protected]'
},
message: 'flow',
parents: [refData.object.sha],
tree: treeData.sha
}),
headers: headers(token)
})
}
async function updateRef(url: string, token: string, commitData: any) {
return await fetch(url, {
method: 'PATCH',
body: JSON.stringify({ sha: commitData.sha }),
headers: headers(token, true)
})
}
const headers = (token: string, hasBody = true) => ({
Accept: 'application/vnd.github.v3+json',
Authorization: `Bearer ${token}`,
'Content-Type': hasBody ? 'application/json' : 'text/plain'
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment