From 79885e792853430425b14a9b60905c059bddf150 Mon Sep 17 00:00:00 2001 From: Opportunity Date: Sat, 23 May 2020 23:36:59 +0800 Subject: [PATCH] support sha --- README.md | 8 -------- action.yml | 2 +- dist/versions.js | 39 ++++++++++++++++++++++++++++++++++----- dist/win-install.js | 39 +++++++++++++++++++++++++-------------- src/version.spec.ts | 38 +++++++++++++++++++++++++++++++++++++- src/versions.ts | 45 ++++++++++++++++++++++++++++++++++++--------- src/win-install.ts | 37 +++++++++++++++++++++++++------------ 7 files changed, 158 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index ff18de7..ddb5195 100644 --- a/README.md +++ b/README.md @@ -34,14 +34,6 @@ with: xmake-version: branch@master ``` -Use specified pr: - -```yml -uses: xmake-io/github-action-setup-xmake@v1 -with: - xmake-version: pr@1 -``` - Use semver: ```yml diff --git a/action.yml b/action.yml index 30d826a..0d96413 100644 --- a/action.yml +++ b/action.yml @@ -9,7 +9,7 @@ inputs: xmake-version: required: true default: latest - description: The version to use. Should be a semver range or 'latest'. Or use pr@{pr_number} to select a pr, use branch@{branch_name} to select a branch + description: The version to use. Should be a semver range or 'latest'. Or use branch@{branch_name} to select a branch. runs: using: 'node12' diff --git a/dist/versions.js b/dist/versions.js index f01d5ea..90a8519 100644 --- a/dist/versions.js +++ b/dist/versions.js @@ -17,6 +17,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); const core = require("@actions/core"); const semver = require("semver"); const git_1 = require("./git"); +let VERSIONS; +async function getVersions() { + if (VERSIONS) + return VERSIONS; + return (VERSIONS = await git_1.lsRemote()); +} class VersionImpl { constructor(version, sha, type, toString) { this.version = version; @@ -31,19 +37,20 @@ class VersionImpl { } _string = new WeakMap(); async function selectBranch(branch) { - const versions = await git_1.lsRemote(); + const versions = await getVersions(); if (branch in versions.heads) { return new VersionImpl(branch, versions.heads[branch], 'heads', `branch ${branch}`); } throw new Error(`Branch ${branch} not found`); } async function selectPr(pr) { - const versions = await git_1.lsRemote(); + var _a; + const versions = await getVersions(); if (pr in versions.pull) { const prheads = versions.pull[pr]; - const sha = prheads.head; + const sha = (_a = prheads.merge) !== null && _a !== void 0 ? _a : prheads.head; if (sha) { - return new VersionImpl(`#${pr}`, sha, 'pull', `pull request #${pr}`); + return new VersionImpl(`pr#${pr}`, sha, 'pull', `pull request #${pr}`); } } throw new Error(`Pull requrest #${pr} not found`); @@ -54,7 +61,7 @@ async function selectSemver(version) { if (!v) { throw new Error(`Invalid semver`); } - const versions = await git_1.lsRemote(); + const versions = await getVersions(); const ver = semver.maxSatisfying(Object.keys(versions.tags), v); if (!ver) { throw new Error(`No matched releases of xmake-version ${v.format()}`); @@ -62,6 +69,23 @@ async function selectSemver(version) { const sha = versions.tags[ver]; return new VersionImpl(ver, sha, 'tags', ver); } +async function selectSha(sha) { + sha = sha.toLowerCase(); + if (!/^[a-f0-9]{40}$/gi.test(sha)) + throw new Error(`Invalid sha value ${sha}`); + const versions = await getVersions(); + for (const branch in versions.heads) { + if (versions.heads[branch] === sha) { + return selectBranch(branch); + } + } + for (const tag in versions.tags) { + if (versions.tags[tag] === sha) { + return selectSemver(tag); + } + } + return Promise.resolve(new VersionImpl(`sha#${sha}`, sha, 'sha', `commit ${sha.substr(0, 8)}`)); +} async function selectVersion(version) { // get version string version = (version !== null && version !== void 0 ? version : core.getInput('xmake-version')) || 'latest'; @@ -81,6 +105,11 @@ async function selectVersion(version) { } ret = await selectPr(pr); } + // select sha + if (version.startsWith('sha@')) { + const sha = version.substr('sha@'.length); + ret = await selectSha(sha); + } // select version if (semver.validRange(version)) { ret = await selectSemver(version); diff --git a/dist/win-install.js b/dist/win-install.js index ef85613..c9fc8b6 100644 --- a/dist/win-install.js +++ b/dist/win-install.js @@ -9,20 +9,31 @@ const path = require("path"); const semver = require("semver"); function getInstallerUrl(version) { const ver = version.version; - if (version.type === 'heads') { - // we only use appveyor ci artifacts for branch version - const arch = os.arch() === 'x64' ? 'x64' : 'x86'; - return `https://ci.appveyor.com/api/projects/waruqi/xmake/artifacts/xmake-installer.exe?branch=${ver}&pr=false&job=Image%3A+Visual+Studio+2017%3B+Platform%3A+${arch}`; - } - else if (version.type === 'pull') { - throw new Error('PR builds for windows is not supported'); - } - else { - // we cannot use appveyor ci artifacts, the old version links may be broken. - const arch = os.arch() === 'x64' ? 'win64' : 'win32'; - return semver.gt(ver, '2.2.6') - ? `https://github.com/xmake-io/xmake/releases/download/${ver}/xmake-${ver}.${arch}.exe` - : `https://github.com/xmake-io/xmake/releases/download/${ver}/xmake-${ver}.exe`; + switch (version.type) { + case 'heads': { + // we only use appveyor ci artifacts for branch version + const arch = os.arch() === 'x64' ? 'x64' : 'x86'; + return `https://ci.appveyor.com/api/projects/waruqi/xmake/artifacts/xmake-installer.exe?branch=${ver}&pr=false&job=Image%3A+Visual+Studio+2017%3B+Platform%3A+${arch}`; + } + case 'pull': { + throw new Error('PR builds for windows is not supported'); + } + case 'sha': { + throw new Error('Sha builds for windows is not supported'); + } + case 'tags': { + // we cannot use appveyor ci artifacts, the old version links may be broken. + const arch = os.arch() === 'x64' ? 'win64' : 'win32'; + return semver.gt(ver, '2.2.6') + ? `https://github.com/xmake-io/xmake/releases/download/${ver}/xmake-${ver}.${arch}.exe` + : `https://github.com/xmake-io/xmake/releases/download/${ver}/xmake-${ver}.exe`; + } + default: { + // check that we have tested all types + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const _ = version.type; + throw new Error('Unknown version type'); + } } } async function winInstall(version) { diff --git a/src/version.spec.ts b/src/version.spec.ts index e622edc..ce47f69 100644 --- a/src/version.spec.ts +++ b/src/version.spec.ts @@ -302,7 +302,7 @@ describe('selectVersion', () => { it('should return correct pr', async () => { await expect(selectVersion('pr@708')).resolves.toEqual({ - version: '#708', + version: 'pr#708', sha: 'af28dba1f52990cb7b6c3c8f69f1f1bcf017c90a', type: 'pull', }); @@ -315,4 +315,40 @@ describe('selectVersion', () => { it('should throw invalid pr', async () => { await expect(selectVersion('pr@xxx')).rejects.toThrowError('Invalid pull requrest xxx, should be a positive integer'); }); + + it('should return branch of sha', async () => { + await expect(selectVersion('sha@efad01e547f30d66d90e486c91c3afa0dbaceed3')).resolves.toEqual({ + version: 'master', + sha: 'efad01e547f30d66d90e486c91c3afa0dbaceed3', + type: 'heads', + }); + }); + + it('should return tag of sha', async () => { + await expect(selectVersion('sha@31bacc4f76101e6a865ec254c48d8bcba456378f')).resolves.toEqual({ + version: 'v2.3.2', + sha: '31bacc4f76101e6a865ec254c48d8bcba456378f', + type: 'tags', + }); + }); + + it('should return correct normalized sha', async () => { + await expect(selectVersion('sha@Af28dba1f52990cb7b6c3c8f69f1f1bcf017c90b')).resolves.toEqual({ + version: 'sha#af28dba1f52990cb7b6c3c8f69f1f1bcf017c90b', + sha: 'af28dba1f52990cb7b6c3c8f69f1f1bcf017c90b', + type: 'sha', + }); + }); + + it('should throw invalid length sha', async () => { + await expect(selectVersion('sha@af28dba1f52990cb7b6c3c8f69f1f1bcf017c90')).rejects.toThrowError( + 'Invalid sha value af28dba1f52990cb7b6c3c8f69f1f1bcf017c90', + ); + }); + + it('should throw invalid char sha', async () => { + await expect(selectVersion('sha@af28dba1f52990cb7b6c3c8f69f1f1bcf017c90g')).rejects.toThrowError( + 'Invalid sha value af28dba1f52990cb7b6c3c8f69f1f1bcf017c90g', + ); + }); }); diff --git a/src/versions.ts b/src/versions.ts index e315560..7d5bd30 100644 --- a/src/versions.ts +++ b/src/versions.ts @@ -5,11 +5,18 @@ import { lsRemote, RefDic } from './git'; export interface Version { version: string; sha: string; - type: keyof RefDic; + type: keyof RefDic | 'sha'; +} + +let VERSIONS: RefDic | undefined; + +async function getVersions(): Promise { + if (VERSIONS) return VERSIONS; + return (VERSIONS = await lsRemote()); } class VersionImpl implements Version { - constructor(readonly version: string, readonly sha: string, readonly type: keyof RefDic, toString: string) { + constructor(readonly version: string, readonly sha: string, readonly type: Version['type'], toString: string) { this.#string = toString; } readonly #string: string; @@ -19,7 +26,7 @@ class VersionImpl implements Version { } async function selectBranch(branch: string): Promise { - const versions = await lsRemote(); + const versions = await getVersions(); if (branch in versions.heads) { return new VersionImpl(branch, versions.heads[branch], 'heads', `branch ${branch}`); } @@ -27,12 +34,12 @@ async function selectBranch(branch: string): Promise { } async function selectPr(pr: number): Promise { - const versions = await lsRemote(); + const versions = await getVersions(); if (pr in versions.pull) { const prheads = versions.pull[pr]; - const sha = prheads.head; + const sha = prheads.merge ?? prheads.head; if (sha) { - return new VersionImpl(`#${pr}`, sha, 'pull', `pull request #${pr}`); + return new VersionImpl(`pr#${pr}`, sha, 'pull', `pull request #${pr}`); } } throw new Error(`Pull requrest #${pr} not found`); @@ -45,7 +52,7 @@ async function selectSemver(version: string): Promise { throw new Error(`Invalid semver`); } - const versions = await lsRemote(); + const versions = await getVersions(); const ver = semver.maxSatisfying(Object.keys(versions.tags), v); if (!ver) { throw new Error(`No matched releases of xmake-version ${v.format()}`); @@ -55,6 +62,23 @@ async function selectSemver(version: string): Promise { return new VersionImpl(ver, sha, 'tags', ver); } +async function selectSha(sha: string): Promise { + sha = sha.toLowerCase(); + if (!/^[a-f0-9]{40}$/gi.test(sha)) throw new Error(`Invalid sha value ${sha}`); + const versions = await getVersions(); + for (const branch in versions.heads) { + if (versions.heads[branch] === sha) { + return selectBranch(branch); + } + } + for (const tag in versions.tags) { + if (versions.tags[tag] === sha) { + return selectSemver(tag); + } + } + return Promise.resolve(new VersionImpl(`sha#${sha}`, sha, 'sha', `commit ${sha.substr(0, 8)}`)); +} + export async function selectVersion(version?: string): Promise { // get version string version = (version ?? core.getInput('xmake-version')) || 'latest'; @@ -66,7 +90,6 @@ export async function selectVersion(version?: string): Promise { const branch = version.substr('branch@'.length); ret = await selectBranch(branch); } - // select pr if (version.startsWith('pr@')) { const pr = Number.parseInt(version.substr('pr@'.length)); @@ -75,6 +98,11 @@ export async function selectVersion(version?: string): Promise { } ret = await selectPr(pr); } + // select sha + if (version.startsWith('sha@')) { + const sha = version.substr('sha@'.length); + ret = await selectSha(sha); + } // select version if (semver.validRange(version)) { ret = await selectSemver(version); @@ -82,7 +110,6 @@ export async function selectVersion(version?: string): Promise { if (!ret) { throw new Error(`Invalid input xmake-version ${core.getInput('xmake-version')}`); } - core.info(`Selected xmake ${ret} (commit: ${ret.sha.substr(0, 8)})`); return ret; } diff --git a/src/win-install.ts b/src/win-install.ts index ee45fa6..fb2c415 100644 --- a/src/win-install.ts +++ b/src/win-install.ts @@ -9,18 +9,31 @@ import { Version } from './versions'; function getInstallerUrl(version: Version): string { const ver = version.version; - if (version.type === 'heads') { - // we only use appveyor ci artifacts for branch version - const arch = os.arch() === 'x64' ? 'x64' : 'x86'; - return `https://ci.appveyor.com/api/projects/waruqi/xmake/artifacts/xmake-installer.exe?branch=${ver}&pr=false&job=Image%3A+Visual+Studio+2017%3B+Platform%3A+${arch}`; - } else if (version.type === 'pull') { - throw new Error('PR builds for windows is not supported'); - } else { - // we cannot use appveyor ci artifacts, the old version links may be broken. - const arch = os.arch() === 'x64' ? 'win64' : 'win32'; - return semver.gt(ver, '2.2.6') - ? `https://github.com/xmake-io/xmake/releases/download/${ver}/xmake-${ver}.${arch}.exe` - : `https://github.com/xmake-io/xmake/releases/download/${ver}/xmake-${ver}.exe`; + switch (version.type) { + case 'heads': { + // we only use appveyor ci artifacts for branch version + const arch = os.arch() === 'x64' ? 'x64' : 'x86'; + return `https://ci.appveyor.com/api/projects/waruqi/xmake/artifacts/xmake-installer.exe?branch=${ver}&pr=false&job=Image%3A+Visual+Studio+2017%3B+Platform%3A+${arch}`; + } + case 'pull': { + throw new Error('PR builds for windows is not supported'); + } + case 'sha': { + throw new Error('Sha builds for windows is not supported'); + } + case 'tags': { + // we cannot use appveyor ci artifacts, the old version links may be broken. + const arch = os.arch() === 'x64' ? 'win64' : 'win32'; + return semver.gt(ver, '2.2.6') + ? `https://github.com/xmake-io/xmake/releases/download/${ver}/xmake-${ver}.${arch}.exe` + : `https://github.com/xmake-io/xmake/releases/download/${ver}/xmake-${ver}.exe`; + } + default: { + // check that we have tested all types + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const _: never = version.type; + throw new Error('Unknown version type'); + } } }