From 91263d484bd4c40da65db335d4c6a662362772e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=89=BE=E6=96=AF=E7=89=B9=E6=B4=9B?= Date: Sat, 27 Jun 2020 13:06:31 +0800 Subject: [PATCH] fix: deno version match not work (#43) * fix: deno version match not work --- .github/workflows/ci.yml | 2 + dist/index.js | 26 ++- src/installer.ts | 410 ++++++++++++++++++++------------------- 3 files changed, 229 insertions(+), 209 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5560249d..1e0d0e37 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,8 @@ jobs: - name: Set up Deno v${{ matrix.deno }} uses: ./ + with: + deno-version: ${{ matrix.deno }} - name: Run deno run: | diff --git a/dist/index.js b/dist/index.js index 15635c79..497075e8 100644 --- a/dist/index.js +++ b/dist/index.js @@ -4578,7 +4578,6 @@ async function getDeno(version) { toolPath = tc.find("deno", version); if (toolPath) break walk; - version = await clearVersion(version); // check cache toolPath = tc.find("deno", version); if (toolPath) @@ -4591,6 +4590,11 @@ async function getDeno(version) { core.addPath(toolPath); } exports.getDeno = getDeno; +// Get a clear version +// eg. +// 1.x -> 1.1.2 +// 1.1.x -> 1.1.2 +// 0.x -> 0.43.0 async function clearVersion(version) { const c = semver.clean(version) || ""; if (semver.valid(c)) { @@ -4614,6 +4618,7 @@ async function queryLatestMatch(versionSpec) { } let version = ""; const versions = (await getAvailableVersions()).sort(cmp); + core.debug(`found Deno versions '${JSON.stringify(versions, null, 2)}'`); for (let i = versions.length - 1; i >= 0; --i) { if (semver.satisfies(versions[i], versionSpec)) { version = versions[i]; @@ -4632,8 +4637,11 @@ async function getAvailableVersions() { // a temporary workaround until a Release API is provided. (#11) const httpc = new HttpClient_1.HttpClient("setup-deno"); const body = await (await httpc.get("https://raw.githubusercontent.com/denoland/deno/master/Releases.md")).readBody(); - const matches = body.matchAll(/### (v\d+\.\d+\.\d+)/g); - return [...matches].map(m => m[1]).filter(v => v !== "v0.0.0"); + const matches = body.matchAll(/### (v?\d+\.\d+\.\d+)/g); + return [...matches] + .map(m => m[1]) + .filter(v => v && v !== "v0.0.0") + .map(version => (version.startsWith("v") ? version : "v" + version)); } exports.getAvailableVersions = getAvailableVersions; function getDownloadUrl(version) { @@ -4648,6 +4656,7 @@ function getDownloadUrl(version) { else { filename = `deno-${arch}-${platform}.zip`; } + version = version.replace(/^v/, ""); return `https://github.com/denoland/deno/releases/download/v${version}/${filename}`; } exports.getDownloadUrl = getDownloadUrl; @@ -4673,17 +4682,14 @@ async function extractDenoArchive(version, archiveFilepath) { } exports.extractDenoArchive = extractDenoArchive; async function acquireDeno(version) { + core.debug(`acquire Deno '${version}'`); // // Download - a tool installer intimately knows how to get the tool (and construct urls) // - const c = semver.clean(version); - if (c) { - version = c; - } - else { - throw new Error(`Unable to find Deno version ${version}`); - } + version = await clearVersion(version); + core.debug(`resolve Deno '${version}'`); const downloadUrl = getDownloadUrl(version); + core.debug(`download Deno from '${downloadUrl}'`); const downloadPath = await tc.downloadTool(downloadUrl); // // Extract diff --git a/src/installer.ts b/src/installer.ts index 5e6969ea..384b9a22 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -1,199 +1,211 @@ -import * as os from "os"; -import * as path from "path"; - -type PlatformOld = "win" | "osx" | "linux"; -type Platform = - | "pc-windows-msvc" - | "unknown-linux-gnu" - | "apple-darwin" - | PlatformOld; - -type ArchOld = "x64"; -type Arch = "x86_64" | ArchOld; - -// On load grab temp directory and cache directory and remove them from env (currently don't want to expose this) -let tempDirectory: string = process.env["RUNNER_TEMP"] || ""; -let cacheRoot: string = process.env["RUNNER_TOOL_CACHE"] || ""; -// If directories not found, place them in common temp locations -if (!tempDirectory || !cacheRoot) { - let baseLocation: string; - if (process.platform === "win32") { - // On windows use the USERPROFILE env variable - baseLocation = process.env["USERPROFILE"] || "C:\\"; - } else { - if (process.platform === "darwin") { - baseLocation = process.env["HOME"] || "/Users"; - } else { - baseLocation = process.env["HOME"] || "/home"; - } - } - if (!tempDirectory) { - tempDirectory = path.join(baseLocation, "actions", "temp"); - } - if (!cacheRoot) { - cacheRoot = path.join(baseLocation, "actions", "cache"); - } - process.env["RUNNER_TEMP"] = tempDirectory; - process.env["RUNNER_TOOL_CACHE"] = cacheRoot; -} - -import * as fs from "fs"; -import * as semver from "semver"; -import * as core from "@actions/core"; -import * as tc from "@actions/tool-cache"; -import * as exec from "@actions/exec"; -import * as io from "@actions/io"; -import * as uuidV4 from "uuid"; -import { HttpClient } from "typed-rest-client/HttpClient"; - -function getDenoArch(version: string): Arch { - return semver.lte(version, "0.38.0") ? "x64" : "x86_64"; -} -function getDenoPlatform(version: string): Platform { - const platform = os.platform(); - const isLessThenV35 = semver.lte(version, "0.38.0"); - - let rtv: Platform | null = null; - if (platform === "darwin") rtv = isLessThenV35 ? "osx" : "apple-darwin"; - else if (platform === "win32") - rtv = isLessThenV35 ? "win" : "pc-windows-msvc"; - else if (platform === "linux") - rtv = isLessThenV35 ? "linux" : "unknown-linux-gnu"; - if (!rtv) throw new Error(`Unexpected OS ${platform}`); - return rtv; -} - -export async function getDeno(version: string) { - let toolPath: string; - walk: { - // check cache - toolPath = tc.find("deno", version); - if (toolPath) break walk; - - version = await clearVersion(version); - // check cache - toolPath = tc.find("deno", version); - if (toolPath) break walk; - - // If not found in cache, download - core.debug(`Downloading deno at version ${version}`); - toolPath = await acquireDeno(version); - } - - // prepend the tools path. instructs the agent to prepend for future tasks - core.addPath(toolPath); -} - -export async function clearVersion(version: string) { - const c = semver.clean(version) || ""; - if (semver.valid(c)) { - version = c; - } else { - // query deno tags for a matching version - version = await queryLatestMatch(version); - if (!version) { - throw new Error(`Unable to find Deno version ${version}`); - } - } - return version; -} - -async function queryLatestMatch(versionSpec: string) { - function cmp(a: string, b: string) { - if (semver.gt(a, b)) return 1; - return -1; - } - let version = ""; - const versions = (await getAvailableVersions()).sort(cmp); - for (let i = versions.length - 1; i >= 0; --i) { - if (semver.satisfies(versions[i], versionSpec)) { - version = versions[i]; - break; - } - } - - if (version) { - core.debug(`matched: ${version}`); - } else { - core.debug(`match not found`); - } - - return version; -} - -export async function getAvailableVersions() { - // a temporary workaround until a Release API is provided. (#11) - const httpc = new HttpClient("setup-deno"); - const body = await ( - await httpc.get( - "https://raw.githubusercontent.com/denoland/deno/master/Releases.md" - ) - ).readBody(); - const matchIterator = body.matchAll(/### v?((\d+\.){2}(\d+)(-[\d\w]+)?)/g); - const matches = [...matchIterator]; - // console.log(matches.map(m => m[1])); - return matches.map(m => m[1]).filter(v => v !== "0.0.0"); -} - -export function getDownloadUrl(version: string): string { - // The old release file only keep to Deno v0.38.0 - const platform = getDenoPlatform(version); - const arch = getDenoArch(version); - let filename: string; - if (semver.lte(version, "0.38.0")) { - const extName = process.platform === "win32" ? "zip" : "gz"; - filename = `deno_${platform}_${arch}.${extName}`; - } else { - filename = `deno-${arch}-${platform}.zip`; - } - - return `https://github.com/denoland/deno/releases/download/v${version}/${filename}`; -} - -export async function extractDenoArchive( - version: string, - archiveFilepath: string -): Promise { - let extPath = ""; - if (semver.lte(version, "0.38.0")) { - if (process.platform === "win32") { - extPath = await tc.extractZip(archiveFilepath); - } else { - extPath = path.join(archiveFilepath, "..", uuidV4()); - const gzFile = path.join(extPath, "deno.gz"); - await io.mv(archiveFilepath, gzFile); - const gzPzth = await io.which("gzip"); - await exec.exec(gzPzth, ["-d", gzFile]); - fs.chmodSync(path.join(extPath, "deno"), "755"); - } - } else { - extPath = await tc.extractZip(archiveFilepath); - } - - return extPath; -} - -export async function acquireDeno(version: string) { - // - // Download - a tool installer intimately knows how to get the tool (and construct urls) - // - const c = semver.clean(version); - if (c) { - version = c; - } else { - throw new Error(`Unable to find Deno version ${version}`); - } - const downloadUrl = getDownloadUrl(version); - const downloadPath = await tc.downloadTool(downloadUrl); - - // - // Extract - // - const extPath = await extractDenoArchive(version, downloadPath); - - // - // Install into the local tool cache - deno extracts a file that matches the fileName downloaded - // - const toolPath = await tc.cacheDir(extPath, "deno", version); - return toolPath; -} +import * as os from "os"; +import * as path from "path"; + +type PlatformOld = "win" | "osx" | "linux"; +type Platform = + | "pc-windows-msvc" + | "unknown-linux-gnu" + | "apple-darwin" + | PlatformOld; + +type ArchOld = "x64"; +type Arch = "x86_64" | ArchOld; + +// On load grab temp directory and cache directory and remove them from env (currently don't want to expose this) +let tempDirectory: string = process.env["RUNNER_TEMP"] || ""; +let cacheRoot: string = process.env["RUNNER_TOOL_CACHE"] || ""; +// If directories not found, place them in common temp locations +if (!tempDirectory || !cacheRoot) { + let baseLocation: string; + if (process.platform === "win32") { + // On windows use the USERPROFILE env variable + baseLocation = process.env["USERPROFILE"] || "C:\\"; + } else { + if (process.platform === "darwin") { + baseLocation = process.env["HOME"] || "/Users"; + } else { + baseLocation = process.env["HOME"] || "/home"; + } + } + if (!tempDirectory) { + tempDirectory = path.join(baseLocation, "actions", "temp"); + } + if (!cacheRoot) { + cacheRoot = path.join(baseLocation, "actions", "cache"); + } + process.env["RUNNER_TEMP"] = tempDirectory; + process.env["RUNNER_TOOL_CACHE"] = cacheRoot; +} + +import * as fs from "fs"; +import * as semver from "semver"; +import * as core from "@actions/core"; +import * as tc from "@actions/tool-cache"; +import * as exec from "@actions/exec"; +import * as io from "@actions/io"; +import * as uuidV4 from "uuid"; +import { HttpClient } from "typed-rest-client/HttpClient"; + +function getDenoArch(version: string): Arch { + return semver.lte(version, "0.38.0") ? "x64" : "x86_64"; +} +function getDenoPlatform(version: string): Platform { + const platform = os.platform(); + const isLessThenV35 = semver.lte(version, "0.38.0"); + + let rtv: Platform | null = null; + if (platform === "darwin") rtv = isLessThenV35 ? "osx" : "apple-darwin"; + else if (platform === "win32") + rtv = isLessThenV35 ? "win" : "pc-windows-msvc"; + else if (platform === "linux") + rtv = isLessThenV35 ? "linux" : "unknown-linux-gnu"; + if (!rtv) throw new Error(`Unexpected OS ${platform}`); + return rtv; +} + +export async function getDeno(version: string) { + let toolPath: string; + walk: { + // check cache + toolPath = tc.find("deno", version); + if (toolPath) break walk; + + // check cache + toolPath = tc.find("deno", version); + if (toolPath) break walk; + + // If not found in cache, download + core.debug(`Downloading deno at version ${version}`); + toolPath = await acquireDeno(version); + } + + // prepend the tools path. instructs the agent to prepend for future tasks + core.addPath(toolPath); +} + +// Get a clear version +// eg. +// 1.x -> 1.1.2 +// 1.1.x -> 1.1.2 +// 0.x -> 0.43.0 +export async function clearVersion(version: string) { + const c = semver.clean(version) || ""; + if (semver.valid(c)) { + version = c; + } else { + // query deno tags for a matching version + version = await queryLatestMatch(version); + if (!version) { + throw new Error(`Unable to find Deno version ${version}`); + } + } + return version; +} + +async function queryLatestMatch(versionSpec: string) { + function cmp(a: string, b: string) { + if (semver.gt(a, b)) return 1; + return -1; + } + let version = ""; + const versions = (await getAvailableVersions()).sort(cmp); + core.debug(`found Deno versions '${JSON.stringify(versions, null, 2)}'`); + for (let i = versions.length - 1; i >= 0; --i) { + if (semver.satisfies(versions[i], versionSpec)) { + version = versions[i]; + break; + } + } + + if (version) { + core.debug(`matched: ${version}`); + } else { + core.debug(`match not found`); + } + + return version; +} + +export async function getAvailableVersions(): Promise { + // a temporary workaround until a Release API is provided. (#11) + const httpc = new HttpClient("setup-deno"); + const body = await ( + await httpc.get( + "https://raw.githubusercontent.com/denoland/deno/master/Releases.md" + ) + ).readBody(); + const matches = body.matchAll(/### (v?\d+\.\d+\.\d+)/g); + + return [...matches] + .map(m => m[1]) + .filter(v => v && v !== "v0.0.0") + .map(version => (version.startsWith("v") ? version : "v" + version)); +} + +export function getDownloadUrl(version: string): string { + // The old release file only keep to Deno v0.38.0 + const platform = getDenoPlatform(version); + const arch = getDenoArch(version); + let filename: string; + if (semver.lte(version, "0.38.0")) { + const extName = process.platform === "win32" ? "zip" : "gz"; + filename = `deno_${platform}_${arch}.${extName}`; + } else { + filename = `deno-${arch}-${platform}.zip`; + } + + version = version.replace(/^v/, ""); + + return `https://github.com/denoland/deno/releases/download/v${version}/${filename}`; +} + +export async function extractDenoArchive( + version: string, + archiveFilepath: string +): Promise { + let extPath = ""; + if (semver.lte(version, "0.38.0")) { + if (process.platform === "win32") { + extPath = await tc.extractZip(archiveFilepath); + } else { + extPath = path.join(archiveFilepath, "..", uuidV4()); + const gzFile = path.join(extPath, "deno.gz"); + await io.mv(archiveFilepath, gzFile); + const gzPzth = await io.which("gzip"); + await exec.exec(gzPzth, ["-d", gzFile]); + fs.chmodSync(path.join(extPath, "deno"), "755"); + } + } else { + extPath = await tc.extractZip(archiveFilepath); + } + + return extPath; +} + +export async function acquireDeno(version: string) { + core.debug(`acquire Deno '${version}'`); + // + // Download - a tool installer intimately knows how to get the tool (and construct urls) + // + + version = await clearVersion(version); + + core.debug(`resolve Deno '${version}'`); + + const downloadUrl = getDownloadUrl(version); + + core.debug(`download Deno from '${downloadUrl}'`); + + const downloadPath = await tc.downloadTool(downloadUrl); + + // + // Extract + // + const extPath = await extractDenoArchive(version, downloadPath); + + // + // Install into the local tool cache - deno extracts a file that matches the fileName downloaded + // + const toolPath = await tc.cacheDir(extPath, "deno", version); + return toolPath; +}