Skip to content

Commit

Permalink
Merge pull request #444 from scala-steward-org/refactor/tool-install
Browse files Browse the repository at this point in the history
Refactor tool installing
  • Loading branch information
alejandrohdezma authored Jan 3, 2023
2 parents bb0c915 + 88dd0c5 commit b9e6f5d
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 95 deletions.
5 changes: 2 additions & 3 deletions src/action/pre.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as mill from '../modules/mill'
*
* - Check connection with Maven Central
* - Install Coursier
* - Install JVM
* - Install Scalafmt
* - Install Scalafix
* - Install Mill
Expand All @@ -18,9 +19,7 @@ async function run(): Promise<void> {
const healthCheck: HealthCheck = HealthCheck.from(core, {run: async url => fetch(url)})
await healthCheck.mavenCentral()

await coursier.selfInstall()
await coursier.install('scalafmt')
await coursier.install('scalafix')
await coursier.install()
await mill.install()
} catch (error: unknown) {
core.setFailed(` ✕ ${(error as Error).message}`)
Expand Down
101 changes: 43 additions & 58 deletions src/modules/coursier.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import process from 'process'
import * as path from 'path'
import * as os from 'os'
import * as core from '@actions/core'
Expand All @@ -8,11 +7,14 @@ import * as exec from '@actions/exec'
import {type NonEmptyString} from '../core/types'

/**
* Install `coursier` and add its executable to the `PATH`.
* Installs `coursier` and add its executable to the `PATH`.
*
* Once coursier is installed, installs the JVM and the `scalafmt`
* and `scalafix` tools.
*
* Throws error if the installation fails.
*/
export async function selfInstall(): Promise<void> {
export async function install(): Promise<void> {
try {
const coursierUrl = core.getInput('coursier-cli-url')

Expand All @@ -28,68 +30,30 @@ export async function selfInstall(): Promise<void> {

core.addPath(binPath)

await exec.exec('cs', ['setup', '--yes', '--jvm', 'adoptium:17'], {
silent: true,
listeners: {stdline: core.debug, errline: core.debug},
})

let version = ''

const code = await exec.exec('cs', ['version'], {
silent: true,
ignoreReturnCode: true,
listeners: {stdout(data) {
(version += data.toString())
}, errline: core.error},
})

if (code !== 0) {
throw new Error('Coursier didn\t install correctly')
}

core.info(`✓ Coursier installed, version: ${version.trim()}`)
} catch (error: unknown) {
core.debug((error as Error).message)
throw new Error('Unable to install coursier')
}
}
await exec.exec(
'cs',
['setup', '--yes', '--jvm', 'adoptium:17', '--apps', 'scalafmt,scalafix', '--install-dir', binPath],
{
silent: true,
listeners: {stdline: core.debug, errline: core.debug},
},
)

/**
* Installs an app using `coursier`.
*
* Refer to [coursier](https://get-coursier.io/docs/cli-launch) for more information.
*
* @param {string} app - The application's name.
*/
export async function install(app: string): Promise<void> {
const homedir = os.homedir()
const binPath = path.join(homedir, 'bin')
const coursierVersion = await execute('cs', 'version')

let code = await exec.exec('cs', ['install', app, '--install-dir', binPath], {
silent: true,
ignoreReturnCode: true,
listeners: {stdline: core.info, errline: core.debug},
})
core.info(`✓ Coursier installed, version: ${coursierVersion.trim()}`)

if (code !== 0) {
throw new Error(`Installing ${app} failed`)
}
const scalafmtVersion = await execute('scalafmt', '--version')

let version = ''
core.info(`✓ Scalafmt installed, version: ${scalafmtVersion.replace(/^scalafmt /, '').trim()}`)

code = await exec.exec(app, ['--version'], {
silent: true,
ignoreReturnCode: true,
listeners: {stdout(data) {
(version += data.toString())
}, errline: core.error},
})
const scalafixVersion = await execute('scalafix', '--version')

if (code !== 0) {
throw new Error(`Installing ${app} failed`)
core.info(`✓ Scalafix installed, version: ${scalafixVersion.trim()}`)
} catch (error: unknown) {
core.debug((error as Error).message)
throw new Error('Unable to install coursier or managed tools')
}

core.info(`✓ ${app} installed, version: ${version.trim()}`)
}

/**
Expand Down Expand Up @@ -147,3 +111,24 @@ export async function remove(): Promise<void> {
await io.rmRF(path.join(os.homedir(), 'bin', 'scalafmt'))
await io.rmRF(path.join(os.homedir(), 'bin', 'scalafix'))
}

/**
* Executes a tool and returns its output.
*/
async function execute(tool: string, ...args: string[]): Promise<string> {
let output = ''

const code = await exec.exec(tool, args, {
silent: true,
ignoreReturnCode: true,
listeners: {stdout(data) {
(output += data.toString())
}, errline: core.debug},
})

if (code !== 0) {
throw new Error(`There was an error while executing '${tool} ${args.join(' ')}'`)
}

return output
}
60 changes: 26 additions & 34 deletions src/modules/mill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,60 +10,52 @@ import * as exec from '@actions/exec'
*
* Throws error if the installation fails.
*/
export async function install(): Promise<string> {
export async function install(): Promise<void> {
try {
const millVersion = core.getInput('mill-version') || '0.10.9'

const cachedPath = tc.find('mill', millVersion)

if (!cachedPath) {
if (cachedPath) {
core.addPath(cachedPath)
} else {
const millUrl = `https://github.com/lihaoyi/mill/releases/download/${millVersion}/${millVersion}`

core.debug(`Attempting to install Mill from ${millUrl}`)

const millDownload = await tc.downloadTool(millUrl)
const binPath = path.join(os.homedir(), 'bin')
await io.mkdirP(binPath)

await exec.exec('chmod', ['+x', millDownload], {silent: true, ignoreReturnCode: true})
const mill = await tc.downloadTool(millUrl, path.join(binPath, 'mill'))

const homedir = os.homedir()
await exec.exec('chmod', ['+x', mill], {silent: true, ignoreReturnCode: true})

const binPath = path.join(homedir, 'bin')
await tc.cacheFile(mill, 'mill', 'mill', millVersion)
}

const millBin = path.join(binPath, 'mill')
let output = ''

// We first copy and then remove here to avoid this
// https://stackoverflow.com/questions/44146393/error-exdev-cross-device-link-not-permitted-rename-nodejs
// This idea is taken from https://github.com/shelljs/shelljs/pull/187
// It didn't get merged there, but for our usecase just mimicking this
// should hopefully work fine.
await io.cp(millDownload, millBin)
await io.rmRF(millDownload)
const code = await exec.exec('mill', ['--version'], {
silent: true,
ignoreReturnCode: true,
listeners: {
stdout(data) {
(output += data.toString())
}, errline: core.debug,
},
})

await tc.cacheFile(millBin, 'mill', 'mill', millVersion)
if (code !== 0) {
throw new Error('Unable to install Mill')
}
} catch (error: unknown) {
core.error((error as Error).message)
throw new Error('Unable to install Mill')
}

let version = ''
const version = output.split('\n')[0].replace(/^Mill Build Tool version /, '').trim()

const code = await exec.exec('mill', ['--version'], {
silent: true,
ignoreReturnCode: true,
listeners: {
stdout(data) {
(version += data.toString())
}, errline: core.error,
},
})

if (code !== 0) {
core.info(`✓ Mill installed, version: ${version}`)
} catch (error: unknown) {
core.error((error as Error).message)
throw new Error('Unable to install Mill')
}

core.info(`✓ Mill installed, version: ${version.trim()}`)
return version
}

/**
Expand Down

0 comments on commit b9e6f5d

Please sign in to comment.