Skip to content

Commit

Permalink
feat: add validation .tool-versions file
Browse files Browse the repository at this point in the history
  • Loading branch information
kamontat committed Jun 17, 2024
1 parent 1ea79dc commit 9bf277e
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 148 deletions.
6 changes: 3 additions & 3 deletions actions/setup-asdf/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const createConfig = require("@kcws/eslint-config")
const createConfig = require('@kcws/eslint-config')
module.exports = createConfig({
cwd: __dirname,
profile: "node",
profile: 'node',
jest: true,
prettier: true,
ecma: "latest",
ecma: 'latest',
})
59 changes: 21 additions & 38 deletions actions/setup-asdf/src/apis/asdf.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,38 @@
import type { ToolVersion } from "./asdf.type"
import type { ToolVersion } from './asdf.type'

import { join } from "node:path"
import { readFile } from "node:fs/promises"
import { AppContext } from "@kcws/github-actions"
import { readFile } from 'node:fs/promises'
import { AppContext } from '@kcws/github-actions'

import { getPluginUrl } from "./constants"
import app from "../app"
import { getPluginUrl } from './constants'
import app from '../app'

export const asdfPluginList = async (context: AppContext<typeof app>) => {
const executors = context.use("exec")

const { code, stdout, stderr } = await executors.captureRun(
"asdf",
"plugin",
"list"
)
if (code > 0) throw new Error(stderr?.toString() ?? "unknown error occurred")
return stdout?.toString().split("\n") ?? []
const executors = context.use('exec')

const { code, stdout, stderr } = await executors.captureRun('asdf', 'plugin', 'list')
if (code > 0) throw new Error(stderr?.toString() ?? 'unknown error occurred')
return stdout?.toString().split('\n') ?? []
}

export const asdfPluginAdd = async (
context: AppContext<typeof app>,
plugin: string,
pluginUrl?: string
) => {
const repo = context
.use("log")
.format(getPluginUrl(plugin, pluginUrl), plugin)
await context.use("exec").run("asdf", "plugin", "add", plugin, repo)
export const asdfPluginAdd = async (context: AppContext<typeof app>, plugin: string, pluginUrl?: string) => {
const repo = context.use('log').format(getPluginUrl(plugin, pluginUrl), plugin)
await context.use('exec').run('asdf', 'plugin', 'add', plugin, repo)
}

export const asdfToolList = async (
_context: AppContext<typeof app>,
cwd: string
): Promise<ToolVersion[]> => {
const toolVersions = await readFile(join(cwd, ".tool-versions"), {
encoding: "utf8",
export const asdfToolList = async (_context: AppContext<typeof app>, toolFile: string): Promise<ToolVersion[]> => {
const toolVersions = await readFile(toolFile, {
encoding: 'utf8',
})

return toolVersions
.split("\n")
.map(x => x.replace(/#.*/, "").trim())
.split('\n')
.map(x => x.replace(/#.*/, '').trim())
.filter(x => x.length > 0)
.map(x => x.split(" "))
.map(x => x.split(' '))
.map(([name, version]) => ({ name, version }))
}

export const asdfToolInstall = async (
context: AppContext<typeof app>,
cwd: string
): Promise<void> => {
export const asdfToolInstall = async (context: AppContext<typeof app>, cwd: string): Promise<void> => {
const options = { cwd }
await context.use("exec").withOptions(options).run("asdf", "install")
await context.use('exec').withOptions(options).run('asdf', 'install')
}
60 changes: 29 additions & 31 deletions actions/setup-asdf/src/app/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
// eslint-disable-next-line import/no-namespace
import * as core from "@actions/core"
import { ContextBuilder } from "@kcws/github-actions"
import * as core from '@actions/core'
import { ContextBuilder } from '@kcws/github-actions'

import app, { context } from "."
import app, { context } from '.'

describe("app", () => {
it("should fail when no required input", async () => {
jest.spyOn(core, "setFailed")
describe('app', () => {
it('should fail when no required input', async () => {
jest.spyOn(core, 'setFailed')

const runner = jest.fn()
await app.exec(runner)

expect(core.setFailed).toHaveBeenCalled()
expect(core.setFailed).toHaveBeenCalledWith(
new Error("Input required and not supplied: ref")
)
expect(core.setFailed).toHaveBeenCalledWith(new Error('Input required and not supplied: ref'))
})

it("should success", async () => {
jest.spyOn(core, "getInput").mockImplementation(name => {
it('should success', async () => {
jest.spyOn(core, 'getInput').mockImplementation(name => {
switch (name) {
case "ref":
return "master"
case "install-tools":
return "true"
case "cache-enabled":
return "true"
case "cache-key":
return ""
case 'ref':
return 'master'
case 'install-tools':
return 'true'
case 'cache-enabled':
return 'true'
case 'cache-key':
return ''
default:
return ""
return ''
}
})

Expand All @@ -40,22 +38,22 @@ describe("app", () => {
})
})

describe("app.context", () => {
it("should contains metadata", () => {
describe('app.context', () => {
it('should contains metadata', () => {
// By default package.json should not found on source code
// because package.json is NOT on the same directory as source code
expect(context.name).toBe("")
expect(context.version).toBe("")
expect(context.name).toBe('')
expect(context.version).toBe('')

ContextBuilder.fromContext(context)
})

it("should contains plugins", () => {
expect(context.use("input")).not.toBeFalsy()
expect(context.use("cache")).not.toBeFalsy()
expect(context.use("log")).not.toBeFalsy()
expect(context.use("exec")).not.toBeFalsy()
expect(context.use("io")).not.toBeFalsy()
expect(context.use("system")).not.toBeFalsy()
it('should contains plugins', () => {
expect(context.use('input')).not.toBeFalsy()
expect(context.use('cache')).not.toBeFalsy()
expect(context.use('log')).not.toBeFalsy()
expect(context.use('exec')).not.toBeFalsy()
expect(context.use('io')).not.toBeFalsy()
expect(context.use('system')).not.toBeFalsy()
})
})
36 changes: 26 additions & 10 deletions actions/setup-asdf/src/app/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { homedir } from "node:os"
import { join } from "node:path"
import { homedir } from 'node:os'
import { join } from 'node:path'
import { existsSync } from 'node:fs'
import {
ContextBuilder,
InputContextPlugin,
Expand All @@ -11,7 +12,7 @@ import {
SystemContextPlugin,
IOContextPlugin,
HelperContextPlugin,
} from "@kcws/github-actions"
} from '@kcws/github-actions'

export const context = ContextBuilder.fromPackageJson()
.addPlugin(new LogContextPlugin())
Expand All @@ -24,16 +25,31 @@ export const context = ContextBuilder.fromPackageJson()
.build()

export default Actions.builder(context, context => {
const inputs = context.use("input")
const inputs = context.use('input')

const cwd = inputs.optionalString('workdir') ?? process.cwd()
const toolFile = join(cwd, '.tool-versions')
let toolInstall = inputs.required('install-tools', toBool)

if (toolInstall && !existsSync(toolFile)) {
context.use('log').warn('cannot install tools because file is missing', {
title: '.tool-versions file is missing',
file: toolFile,
})

// Force tool install to be disabled because no tool-versions found
toolInstall = false
}

return {
ref: inputs.requiredString("ref"),
tool: inputs.required("install-tools", toBool),
ref: inputs.requiredString('ref'),
tool: toolInstall,
cache: {
enabled: inputs.required("cache-enabled", toBool),
key: inputs.optionalString("cache-key") ?? "",
enabled: inputs.required('cache-enabled', toBool),
keys: inputs.optionalString('cache-key') ?? '',
},
asdfDir: inputs.optionalString("asdfdir") ?? join(homedir(), ".asdf"),
workDir: inputs.optionalString("workdir") ?? process.cwd(),
asdfDir: inputs.optionalString('asdfdir') ?? join(homedir(), '.asdf'),
toolFile: toolFile,
workDir: cwd,
}
})
4 changes: 2 additions & 2 deletions actions/setup-asdf/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import app from "./app"
import runner from "./runners/main"
import app from './app'
import runner from './runners/main'

app.exec(runner)
4 changes: 2 additions & 2 deletions actions/setup-asdf/src/post.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import app from "./app"
import runner from "./runners/post"
import app from './app'
import runner from './runners/post'

app.exec(runner)
4 changes: 2 additions & 2 deletions actions/setup-asdf/src/pre.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import app from "./app"
import runner from "./runners/pre"
import app from './app'
import runner from './runners/pre'

app.exec(runner)
89 changes: 29 additions & 60 deletions actions/setup-asdf/src/runners/main.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import type { AppRunner } from "@kcws/github-actions"
import type app from "../app"
import type { AppRunner } from '@kcws/github-actions'
import type app from '../app'

import { join } from "node:path"
import { existsSync } from "node:fs"
import { join } from 'node:path'
import { existsSync } from 'node:fs'

import {
asdfPluginAdd,
asdfPluginList,
asdfToolInstall,
asdfToolList,
} from "../apis/asdf"
import { asdfPluginAdd, asdfPluginList, asdfToolInstall, asdfToolList } from '../apis/asdf'

const runner: AppRunner<typeof app> = async (data, context) => {
await asdfSetup(data, context)

const path = await context.use("io").which("asdf", false)
if (path === undefined || path === null || path === "") {
const path = await context.use('io').which('asdf', false)
if (path === undefined || path === null || path === '') {
await asdfInstall(data, context)
}

Expand All @@ -26,73 +21,47 @@ const runner: AppRunner<typeof app> = async (data, context) => {
}

const asdfSetup: AppRunner<typeof app> = async (data, context) => {
return context.use("helper").group("Set up asdf", async () => {
context.use("log").debug("Setting up system for asdf")
return context.use('helper').group('Set up asdf', async () => {
context.use('log').debug('Setting up system for asdf')

context.use("system").setEnvVar("ASDF_DIR", data.input.asdfDir)
context
.use("system")
.addPaths(
join(data.input.asdfDir, "bin"),
join(data.input.asdfDir, "shims")
)
context.use('system').setEnvVar('ASDF_DIR', data.input.asdfDir)
context.use('system').addPaths(join(data.input.asdfDir, 'bin'), join(data.input.asdfDir, 'shims'))
})
}

const asdfInstall: AppRunner<typeof app> = async (data, context) => {
const executor = context.use("exec")
const logger = context.use("log")
return context.use("helper").group("Install asdf", async () => {
const executor = context.use('exec')
const logger = context.use('log')
return context.use('helper').group('Install asdf', async () => {
if (existsSync(data.input.asdfDir)) {
logger.info(
"Updating asdf to version '{0}' on (ASDF_DIR={1})",
data.input.ref,
data.input.asdfDir
)
logger.info("Updating asdf to version '{0}' on (ASDF_DIR={1})", data.input.ref, data.input.asdfDir)

executor.withOptions({ cwd: data.input.asdfDir })
await executor.rerun(
"git",
"remote",
"set-branches",
"origin",
data.input.ref
)
await executor.rerun(
"git",
"fetch",
"--depth",
"1",
"origin",
data.input.ref
)
await executor.rerun("git", "checkout", "-B", data.input.ref, "origin")
await executor.rerun('git', 'remote', 'set-branches', 'origin', data.input.ref)
await executor.rerun('git', 'fetch', '--depth', '1', 'origin', data.input.ref)
await executor.rerun('git', 'checkout', '-B', data.input.ref, 'origin')
} else {
logger.info(
"Installing asdf version '{0}' on (ASDF_DIR={1})",
data.input.ref,
data.input.asdfDir
)
logger.info("Installing asdf version '{0}' on (ASDF_DIR={1})", data.input.ref, data.input.asdfDir)

await executor.rerun(
"git",
"clone",
"--depth",
"1",
"--branch",
'git',
'clone',
'--depth',
'1',
'--branch',
data.input.ref,
"--single-branch",
"https://github.com/asdf-vm/asdf.git",
'--single-branch',
'https://github.com/asdf-vm/asdf.git',
data.input.asdfDir
)
}
})
}

const asdfInstallPlugins: AppRunner<typeof app> = (data, context) => {
return context.use("helper").group("Install asdf plugins", async () => {
return context.use('helper').group('Install asdf plugins', async () => {
const installed = await asdfPluginList(context)
const toolVersion = await asdfToolList(context, data.input.workDir)
const toolVersion = await asdfToolList(context, data.input.toolFile)
await Promise.all(
toolVersion.map(async ({ name }) => {
if (!installed.includes(name)) {
Expand All @@ -104,7 +73,7 @@ const asdfInstallPlugins: AppRunner<typeof app> = (data, context) => {
}

const asdfInstallTools: AppRunner<typeof app> = (data, context) => {
return context.use("helper").group("Install asdf tools", () => {
return context.use('helper').group('Install asdf tools', () => {
return asdfToolInstall(context, data.input.workDir)
})
}
Expand Down

0 comments on commit 9bf277e

Please sign in to comment.