Skip to content

Commit

Permalink
Refactor to be more testable
Browse files Browse the repository at this point in the history
  • Loading branch information
mislav committed Feb 27, 2021
1 parent a72c013 commit 11ce557
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 104 deletions.
15 changes: 9 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,26 @@
"scripts": {
"build": "rm -rf lib && ncc build src/run.ts -o lib --source-map",
"lint": "eslint --ext '.js,.ts' .",
"test": "tsc && ava"
"test": "tsc --sourceMap && ava"
},
"dependencies": {
"@actions/core": "^1.2.4",
"@octokit/core": "^3.1.1",
"@octokit/plugin-request-log": "^1.0.0",
"@octokit/plugin-rest-endpoint-methods": "^4.1.2"
"@actions/core": "^1.2.6",
"@actions/github": "^4.0.0",
"@octokit/core": "^3.2.5",
"@octokit/plugin-request-log": "^1.0.3",
"@octokit/plugin-rest-endpoint-methods": "^4.10.1"
},
"devDependencies": {
"@types/node": "^12.7.5",
"@types/node": "^14.14.25",
"@types/node-fetch": "^2.5.8",
"@typescript-eslint/eslint-plugin": "^3.7.1",
"@typescript-eslint/parser": "^3.7.1",
"@zeit/ncc": "^0.22.3",
"ava": "^3.11.0",
"eslint": "^7.5.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.4",
"node-fetch": "^2.6.1",
"prettier": "^2.0.5",
"typescript": "^3.9.7"
},
Expand Down
33 changes: 17 additions & 16 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,24 @@ const GitHub = Octokit.plugin(restEndpointMethods, requestLog).defaults({

export type API = InstanceType<typeof GitHub>

type LogMethod = (msg: any, ...params: any[]) => void

type Logger = {
info?: LogMethod
debug?: LogMethod
}

export default function (token: string): API {
const log: Logger = {
info: console.log,
}
if (isDebug()) {
log.debug = console.debug
}

export default function (token: string, options?: {fetch?: any}): API {
return new GitHub({
request: {fetch: options?.fetch},
auth: `token ${token}`,
log,
log: {
info(msg: string) {
return console.info(msg)
},
debug(msg: string) {
if (!isDebug()) return
return console.debug(msg)
},
warn(msg: string) {
return console.warn(msg)
},
error(msg: string) {
return console.error(msg)
},
},
})
}
5 changes: 3 additions & 2 deletions src/calculate-download-checksum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ async function resolveDownload(api: API, url: URL): Promise<URL> {
)
if (archive != null) {
const [, owner, repo, ref, ext] = archive
const res = await api.repos.downloadArchive({
const res = await (ext == '.zip'
? api.repos.downloadZipballArchive
: api.repos.downloadTarballArchive)({
owner,
repo,
archive_format: ext == '.zip' ? 'zipball' : 'tarball',
ref,
request: {
redirect: 'manual',
Expand Down
13 changes: 8 additions & 5 deletions src/edit-github-blob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ async function retry<T>(
}
}

type Options = {
export type Options = {
owner: string
repo: string
filePath: string
Expand All @@ -47,12 +47,15 @@ export default async function (params: Options): Promise<string> {
branch: baseBranch,
})

const needsFork = !repoRes.data.permissions.push
const needsFork = !repoRes.data.permissions?.push
if (needsFork) {
const forkRes = await api.repos.createFork(baseRepo)
const res = await Promise.all([
api.repos.createFork(baseRepo),
api.users.getAuthenticated(),
])
headRepo = {
owner: forkRes.data.owner.login,
repo: forkRes.data.name,
owner: res[1].data.login,
repo: baseRepo.repo,
}
}

Expand Down
81 changes: 81 additions & 0 deletions src/main-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import test from 'ava'
import api from './api'
import { commitForRelease, prepareEdit } from './main'
import { Response } from 'node-fetch'

test('commitForRelease()', (t) => {
t.is(
commitForRelease('This is a fixed commit message', {
formulaName: 'test formula',
}),
'This is a fixed commit message'
)
t.is(
commitForRelease('chore({{formulaName}}): version {{version}}', {
formulaName: 'test formula',
}),
'chore(test formula): version {{version}}'
)
t.is(
commitForRelease('chore({{formulaName}}): upgrade to version {{version}}', {
formulaName: 'test formula',
version: 'v1.2.3',
}),
'chore(test formula): upgrade to version v1.2.3'
)
})

test('prepareEdit()', async (t) => {
const ctx = {
sha: 'TAGSHA',
ref: 'refs/tags/v0.8.2',
repo: {
owner: 'OWNER',
repo: 'REPO',
},
}

process.env['INPUT_HOMEBREW-TAP'] = 'Homebrew/homebrew-core'
process.env['INPUT_COMMIT-MESSAGE'] = 'Upgrade {{formulaName}} to {{version}}'

// FIXME: this tests results in a live HTTP request. Figure out how to stub the `stream()` method in
// calculate-download-checksum.
const stubbedFetch = function (url: string) {
if (url == 'https://api.github.com/repos/OWNER/REPO/tarball/v0.8.2') {
return Promise.resolve(
new Response('', {
status: 301,
headers: {
Location:
'https://github.com/mislav/bump-homebrew-formula-action/archive/v1.9.tar.gz',
},
})
)
}
throw url
}
const apiClient = api('ATOKEN', { fetch: stubbedFetch })

const opts = await prepareEdit(ctx, apiClient, apiClient)
t.is(opts.owner, 'Homebrew')
t.is(opts.repo, 'homebrew-core')
t.is(opts.branch, '')
t.is(opts.filePath, 'Formula/repo.rb')
t.is(opts.commitMessage, 'Upgrade repo to 0.8.2')

const oldFormula = `
class MyProgram < Formula
url "OLDURL"
sha256 "OLDSHA"
end
`
t.is(
opts.replace(oldFormula),
`
class MyProgram < Formula
url "https://github.com/OWNER/REPO/archive/v0.8.2.tar.gz"
sha256 "c036fbc44901b266f6d408d6ca36ba56f63c14cc97994a935fb9741b55edee83"
end
`
)
})
53 changes: 39 additions & 14 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { getInput } from '@actions/core'
import type { API } from './api'
import editGitHubBlob from './edit-github-blob'
import { Options as EditOptions } from './edit-github-blob'
import { replaceFields } from './replace-formula-fields'
import calculateDownloadChecksum from './calculate-download-checksum'
import { context } from '@actions/github'

function tarballForRelease(
owner: string,
Expand All @@ -27,31 +29,55 @@ export default async function (api: (token: string) => API): Promise<void> {
process.env.GITHUB_TOKEN || process.env.COMMITTER_TOKEN || ''
const externalToken = process.env.COMMITTER_TOKEN || ''

const [contextOwner, contextRepoName] = (process.env
.GITHUB_REPOSITORY as string).split('/')
const options = await prepareEdit(context, api(internalToken), api(externalToken))
const createdUrl = await editGitHubBlob(options)
console.log(createdUrl)
}

type Context = {
ref: string
sha: string
repo: {
owner: string
repo: string
}
}

export async function prepareEdit(ctx: Context, sameRepoClient: API, crossRepoClient: API): Promise<EditOptions> {
const tagName = getInput('tag-name') || ((ref) => {
if (!ref.startsWith('refs/tags/')) throw `invalid ref: ${ref}`
return ref.replace('refs/tags/', '')
})(ctx.ref)

const [owner, repo] = getInput('homebrew-tap', { required: true }).split('/')
const formulaName = getInput('formula-name') || contextRepoName.toLowerCase()
const formulaName = getInput('formula-name') || ctx.repo.repo.toLowerCase()
const branch = getInput('base-branch')
const filePath = `Formula/${formulaName}.rb`
const tagName = (process.env.GITHUB_REF as string).replace('refs/tags/', '')
const tagSha = process.env.GITHUB_SHA as string
const version = getInput('tag-name') || tagName.replace(/^v(\d)/, '$1')
const version = tagName.replace(/^v(\d)/, '$1')
const downloadUrl =
getInput('download-url') ||
tarballForRelease(contextOwner, contextRepoName, tagName)
tarballForRelease(ctx.repo.owner, ctx.repo.repo, tagName)
const messageTemplate = getInput('commit-message', { required: true })

const replacements = new Map<string, string>()
replacements.set('version', version)
replacements.set('url', downloadUrl)
if (downloadUrl.endsWith('.git')) {
replacements.set('tag', tagName)
replacements.set('revision', tagSha)
replacements.set('revision', await (async () => {
if (ctx.ref == `refs/tags/${tagName}`) return ctx.sha
else {
const res = await sameRepoClient.git.getRef({
...ctx.repo,
ref: `tags/${tagName}`
})
return res.data.object.sha
}
})())
} else {
replacements.set(
'sha256',
await calculateDownloadChecksum(api(internalToken), downloadUrl, 'sha256')
await calculateDownloadChecksum(sameRepoClient, downloadUrl, 'sha256')
)
}

Expand All @@ -60,16 +86,15 @@ export default async function (api: (token: string) => API): Promise<void> {
version,
})

const createdUrl = await editGitHubBlob({
apiClient: api(externalToken),
return {
apiClient: crossRepoClient,
owner,
repo,
branch,
filePath,
commitMessage,
replace(oldContent) {
replace(oldContent: string) {
return replaceFields(oldContent, replacements)
},
})
console.log(createdUrl)
}
}
22 changes: 22 additions & 0 deletions src/replace-formula-fields-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import test from 'ava'
import { replaceFields } from './replace-formula-fields'

test('replaceFields()', (t) => {
const input = `
url "https://github.com/old/url.git",
tag: 'v0.9.0',
revision => "OLDREV"
`
const expected = `
url "https://github.com/cli/cli.git",
tag: 'v0.11.1',
revision => "NEWREV"
`

const replacements = new Map<string, string>()
replacements.set('url', 'https://github.com/cli/cli.git')
replacements.set('tag', 'v0.11.1')
replacements.set('revision', 'NEWREV')

t.is(replaceFields(input, replacements), expected)
})
61 changes: 0 additions & 61 deletions src/test.ts

This file was deleted.

17 changes: 17 additions & 0 deletions src/version-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import test from 'ava'
import { fromUrl } from './version'

test('fromUrl()', (t) => {
t.is(
fromUrl('https://github.com/me/myproject/archive/v1.2.3.tar.gz'),
'v1.2.3'
)
t.is(
fromUrl(
'https://github.com/me/myproject/releases/download/v1.2.3/file.tgz'
),
'v1.2.3'
)
t.is(fromUrl('http://myproject.net/download/v1.2.3.tgz'), 'v1.2.3')
t.is(fromUrl('https://example.com/v1.2.3.zip'), 'v1.2.3')
})

0 comments on commit 11ce557

Please sign in to comment.