From 6cdf16d86ab2606f55bb735356563ebc28e0fbde Mon Sep 17 00:00:00 2001 From: Nikita Galaiko Date: Wed, 1 Jun 2022 11:19:02 +0200 Subject: [PATCH 1/6] add dist to .gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f7340dd..7c79708 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ node_modules # Ignore built ts files __tests__/runner/* lib/**/* - +dist From d7877653d74a749878285a09bea057b9581a1fac Mon Sep 17 00:00:00 2001 From: Nikita Galaiko Date: Wed, 1 Jun 2022 11:19:27 +0200 Subject: [PATCH 2/6] hack/e2e: sanity checks --- hack/run-e2e-tests.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hack/run-e2e-tests.sh b/hack/run-e2e-tests.sh index edb9f90..545ed27 100755 --- a/hack/run-e2e-tests.sh +++ b/hack/run-e2e-tests.sh @@ -2,9 +2,12 @@ set -euo pipefail +[[ -z $(command -v act) ]] && echo "act not found, install https://github.com/nektos/act" && exit 1 +[[ -z ${GITHUB_TOKEN} ]] && echo "GITHUB_TOKEN env variable is required. obtail one from https://github.com/settings/tokens/new" && exit 1 + yarn build yarn package act pull_request -e tests/act-pull-request.json \ - -s GITHUB_TOKEN=${GITHUB_TOKEN} \ - --env CODEBALL_API_HOST=http://host.docker.internal:8080 \ No newline at end of file + -s GITHUB_TOKEN=${GITHUB_TOKEN} \ + --env CODEBALL_API_HOST=http://host.docker.internal:8080 From 41892f01acdbc92fdf51a17f3164b84ef6f02200 Mon Sep 17 00:00:00 2001 From: Nikita Galaiko Date: Wed, 1 Jun 2022 11:22:43 +0200 Subject: [PATCH 3/6] ignore lib --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7c79708..6195d19 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,5 @@ node_modules .idea # Ignore built ts files __tests__/runner/* -lib/**/* +lib dist From 5c6faa2d803f7c15735f95a5af37943e9ec80988 Mon Sep 17 00:00:00 2001 From: Nikita Galaiko Date: Wed, 1 Jun 2022 11:49:58 +0200 Subject: [PATCH 4/6] refactor: extract shared library --- .gitignore | 2 - hack/run-e2e-tests.sh | 1 - package.json | 13 +++-- src/approver/main.ts | 2 +- src/labeler/main.ts | 2 +- src/labeler/octokit.ts | 29 ----------- src/lib/index.ts | 2 + src/lib/jobs/index.ts | 2 + src/{approver => lib/jobs}/types.ts | 0 src/{approver => lib/jobs}/utils.ts | 0 .../octokit.ts => lib/octokit/index.ts} | 0 src/status/main.ts | 3 +- src/status/types.ts | 48 ------------------- src/status/utils.ts | 7 --- tsconfig.json | 16 +++---- 15 files changed, 21 insertions(+), 106 deletions(-) delete mode 100644 src/labeler/octokit.ts create mode 100644 src/lib/index.ts create mode 100644 src/lib/jobs/index.ts rename src/{approver => lib/jobs}/types.ts (100%) rename src/{approver => lib/jobs}/utils.ts (100%) rename src/{approver/octokit.ts => lib/octokit/index.ts} (100%) delete mode 100644 src/status/types.ts delete mode 100644 src/status/utils.ts diff --git a/.gitignore b/.gitignore index 6195d19..5cec262 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,3 @@ node_modules .idea # Ignore built ts files __tests__/runner/* -lib -dist diff --git a/hack/run-e2e-tests.sh b/hack/run-e2e-tests.sh index 545ed27..0af6eb2 100755 --- a/hack/run-e2e-tests.sh +++ b/hack/run-e2e-tests.sh @@ -6,7 +6,6 @@ set -euo pipefail [[ -z ${GITHUB_TOKEN} ]] && echo "GITHUB_TOKEN env variable is required. obtail one from https://github.com/settings/tokens/new" && exit 1 yarn build -yarn package act pull_request -e tests/act-pull-request.json \ -s GITHUB_TOKEN=${GITHUB_TOKEN} \ diff --git a/package.json b/package.json index 638faee..3603543 100644 --- a/package.json +++ b/package.json @@ -4,17 +4,16 @@ "description": "", "main": "lib/main.js", "scripts": { - "build": "tsc", + "build": "yarn baller:build && yarn approver:build && yarn status:build && yarn labeler:build", "format": "prettier --write '**/*.ts'", "format-check": "prettier --check '**/*.ts'", "lint": "eslint src/**/*.ts", - "package-baller": "ncc build lib/baller/main.js --out dist/baller --source-map --license licenses.txt", - "package-approver": "ncc build lib/approver/main.js --out dist/approver --source-map --license licenses.txt", - "package-status": "ncc build lib/status/main.js --out dist/status --source-map --license licenses.txt", - "package-labeler": "ncc build lib/labeler/main.js --out dist/labeler --source-map --license licenses.txt", - "package": "yarn package-baller && yarn package-approver && yarn package-status && yarn package-labeler", + "baller:build": "ncc build src/baller/main.ts --out dist/baller --source-map --license licenses.txt", + "approver:build": "ncc build src/approver/main.ts --out dist/approver --source-map --license licenses.txt", + "status:build": "ncc build src/status/main.ts --out dist/status --source-map --license licenses.txt", + "labeler:build": "ncc build src/labeler/main.ts --out dist/labeler --source-map --license licenses.txt", "test": "jest", - "all": "yarn build && yarn format && yarn lint && yarn package" + "all": "yarn format && yarn lint && yarn build" }, "repository": { "type": "git", diff --git a/src/approver/main.ts b/src/approver/main.ts index 1d100f9..db1e367 100644 --- a/src/approver/main.ts +++ b/src/approver/main.ts @@ -1,6 +1,6 @@ import * as core from '@actions/core' import * as github from '@actions/github' -import {Octokit} from './octokit' +import {Octokit} from '../lib' async function run(): Promise { try { diff --git a/src/labeler/main.ts b/src/labeler/main.ts index 88b3cd7..9f379f5 100644 --- a/src/labeler/main.ts +++ b/src/labeler/main.ts @@ -1,6 +1,6 @@ import * as core from '@actions/core' import * as github from '@actions/github' -import {Octokit} from './octokit' +import {Octokit} from '../lib' async function run(): Promise { try { diff --git a/src/labeler/octokit.ts b/src/labeler/octokit.ts deleted file mode 100644 index 271eae6..0000000 --- a/src/labeler/octokit.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {Octokit as Core} from '@octokit/core' -import {paginateRest} from '@octokit/plugin-paginate-rest' -import {legacyRestEndpointMethods} from '@octokit/plugin-rest-endpoint-methods' -import ProxyAgent from 'proxy-agent' - -const DEFAULTS = { - baseUrl: getApiBaseUrl() -} - -export const Octokit = Core.plugin( - paginateRest, - legacyRestEndpointMethods -).defaults(function buildDefaults(options: any): any { - return { - ...DEFAULTS, - ...options, - request: { - agent: new ProxyAgent(), - ...options.request - } - } -}) - -// export type OC = InstanceType - -function getApiBaseUrl(): string { - /* istanbul ignore next */ - return process.env['GITHUB_API_URL'] || 'https://api.github.com' -} diff --git a/src/lib/index.ts b/src/lib/index.ts new file mode 100644 index 0000000..af44c56 --- /dev/null +++ b/src/lib/index.ts @@ -0,0 +1,2 @@ +export * from './jobs' +export * from './octokit' diff --git a/src/lib/jobs/index.ts b/src/lib/jobs/index.ts new file mode 100644 index 0000000..6d5a6ef --- /dev/null +++ b/src/lib/jobs/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './utils'; diff --git a/src/approver/types.ts b/src/lib/jobs/types.ts similarity index 100% rename from src/approver/types.ts rename to src/lib/jobs/types.ts diff --git a/src/approver/utils.ts b/src/lib/jobs/utils.ts similarity index 100% rename from src/approver/utils.ts rename to src/lib/jobs/utils.ts diff --git a/src/approver/octokit.ts b/src/lib/octokit/index.ts similarity index 100% rename from src/approver/octokit.ts rename to src/lib/octokit/index.ts diff --git a/src/status/main.ts b/src/status/main.ts index 0928759..51e6fb9 100644 --- a/src/status/main.ts +++ b/src/status/main.ts @@ -1,6 +1,5 @@ import fetch from 'node-fetch' -import {Job} from './types' -import {isContributionJob, isFinalStatus} from './utils' +import {Job, isContributionJob, isFinalStatus} from '../lib' import * as core from '@actions/core' async function getJob(id: string): Promise { diff --git a/src/status/types.ts b/src/status/types.ts deleted file mode 100644 index 1f74caf..0000000 --- a/src/status/types.ts +++ /dev/null @@ -1,48 +0,0 @@ -export type Status = - | 'registered' - | 'running' - | 'failure' - | 'success' - | 'unknown' - -export type Job = { - id: string - created_at: string - started_at: string - completed_at: any - status: Status - error: any - repository?: Repository - contribution?: Contribution -} - -export type Repository = { - url: string - name: string - contribution_jobs: ContributionJob[] -} - -export type ContributionJob = { - id: string - parent: string - created_at: string - started_at: string - completed_at: string - status: Status - error?: Error - contribution: Contribution -} - -export type Error = { - message: string -} - -export type Contribution = { - url: string - number: number - title: string - merged_without_objections: boolean - created_at: string - merged_at: any - result: 'inconclusive' | 'approved' | 'not_approved' | null -} diff --git a/src/status/utils.ts b/src/status/utils.ts deleted file mode 100644 index d3744a0..0000000 --- a/src/status/utils.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type {Status, Job} from './types' - -export const isFinalStatus = (st: Status): Boolean => - st === 'failure' || st === 'success' - -export const isContributionJob = (job: Job): Boolean => - job.contribution !== undefined diff --git a/tsconfig.json b/tsconfig.json index 17f434a..3d1b548 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,12 +1,12 @@ { "compilerOptions": { - "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ - "outDir": "./lib", /* Redirect output structure to the directory. */ - "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - "strict": true, /* Enable all strict type-checking options. */ - "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + "target": "es2015", + "moduleResolution": "node", + "module": "commonjs", + "rootDir": "./src", + "strict": true, + "noImplicitAny": true, + "esModuleInterop": true }, "exclude": ["node_modules", "src/**/*.test.ts"] -} \ No newline at end of file +} From 2dc1433af12ba143e03461789b9603a311612f9a Mon Sep 17 00:00:00 2001 From: Nikita Galaiko Date: Wed, 1 Jun 2022 12:54:15 +0200 Subject: [PATCH 5/6] refactor: extract api calls to a shared lib --- src/baller/main.ts | 22 ++++------------------ src/lib/api/index.ts | 44 +++++++++++++++++++++++++++++++++++++++++++ src/lib/jobs/api.ts | 6 ++++++ src/lib/jobs/index.ts | 1 + src/status/main.ts | 13 +++---------- 5 files changed, 58 insertions(+), 28 deletions(-) create mode 100644 src/lib/api/index.ts create mode 100644 src/lib/jobs/api.ts diff --git a/src/baller/main.ts b/src/baller/main.ts index 260da66..6e6ca70 100644 --- a/src/baller/main.ts +++ b/src/baller/main.ts @@ -1,16 +1,9 @@ -import fetch from 'node-fetch' import * as core from '@actions/core' import * as github from '@actions/github' - -type JobResponse = { - id: string - status: string -} +import {create} from '../lib' async function run(): Promise { try { - const hostName = process.env.CODEBALL_API_HOST || 'https://api.codeball.ai' - const pullRequestURL = github.context.payload?.pull_request?.html_url if (!pullRequestURL) { core.setFailed('No pull request URL found') @@ -25,20 +18,13 @@ async function run(): Promise { core.info(`Found contribution: ${pullRequestURL}`) - const data = { + const job = await create({ url: pullRequestURL, access_token: githubToken - } - - const response = await fetch(`${hostName}/jobs`, { - method: 'POST', - body: JSON.stringify(data) }) - const resData = (await response.json()) as JobResponse - - core.info(`Job created: ${resData.id}`) - core.setOutput('codeball-job-id', resData.id) + core.info(`Job created: ${job.id}`) + core.setOutput('codeball-job-id', job.id) } catch (error) { if (error instanceof Error) core.setFailed(error.message) } diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts new file mode 100644 index 0000000..444f8d4 --- /dev/null +++ b/src/lib/api/index.ts @@ -0,0 +1,44 @@ +import fetch, {Response} from 'node-fetch' + +const BASE_URL = process.env.CODEBALL_API_HOST || 'https://api.codeball.ai' + +export class BadRequestError extends Error { + constructor(message: string) { + super(message); + this.name = 'BadRequestError'; + } +} + +export class NotFoundError extends Error { + constructor() { + super('Not found'); + this.name = 'NotFoundError'; + } +} + +const handleResponse = async (response: Response): Promise => { + if (response.ok) { + return await response.json(); + } else if (response.status === 404) { + throw new NotFoundError(); + } else if (response.status === 400) { + throw new BadRequestError(await response.text()); + } else { + throw new Error(await response.text()); + } +}; + +export const get = async (path: string) => + fetch(new URL(path, BASE_URL).toString(), { + redirect: 'follow' + }).then(handleResponse); + +export const post = async (path: string, body: any) => + fetch(new URL(path, BASE_URL).toString(), { + method: 'POST', + redirect: 'follow', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(body) + }).then(handleResponse); diff --git a/src/lib/jobs/api.ts b/src/lib/jobs/api.ts new file mode 100644 index 0000000..83f4119 --- /dev/null +++ b/src/lib/jobs/api.ts @@ -0,0 +1,6 @@ +import { get as apiGET, post } from '../api'; +import type { Job } from './types'; + +export const get = (id: string): Promise => apiGET(`/jobs/${id}`); + +export const create = ({ url, access_token }: { url: string, access_token: string }): Promise => post('/jobs', { url, access_token }); diff --git a/src/lib/jobs/index.ts b/src/lib/jobs/index.ts index 6d5a6ef..aac8e2b 100644 --- a/src/lib/jobs/index.ts +++ b/src/lib/jobs/index.ts @@ -1,2 +1,3 @@ export * from './types'; export * from './utils'; +export * from './api'; diff --git a/src/status/main.ts b/src/status/main.ts index 51e6fb9..484e30a 100644 --- a/src/status/main.ts +++ b/src/status/main.ts @@ -1,13 +1,6 @@ -import fetch from 'node-fetch' -import {Job, isContributionJob, isFinalStatus} from '../lib' +import {isContributionJob, isFinalStatus, get} from '../lib' import * as core from '@actions/core' -async function getJob(id: string): Promise { - const res = await fetch(`https://api.codeball.ai/jobs/${id}`) - const data = (await res.json()) as Job - return data -} - async function run(): Promise { try { const jobID = core.getInput('codeball-job-id') @@ -17,7 +10,7 @@ async function run(): Promise { core.info(`Job ID: ${jobID}`) - let job = await getJob(jobID) + let job = await get(jobID) let attempts = 0 const maxAttempts = 60 while (attempts < maxAttempts && !isFinalStatus(job.status)) { @@ -26,7 +19,7 @@ async function run(): Promise { `Waiting for job ${jobID} to complete... (${attempts}/${maxAttempts})` ) await new Promise(resolve => setTimeout(resolve, 5000)) - job = await getJob(jobID) + job = await get(jobID) } if (!isFinalStatus(job.status)) { From 42e5e122d3d2af31b2e8d5962aaa16c91f8f1873 Mon Sep 17 00:00:00 2001 From: Nikita Galaiko Date: Wed, 1 Jun 2022 13:16:30 +0200 Subject: [PATCH 6/6] add user agent to outgoing requests --- src/lib/api/index.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts index 444f8d4..61dde34 100644 --- a/src/lib/api/index.ts +++ b/src/lib/api/index.ts @@ -30,15 +30,19 @@ const handleResponse = async (response: Response): Promise => { export const get = async (path: string) => fetch(new URL(path, BASE_URL).toString(), { - redirect: 'follow' + headers: { + 'User-Agent': 'github-actions', + }, + redirect: 'follow', }).then(handleResponse); export const post = async (path: string, body: any) => fetch(new URL(path, BASE_URL).toString(), { method: 'POST', - redirect: 'follow', + body: JSON.stringify(body), headers: { + 'User-Agent': 'github-actions', 'Content-Type': 'application/json' }, - body: JSON.stringify(body) + redirect: 'follow', }).then(handleResponse);