Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 48 additions & 20 deletions src/calculate-download-checksum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { debug } from '@actions/core'
import { URL } from 'url'
import { createHash } from 'crypto'
import { get as HTTP } from 'http'
import { get as HTTPS } from 'https'
import { get as HTTPS, request } from 'https'

interface Headers {
[name: string]: string
Expand Down Expand Up @@ -32,27 +32,60 @@ function stream(
})
}

type authInfo = {
token: string
}

async function resolveRedirect(
apiClient: API,
url: URL,
asBinary: boolean
): Promise<URL> {
const authInfo = (await apiClient.auth()) as authInfo
return new Promise((resolve, reject) => {
const req = request(
url,
{
method: 'HEAD',
headers: {
authorization: authInfo.token ? `bearer ${authInfo.token}` : '',
accept: asBinary ? 'application/octet-stream' : '*/*',
'User-Agent': 'bump-homebrew-formula-action',
},
},
(res) => {
if (res.statusCode == 302) {
const loc = res.headers['location']
if (loc != null) {
resolve(new URL(loc))
} else {
reject(
new Error(`got HTTP ${res.statusCode} but no Location header`)
)
}
} else {
reject(new Error(`unexpected HTTP ${res.statusCode} response`))
}
}
)
req.end()
})
}

async function resolveDownload(apiClient: API, url: URL): Promise<URL> {
if (url.hostname == 'github.com') {
const api = apiClient.rest
const archive = parseArchiveUrl(url)
if (archive != null) {
const { owner, repo, ref } = archive
const res = await (archive.ext == '.zip'
? api.repos.downloadZipballArchive
: api.repos.downloadTarballArchive)({
owner,
repo,
ref,
request: {
redirect: 'manual',
},
})
const loc = res.headers['location'] as string
const archiveType = archive.ext == '.zip' ? 'zipball' : 'tarball'
const endpoint = new URL(
`https://api.github.com/repos/${archive.owner}/${archive.repo}/${archiveType}/${archive.ref}`
)
const loc = await resolveRedirect(apiClient, endpoint, false)
// HACK: removing "legacy" from the codeload URL ensures that we get the
// same archive file as web download. Otherwise, the downloaded archive
// contains resolved commit SHA instead of the tag name in directory path.
return new URL(loc.replace('/legacy.', '/'))
return new URL(loc.href.replace('/legacy.', '/'))
}

const download = parseReleaseDownloadUrl(url)
Expand All @@ -66,12 +99,7 @@ async function resolveDownload(apiClient: API, url: URL): Promise<URL> {
`could not find asset '${download.name}' in '${tag}' release`
)
}
const assetRes = await apiClient.request(asset.url, {
headers: { accept: 'application/octet-stream' },
request: { redirect: 'manual' },
})
const loc = assetRes.headers['location'] as string
return new URL(loc)
return await resolveRedirect(apiClient, new URL(asset.url), true)
}
}
return url
Expand Down
33 changes: 9 additions & 24 deletions src/main-test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import test from 'ava'
import api from './api'
import { commitForRelease, prepareEdit } from './main'
import { Response } from 'node-fetch'

test('commitForRelease()', (t) => {
t.is(
Expand Down Expand Up @@ -53,44 +52,30 @@ test('commitForRelease()', (t) => {
test('prepareEdit() homebrew-core', async (t) => {
const ctx = {
sha: 'TAGSHA',
ref: 'refs/tags/v0.8.2',
ref: 'refs/tags/v1.9',
repo: {
owner: 'OWNER',
repo: 'REPO',
owner: 'mislav',
repo: 'bump-homebrew-formula-action',
},
}

process.env['GITHUB_REPOSITORY'] = 'monalisa/hello-world'
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.
// FIXME: this tests results in a live HTTP request. Figure out how to stub
// `stream()` and `resolveRedirect()` methods in calculate-download-checksum.
const stubbedFetch = function (url: string) {
if (
url ==
'https://api.github.com/repos/OWNER/REPO/tarball/refs%2Ftags%2Fv0.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, logRequests: false })
const apiClient = api('', { fetch: stubbedFetch, logRequests: false })

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/r/repo.rb')
t.is(opts.commitMessage, 'Upgrade repo to 0.8.2')
t.is(opts.filePath, 'Formula/b/bump-homebrew-formula-action.rb')
t.is(opts.commitMessage, 'Upgrade bump-homebrew-formula-action to 1.9')

const oldFormula = `
class MyProgram < Formula
Expand All @@ -104,7 +89,7 @@ test('prepareEdit() homebrew-core', async (t) => {
t.is(
`
class MyProgram < Formula
url "https://github.com/OWNER/REPO/archive/refs/tags/v0.8.2.tar.gz"
url "https://github.com/mislav/bump-homebrew-formula-action/archive/refs/tags/v1.9.tar.gz"
sha256 "c036fbc44901b266f6d408d6ca36ba56f63c14cc97994a935fb9741b55edee83"
head "git://example.com/repo.git",
revision: "GITSHA"
Expand Down