feat: use cache
All checks were successful
Check Transpiled JavaScript / Check dist/ (push) Successful in 31s
Continuous Integration / GitHub Actions Test (push) Successful in 9s
Continuous Integration / TypeScript Tests (push) Successful in 47s

This commit is contained in:
Peter 2024-05-03 16:17:32 +02:00
parent 27c977abb6
commit 034dd15f69
Signed by: prskr
GPG key ID: F56BED6903BC5E37
14 changed files with 212 additions and 60 deletions

View file

@ -41,6 +41,8 @@ rules:
'eslint-comments/no-unused-disable': 'off',
'i18n-text/no-en': 'off',
'import/no-namespace': 'off',
'import/no-unresolved': 'warn',
'no-shadow': 'warn',
'no-console': 'off',
'no-unused-vars': 'off',
'prettier/prettier': 'error',
@ -79,5 +81,6 @@ rules:
'@typescript-eslint/semi': ['error', 'never'],
'@typescript-eslint/space-before-function-paren': 'off',
'@typescript-eslint/type-annotation-spacing': 'error',
'@typescript-eslint/unbound-method': 'error'
'@typescript-eslint/unbound-method': 'error',
'@typescript-eslint/no-duplicate-enum-values': 'off'
}

View file

@ -10,9 +10,9 @@ beforeEach(() => {
describe('Asset lookup', () => {
test('Hugo: should return valid version', async () => {
const octoVersionDetermination = new OctokitReleaseLookup()
const releaseLookup = new OctokitReleaseLookup()
const release = await octoVersionDetermination.getRelease(
const release = await releaseLookup.getRelease(
Hugo.Org,
Hugo.Repo,
'latest',

32
__tests__/hugo.test.ts Normal file
View file

@ -0,0 +1,32 @@
import { HugoInstaller } from '../src/hugo'
import { OctokitReleaseLookup } from '../src/asset-lookup'
import * as fs from 'node:fs'
import path from 'path'
import * as os from 'node:os'
import { Platform } from '../src/os'
let tmpDir = ''
beforeEach(() => {
jest.resetModules()
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-hugo-'))
})
afterEach(() => {
fs.rmSync(tmpDir, { recursive: true })
})
describe('Install Hugo', () => {
test('Download latest Hugo', async () => {
const releaseLookup = new OctokitReleaseLookup()
const platformMock = new Platform('linux', undefined, { HOME: tmpDir })
const hugo = new HugoInstaller(releaseLookup, platformMock)
expect(
async () =>
await hugo.install({
version: 'latest'
})
).not.toThrow()
}, 30_000)
})

View file

@ -10,7 +10,7 @@ const runMock = jest.spyOn(main, 'run').mockImplementation()
describe('index', () => {
it('calls run when imported', async () => {
// eslint-disable-next-line @typescript-eslint/no-require-imports
require('../src/index.ts')
require('../src/index')
expect(runMock).toHaveBeenCalled()
})

95
dist/index.js vendored
View file

@ -49333,12 +49333,10 @@ var Hugo;
Hugo["Org"] = "gohugoio";
Hugo["Repo"] = "hugo";
Hugo["CmdName"] = "hugo";
Hugo["CmdOptVersion"] = "version";
Hugo["TestVersionLatest"] = "0.83.1";
Hugo["TestVersionSpec"] = "0.82.1";
})(Hugo || (Hugo = {}));
var DartSass;
(function (DartSass) {
DartSass["Name"] = "dart-sass";
DartSass["Org"] = "sass";
DartSass["Repo"] = "dart-sass";
})(DartSass || (DartSass = {}));
@ -49411,6 +49409,18 @@ class Platform {
var tool_cache = __nccwpck_require__(7784);
;// CONCATENATED MODULE: external "node:os"
const external_node_os_namespaceObject = require("node:os");
// EXTERNAL MODULE: external "crypto"
var external_crypto_ = __nccwpck_require__(6113);
;// CONCATENATED MODULE: ./src/utils/error.ts
function errorMsg(e) {
if (typeof e === 'string') {
return e;
}
else if (e instanceof Error) {
return e.message;
}
}
;// CONCATENATED MODULE: ./src/hugo.ts
@ -49419,11 +49429,13 @@ const external_node_os_namespaceObject = require("node:os");
class HugoInstaller {
releaseLookup;
platform;
constructor(releaseLookup) {
this.platform = new Platform();
constructor(releaseLookup, platform) {
this.platform = platform ?? new Platform();
this.releaseLookup = releaseLookup;
}
async install(cmd) {
@ -49431,14 +49443,28 @@ class HugoInstaller {
core.debug(`Hugo extended: ${cmd.extended}`);
core.debug(`Operating System: ${this.platform.os}`);
core.debug(`Processor Architecture: ${this.platform.arch}`);
const hugoBinName = this.platform.binaryName(Hugo.CmdName);
const workDir = await this.platform.createWorkDir();
const binDir = await this.platform.ensureBinDir(workDir);
const tmpDir = external_node_os_namespaceObject.tmpdir();
try {
const cachedTool = tool_cache.find(Hugo.Name, release.tag_name, this.platform.arch);
if (cachedTool) {
await (0,io.cp)(cachedTool, external_path_default().join(binDir, hugoBinName));
return;
}
else {
core.info('Tool not present in cache - downloading it...');
}
}
catch (e) {
core.warning(`Failed to lookup tool in cache: ${errorMsg(e)}`);
}
const toolUrl = release.assetUrl(this.platform, cmd.extended);
if (!toolUrl) {
throw new Error('No matching URL detected for given platform');
}
const destPath = external_path_default().join(tmpDir, `hugo${this.platform.archiveExtension()}`);
const destPath = external_path_default().join(tmpDir, `hugo_${(0,external_crypto_.randomUUID)()}${this.platform.archiveExtension()}`);
await tool_cache.downloadTool(toolUrl, destPath);
core.debug(`Extract archive: ${destPath}`);
if (this.platform.isWindows()) {
@ -49447,8 +49473,15 @@ class HugoInstaller {
else {
await tool_cache.extractTar(destPath, tmpDir);
}
await (0,io.rmRF)(destPath);
core.debug(`move binaries to binDir: ${binDir}`);
await (0,io.mv)(external_path_default().join(tmpDir, this.platform.binaryName(Hugo.CmdName)), binDir);
await (0,io.mv)(external_path_default().join(tmpDir, hugoBinName), binDir);
try {
await tool_cache.cacheFile(external_path_default().join(binDir, hugoBinName), hugoBinName, Hugo.Name, release.tag_name, this.platform.arch);
}
catch (e) {
core.warning(`Failed to cache Hugo install: ${errorMsg(e)}`);
}
}
}
const HugoReleaseTransformer = {
@ -49465,14 +49498,14 @@ class HugoRelease {
this.tag_name = tag_name;
this.defaultAssets = new Map();
this.extendedAssets = new Map();
assets.forEach(asset => {
for (const asset of assets) {
if (asset.name.includes('extended')) {
this.extendedAssets.set(asset.name.replace(HugoRelease.keyReplacementRegex, ''), asset.url);
this.extendedAssets.set(asset.name.replace(HugoRelease.keyReplacementRegex, ''), asset.browser_download_url);
}
else {
this.defaultAssets.set(asset.name.replace(HugoRelease.keyReplacementRegex, ''), asset.url);
this.defaultAssets.set(asset.name.replace(HugoRelease.keyReplacementRegex, ''), asset.browser_download_url);
}
});
}
}
assetUrl(platform, extended) {
const src = extended ? this.extendedAssets : this.defaultAssets;
@ -49497,13 +49530,13 @@ class OctokitReleaseLookup {
async getRelease(owner, repo, version, transformer) {
const latestRelease = version && version !== 'latest'
? await this.octokit.rest.repos.getReleaseByTag({
owner: owner,
repo: repo,
owner,
repo,
tag: version
})
: await this.octokit.rest.repos.getLatestRelease({
owner: owner,
repo: repo
owner,
repo
});
return transformer.map(latestRelease.data);
}
@ -49517,6 +49550,8 @@ class OctokitReleaseLookup {
class DartSassInstaller {
releaseLookup;
platform;
@ -49531,11 +49566,18 @@ class DartSassInstaller {
const workDir = await this.platform.createWorkDir();
const binDir = await this.platform.ensureBinDir(workDir);
const tmpDir = external_node_os_namespaceObject.tmpdir();
try {
core.addPath(tool_cache.find(DartSass.Name, release.tag_name, this.platform.arch));
return;
}
catch (e) {
core.warning(`Failed to lookup cached version: ${errorMsg(e)}`);
}
const toolUrl = release.assetUrl(this.platform);
if (!toolUrl) {
throw new Error('No matching URL detected for given platform');
}
const destPath = external_path_default().join(tmpDir, `dart-sass${this.platform.archiveExtension()}`);
const destPath = external_path_default().join(tmpDir, `dart-sass-${(0,external_crypto_.randomUUID)()}${this.platform.archiveExtension()}`);
await tool_cache.downloadTool(toolUrl, destPath);
core.debug(`Extract archive: ${destPath}`);
if (this.platform.isWindows()) {
@ -49544,8 +49586,16 @@ class DartSassInstaller {
else {
await tool_cache.extractTar(destPath, tmpDir);
}
core.debug(`move binaries to binDir: ${binDir}`);
await (0,io.mv)(external_path_default().join(tmpDir, 'dart-sass', '*'), binDir);
await (0,io.rmRF)(destPath);
core.debug(`Move binaries to binDir: ${binDir}`);
await (0,io.mv)(external_path_default().join(tmpDir, 'dart-sass'), binDir);
core.debug(`Add 'dart-sass' directory to cache`);
try {
core.addPath(await tool_cache.cacheDir(external_path_default().join(binDir, 'dart-sass'), DartSass.Name, release.tag_name, this.platform.arch));
}
catch (e) {
core.warning(`Failed to cache dart-sass directory: ${errorMsg(e)}`);
}
}
}
const DartSassReleaseTransformer = {
@ -49565,9 +49615,9 @@ class DartSassRelease {
constructor(tag_name, assets) {
this.tag_name = tag_name;
this.assets = new Map();
assets.forEach(asset => {
this.assets.set(asset.name.replace(DartSassRelease.keyReplacementRegex, ''), asset.url);
});
for (const asset of assets) {
this.assets.set(asset.name.replace(DartSassRelease.keyReplacementRegex, ''), asset.browser_download_url);
}
}
assetUrl(platform) {
const mappedOS = DartSassRelease.platformMapping[platform.os];
@ -49598,12 +49648,13 @@ async function run() {
;// CONCATENATED MODULE: ./src/index.ts
(async () => {
try {
await run();
}
catch (e) {
core.setFailed(`Action failed with error ${e.message}`);
core.setFailed(`Action failed with error ${errorMsg(e)}`);
}
})();

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

View file

@ -27,8 +27,8 @@
},
"lint-staged": {
"{src,__tests__}/**/*.ts": [
"prettier --check",
"eslint"
"npx prettier --check",
"npx eslint . -c ./.forgejo/linters/.eslintrc.yml"
],
"README.md": [
"npx doctoc@2.1.0 --github"

View file

@ -36,13 +36,13 @@ export class OctokitReleaseLookup implements IReleaseLookup {
const latestRelease =
version && version !== 'latest'
? await this.octokit.rest.repos.getReleaseByTag({
owner: owner,
repo: repo,
owner,
repo,
tag: version
})
: await this.octokit.rest.repos.getLatestRelease({
owner: owner,
repo: repo
owner,
repo
})
return transformer.map(latestRelease.data)
}

View file

@ -2,13 +2,11 @@ export enum Hugo {
Name = 'Hugo',
Org = 'gohugoio',
Repo = 'hugo',
CmdName = 'hugo',
CmdOptVersion = 'version',
TestVersionLatest = '0.83.1',
TestVersionSpec = '0.82.1'
CmdName = 'hugo'
}
export enum DartSass {
Name = 'dart-sass',
Org = 'sass',
Repo = 'dart-sass'
}

View file

@ -1,12 +1,14 @@
import { IGithubRelease, IReleaseLookup } from './asset-lookup'
import { DartSass, Hugo } from './constants'
import { DartSass } from './constants'
import { components } from '@octokit/openapi-types'
import * as tc from '@actions/tool-cache'
import * as core from '@actions/core'
import { Platform } from './os'
import * as os from 'node:os'
import path from 'path'
import { mv } from '@actions/io'
import { mv, rmRF } from '@actions/io'
import { randomUUID } from 'crypto'
import { errorMsg } from './utils/error'
export interface IDartSassInstallCommand {
version: string
@ -36,6 +38,13 @@ export class DartSassInstaller {
const binDir = await this.platform.ensureBinDir(workDir)
const tmpDir = os.tmpdir()
try {
core.addPath(tc.find(DartSass.Name, release.tag_name, this.platform.arch))
return
} catch (e) {
core.warning(`Failed to lookup cached version: ${errorMsg(e)}`)
}
const toolUrl = release.assetUrl(this.platform)
if (!toolUrl) {
@ -44,7 +53,7 @@ export class DartSassInstaller {
const destPath = path.join(
tmpDir,
`dart-sass${this.platform.archiveExtension()}`
`dart-sass-${randomUUID()}${this.platform.archiveExtension()}`
)
await tc.downloadTool(toolUrl, destPath)
@ -55,8 +64,25 @@ export class DartSassInstaller {
await tc.extractTar(destPath, tmpDir)
}
core.debug(`move binaries to binDir: ${binDir}`)
await mv(path.join(tmpDir, 'dart-sass', '*'), binDir)
await rmRF(destPath)
core.debug(`Move binaries to binDir: ${binDir}`)
await mv(path.join(tmpDir, 'dart-sass'), binDir)
core.debug(`Add 'dart-sass' directory to cache`)
try {
core.addPath(
await tc.cacheDir(
path.join(binDir, 'dart-sass'),
DartSass.Name,
release.tag_name,
this.platform.arch
)
)
} catch (e) {
core.warning(`Failed to cache dart-sass directory: ${errorMsg(e)}`)
}
}
}
@ -90,12 +116,12 @@ export class DartSassRelease implements IGithubRelease {
this.tag_name = tag_name
this.assets = new Map<string, string>()
assets.forEach(asset => {
for (const asset of assets) {
this.assets.set(
asset.name.replace(DartSassRelease.keyReplacementRegex, ''),
asset.url
asset.browser_download_url
)
})
}
}
assetUrl(platform: Platform): string | undefined {

View file

@ -6,19 +6,21 @@ import { components } from '@octokit/openapi-types'
import * as tc from '@actions/tool-cache'
import path from 'path'
import * as os from 'node:os'
import { mv } from '@actions/io'
import { mv, rmRF, cp } from '@actions/io'
import { randomUUID } from 'crypto'
import { errorMsg } from './utils/error'
export interface IHugoInstallCommand {
version: string
extended: boolean
version?: string
extended?: boolean
}
export class HugoInstaller {
private readonly releaseLookup: IReleaseLookup
private readonly platform: Platform
constructor(releaseLookup: IReleaseLookup) {
this.platform = new Platform()
constructor(releaseLookup: IReleaseLookup, platform?: Platform) {
this.platform = platform ?? new Platform()
this.releaseLookup = releaseLookup
}
@ -34,10 +36,27 @@ export class HugoInstaller {
core.debug(`Operating System: ${this.platform.os}`)
core.debug(`Processor Architecture: ${this.platform.arch}`)
const hugoBinName = this.platform.binaryName(Hugo.CmdName)
const workDir = await this.platform.createWorkDir()
const binDir = await this.platform.ensureBinDir(workDir)
const tmpDir = os.tmpdir()
try {
const cachedTool = tc.find(
Hugo.Name,
release.tag_name,
this.platform.arch
)
if (cachedTool) {
await cp(cachedTool, path.join(binDir, hugoBinName))
return
} else {
core.info('Tool not present in cache - downloading it...')
}
} catch (e) {
core.warning(`Failed to lookup tool in cache: ${errorMsg(e)}`)
}
const toolUrl = release.assetUrl(this.platform, cmd.extended)
if (!toolUrl) {
@ -46,7 +65,7 @@ export class HugoInstaller {
const destPath = path.join(
tmpDir,
`hugo${this.platform.archiveExtension()}`
`hugo_${randomUUID()}${this.platform.archiveExtension()}`
)
await tc.downloadTool(toolUrl, destPath)
@ -57,8 +76,22 @@ export class HugoInstaller {
await tc.extractTar(destPath, tmpDir)
}
await rmRF(destPath)
core.debug(`move binaries to binDir: ${binDir}`)
await mv(path.join(tmpDir, this.platform.binaryName(Hugo.CmdName)), binDir)
await mv(path.join(tmpDir, hugoBinName), binDir)
try {
await tc.cacheFile(
path.join(binDir, hugoBinName),
hugoBinName,
Hugo.Name,
release.tag_name,
this.platform.arch
)
} catch (e) {
core.warning(`Failed to cache Hugo install: ${errorMsg(e)}`)
}
}
}
@ -86,22 +119,22 @@ export class HugoRelease implements IGithubRelease {
this.defaultAssets = new Map<string, string>()
this.extendedAssets = new Map<string, string>()
assets.forEach(asset => {
for (const asset of assets) {
if (asset.name.includes('extended')) {
this.extendedAssets.set(
asset.name.replace(HugoRelease.keyReplacementRegex, ''),
asset.url
asset.browser_download_url
)
} else {
this.defaultAssets.set(
asset.name.replace(HugoRelease.keyReplacementRegex, ''),
asset.url
asset.browser_download_url
)
}
})
}
}
assetUrl(platform: Platform, extended: boolean): string | undefined {
assetUrl(platform: Platform, extended?: boolean): string | undefined {
const src = extended ? this.extendedAssets : this.defaultAssets
const arch = platform.os === 'darwin' ? 'universal' : platform.arch
const key = `${platform.os}-${arch}${platform.archiveExtension()}`

View file

@ -1,9 +1,10 @@
import * as core from '@actions/core'
import * as main from './main'
import { errorMsg } from './utils/error'
;(async (): Promise<void> => {
try {
await main.run()
} catch (e: any) {
core.setFailed(`Action failed with error ${e.message}`)
} catch (e) {
core.setFailed(`Action failed with error ${errorMsg(e)}`)
}
})()

7
src/utils/error.ts Normal file
View file

@ -0,0 +1,7 @@
export function errorMsg(e: unknown): string | undefined {
if (typeof e === 'string') {
return e
} else if (e instanceof Error) {
return e.message
}
}

View file

@ -12,7 +12,8 @@
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"newLine": "lf"
"newLine": "lf",
"useUnknownInCatchVariables": true
},
"exclude": ["./dist", "./node_modules", "./__tests__", "./coverage"]
}