From 40bf055beea3e92c597a78fcd46b383931398be2 Mon Sep 17 00:00:00 2001 From: Brandon Chinn Date: Mon, 3 Jul 2023 15:42:52 -0700 Subject: [PATCH 01/10] Remove broken 'ghc-version: head' logic --- action.yml | 2 +- dist/index.js | 24 ------------------------ lib/installer.js | 24 ------------------------ src/installer.ts | 28 ---------------------------- 4 files changed, 1 insertion(+), 77 deletions(-) diff --git a/action.yml b/action.yml index ba95487..7f9b486 100644 --- a/action.yml +++ b/action.yml @@ -4,7 +4,7 @@ author: 'GitHub' inputs: ghc-version: required: false - description: 'Version of GHC to use. If set to "latest", it will always get the latest stable version. If set to "head", it will always get the latest build of GHC.' + description: 'Version of GHC to use. If set to "latest", it will always get the latest stable version.' default: 'latest' cabal-version: required: false diff --git a/dist/index.js b/dist/index.js index 4461716..25562ed 100644 --- a/dist/index.js +++ b/dist/index.js @@ -13436,12 +13436,6 @@ async function installTool(tool, version, os) { } switch (os) { case 'linux': - if (tool === 'ghc' && version === 'head') { - if (!(await aptBuildEssential())) - break; - await ghcupGHCHead(); - break; - } if (tool === 'ghc' && (0, compare_versions_1.compareVersions)('8.3', version)) { // Andreas, 2022-12-09: The following errors out if we are not ubuntu-20.04. // Atm, I do not know how to check whether we are on ubuntu-20.04. @@ -13508,11 +13502,6 @@ async function stack(version, os) { .then(async (g) => g.glob()); await tc.cacheDir(stackPath, 'stack', version); } -async function aptBuildEssential() { - core.info(`Installing build-essential using apt-get (for ghc-head)`); - const returnCode = await exec(`sudo -- sh -c "apt-get update && apt-get -y install build-essential"`); - return returnCode === 0; -} async function aptLibNCurses5() { core.info(`Installing libcurses5 and libtinfo5 using apt-get (for ghc < 8.3)`); const returnCode = await exec(`sudo -- sh -c "apt-get update && apt-get -y install libncurses5 libtinfo5"`); @@ -13581,19 +13570,6 @@ async function ghcup(tool, version, os) { if (returnCode === 0) await exec(bin, ['set', tool, version]); } -async function ghcupGHCHead() { - core.info(`Attempting to install ghc head using ghcup`); - const bin = await ghcupBin('linux'); - const returnCode = await exec(bin, [ - 'install', - 'ghc', - '-u', - 'https://gitlab.haskell.org/ghc/ghc/-/jobs/artifacts/master/raw/ghc-x86_64-deb9-linux-integer-simple.tar.xz?job=validate-x86_64-linux-deb9-integer-simple', - 'head' - ]); - if (returnCode === 0) - await exec(bin, ['set', 'ghc', 'head']); -} async function getChocoPath(tool, version, revision) { // Environment variable 'ChocolateyToolsLocation' will be added to Hosted images soon // fallback to C:\\tools for now until variable is available diff --git a/lib/installer.js b/lib/installer.js index 70c9429..798b54f 100644 --- a/lib/installer.js +++ b/lib/installer.js @@ -155,12 +155,6 @@ async function installTool(tool, version, os) { } switch (os) { case 'linux': - if (tool === 'ghc' && version === 'head') { - if (!(await aptBuildEssential())) - break; - await ghcupGHCHead(); - break; - } if (tool === 'ghc' && (0, compare_versions_1.compareVersions)('8.3', version)) { // Andreas, 2022-12-09: The following errors out if we are not ubuntu-20.04. // Atm, I do not know how to check whether we are on ubuntu-20.04. @@ -227,11 +221,6 @@ async function stack(version, os) { .then(async (g) => g.glob()); await tc.cacheDir(stackPath, 'stack', version); } -async function aptBuildEssential() { - core.info(`Installing build-essential using apt-get (for ghc-head)`); - const returnCode = await exec(`sudo -- sh -c "apt-get update && apt-get -y install build-essential"`); - return returnCode === 0; -} async function aptLibNCurses5() { core.info(`Installing libcurses5 and libtinfo5 using apt-get (for ghc < 8.3)`); const returnCode = await exec(`sudo -- sh -c "apt-get update && apt-get -y install libncurses5 libtinfo5"`); @@ -300,19 +289,6 @@ async function ghcup(tool, version, os) { if (returnCode === 0) await exec(bin, ['set', tool, version]); } -async function ghcupGHCHead() { - core.info(`Attempting to install ghc head using ghcup`); - const bin = await ghcupBin('linux'); - const returnCode = await exec(bin, [ - 'install', - 'ghc', - '-u', - 'https://gitlab.haskell.org/ghc/ghc/-/jobs/artifacts/master/raw/ghc-x86_64-deb9-linux-integer-simple.tar.xz?job=validate-x86_64-linux-deb9-integer-simple', - 'head' - ]); - if (returnCode === 0) - await exec(bin, ['set', 'ghc', 'head']); -} async function getChocoPath(tool, version, revision) { // Environment variable 'ChocolateyToolsLocation' will be added to Hosted images soon // fallback to C:\\tools for now until variable is available diff --git a/src/installer.ts b/src/installer.ts index 6e7f24f..9d30f41 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -165,12 +165,6 @@ export async function installTool( switch (os) { case 'linux': - if (tool === 'ghc' && version === 'head') { - if (!(await aptBuildEssential())) break; - - await ghcupGHCHead(); - break; - } if (tool === 'ghc' && compareVersions('8.3', version)) { // Andreas, 2022-12-09: The following errors out if we are not ubuntu-20.04. // Atm, I do not know how to check whether we are on ubuntu-20.04. @@ -244,15 +238,6 @@ async function stack(version: string, os: OS): Promise { await tc.cacheDir(stackPath, 'stack', version); } -async function aptBuildEssential(): Promise { - core.info(`Installing build-essential using apt-get (for ghc-head)`); - - const returnCode = await exec( - `sudo -- sh -c "apt-get update && apt-get -y install build-essential"` - ); - return returnCode === 0; -} - async function aptLibNCurses5(): Promise { core.info( `Installing libcurses5 and libtinfo5 using apt-get (for ghc < 8.3)` @@ -345,19 +330,6 @@ async function ghcup(tool: Tool, version: string, os: OS): Promise { if (returnCode === 0) await exec(bin, ['set', tool, version]); } -async function ghcupGHCHead(): Promise { - core.info(`Attempting to install ghc head using ghcup`); - const bin = await ghcupBin('linux'); - const returnCode = await exec(bin, [ - 'install', - 'ghc', - '-u', - 'https://gitlab.haskell.org/ghc/ghc/-/jobs/artifacts/master/raw/ghc-x86_64-deb9-linux-integer-simple.tar.xz?job=validate-x86_64-linux-deb9-integer-simple', - 'head' - ]); - if (returnCode === 0) await exec(bin, ['set', 'ghc', 'head']); -} - async function getChocoPath( tool: Tool, version: string, From b34ec7cf924856326fe38ff979d220f444e92345 Mon Sep 17 00:00:00 2001 From: Brandon Chinn Date: Tue, 11 Jul 2023 20:20:51 -0700 Subject: [PATCH 02/10] Fix unidiomatic typescript --- dist/index.js | 4 ++-- lib/installer.js | 2 +- src/installer.ts | 2 +- src/opts.ts | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dist/index.js b/dist/index.js index 25562ed..03927b5 100644 --- a/dist/index.js +++ b/dist/index.js @@ -13321,7 +13321,7 @@ const fs = __importStar(__nccwpck_require__(7147)); const compare_versions_1 = __nccwpck_require__(4773); // compareVersions can be used in the sense of > // Don't throw on non-zero. const exec = async (cmd, args) => (0, exec_1.exec)(cmd, args, { ignoreReturnCode: true }); -function failed(tool, version) { +async function failed(tool, version) { throw new Error(`All install methods for ${tool} ${version} failed`); } async function configureOutputs(tool, version, path, os) { @@ -13767,7 +13767,7 @@ function parseYAMLBoolean(name, val) { exports.parseYAMLBoolean = parseYAMLBoolean; function parseURL(name, val) { if (val === '') - return undefined; + return null; try { return new URL(val); } diff --git a/lib/installer.js b/lib/installer.js index 798b54f..3902a03 100644 --- a/lib/installer.js +++ b/lib/installer.js @@ -40,7 +40,7 @@ const fs = __importStar(require("fs")); const compare_versions_1 = require("compare-versions"); // compareVersions can be used in the sense of > // Don't throw on non-zero. const exec = async (cmd, args) => (0, exec_1.exec)(cmd, args, { ignoreReturnCode: true }); -function failed(tool, version) { +async function failed(tool, version) { throw new Error(`All install methods for ${tool} ${version} failed`); } async function configureOutputs(tool, version, path, os) { diff --git a/src/installer.ts b/src/installer.ts index 9d30f41..1b682fb 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -14,7 +14,7 @@ import {compareVersions} from 'compare-versions'; // compareVersions can be used const exec = async (cmd: string, args?: string[]): Promise => e(cmd, args, {ignoreReturnCode: true}); -function failed(tool: Tool, version: string): void { +async function failed(tool: Tool, version: string): Promise { throw new Error(`All install methods for ${tool} ${version} failed`); } diff --git a/src/opts.ts b/src/opts.ts index 9fe2dc1..7818af5 100644 --- a/src/opts.ts +++ b/src/opts.ts @@ -24,7 +24,7 @@ export interface ProgramOpt { export interface Options { ghc: ProgramOpt; - ghcup: {releaseChannel?: URL}; + ghcup: {releaseChannel: URL | null}; cabal: ProgramOpt & {update: boolean}; stack: ProgramOpt & {setup: boolean}; general: {matcher: {enable: boolean}}; @@ -138,8 +138,8 @@ export function parseYAMLBoolean(name: string, val: string): boolean { ); } -export function parseURL(name: string, val: string): URL | undefined { - if (val === '') return undefined; +export function parseURL(name: string, val: string): URL | null { + if (val === '') return null; try { return new URL(val); } catch (e) { From 8ca17812a7240648fca901cdc73dc9fef9ad1b99 Mon Sep 17 00:00:00 2001 From: Brandon Chinn Date: Mon, 3 Jul 2023 16:32:24 -0700 Subject: [PATCH 03/10] Support latest-nightly --- README.md | 1 + action.yml | 2 +- dist/index.js | 49 ++++++++++++++++++++++++++++++++++++-------- lib/installer.js | 35 ++++++++++++++++++++++++------- lib/opts.d.ts | 4 ++-- lib/opts.js | 2 +- lib/setup-haskell.js | 14 +++++++++++-- src/installer.ts | 42 ++++++++++++++++++++++++++++++------- src/setup-haskell.ts | 18 ++++++++++++---- 9 files changed, 134 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 3813355..c3a2eea 100644 --- a/README.md +++ b/README.md @@ -236,6 +236,7 @@ E.g., `8.10` will be resolved to `8.10.7`, and so will `8`. **GHC:** +- `latest-nightly` - `latest` (default) - `9.6.2` `9.6` - `9.6.1` diff --git a/action.yml b/action.yml index 7f9b486..fa7c89a 100644 --- a/action.yml +++ b/action.yml @@ -4,7 +4,7 @@ author: 'GitHub' inputs: ghc-version: required: false - description: 'Version of GHC to use. If set to "latest", it will always get the latest stable version.' + description: 'Version of GHC to use. If set to "latest", it will always get the latest stable version. If set to "latest-nightly", it will always get the latest nightly version of GHC' default: 'latest' cabal-version: required: false diff --git a/dist/index.js b/dist/index.js index 03927b5..f605ab3 100644 --- a/dist/index.js +++ b/dist/index.js @@ -13312,6 +13312,7 @@ const core = __importStar(__nccwpck_require__(2186)); const exec_1 = __nccwpck_require__(1514); const io_1 = __nccwpck_require__(7436); const tc = __importStar(__nccwpck_require__(7784)); +const child_process = __importStar(__nccwpck_require__(2081)); const fs_1 = __nccwpck_require__(7147); const path_1 = __nccwpck_require__(1017); const opts_1 = __nccwpck_require__(8131); @@ -13334,7 +13335,25 @@ async function configureOutputs(tool, version, path, os) { if (os === 'win32') core.exportVariable('STACK_ROOT', sr); } - core.setOutput(`${tool}-version`, version); + // can't put this in resolve() because it might run before ghcup is installed + let resolvedVersion = version; + if (version === 'latest-nightly') { + try { + const ghcupExe = await ghcupBin(os); + const out = await new Promise((resolve, reject) => child_process.execFile(ghcupExe, ['list', '-nr'], { encoding: 'utf-8' }, (error, stdout) => (error ? reject(error) : resolve(stdout)))); + resolvedVersion = + out + .split('\n') + .map(line => line.split(' ')) + .filter(line => line[2] === 'latest-nightly') + .map(line => line[1]) + .at(0) ?? version; + } + catch (error) { + // swallow failures, just leave version as 'latest-nightly' + } + } + core.setOutput(`${tool}-version`, resolvedVersion); } async function success(tool, version, path, os) { core.addPath(path); @@ -13436,12 +13455,14 @@ async function installTool(tool, version, os) { } switch (os) { case 'linux': - if (tool === 'ghc' && (0, compare_versions_1.compareVersions)('8.3', version)) { - // Andreas, 2022-12-09: The following errors out if we are not ubuntu-20.04. - // Atm, I do not know how to check whether we are on ubuntu-20.04. - // So, ignore the error. - // if (!(await aptLibCurses5())) break; - await aptLibNCurses5(); + if (tool === 'ghc') { + if (version !== 'latest-nightly' && (0, compare_versions_1.compareVersions)('8.3', version)) { + // Andreas, 2022-12-09: The following errors out if we are not ubuntu-20.04. + // Atm, I do not know how to check whether we are on ubuntu-20.04. + // So, ignore the error. + // if (!(await aptLibCurses5())) break; + await aptLibNCurses5(); + } } await ghcup(tool, version, os); if (await isInstalled(tool, version, os)) @@ -13898,8 +13919,18 @@ async function run(inputs) { core.debug(`run: inputs = ${JSON.stringify(inputs)}`); core.debug(`run: os = ${JSON.stringify(os)}`); core.debug(`run: opts = ${JSON.stringify(opts)}`); - if (opts.ghcup.releaseChannel) { - await core.group(`Preparing ghcup environment`, async () => (0, installer_1.addGhcupReleaseChannel)(opts.ghcup.releaseChannel, os)); + const releaseChannels = [ + opts.ghcup.releaseChannel, + opts.ghc.raw === 'latest-nightly' + ? new URL('https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml') + : null + ].filter((v) => v !== null); + if (releaseChannels.length > 0) { + await core.group(`Setting release channels`, async () => { + for (const channel of releaseChannels) { + await (0, installer_1.addGhcupReleaseChannel)(channel, os); + } + }); } for (const [t, { resolved }] of Object.entries(opts).filter(o => o[1].enable)) { await core.group(`Preparing ${t} environment`, async () => (0, installer_1.resetTool)(t, resolved, os)); diff --git a/lib/installer.js b/lib/installer.js index 3902a03..2ab7fd0 100644 --- a/lib/installer.js +++ b/lib/installer.js @@ -31,6 +31,7 @@ const core = __importStar(require("@actions/core")); const exec_1 = require("@actions/exec"); const io_1 = require("@actions/io"); const tc = __importStar(require("@actions/tool-cache")); +const child_process = __importStar(require("child_process")); const fs_1 = require("fs"); const path_1 = require("path"); const opts_1 = require("./opts"); @@ -53,7 +54,25 @@ async function configureOutputs(tool, version, path, os) { if (os === 'win32') core.exportVariable('STACK_ROOT', sr); } - core.setOutput(`${tool}-version`, version); + // can't put this in resolve() because it might run before ghcup is installed + let resolvedVersion = version; + if (version === 'latest-nightly') { + try { + const ghcupExe = await ghcupBin(os); + const out = await new Promise((resolve, reject) => child_process.execFile(ghcupExe, ['list', '-nr'], { encoding: 'utf-8' }, (error, stdout) => (error ? reject(error) : resolve(stdout)))); + resolvedVersion = + out + .split('\n') + .map(line => line.split(' ')) + .filter(line => line[2] === 'latest-nightly') + .map(line => line[1]) + .at(0) ?? version; + } + catch (error) { + // swallow failures, just leave version as 'latest-nightly' + } + } + core.setOutput(`${tool}-version`, resolvedVersion); } async function success(tool, version, path, os) { core.addPath(path); @@ -155,12 +174,14 @@ async function installTool(tool, version, os) { } switch (os) { case 'linux': - if (tool === 'ghc' && (0, compare_versions_1.compareVersions)('8.3', version)) { - // Andreas, 2022-12-09: The following errors out if we are not ubuntu-20.04. - // Atm, I do not know how to check whether we are on ubuntu-20.04. - // So, ignore the error. - // if (!(await aptLibCurses5())) break; - await aptLibNCurses5(); + if (tool === 'ghc') { + if (version !== 'latest-nightly' && (0, compare_versions_1.compareVersions)('8.3', version)) { + // Andreas, 2022-12-09: The following errors out if we are not ubuntu-20.04. + // Atm, I do not know how to check whether we are on ubuntu-20.04. + // So, ignore the error. + // if (!(await aptLibCurses5())) break; + await aptLibNCurses5(); + } } await ghcup(tool, version, os); if (await isInstalled(tool, version, os)) diff --git a/lib/opts.d.ts b/lib/opts.d.ts index 5b5a360..768fa1d 100644 --- a/lib/opts.d.ts +++ b/lib/opts.d.ts @@ -16,7 +16,7 @@ export interface ProgramOpt { export interface Options { ghc: ProgramOpt; ghcup: { - releaseChannel?: URL; + releaseChannel: URL | null; }; cabal: ProgramOpt & { update: boolean; @@ -85,6 +85,6 @@ export declare function releaseRevision(version: string, tool: Tool, os: OS): st * @returns boolean */ export declare function parseYAMLBoolean(name: string, val: string): boolean; -export declare function parseURL(name: string, val: string): URL | undefined; +export declare function parseURL(name: string, val: string): URL | null; export declare function getOpts({ ghc, cabal, stack }: Defaults, os: OS, inputs: Record): Options; export {}; diff --git a/lib/opts.js b/lib/opts.js index fb933de..e2734ca 100644 --- a/lib/opts.js +++ b/lib/opts.js @@ -125,7 +125,7 @@ function parseYAMLBoolean(name, val) { exports.parseYAMLBoolean = parseYAMLBoolean; function parseURL(name, val) { if (val === '') - return undefined; + return null; try { return new URL(val); } diff --git a/lib/setup-haskell.js b/lib/setup-haskell.js index 4285907..fb23933 100644 --- a/lib/setup-haskell.js +++ b/lib/setup-haskell.js @@ -52,8 +52,18 @@ async function run(inputs) { core.debug(`run: inputs = ${JSON.stringify(inputs)}`); core.debug(`run: os = ${JSON.stringify(os)}`); core.debug(`run: opts = ${JSON.stringify(opts)}`); - if (opts.ghcup.releaseChannel) { - await core.group(`Preparing ghcup environment`, async () => (0, installer_1.addGhcupReleaseChannel)(opts.ghcup.releaseChannel, os)); + const releaseChannels = [ + opts.ghcup.releaseChannel, + opts.ghc.raw === 'latest-nightly' + ? new URL('https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml') + : null + ].filter((v) => v !== null); + if (releaseChannels.length > 0) { + await core.group(`Setting release channels`, async () => { + for (const channel of releaseChannels) { + await (0, installer_1.addGhcupReleaseChannel)(channel, os); + } + }); } for (const [t, { resolved }] of Object.entries(opts).filter(o => o[1].enable)) { await core.group(`Preparing ${t} environment`, async () => (0, installer_1.resetTool)(t, resolved, os)); diff --git a/src/installer.ts b/src/installer.ts index 1b682fb..3202706 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -2,6 +2,7 @@ import * as core from '@actions/core'; import {exec as e} from '@actions/exec'; import {which} from '@actions/io'; import * as tc from '@actions/tool-cache'; +import * as child_process from 'child_process'; import {promises as afs} from 'fs'; import {join, dirname} from 'path'; import {ghcup_version, OS, Tool, releaseRevision} from './opts'; @@ -33,7 +34,32 @@ async function configureOutputs( core.setOutput('stack-root', sr); if (os === 'win32') core.exportVariable('STACK_ROOT', sr); } - core.setOutput(`${tool}-version`, version); + + // can't put this in resolve() because it might run before ghcup is installed + let resolvedVersion = version; + if (version === 'latest-nightly') { + try { + const ghcupExe = await ghcupBin(os); + const out = await new Promise((resolve, reject) => + child_process.execFile( + ghcupExe, + ['list', '-nr'], + {encoding: 'utf-8'}, + (error, stdout) => (error ? reject(error) : resolve(stdout)) + ) + ); + resolvedVersion = + out + .split('\n') + .map(line => line.split(' ')) + .filter(line => line[2] === 'latest-nightly') + .map(line => line[1]) + .at(0) ?? version; + } catch (error) { + // swallow failures, just leave version as 'latest-nightly' + } + } + core.setOutput(`${tool}-version`, resolvedVersion); } async function success( @@ -165,12 +191,14 @@ export async function installTool( switch (os) { case 'linux': - if (tool === 'ghc' && compareVersions('8.3', version)) { - // Andreas, 2022-12-09: The following errors out if we are not ubuntu-20.04. - // Atm, I do not know how to check whether we are on ubuntu-20.04. - // So, ignore the error. - // if (!(await aptLibCurses5())) break; - await aptLibNCurses5(); + if (tool === 'ghc') { + if (version !== 'latest-nightly' && compareVersions('8.3', version)) { + // Andreas, 2022-12-09: The following errors out if we are not ubuntu-20.04. + // Atm, I do not know how to check whether we are on ubuntu-20.04. + // So, ignore the error. + // if (!(await aptLibCurses5())) break; + await aptLibNCurses5(); + } } await ghcup(tool, version, os); if (await isInstalled(tool, version, os)) return; diff --git a/src/setup-haskell.ts b/src/setup-haskell.ts index a0502e4..a6b43d0 100644 --- a/src/setup-haskell.ts +++ b/src/setup-haskell.ts @@ -30,10 +30,20 @@ export default async function run( core.debug(`run: os = ${JSON.stringify(os)}`); core.debug(`run: opts = ${JSON.stringify(opts)}`); - if (opts.ghcup.releaseChannel) { - await core.group(`Preparing ghcup environment`, async () => - addGhcupReleaseChannel(opts.ghcup.releaseChannel!, os) - ); + const releaseChannels = [ + opts.ghcup.releaseChannel, + opts.ghc.raw === 'latest-nightly' + ? new URL( + 'https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml' + ) + : null + ].filter((v): v is URL => v !== null); + if (releaseChannels.length > 0) { + await core.group(`Setting release channels`, async () => { + for (const channel of releaseChannels) { + await addGhcupReleaseChannel(channel, os); + } + }); } for (const [t, {resolved}] of Object.entries(opts).filter( From e2a91ebfd33d5c1336ff88be41e248241855ac83 Mon Sep 17 00:00:00 2001 From: Brandon Chinn Date: Tue, 11 Jul 2023 18:48:54 -0700 Subject: [PATCH 04/10] Add latest-nightly to CI --- .github/workflows/workflow.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 9a32d34..05023fc 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -43,6 +43,9 @@ jobs: matrix: os: [ubuntu-latest, macOS-latest, windows-latest] plan: + # Nightly releases + - ghc: latest-nightly + cabal: latest # Latest releases - ghc: latest cabal: latest From 85eb216505e3d6932945b773d50076e7434bd1c9 Mon Sep 17 00:00:00 2001 From: Brandon Chinn Date: Wed, 12 Jul 2023 21:23:53 -0700 Subject: [PATCH 05/10] Break out getLatestNightlyFromGhcup --- dist/index.js | 43 +++++++++++++++++++++++------------ lib/installer.js | 43 +++++++++++++++++++++++------------ src/installer.ts | 58 +++++++++++++++++++++++++++++++----------------- 3 files changed, 96 insertions(+), 48 deletions(-) diff --git a/dist/index.js b/dist/index.js index f605ab3..9a2c1b5 100644 --- a/dist/index.js +++ b/dist/index.js @@ -13338,20 +13338,7 @@ async function configureOutputs(tool, version, path, os) { // can't put this in resolve() because it might run before ghcup is installed let resolvedVersion = version; if (version === 'latest-nightly') { - try { - const ghcupExe = await ghcupBin(os); - const out = await new Promise((resolve, reject) => child_process.execFile(ghcupExe, ['list', '-nr'], { encoding: 'utf-8' }, (error, stdout) => (error ? reject(error) : resolve(stdout)))); - resolvedVersion = - out - .split('\n') - .map(line => line.split(' ')) - .filter(line => line[2] === 'latest-nightly') - .map(line => line[1]) - .at(0) ?? version; - } - catch (error) { - // swallow failures, just leave version as 'latest-nightly' - } + resolvedVersion = (await getLatestNightlyFromGhcup(os)) ?? version; } core.setOutput(`${tool}-version`, resolvedVersion); } @@ -13584,6 +13571,34 @@ async function addGhcupReleaseChannel(channel, os) { await exec(bin, ['config', 'add-release-channel', channel.toString()]); } exports.addGhcupReleaseChannel = addGhcupReleaseChannel; +/** + * Get the resolved version of the `latest-nightly` GHC tag from ghcup, + * e.g. '9.9.20230711' + */ +async function getLatestNightlyFromGhcup(os) { + try { + const ghcupExe = await ghcupBin(os); + /* Example output: + + ghc 9.0.2 base-4.15.1.0 + ghc 9.7.20230526 nightly 2023-06-27 + ghc 9.9.20230711 latest-nightly 2023-07-12 + cabal 2.4.1.0 no-bindist + cabal 3.6.2.0 recommended + */ + const out = await new Promise((resolve, reject) => child_process.execFile(ghcupExe, ['list', '-nr'], { encoding: 'utf-8' }, (error, stdout) => (error ? reject(error) : resolve(stdout)))); + return (out + .split('\n') + .map(line => line.split(' ')) + .filter(line => line[2] === 'latest-nightly') + .map(line => line[1]) + .at(0) ?? null); + } + catch (error) { + // swallow failures, just return null + return null; + } +} async function ghcup(tool, version, os) { core.info(`Attempting to install ${tool} ${version} using ghcup`); const bin = await ghcupBin(os); diff --git a/lib/installer.js b/lib/installer.js index 2ab7fd0..a42db22 100644 --- a/lib/installer.js +++ b/lib/installer.js @@ -57,20 +57,7 @@ async function configureOutputs(tool, version, path, os) { // can't put this in resolve() because it might run before ghcup is installed let resolvedVersion = version; if (version === 'latest-nightly') { - try { - const ghcupExe = await ghcupBin(os); - const out = await new Promise((resolve, reject) => child_process.execFile(ghcupExe, ['list', '-nr'], { encoding: 'utf-8' }, (error, stdout) => (error ? reject(error) : resolve(stdout)))); - resolvedVersion = - out - .split('\n') - .map(line => line.split(' ')) - .filter(line => line[2] === 'latest-nightly') - .map(line => line[1]) - .at(0) ?? version; - } - catch (error) { - // swallow failures, just leave version as 'latest-nightly' - } + resolvedVersion = (await getLatestNightlyFromGhcup(os)) ?? version; } core.setOutput(`${tool}-version`, resolvedVersion); } @@ -303,6 +290,34 @@ async function addGhcupReleaseChannel(channel, os) { await exec(bin, ['config', 'add-release-channel', channel.toString()]); } exports.addGhcupReleaseChannel = addGhcupReleaseChannel; +/** + * Get the resolved version of the `latest-nightly` GHC tag from ghcup, + * e.g. '9.9.20230711' + */ +async function getLatestNightlyFromGhcup(os) { + try { + const ghcupExe = await ghcupBin(os); + /* Example output: + + ghc 9.0.2 base-4.15.1.0 + ghc 9.7.20230526 nightly 2023-06-27 + ghc 9.9.20230711 latest-nightly 2023-07-12 + cabal 2.4.1.0 no-bindist + cabal 3.6.2.0 recommended + */ + const out = await new Promise((resolve, reject) => child_process.execFile(ghcupExe, ['list', '-nr'], { encoding: 'utf-8' }, (error, stdout) => (error ? reject(error) : resolve(stdout)))); + return (out + .split('\n') + .map(line => line.split(' ')) + .filter(line => line[2] === 'latest-nightly') + .map(line => line[1]) + .at(0) ?? null); + } + catch (error) { + // swallow failures, just return null + return null; + } +} async function ghcup(tool, version, os) { core.info(`Attempting to install ${tool} ${version} using ghcup`); const bin = await ghcupBin(os); diff --git a/src/installer.ts b/src/installer.ts index 3202706..ca1296b 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -38,26 +38,7 @@ async function configureOutputs( // can't put this in resolve() because it might run before ghcup is installed let resolvedVersion = version; if (version === 'latest-nightly') { - try { - const ghcupExe = await ghcupBin(os); - const out = await new Promise((resolve, reject) => - child_process.execFile( - ghcupExe, - ['list', '-nr'], - {encoding: 'utf-8'}, - (error, stdout) => (error ? reject(error) : resolve(stdout)) - ) - ); - resolvedVersion = - out - .split('\n') - .map(line => line.split(' ')) - .filter(line => line[2] === 'latest-nightly') - .map(line => line[1]) - .at(0) ?? version; - } catch (error) { - // swallow failures, just leave version as 'latest-nightly' - } + resolvedVersion = (await getLatestNightlyFromGhcup(os)) ?? version; } core.setOutput(`${tool}-version`, resolvedVersion); } @@ -351,6 +332,43 @@ export async function addGhcupReleaseChannel( await exec(bin, ['config', 'add-release-channel', channel.toString()]); } +/** + * Get the resolved version of the `latest-nightly` GHC tag from ghcup, + * e.g. '9.9.20230711' + */ +async function getLatestNightlyFromGhcup(os: OS): Promise { + try { + const ghcupExe = await ghcupBin(os); + /* Example output: + + ghc 9.0.2 base-4.15.1.0 + ghc 9.7.20230526 nightly 2023-06-27 + ghc 9.9.20230711 latest-nightly 2023-07-12 + cabal 2.4.1.0 no-bindist + cabal 3.6.2.0 recommended + */ + const out = await new Promise((resolve, reject) => + child_process.execFile( + ghcupExe, + ['list', '-nr'], + {encoding: 'utf-8'}, + (error, stdout) => (error ? reject(error) : resolve(stdout)) + ) + ); + return ( + out + .split('\n') + .map(line => line.split(' ')) + .filter(line => line[2] === 'latest-nightly') + .map(line => line[1]) + .at(0) ?? null + ); + } catch (error) { + // swallow failures, just return null + return null; + } +} + async function ghcup(tool: Tool, version: string, os: OS): Promise { core.info(`Attempting to install ${tool} ${version} using ghcup`); const bin = await ghcupBin(os); From 45134a28b0b0545d8e39f37cd23bb546fb0fd6a0 Mon Sep 17 00:00:00 2001 From: Brandon Chinn Date: Wed, 12 Jul 2023 21:45:45 -0700 Subject: [PATCH 06/10] Add new ghcup-release-channels input --- .github/workflows/workflow.yml | 19 +++++++++++++- README.md | 47 ++++++++++++++++++++++------------ action.yml | 5 +++- dist/index.js | 45 +++++++++++++++++--------------- lib/opts.d.ts | 3 +-- lib/opts.js | 35 +++++++++++++++---------- lib/setup-haskell.js | 10 ++------ src/opts.ts | 41 +++++++++++++++++++---------- src/setup-haskell.ts | 12 ++------- 9 files changed, 131 insertions(+), 86 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 05023fc..10d84ec 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -93,13 +93,29 @@ jobs: # and of cabal just 2.4, 3.0, 3.2, 3.4 # according to https://launchpad.net/~hvr/+archive/ubuntu/ghc?field.series_filter=focal - # Test ghcup pre-release channel + # Any matrix combinations with latest-nightly should add the appropriate release channel + - plan: + ghc: latest-nightly + ghcup_release_channels: > + https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml + + # Test deprecated release channel still works for now - os: ubuntu-latest ghcup_release_channel: "https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.7.yaml" plan: ghc: "9.6.0.20230111" cabal: "3.8" + # Test ghcup release channels + - os: ubuntu-latest + ghcup_release_channels: > + https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-0.0.7.yaml, + https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.7.yaml, + https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-vanilla-0.0.7.yaml, + plan: + ghc: "9.6.0.20230111" + cabal: "3.8" + # setup does something special for 7.10.3 (issue #79) - os: ubuntu-20.04 plan: @@ -146,6 +162,7 @@ jobs: with: ghc-version: ${{ matrix.plan.ghc }} ghcup-release-channel: ${{ matrix.ghcup_release_channel }} + ghcup-release-channels: ${{ matrix.ghcup_release_channels }} cabal-version: ${{ matrix.plan.cabal }} cabal-update: ${{ matrix.cabal_update }} diff --git a/README.md b/README.md index c3a2eea..6624b89 100644 --- a/README.md +++ b/README.md @@ -184,23 +184,35 @@ jobs: ## Inputs -| Name | Description | Type | Default | -| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------- | -| `ghc-version` | GHC version to use, e.g. `9.2` or `9.2.5`. | `string` | `latest` | -| `cabal-version` | Cabal version to use, e.g. `3.6`. | `string` | `latest` | -| `stack-version` | Stack version to use, e.g. `latest`. Stack will only be installed if `enable-stack` is set. | `string` | `latest` | -| `enable-stack` | If set, will setup Stack. | "boolean" | false/unset | -| `stack-no-global` | If set, `enable-stack` must be set. Prevents installing GHC and Cabal globally. | "boolean" | false/unset | -| `stack-setup-ghc` | If set, `enable-stack` must be set. Runs stack setup to install the specified GHC. (Note: setting this does _not_ imply `stack-no-global`.) | "boolean" | false/unset | -| `disable-matcher` | If set, disables match messages from GHC as GitHub CI annotations. | "boolean" | false/unset | -| `cabal-update` | If set to `false`, skip `cabal update` step. | `boolean` | `true` | -| `ghcup-release-channel` | If set, add a [release channel](https://www.haskell.org/ghcup/guide/#pre-release-channels) to ghcup. | `URL` | none | - -Note: "boolean" types are set/unset, not true/false. -That is, setting any "boolean" to a value other than the empty string (`""`) will be considered true/set. -However, to avoid confusion and for forward compatibility, it is still recommended to **only use value `true` to set a "boolean" flag.** - -In contrast, a proper `boolean` input like `cabal-update` only accepts values `true` and `false`. +| Name | Description | Type | Default | +| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------- | +| `ghc-version` | GHC version to use, e.g. `9.2` or `9.2.5`. | `string` | `latest` | +| `cabal-version` | Cabal version to use, e.g. `3.6`. | `string` | `latest` | +| `stack-version` | Stack version to use, e.g. `latest`. Stack will only be installed if `enable-stack` is set. | `string` | `latest` | +| `enable-stack` | If set, will setup Stack. | "boolean" | false/unset | +| `stack-no-global` | If set, `enable-stack` must be set. Prevents installing GHC and Cabal globally. | "boolean" | false/unset | +| `stack-setup-ghc` | If set, `enable-stack` must be set. Runs stack setup to install the specified GHC. (Note: setting this does _not_ imply `stack-no-global`.) | "boolean" | false/unset | +| `disable-matcher` | If set, disables match messages from GHC as GitHub CI annotations. | "boolean" | false/unset | +| `cabal-update` | If set to `false`, skip `cabal update` step. | `boolean` | `true` | +| `ghcup-release-channels` | If set, add [release channels](https://www.haskell.org/ghcup/guide/#pre-release-channels) to ghcup. | `URL[]` | none | + +Notes: + +- "boolean" types are set/unset, not true/false. That is, setting any "boolean" to a value other than the empty string (`""`) will be considered true/set. + However, to avoid confusion and for forward compatibility, it is still recommended to **only use value `true` to set a "boolean" flag.** + + In contrast, a proper `boolean` input like `cabal-update` only accepts values `true` and `false`. + +- Inputs that can take multiple values (like `ghcup-release-channels`) should be specified as a comma separated list, e.g. + + ```yaml + - uses: haskell-actions/setup@v2 + with: + ghcup-release-channels: > + https://example.com/channel1, + https://example.com/channel2, + https://example.com/channel3, + ``` ## Outputs @@ -237,6 +249,7 @@ E.g., `8.10` will be resolved to `8.10.7`, and so will `8`. **GHC:** - `latest-nightly` + - This requires adding https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml to `ghcup-release-channels` - `latest` (default) - `9.6.2` `9.6` - `9.6.1` diff --git a/action.yml b/action.yml index fa7c89a..0e05e8d 100644 --- a/action.yml +++ b/action.yml @@ -30,9 +30,12 @@ inputs: # Note: 'cabal-update' only accepts 'true' and 'false' as values. # This is different from the other flags ('enable-stack', 'disable-matcher' etc.) # which are true as soon as they are not null. + ghcup-release-channels: + required: false + description: "Release channel URLs to add to ghcup via `ghcup config add-release-channel`." ghcup-release-channel: required: false - description: "A release channel URL to add to ghcup via `ghcup config add-release-channel`." + description: "Deprecated by ghcup-release-channels." disable-matcher: required: false description: 'If specified, disables match messages from GHC as GitHub CI annotations.' diff --git a/dist/index.js b/dist/index.js index 9a2c1b5..ec59d7e 100644 --- a/dist/index.js +++ b/dist/index.js @@ -13701,7 +13701,7 @@ var __importStar = (this && this.__importStar) || function (mod) { return result; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.getOpts = exports.parseURL = exports.parseYAMLBoolean = exports.releaseRevision = exports.getDefaults = exports.yamlInputs = exports.ghcup_version = exports.supported_versions = exports.release_revisions = void 0; +exports.getOpts = exports.parseYAMLBoolean = exports.releaseRevision = exports.getDefaults = exports.yamlInputs = exports.ghcup_version = exports.supported_versions = exports.release_revisions = void 0; const core = __importStar(__nccwpck_require__(2186)); const fs_1 = __nccwpck_require__(7147); const js_yaml_1 = __nccwpck_require__(1917); @@ -13801,24 +13801,33 @@ function parseYAMLBoolean(name, val) { `Supported boolean values: \`true | True | TRUE | false | False | FALSE\``); } exports.parseYAMLBoolean = parseYAMLBoolean; -function parseURL(name, val) { - if (val === '') - return null; - try { - return new URL(val); - } - catch (e) { - throw new TypeError(`Action input "${name}" is not a valid URL`); - } +/** + * Parse a string as a comma-separated list. + */ +function parseCSV(val) { + return val + .split(',') + .map(s => s.trim()) + .filter(s => s != ''); } -exports.parseURL = parseURL; function getOpts({ ghc, cabal, stack }, os, inputs) { core.debug(`Inputs are: ${JSON.stringify(inputs)}`); const stackNoGlobal = (inputs['stack-no-global'] || '') !== ''; const stackSetupGhc = (inputs['stack-setup-ghc'] || '') !== ''; const stackEnable = (inputs['enable-stack'] || '') !== ''; const matcherDisable = (inputs['disable-matcher'] || '') !== ''; - const ghcupReleaseChannel = parseURL('ghcup-release-channel', inputs['ghcup-release-channel'] || ''); + if (inputs['ghcup-release-channel']) { + core.warning('ghcup-release-channel is deprecated in favor of ghcup-release-channels'); + inputs['ghcup-release-channels'] = inputs['ghcup-release-channel']; + } + const ghcupReleaseChannels = parseCSV(inputs['ghcup-release-channels'] ?? '').map(v => { + try { + return new URL(v); + } + catch (e) { + throw new TypeError(`Not a valid URL: ${v}`); + } + }); // Andreas, 2023-01-05, issue #29: // 'cabal-update' has a default value, so we should get a proper boolean always. // Andreas, 2023-01-06: This is not true if we use the action as a library. @@ -13850,7 +13859,7 @@ function getOpts({ ghc, cabal, stack }, os, inputs) { enable: ghcEnable }, ghcup: { - releaseChannel: ghcupReleaseChannel + releaseChannels: ghcupReleaseChannels }, cabal: { raw: verInpt.cabal, @@ -13934,15 +13943,9 @@ async function run(inputs) { core.debug(`run: inputs = ${JSON.stringify(inputs)}`); core.debug(`run: os = ${JSON.stringify(os)}`); core.debug(`run: opts = ${JSON.stringify(opts)}`); - const releaseChannels = [ - opts.ghcup.releaseChannel, - opts.ghc.raw === 'latest-nightly' - ? new URL('https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml') - : null - ].filter((v) => v !== null); - if (releaseChannels.length > 0) { + if (opts.ghcup.releaseChannels.length > 0) { await core.group(`Setting release channels`, async () => { - for (const channel of releaseChannels) { + for (const channel of opts.ghcup.releaseChannels) { await (0, installer_1.addGhcupReleaseChannel)(channel, os); } }); diff --git a/lib/opts.d.ts b/lib/opts.d.ts index 768fa1d..dce6ff8 100644 --- a/lib/opts.d.ts +++ b/lib/opts.d.ts @@ -16,7 +16,7 @@ export interface ProgramOpt { export interface Options { ghc: ProgramOpt; ghcup: { - releaseChannel: URL | null; + releaseChannels: URL[]; }; cabal: ProgramOpt & { update: boolean; @@ -85,6 +85,5 @@ export declare function releaseRevision(version: string, tool: Tool, os: OS): st * @returns boolean */ export declare function parseYAMLBoolean(name: string, val: string): boolean; -export declare function parseURL(name: string, val: string): URL | null; export declare function getOpts({ ghc, cabal, stack }: Defaults, os: OS, inputs: Record): Options; export {}; diff --git a/lib/opts.js b/lib/opts.js index e2734ca..b7ced5a 100644 --- a/lib/opts.js +++ b/lib/opts.js @@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) { return result; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.getOpts = exports.parseURL = exports.parseYAMLBoolean = exports.releaseRevision = exports.getDefaults = exports.yamlInputs = exports.ghcup_version = exports.supported_versions = exports.release_revisions = void 0; +exports.getOpts = exports.parseYAMLBoolean = exports.releaseRevision = exports.getDefaults = exports.yamlInputs = exports.ghcup_version = exports.supported_versions = exports.release_revisions = void 0; const core = __importStar(require("@actions/core")); const fs_1 = require("fs"); const js_yaml_1 = require("js-yaml"); @@ -123,24 +123,33 @@ function parseYAMLBoolean(name, val) { `Supported boolean values: \`true | True | TRUE | false | False | FALSE\``); } exports.parseYAMLBoolean = parseYAMLBoolean; -function parseURL(name, val) { - if (val === '') - return null; - try { - return new URL(val); - } - catch (e) { - throw new TypeError(`Action input "${name}" is not a valid URL`); - } +/** + * Parse a string as a comma-separated list. + */ +function parseCSV(val) { + return val + .split(',') + .map(s => s.trim()) + .filter(s => s != ''); } -exports.parseURL = parseURL; function getOpts({ ghc, cabal, stack }, os, inputs) { core.debug(`Inputs are: ${JSON.stringify(inputs)}`); const stackNoGlobal = (inputs['stack-no-global'] || '') !== ''; const stackSetupGhc = (inputs['stack-setup-ghc'] || '') !== ''; const stackEnable = (inputs['enable-stack'] || '') !== ''; const matcherDisable = (inputs['disable-matcher'] || '') !== ''; - const ghcupReleaseChannel = parseURL('ghcup-release-channel', inputs['ghcup-release-channel'] || ''); + if (inputs['ghcup-release-channel']) { + core.warning('ghcup-release-channel is deprecated in favor of ghcup-release-channels'); + inputs['ghcup-release-channels'] = inputs['ghcup-release-channel']; + } + const ghcupReleaseChannels = parseCSV(inputs['ghcup-release-channels'] ?? '').map(v => { + try { + return new URL(v); + } + catch (e) { + throw new TypeError(`Not a valid URL: ${v}`); + } + }); // Andreas, 2023-01-05, issue #29: // 'cabal-update' has a default value, so we should get a proper boolean always. // Andreas, 2023-01-06: This is not true if we use the action as a library. @@ -172,7 +181,7 @@ function getOpts({ ghc, cabal, stack }, os, inputs) { enable: ghcEnable }, ghcup: { - releaseChannel: ghcupReleaseChannel + releaseChannels: ghcupReleaseChannels }, cabal: { raw: verInpt.cabal, diff --git a/lib/setup-haskell.js b/lib/setup-haskell.js index fb23933..8d4f8fc 100644 --- a/lib/setup-haskell.js +++ b/lib/setup-haskell.js @@ -52,15 +52,9 @@ async function run(inputs) { core.debug(`run: inputs = ${JSON.stringify(inputs)}`); core.debug(`run: os = ${JSON.stringify(os)}`); core.debug(`run: opts = ${JSON.stringify(opts)}`); - const releaseChannels = [ - opts.ghcup.releaseChannel, - opts.ghc.raw === 'latest-nightly' - ? new URL('https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml') - : null - ].filter((v) => v !== null); - if (releaseChannels.length > 0) { + if (opts.ghcup.releaseChannels.length > 0) { await core.group(`Setting release channels`, async () => { - for (const channel of releaseChannels) { + for (const channel of opts.ghcup.releaseChannels) { await (0, installer_1.addGhcupReleaseChannel)(channel, os); } }); diff --git a/src/opts.ts b/src/opts.ts index 7818af5..3abe297 100644 --- a/src/opts.ts +++ b/src/opts.ts @@ -24,7 +24,7 @@ export interface ProgramOpt { export interface Options { ghc: ProgramOpt; - ghcup: {releaseChannel: URL | null}; + ghcup: {releaseChannels: URL[]}; cabal: ProgramOpt & {update: boolean}; stack: ProgramOpt & {setup: boolean}; general: {matcher: {enable: boolean}}; @@ -138,13 +138,14 @@ export function parseYAMLBoolean(name: string, val: string): boolean { ); } -export function parseURL(name: string, val: string): URL | null { - if (val === '') return null; - try { - return new URL(val); - } catch (e) { - throw new TypeError(`Action input "${name}" is not a valid URL`); - } +/** + * Parse a string as a comma-separated list. + */ +function parseCSV(val: string): string[] { + return val + .split(',') + .map(s => s.trim()) + .filter(s => s != ''); } export function getOpts( @@ -157,10 +158,24 @@ export function getOpts( const stackSetupGhc = (inputs['stack-setup-ghc'] || '') !== ''; const stackEnable = (inputs['enable-stack'] || '') !== ''; const matcherDisable = (inputs['disable-matcher'] || '') !== ''; - const ghcupReleaseChannel = parseURL( - 'ghcup-release-channel', - inputs['ghcup-release-channel'] || '' - ); + + if (inputs['ghcup-release-channel']) { + core.warning( + 'ghcup-release-channel is deprecated in favor of ghcup-release-channels' + ); + inputs['ghcup-release-channels'] = inputs['ghcup-release-channel']; + } + + const ghcupReleaseChannels = parseCSV( + inputs['ghcup-release-channels'] ?? '' + ).map(v => { + try { + return new URL(v); + } catch (e) { + throw new TypeError(`Not a valid URL: ${v}`); + } + }); + // Andreas, 2023-01-05, issue #29: // 'cabal-update' has a default value, so we should get a proper boolean always. // Andreas, 2023-01-06: This is not true if we use the action as a library. @@ -204,7 +219,7 @@ export function getOpts( enable: ghcEnable }, ghcup: { - releaseChannel: ghcupReleaseChannel + releaseChannels: ghcupReleaseChannels }, cabal: { raw: verInpt.cabal, diff --git a/src/setup-haskell.ts b/src/setup-haskell.ts index a6b43d0..533e9a9 100644 --- a/src/setup-haskell.ts +++ b/src/setup-haskell.ts @@ -30,17 +30,9 @@ export default async function run( core.debug(`run: os = ${JSON.stringify(os)}`); core.debug(`run: opts = ${JSON.stringify(opts)}`); - const releaseChannels = [ - opts.ghcup.releaseChannel, - opts.ghc.raw === 'latest-nightly' - ? new URL( - 'https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml' - ) - : null - ].filter((v): v is URL => v !== null); - if (releaseChannels.length > 0) { + if (opts.ghcup.releaseChannels.length > 0) { await core.group(`Setting release channels`, async () => { - for (const channel of releaseChannels) { + for (const channel of opts.ghcup.releaseChannels) { await addGhcupReleaseChannel(channel, os); } }); From d062893bcde8280cf89bb163b6aece6d9df4394b Mon Sep 17 00:00:00 2001 From: Brandon Chinn Date: Thu, 13 Jul 2023 09:03:23 -0700 Subject: [PATCH 07/10] Parse inputs in main.ts --- __tests__/find-haskell.test.ts | 40 +++++++++++++------------- dist/index.js | 36 +++++++++++++++--------- lib/opts.d.ts | 14 +++++++++- lib/opts.js | 22 +++++++-------- lib/setup-haskell.d.ts | 3 +- src/main.ts | 16 ++++++++--- src/opts.ts | 51 +++++++++++++++++++++------------- src/setup-haskell.ts | 6 ++-- 8 files changed, 115 insertions(+), 73 deletions(-) diff --git a/__tests__/find-haskell.test.ts b/__tests__/find-haskell.test.ts index 5aaa396..15a7748 100644 --- a/__tests__/find-haskell.test.ts +++ b/__tests__/find-haskell.test.ts @@ -46,7 +46,7 @@ describe('haskell/actions/setup', () => { it('Setting disable-matcher to true disables matcher', () => { forAllOS(os => { const options = getOpts(def(os), os, { - 'disable-matcher': 'true' + disableMatcher: 'true' }); expect(options.general.matcher.enable).toBe(false); }); @@ -70,10 +70,10 @@ describe('haskell/actions/setup', () => { const v = {ghc: '8.6.5', cabal: '3.4.1.0', stack: '1.9.3'}; forAllOS(os => { const options = getOpts(def(os), os, { - 'enable-stack': 'true', - 'stack-version': '1', - 'ghc-version': '8.6', - 'cabal-version': '3.4' + enableStack: 'true', + stackVersion: '1', + ghcVersion: '8.6', + cabalVersion: '3.4' }); forAllTools(t => expect(options[t].resolved).toBe(v[t])); }); @@ -82,10 +82,10 @@ describe('haskell/actions/setup', () => { it('"latest" Versions resolve correctly', () => { forAllOS(os => { const options = getOpts(def(os), os, { - 'enable-stack': 'true', - 'stack-version': 'latest', - 'ghc-version': 'latest', - 'cabal-version': 'latest' + enableStack: 'true', + stackVersion: 'latest', + ghcVersion: 'latest', + cabalVersion: 'latest' }); forAllTools(t => expect(options[t].resolved).toBe( @@ -100,10 +100,10 @@ describe('haskell/actions/setup', () => { const v = {ghc: '8.10.7', cabal: '2.4.1.0', stack: '2.1.3'}; forAllOS(os => { const options = getOpts(def(os), os, { - 'enable-stack': 'true', - 'stack-version': '2.1', - 'ghc-version': '8.10', - 'cabal-version': '2' + enableStack: 'true', + stackVersion: '2.1', + ghcVersion: '8.10', + cabalVersion: '2' }); forAllTools(t => expect(options[t].resolved).toBe(v[t])); }); @@ -112,7 +112,7 @@ describe('haskell/actions/setup', () => { it('Enabling stack does not disable GHC or Cabal', () => { forAllOS(os => { const {ghc, cabal, stack} = getOpts(def(os), os, { - 'enable-stack': 'true' + enableStack: 'true' }); expect({ ghc: ghc.enable, @@ -125,20 +125,20 @@ describe('haskell/actions/setup', () => { it('Resolves revisions correctly on Windows', () => { // Test the case where there is a revision in chocolatey expect( - getOpts(def('win32'), 'win32', {'ghc-version': '8.10.2'}).ghc.resolved + getOpts(def('win32'), 'win32', {ghcVersion: '8.10.2'}).ghc.resolved ).toBe('8.10.2'); // Andreas, 2022-12-29: revisions are handled locally in choco() now // Test the case where there is not a revision in chocolatey expect( - getOpts(def('win32'), 'win32', {'ghc-version': '8.8.1'}).ghc.resolved + getOpts(def('win32'), 'win32', {ghcVersion: '8.8.1'}).ghc.resolved ).toBe('8.8.1'); }); it('Enabling stack-no-global disables GHC and Cabal', () => { forAllOS(os => { const {ghc, cabal, stack} = getOpts(def(os), os, { - 'enable-stack': 'true', - 'stack-no-global': 'true' + enableStack: 'true', + stackNoGlobal: 'true' }); expect({ ghc: ghc.enable, @@ -150,13 +150,13 @@ describe('haskell/actions/setup', () => { it('Enabling stack-no-global without setting enable-stack errors', () => { forAllOS(os => - expect(() => getOpts(def(os), os, {'stack-no-global': 'true'})).toThrow() + expect(() => getOpts(def(os), os, {stackNoGlobal: 'true'})).toThrow() ); }); it('Enabling stack-setup-ghc without setting enable-stack errors', () => { forAllOS(os => - expect(() => getOpts(def(os), os, {'stack-setup-ghc': 'true'})).toThrow() + expect(() => getOpts(def(os), os, {stackNoGlobal: 'true'})).toThrow() ); }); }); diff --git a/dist/index.js b/dist/index.js index ec59d7e..3fbd384 100644 --- a/dist/index.js +++ b/dist/index.js @@ -13665,9 +13665,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", ({ value: true })); const core = __importStar(__nccwpck_require__(2186)); -const opts_1 = __nccwpck_require__(8131); const setup_haskell_1 = __importDefault(__nccwpck_require__(9351)); -(0, setup_haskell_1.default)(Object.fromEntries(Object.keys(opts_1.yamlInputs).map(k => [k, core.getInput(k)]))); +(0, setup_haskell_1.default)({ + ghcVersion: core.getInput('ghc-version'), + cabalVersion: core.getInput('cabal-version'), + stackVersion: core.getInput('stack-version'), + enableStack: core.getInput('enable-stack'), + stackNoGlobal: core.getInput('stack-no-global'), + stackSetupGhc: core.getInput('stack-setup-ghc'), + cabalUpdate: core.getInput('cabal-update'), + ghcupReleaseChannels: core.getInput('ghcup-release-channels'), + ghcupReleaseChannel: core.getInput('ghcup-release-channel'), + disableMatcher: core.getInput('disable-matcher') +}); /***/ }), @@ -13812,15 +13822,15 @@ function parseCSV(val) { } function getOpts({ ghc, cabal, stack }, os, inputs) { core.debug(`Inputs are: ${JSON.stringify(inputs)}`); - const stackNoGlobal = (inputs['stack-no-global'] || '') !== ''; - const stackSetupGhc = (inputs['stack-setup-ghc'] || '') !== ''; - const stackEnable = (inputs['enable-stack'] || '') !== ''; - const matcherDisable = (inputs['disable-matcher'] || '') !== ''; - if (inputs['ghcup-release-channel']) { + const stackNoGlobal = (inputs.stackNoGlobal ?? '') !== ''; + const stackSetupGhc = (inputs.stackSetupGhc ?? '') !== ''; + const stackEnable = (inputs.enableStack ?? '') !== ''; + const matcherDisable = (inputs.disableMatcher ?? '') !== ''; + if (inputs.ghcupReleaseChannel) { core.warning('ghcup-release-channel is deprecated in favor of ghcup-release-channels'); - inputs['ghcup-release-channels'] = inputs['ghcup-release-channel']; + inputs.ghcupReleaseChannels = inputs.ghcupReleaseChannel; } - const ghcupReleaseChannels = parseCSV(inputs['ghcup-release-channels'] ?? '').map(v => { + const ghcupReleaseChannels = parseCSV(inputs.ghcupReleaseChannels ?? '').map(v => { try { return new URL(v); } @@ -13832,12 +13842,12 @@ function getOpts({ ghc, cabal, stack }, os, inputs) { // 'cabal-update' has a default value, so we should get a proper boolean always. // Andreas, 2023-01-06: This is not true if we use the action as a library. // Thus, need to patch with default value here. - const cabalUpdate = parseYAMLBoolean('cabal-update', inputs['cabal-update'] || 'true'); + const cabalUpdate = parseYAMLBoolean('cabal-update', inputs.cabalUpdate ?? 'true'); core.debug(`${stackNoGlobal}/${stackSetupGhc}/${stackEnable}`); const verInpt = { - ghc: inputs['ghc-version'] || ghc.version, - cabal: inputs['cabal-version'] || cabal.version, - stack: inputs['stack-version'] || stack.version + ghc: inputs.ghcVersion || ghc.version, + cabal: inputs.cabalVersion || cabal.version, + stack: inputs.stackVersion || stack.version }; const errors = []; if (stackNoGlobal && !stackEnable) { diff --git a/lib/opts.d.ts b/lib/opts.d.ts index dce6ff8..7c0a633 100644 --- a/lib/opts.d.ts +++ b/lib/opts.d.ts @@ -85,5 +85,17 @@ export declare function releaseRevision(version: string, tool: Tool, os: OS): st * @returns boolean */ export declare function parseYAMLBoolean(name: string, val: string): boolean; -export declare function getOpts({ ghc, cabal, stack }: Defaults, os: OS, inputs: Record): Options; +export type RawInputs = { + ghcVersion?: string; + cabalVersion?: string; + stackVersion?: string; + enableStack?: string; + stackNoGlobal?: string; + stackSetupGhc?: string; + cabalUpdate?: string; + ghcupReleaseChannels?: string; + ghcupReleaseChannel?: string; + disableMatcher?: string; +}; +export declare function getOpts({ ghc, cabal, stack }: Defaults, os: OS, inputs: RawInputs): Options; export {}; diff --git a/lib/opts.js b/lib/opts.js index b7ced5a..7d92ad1 100644 --- a/lib/opts.js +++ b/lib/opts.js @@ -134,15 +134,15 @@ function parseCSV(val) { } function getOpts({ ghc, cabal, stack }, os, inputs) { core.debug(`Inputs are: ${JSON.stringify(inputs)}`); - const stackNoGlobal = (inputs['stack-no-global'] || '') !== ''; - const stackSetupGhc = (inputs['stack-setup-ghc'] || '') !== ''; - const stackEnable = (inputs['enable-stack'] || '') !== ''; - const matcherDisable = (inputs['disable-matcher'] || '') !== ''; - if (inputs['ghcup-release-channel']) { + const stackNoGlobal = (inputs.stackNoGlobal ?? '') !== ''; + const stackSetupGhc = (inputs.stackSetupGhc ?? '') !== ''; + const stackEnable = (inputs.enableStack ?? '') !== ''; + const matcherDisable = (inputs.disableMatcher ?? '') !== ''; + if (inputs.ghcupReleaseChannel) { core.warning('ghcup-release-channel is deprecated in favor of ghcup-release-channels'); - inputs['ghcup-release-channels'] = inputs['ghcup-release-channel']; + inputs.ghcupReleaseChannels = inputs.ghcupReleaseChannel; } - const ghcupReleaseChannels = parseCSV(inputs['ghcup-release-channels'] ?? '').map(v => { + const ghcupReleaseChannels = parseCSV(inputs.ghcupReleaseChannels ?? '').map(v => { try { return new URL(v); } @@ -154,12 +154,12 @@ function getOpts({ ghc, cabal, stack }, os, inputs) { // 'cabal-update' has a default value, so we should get a proper boolean always. // Andreas, 2023-01-06: This is not true if we use the action as a library. // Thus, need to patch with default value here. - const cabalUpdate = parseYAMLBoolean('cabal-update', inputs['cabal-update'] || 'true'); + const cabalUpdate = parseYAMLBoolean('cabal-update', inputs.cabalUpdate ?? 'true'); core.debug(`${stackNoGlobal}/${stackSetupGhc}/${stackEnable}`); const verInpt = { - ghc: inputs['ghc-version'] || ghc.version, - cabal: inputs['cabal-version'] || cabal.version, - stack: inputs['stack-version'] || stack.version + ghc: inputs.ghcVersion || ghc.version, + cabal: inputs.cabalVersion || cabal.version, + stack: inputs.stackVersion || stack.version }; const errors = []; if (stackNoGlobal && !stackEnable) { diff --git a/lib/setup-haskell.d.ts b/lib/setup-haskell.d.ts index 10f9366..764b778 100644 --- a/lib/setup-haskell.d.ts +++ b/lib/setup-haskell.d.ts @@ -1 +1,2 @@ -export default function run(inputs: Record): Promise; +import { RawInputs } from './opts'; +export default function run(inputs: RawInputs): Promise; diff --git a/src/main.ts b/src/main.ts index 61a8ddb..a7bba4f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,15 @@ import * as core from '@actions/core'; -import {yamlInputs} from './opts'; import run from './setup-haskell'; -run( - Object.fromEntries(Object.keys(yamlInputs).map(k => [k, core.getInput(k)])) -); +run({ + ghcVersion: core.getInput('ghc-version'), + cabalVersion: core.getInput('cabal-version'), + stackVersion: core.getInput('stack-version'), + enableStack: core.getInput('enable-stack'), + stackNoGlobal: core.getInput('stack-no-global'), + stackSetupGhc: core.getInput('stack-setup-ghc'), + cabalUpdate: core.getInput('cabal-update'), + ghcupReleaseChannels: core.getInput('ghcup-release-channels'), + ghcupReleaseChannel: core.getInput('ghcup-release-channel'), + disableMatcher: core.getInput('disable-matcher') +}); diff --git a/src/opts.ts b/src/opts.ts index 3abe297..376895a 100644 --- a/src/opts.ts +++ b/src/opts.ts @@ -148,33 +148,46 @@ function parseCSV(val: string): string[] { .filter(s => s != ''); } +export type RawInputs = { + ghcVersion?: string; + cabalVersion?: string; + stackVersion?: string; + enableStack?: string; + stackNoGlobal?: string; + stackSetupGhc?: string; + cabalUpdate?: string; + ghcupReleaseChannels?: string; + ghcupReleaseChannel?: string; + disableMatcher?: string; +}; + export function getOpts( {ghc, cabal, stack}: Defaults, os: OS, - inputs: Record + inputs: RawInputs ): Options { core.debug(`Inputs are: ${JSON.stringify(inputs)}`); - const stackNoGlobal = (inputs['stack-no-global'] || '') !== ''; - const stackSetupGhc = (inputs['stack-setup-ghc'] || '') !== ''; - const stackEnable = (inputs['enable-stack'] || '') !== ''; - const matcherDisable = (inputs['disable-matcher'] || '') !== ''; + const stackNoGlobal = (inputs.stackNoGlobal ?? '') !== ''; + const stackSetupGhc = (inputs.stackSetupGhc ?? '') !== ''; + const stackEnable = (inputs.enableStack ?? '') !== ''; + const matcherDisable = (inputs.disableMatcher ?? '') !== ''; - if (inputs['ghcup-release-channel']) { + if (inputs.ghcupReleaseChannel) { core.warning( 'ghcup-release-channel is deprecated in favor of ghcup-release-channels' ); - inputs['ghcup-release-channels'] = inputs['ghcup-release-channel']; + inputs.ghcupReleaseChannels = inputs.ghcupReleaseChannel; } - const ghcupReleaseChannels = parseCSV( - inputs['ghcup-release-channels'] ?? '' - ).map(v => { - try { - return new URL(v); - } catch (e) { - throw new TypeError(`Not a valid URL: ${v}`); + const ghcupReleaseChannels = parseCSV(inputs.ghcupReleaseChannels ?? '').map( + v => { + try { + return new URL(v); + } catch (e) { + throw new TypeError(`Not a valid URL: ${v}`); + } } - }); + ); // Andreas, 2023-01-05, issue #29: // 'cabal-update' has a default value, so we should get a proper boolean always. @@ -182,13 +195,13 @@ export function getOpts( // Thus, need to patch with default value here. const cabalUpdate = parseYAMLBoolean( 'cabal-update', - inputs['cabal-update'] || 'true' + inputs.cabalUpdate ?? 'true' ); core.debug(`${stackNoGlobal}/${stackSetupGhc}/${stackEnable}`); const verInpt = { - ghc: inputs['ghc-version'] || ghc.version, - cabal: inputs['cabal-version'] || cabal.version, - stack: inputs['stack-version'] || stack.version + ghc: inputs.ghcVersion || ghc.version, + cabal: inputs.cabalVersion || cabal.version, + stack: inputs.stackVersion || stack.version }; const errors = []; diff --git a/src/setup-haskell.ts b/src/setup-haskell.ts index 533e9a9..7c7c2c7 100644 --- a/src/setup-haskell.ts +++ b/src/setup-haskell.ts @@ -4,7 +4,7 @@ import ensureError from 'ensure-error'; import * as fs from 'fs'; import * as path from 'path'; import {EOL} from 'os'; -import {getOpts, getDefaults, Tool} from './opts'; +import {RawInputs, getOpts, getDefaults, Tool} from './opts'; import {addGhcupReleaseChannel, installTool, resetTool} from './installer'; import type {OS} from './opts'; import {exec} from '@actions/exec'; @@ -19,9 +19,7 @@ async function cabalConfig(): Promise { return out.toString().trim().split('\n').slice(-1)[0].trim(); } -export default async function run( - inputs: Record -): Promise { +export default async function run(inputs: RawInputs): Promise { try { core.info('Preparing to setup a Haskell environment'); const os = process.platform as OS; From e7ee5360c62bde467f096dbcef02c62f400a2c91 Mon Sep 17 00:00:00 2001 From: Brandon Chinn Date: Thu, 13 Jul 2023 09:11:00 -0700 Subject: [PATCH 08/10] Parse boolean inputs in main.ts --- README.md | 14 +++++----- __tests__/find-haskell.test.ts | 18 ++++++------- dist/index.js | 48 +++++++++------------------------ lib/opts.d.ts | 21 ++++----------- lib/opts.js | 37 +++++-------------------- src/main.ts | 12 +++++---- src/opts.ts | 49 ++++++++-------------------------- 7 files changed, 56 insertions(+), 143 deletions(-) diff --git a/README.md b/README.md index 6624b89..e4f65a0 100644 --- a/README.md +++ b/README.md @@ -189,19 +189,17 @@ jobs: | `ghc-version` | GHC version to use, e.g. `9.2` or `9.2.5`. | `string` | `latest` | | `cabal-version` | Cabal version to use, e.g. `3.6`. | `string` | `latest` | | `stack-version` | Stack version to use, e.g. `latest`. Stack will only be installed if `enable-stack` is set. | `string` | `latest` | -| `enable-stack` | If set, will setup Stack. | "boolean" | false/unset | -| `stack-no-global` | If set, `enable-stack` must be set. Prevents installing GHC and Cabal globally. | "boolean" | false/unset | -| `stack-setup-ghc` | If set, `enable-stack` must be set. Runs stack setup to install the specified GHC. (Note: setting this does _not_ imply `stack-no-global`.) | "boolean" | false/unset | -| `disable-matcher` | If set, disables match messages from GHC as GitHub CI annotations. | "boolean" | false/unset | +| `enable-stack` | If set, will setup Stack. | `Toggle` | false/unset | +| `stack-no-global` | If set, `enable-stack` must be set. Prevents installing GHC and Cabal globally. | `Toggle` | false/unset | +| `stack-setup-ghc` | If set, `enable-stack` must be set. Runs stack setup to install the specified GHC. (Note: setting this does _not_ imply `stack-no-global`.) | `Toggle` | false/unset | +| `disable-matcher` | If set, disables match messages from GHC as GitHub CI annotations. | `Toggle` | false/unset | | `cabal-update` | If set to `false`, skip `cabal update` step. | `boolean` | `true` | | `ghcup-release-channels` | If set, add [release channels](https://www.haskell.org/ghcup/guide/#pre-release-channels) to ghcup. | `URL[]` | none | Notes: -- "boolean" types are set/unset, not true/false. That is, setting any "boolean" to a value other than the empty string (`""`) will be considered true/set. - However, to avoid confusion and for forward compatibility, it is still recommended to **only use value `true` to set a "boolean" flag.** - - In contrast, a proper `boolean` input like `cabal-update` only accepts values `true` and `false`. +- `Toggle` inputs are booleans that are false when set as the empty string and true when set to _anything_. + However, to avoid confusion and for forward compatibility, it is still recommended to **only use value `true` to set a `Toggle` input.** - Inputs that can take multiple values (like `ghcup-release-channels`) should be specified as a comma separated list, e.g. diff --git a/__tests__/find-haskell.test.ts b/__tests__/find-haskell.test.ts index 15a7748..28f7222 100644 --- a/__tests__/find-haskell.test.ts +++ b/__tests__/find-haskell.test.ts @@ -46,7 +46,7 @@ describe('haskell/actions/setup', () => { it('Setting disable-matcher to true disables matcher', () => { forAllOS(os => { const options = getOpts(def(os), os, { - disableMatcher: 'true' + disableMatcher: true }); expect(options.general.matcher.enable).toBe(false); }); @@ -70,7 +70,7 @@ describe('haskell/actions/setup', () => { const v = {ghc: '8.6.5', cabal: '3.4.1.0', stack: '1.9.3'}; forAllOS(os => { const options = getOpts(def(os), os, { - enableStack: 'true', + enableStack: true, stackVersion: '1', ghcVersion: '8.6', cabalVersion: '3.4' @@ -82,7 +82,7 @@ describe('haskell/actions/setup', () => { it('"latest" Versions resolve correctly', () => { forAllOS(os => { const options = getOpts(def(os), os, { - enableStack: 'true', + enableStack: true, stackVersion: 'latest', ghcVersion: 'latest', cabalVersion: 'latest' @@ -100,7 +100,7 @@ describe('haskell/actions/setup', () => { const v = {ghc: '8.10.7', cabal: '2.4.1.0', stack: '2.1.3'}; forAllOS(os => { const options = getOpts(def(os), os, { - enableStack: 'true', + enableStack: true, stackVersion: '2.1', ghcVersion: '8.10', cabalVersion: '2' @@ -112,7 +112,7 @@ describe('haskell/actions/setup', () => { it('Enabling stack does not disable GHC or Cabal', () => { forAllOS(os => { const {ghc, cabal, stack} = getOpts(def(os), os, { - enableStack: 'true' + enableStack: true }); expect({ ghc: ghc.enable, @@ -137,8 +137,8 @@ describe('haskell/actions/setup', () => { it('Enabling stack-no-global disables GHC and Cabal', () => { forAllOS(os => { const {ghc, cabal, stack} = getOpts(def(os), os, { - enableStack: 'true', - stackNoGlobal: 'true' + enableStack: true, + stackNoGlobal: true }); expect({ ghc: ghc.enable, @@ -150,13 +150,13 @@ describe('haskell/actions/setup', () => { it('Enabling stack-no-global without setting enable-stack errors', () => { forAllOS(os => - expect(() => getOpts(def(os), os, {stackNoGlobal: 'true'})).toThrow() + expect(() => getOpts(def(os), os, {stackNoGlobal: true})).toThrow() ); }); it('Enabling stack-setup-ghc without setting enable-stack errors', () => { forAllOS(os => - expect(() => getOpts(def(os), os, {stackNoGlobal: 'true'})).toThrow() + expect(() => getOpts(def(os), os, {stackNoGlobal: true})).toThrow() ); }); }); diff --git a/dist/index.js b/dist/index.js index 3fbd384..0da42a7 100644 --- a/dist/index.js +++ b/dist/index.js @@ -13666,17 +13666,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) { Object.defineProperty(exports, "__esModule", ({ value: true })); const core = __importStar(__nccwpck_require__(2186)); const setup_haskell_1 = __importDefault(__nccwpck_require__(9351)); +const getToggleInput = (name) => core.getInput(name) !== ''; (0, setup_haskell_1.default)({ ghcVersion: core.getInput('ghc-version'), cabalVersion: core.getInput('cabal-version'), stackVersion: core.getInput('stack-version'), - enableStack: core.getInput('enable-stack'), - stackNoGlobal: core.getInput('stack-no-global'), - stackSetupGhc: core.getInput('stack-setup-ghc'), - cabalUpdate: core.getInput('cabal-update'), + enableStack: getToggleInput('enable-stack'), + stackNoGlobal: getToggleInput('stack-no-global'), + stackSetupGhc: getToggleInput('stack-setup-ghc'), + cabalUpdate: core.getBooleanInput('cabal-update'), ghcupReleaseChannels: core.getInput('ghcup-release-channels'), ghcupReleaseChannel: core.getInput('ghcup-release-channel'), - disableMatcher: core.getInput('disable-matcher') + disableMatcher: getToggleInput('disable-matcher') }); @@ -13711,7 +13712,7 @@ var __importStar = (this && this.__importStar) || function (mod) { return result; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.getOpts = exports.parseYAMLBoolean = exports.releaseRevision = exports.getDefaults = exports.yamlInputs = exports.ghcup_version = exports.supported_versions = exports.release_revisions = void 0; +exports.getOpts = exports.releaseRevision = exports.getDefaults = exports.yamlInputs = exports.ghcup_version = exports.supported_versions = exports.release_revisions = void 0; const core = __importStar(__nccwpck_require__(2186)); const fs_1 = __nccwpck_require__(7147); const js_yaml_1 = __nccwpck_require__(1917); @@ -13790,27 +13791,6 @@ function releaseRevision(version, tool, os) { return result; } exports.releaseRevision = releaseRevision; -/** - * Convert a string input to a boolean according to the YAML 1.2 "core schema" specification. - * Supported boolean renderings: `true | True | TRUE | false | False | FALSE` . - * ref: https://yaml.org/spec/1.2/spec.html#id2804923 - * Adapted from: https://github.com/actions/toolkit/commit/fbdf27470cdcb52f16755d32082f1fee0bfb7d6d#diff-f63fb32fca85d8e177d6400ce078818a4815b80ac7a3319b60d3507354890992R94-R115 - * - * @param name name of the input - * @param val supposed string representation of a boolean - * @returns boolean - */ -function parseYAMLBoolean(name, val) { - const trueValue = ['true', 'True', 'TRUE']; - const falseValue = ['false', 'False', 'FALSE']; - if (trueValue.includes(val)) - return true; - if (falseValue.includes(val)) - return false; - throw new TypeError(`Action input "${name}" does not meet YAML 1.2 "Core Schema" specification: \n` + - `Supported boolean values: \`true | True | TRUE | false | False | FALSE\``); -} -exports.parseYAMLBoolean = parseYAMLBoolean; /** * Parse a string as a comma-separated list. */ @@ -13822,10 +13802,11 @@ function parseCSV(val) { } function getOpts({ ghc, cabal, stack }, os, inputs) { core.debug(`Inputs are: ${JSON.stringify(inputs)}`); - const stackNoGlobal = (inputs.stackNoGlobal ?? '') !== ''; - const stackSetupGhc = (inputs.stackSetupGhc ?? '') !== ''; - const stackEnable = (inputs.enableStack ?? '') !== ''; - const matcherDisable = (inputs.disableMatcher ?? '') !== ''; + const stackNoGlobal = inputs.stackNoGlobal ?? false; + const stackSetupGhc = inputs.stackSetupGhc ?? false; + const stackEnable = inputs.enableStack ?? false; + const cabalUpdate = inputs.cabalUpdate ?? true; + const matcherDisable = inputs.disableMatcher ?? false; if (inputs.ghcupReleaseChannel) { core.warning('ghcup-release-channel is deprecated in favor of ghcup-release-channels'); inputs.ghcupReleaseChannels = inputs.ghcupReleaseChannel; @@ -13838,11 +13819,6 @@ function getOpts({ ghc, cabal, stack }, os, inputs) { throw new TypeError(`Not a valid URL: ${v}`); } }); - // Andreas, 2023-01-05, issue #29: - // 'cabal-update' has a default value, so we should get a proper boolean always. - // Andreas, 2023-01-06: This is not true if we use the action as a library. - // Thus, need to patch with default value here. - const cabalUpdate = parseYAMLBoolean('cabal-update', inputs.cabalUpdate ?? 'true'); core.debug(`${stackNoGlobal}/${stackSetupGhc}/${stackEnable}`); const verInpt = { ghc: inputs.ghcVersion || ghc.version, diff --git a/lib/opts.d.ts b/lib/opts.d.ts index 7c0a633..d43afda 100644 --- a/lib/opts.d.ts +++ b/lib/opts.d.ts @@ -74,28 +74,17 @@ export declare const yamlInputs: Record; export declare function getDefaults(os: OS): Defaults; export declare function releaseRevision(version: string, tool: Tool, os: OS): string; -/** - * Convert a string input to a boolean according to the YAML 1.2 "core schema" specification. - * Supported boolean renderings: `true | True | TRUE | false | False | FALSE` . - * ref: https://yaml.org/spec/1.2/spec.html#id2804923 - * Adapted from: https://github.com/actions/toolkit/commit/fbdf27470cdcb52f16755d32082f1fee0bfb7d6d#diff-f63fb32fca85d8e177d6400ce078818a4815b80ac7a3319b60d3507354890992R94-R115 - * - * @param name name of the input - * @param val supposed string representation of a boolean - * @returns boolean - */ -export declare function parseYAMLBoolean(name: string, val: string): boolean; export type RawInputs = { ghcVersion?: string; cabalVersion?: string; stackVersion?: string; - enableStack?: string; - stackNoGlobal?: string; - stackSetupGhc?: string; - cabalUpdate?: string; + enableStack?: boolean; + stackNoGlobal?: boolean; + stackSetupGhc?: boolean; + cabalUpdate?: boolean; ghcupReleaseChannels?: string; ghcupReleaseChannel?: string; - disableMatcher?: string; + disableMatcher?: boolean; }; export declare function getOpts({ ghc, cabal, stack }: Defaults, os: OS, inputs: RawInputs): Options; export {}; diff --git a/lib/opts.js b/lib/opts.js index 7d92ad1..f26fab4 100644 --- a/lib/opts.js +++ b/lib/opts.js @@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) { return result; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.getOpts = exports.parseYAMLBoolean = exports.releaseRevision = exports.getDefaults = exports.yamlInputs = exports.ghcup_version = exports.supported_versions = exports.release_revisions = void 0; +exports.getOpts = exports.releaseRevision = exports.getDefaults = exports.yamlInputs = exports.ghcup_version = exports.supported_versions = exports.release_revisions = void 0; const core = __importStar(require("@actions/core")); const fs_1 = require("fs"); const js_yaml_1 = require("js-yaml"); @@ -102,27 +102,6 @@ function releaseRevision(version, tool, os) { return result; } exports.releaseRevision = releaseRevision; -/** - * Convert a string input to a boolean according to the YAML 1.2 "core schema" specification. - * Supported boolean renderings: `true | True | TRUE | false | False | FALSE` . - * ref: https://yaml.org/spec/1.2/spec.html#id2804923 - * Adapted from: https://github.com/actions/toolkit/commit/fbdf27470cdcb52f16755d32082f1fee0bfb7d6d#diff-f63fb32fca85d8e177d6400ce078818a4815b80ac7a3319b60d3507354890992R94-R115 - * - * @param name name of the input - * @param val supposed string representation of a boolean - * @returns boolean - */ -function parseYAMLBoolean(name, val) { - const trueValue = ['true', 'True', 'TRUE']; - const falseValue = ['false', 'False', 'FALSE']; - if (trueValue.includes(val)) - return true; - if (falseValue.includes(val)) - return false; - throw new TypeError(`Action input "${name}" does not meet YAML 1.2 "Core Schema" specification: \n` + - `Supported boolean values: \`true | True | TRUE | false | False | FALSE\``); -} -exports.parseYAMLBoolean = parseYAMLBoolean; /** * Parse a string as a comma-separated list. */ @@ -134,10 +113,11 @@ function parseCSV(val) { } function getOpts({ ghc, cabal, stack }, os, inputs) { core.debug(`Inputs are: ${JSON.stringify(inputs)}`); - const stackNoGlobal = (inputs.stackNoGlobal ?? '') !== ''; - const stackSetupGhc = (inputs.stackSetupGhc ?? '') !== ''; - const stackEnable = (inputs.enableStack ?? '') !== ''; - const matcherDisable = (inputs.disableMatcher ?? '') !== ''; + const stackNoGlobal = inputs.stackNoGlobal ?? false; + const stackSetupGhc = inputs.stackSetupGhc ?? false; + const stackEnable = inputs.enableStack ?? false; + const cabalUpdate = inputs.cabalUpdate ?? true; + const matcherDisable = inputs.disableMatcher ?? false; if (inputs.ghcupReleaseChannel) { core.warning('ghcup-release-channel is deprecated in favor of ghcup-release-channels'); inputs.ghcupReleaseChannels = inputs.ghcupReleaseChannel; @@ -150,11 +130,6 @@ function getOpts({ ghc, cabal, stack }, os, inputs) { throw new TypeError(`Not a valid URL: ${v}`); } }); - // Andreas, 2023-01-05, issue #29: - // 'cabal-update' has a default value, so we should get a proper boolean always. - // Andreas, 2023-01-06: This is not true if we use the action as a library. - // Thus, need to patch with default value here. - const cabalUpdate = parseYAMLBoolean('cabal-update', inputs.cabalUpdate ?? 'true'); core.debug(`${stackNoGlobal}/${stackSetupGhc}/${stackEnable}`); const verInpt = { ghc: inputs.ghcVersion || ghc.version, diff --git a/src/main.ts b/src/main.ts index a7bba4f..81eac9e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,15 +1,17 @@ import * as core from '@actions/core'; import run from './setup-haskell'; +const getToggleInput = (name: string) => core.getInput(name) !== ''; + run({ ghcVersion: core.getInput('ghc-version'), cabalVersion: core.getInput('cabal-version'), stackVersion: core.getInput('stack-version'), - enableStack: core.getInput('enable-stack'), - stackNoGlobal: core.getInput('stack-no-global'), - stackSetupGhc: core.getInput('stack-setup-ghc'), - cabalUpdate: core.getInput('cabal-update'), + enableStack: getToggleInput('enable-stack'), + stackNoGlobal: getToggleInput('stack-no-global'), + stackSetupGhc: getToggleInput('stack-setup-ghc'), + cabalUpdate: core.getBooleanInput('cabal-update'), ghcupReleaseChannels: core.getInput('ghcup-release-channels'), ghcupReleaseChannel: core.getInput('ghcup-release-channel'), - disableMatcher: core.getInput('disable-matcher') + disableMatcher: getToggleInput('disable-matcher') }); diff --git a/src/opts.ts b/src/opts.ts index 376895a..4ccd988 100644 --- a/src/opts.ts +++ b/src/opts.ts @@ -117,27 +117,6 @@ export function releaseRevision(version: string, tool: Tool, os: OS): string { return result; } -/** - * Convert a string input to a boolean according to the YAML 1.2 "core schema" specification. - * Supported boolean renderings: `true | True | TRUE | false | False | FALSE` . - * ref: https://yaml.org/spec/1.2/spec.html#id2804923 - * Adapted from: https://github.com/actions/toolkit/commit/fbdf27470cdcb52f16755d32082f1fee0bfb7d6d#diff-f63fb32fca85d8e177d6400ce078818a4815b80ac7a3319b60d3507354890992R94-R115 - * - * @param name name of the input - * @param val supposed string representation of a boolean - * @returns boolean - */ -export function parseYAMLBoolean(name: string, val: string): boolean { - const trueValue = ['true', 'True', 'TRUE']; - const falseValue = ['false', 'False', 'FALSE']; - if (trueValue.includes(val)) return true; - if (falseValue.includes(val)) return false; - throw new TypeError( - `Action input "${name}" does not meet YAML 1.2 "Core Schema" specification: \n` + - `Supported boolean values: \`true | True | TRUE | false | False | FALSE\`` - ); -} - /** * Parse a string as a comma-separated list. */ @@ -152,13 +131,13 @@ export type RawInputs = { ghcVersion?: string; cabalVersion?: string; stackVersion?: string; - enableStack?: string; - stackNoGlobal?: string; - stackSetupGhc?: string; - cabalUpdate?: string; + enableStack?: boolean; + stackNoGlobal?: boolean; + stackSetupGhc?: boolean; + cabalUpdate?: boolean; ghcupReleaseChannels?: string; ghcupReleaseChannel?: string; - disableMatcher?: string; + disableMatcher?: boolean; }; export function getOpts( @@ -167,10 +146,12 @@ export function getOpts( inputs: RawInputs ): Options { core.debug(`Inputs are: ${JSON.stringify(inputs)}`); - const stackNoGlobal = (inputs.stackNoGlobal ?? '') !== ''; - const stackSetupGhc = (inputs.stackSetupGhc ?? '') !== ''; - const stackEnable = (inputs.enableStack ?? '') !== ''; - const matcherDisable = (inputs.disableMatcher ?? '') !== ''; + + const stackNoGlobal = inputs.stackNoGlobal ?? false; + const stackSetupGhc = inputs.stackSetupGhc ?? false; + const stackEnable = inputs.enableStack ?? false; + const cabalUpdate = inputs.cabalUpdate ?? true; + const matcherDisable = inputs.disableMatcher ?? false; if (inputs.ghcupReleaseChannel) { core.warning( @@ -189,14 +170,6 @@ export function getOpts( } ); - // Andreas, 2023-01-05, issue #29: - // 'cabal-update' has a default value, so we should get a proper boolean always. - // Andreas, 2023-01-06: This is not true if we use the action as a library. - // Thus, need to patch with default value here. - const cabalUpdate = parseYAMLBoolean( - 'cabal-update', - inputs.cabalUpdate ?? 'true' - ); core.debug(`${stackNoGlobal}/${stackSetupGhc}/${stackEnable}`); const verInpt = { ghc: inputs.ghcVersion || ghc.version, From 3b8222b7114cfa5466ef2de2ec3e154a1e2d9ebf Mon Sep 17 00:00:00 2001 From: Brandon Chinn Date: Thu, 13 Jul 2023 09:13:50 -0700 Subject: [PATCH 09/10] Parse multiline strings in main.ts --- .github/workflows/workflow.yml | 10 +++++----- README.md | 10 +++++----- action.yml | 2 +- dist/index.js | 15 +++------------ lib/opts.d.ts | 2 +- lib/opts.js | 13 ++----------- src/main.ts | 2 +- src/opts.ts | 28 ++++++++-------------------- 8 files changed, 26 insertions(+), 56 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 10d84ec..e77da72 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -96,7 +96,7 @@ jobs: # Any matrix combinations with latest-nightly should add the appropriate release channel - plan: ghc: latest-nightly - ghcup_release_channels: > + ghcup_release_channels: | https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml # Test deprecated release channel still works for now @@ -108,10 +108,10 @@ jobs: # Test ghcup release channels - os: ubuntu-latest - ghcup_release_channels: > - https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-0.0.7.yaml, - https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.7.yaml, - https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-vanilla-0.0.7.yaml, + ghcup_release_channels: | + https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-0.0.7.yaml + https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.7.yaml + https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-vanilla-0.0.7.yaml plan: ghc: "9.6.0.20230111" cabal: "3.8" diff --git a/README.md b/README.md index e4f65a0..69e6eba 100644 --- a/README.md +++ b/README.md @@ -201,15 +201,15 @@ Notes: - `Toggle` inputs are booleans that are false when set as the empty string and true when set to _anything_. However, to avoid confusion and for forward compatibility, it is still recommended to **only use value `true` to set a `Toggle` input.** -- Inputs that can take multiple values (like `ghcup-release-channels`) should be specified as a comma separated list, e.g. +- Inputs that can take multiple values (like `ghcup-release-channels`) should be specified as a multiline list, e.g. ```yaml - uses: haskell-actions/setup@v2 with: - ghcup-release-channels: > - https://example.com/channel1, - https://example.com/channel2, - https://example.com/channel3, + ghcup-release-channels: | + https://example.com/channel1 + https://example.com/channel2 + https://example.com/channel3 ``` ## Outputs diff --git a/action.yml b/action.yml index 0e05e8d..6f4c012 100644 --- a/action.yml +++ b/action.yml @@ -32,7 +32,7 @@ inputs: # which are true as soon as they are not null. ghcup-release-channels: required: false - description: "Release channel URLs to add to ghcup via `ghcup config add-release-channel`." + description: "Release channel URLs to add to ghcup via `ghcup config add-release-channel`, as a multiline string" ghcup-release-channel: required: false description: "Deprecated by ghcup-release-channels." diff --git a/dist/index.js b/dist/index.js index 0da42a7..fb024eb 100644 --- a/dist/index.js +++ b/dist/index.js @@ -13675,7 +13675,7 @@ const getToggleInput = (name) => core.getInput(name) !== ''; stackNoGlobal: getToggleInput('stack-no-global'), stackSetupGhc: getToggleInput('stack-setup-ghc'), cabalUpdate: core.getBooleanInput('cabal-update'), - ghcupReleaseChannels: core.getInput('ghcup-release-channels'), + ghcupReleaseChannels: core.getMultilineInput('ghcup-release-channels'), ghcupReleaseChannel: core.getInput('ghcup-release-channel'), disableMatcher: getToggleInput('disable-matcher') }); @@ -13791,15 +13791,6 @@ function releaseRevision(version, tool, os) { return result; } exports.releaseRevision = releaseRevision; -/** - * Parse a string as a comma-separated list. - */ -function parseCSV(val) { - return val - .split(',') - .map(s => s.trim()) - .filter(s => s != ''); -} function getOpts({ ghc, cabal, stack }, os, inputs) { core.debug(`Inputs are: ${JSON.stringify(inputs)}`); const stackNoGlobal = inputs.stackNoGlobal ?? false; @@ -13809,9 +13800,9 @@ function getOpts({ ghc, cabal, stack }, os, inputs) { const matcherDisable = inputs.disableMatcher ?? false; if (inputs.ghcupReleaseChannel) { core.warning('ghcup-release-channel is deprecated in favor of ghcup-release-channels'); - inputs.ghcupReleaseChannels = inputs.ghcupReleaseChannel; + inputs.ghcupReleaseChannels = [inputs.ghcupReleaseChannel]; } - const ghcupReleaseChannels = parseCSV(inputs.ghcupReleaseChannels ?? '').map(v => { + const ghcupReleaseChannels = (inputs.ghcupReleaseChannels ?? []).map(v => { try { return new URL(v); } diff --git a/lib/opts.d.ts b/lib/opts.d.ts index d43afda..573aab6 100644 --- a/lib/opts.d.ts +++ b/lib/opts.d.ts @@ -82,7 +82,7 @@ export type RawInputs = { stackNoGlobal?: boolean; stackSetupGhc?: boolean; cabalUpdate?: boolean; - ghcupReleaseChannels?: string; + ghcupReleaseChannels?: string[]; ghcupReleaseChannel?: string; disableMatcher?: boolean; }; diff --git a/lib/opts.js b/lib/opts.js index f26fab4..c1b9e09 100644 --- a/lib/opts.js +++ b/lib/opts.js @@ -102,15 +102,6 @@ function releaseRevision(version, tool, os) { return result; } exports.releaseRevision = releaseRevision; -/** - * Parse a string as a comma-separated list. - */ -function parseCSV(val) { - return val - .split(',') - .map(s => s.trim()) - .filter(s => s != ''); -} function getOpts({ ghc, cabal, stack }, os, inputs) { core.debug(`Inputs are: ${JSON.stringify(inputs)}`); const stackNoGlobal = inputs.stackNoGlobal ?? false; @@ -120,9 +111,9 @@ function getOpts({ ghc, cabal, stack }, os, inputs) { const matcherDisable = inputs.disableMatcher ?? false; if (inputs.ghcupReleaseChannel) { core.warning('ghcup-release-channel is deprecated in favor of ghcup-release-channels'); - inputs.ghcupReleaseChannels = inputs.ghcupReleaseChannel; + inputs.ghcupReleaseChannels = [inputs.ghcupReleaseChannel]; } - const ghcupReleaseChannels = parseCSV(inputs.ghcupReleaseChannels ?? '').map(v => { + const ghcupReleaseChannels = (inputs.ghcupReleaseChannels ?? []).map(v => { try { return new URL(v); } diff --git a/src/main.ts b/src/main.ts index 81eac9e..66b23c0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -11,7 +11,7 @@ run({ stackNoGlobal: getToggleInput('stack-no-global'), stackSetupGhc: getToggleInput('stack-setup-ghc'), cabalUpdate: core.getBooleanInput('cabal-update'), - ghcupReleaseChannels: core.getInput('ghcup-release-channels'), + ghcupReleaseChannels: core.getMultilineInput('ghcup-release-channels'), ghcupReleaseChannel: core.getInput('ghcup-release-channel'), disableMatcher: getToggleInput('disable-matcher') }); diff --git a/src/opts.ts b/src/opts.ts index 4ccd988..aab5548 100644 --- a/src/opts.ts +++ b/src/opts.ts @@ -117,16 +117,6 @@ export function releaseRevision(version: string, tool: Tool, os: OS): string { return result; } -/** - * Parse a string as a comma-separated list. - */ -function parseCSV(val: string): string[] { - return val - .split(',') - .map(s => s.trim()) - .filter(s => s != ''); -} - export type RawInputs = { ghcVersion?: string; cabalVersion?: string; @@ -135,7 +125,7 @@ export type RawInputs = { stackNoGlobal?: boolean; stackSetupGhc?: boolean; cabalUpdate?: boolean; - ghcupReleaseChannels?: string; + ghcupReleaseChannels?: string[]; ghcupReleaseChannel?: string; disableMatcher?: boolean; }; @@ -157,18 +147,16 @@ export function getOpts( core.warning( 'ghcup-release-channel is deprecated in favor of ghcup-release-channels' ); - inputs.ghcupReleaseChannels = inputs.ghcupReleaseChannel; + inputs.ghcupReleaseChannels = [inputs.ghcupReleaseChannel]; } - const ghcupReleaseChannels = parseCSV(inputs.ghcupReleaseChannels ?? '').map( - v => { - try { - return new URL(v); - } catch (e) { - throw new TypeError(`Not a valid URL: ${v}`); - } + const ghcupReleaseChannels = (inputs.ghcupReleaseChannels ?? []).map(v => { + try { + return new URL(v); + } catch (e) { + throw new TypeError(`Not a valid URL: ${v}`); } - ); + }); core.debug(`${stackNoGlobal}/${stackSetupGhc}/${stackEnable}`); const verInpt = { From 3f2715436c49e3e1c7b19450d595348512bbe8eb Mon Sep 17 00:00:00 2001 From: Brandon Chinn Date: Thu, 13 Jul 2023 20:42:11 -0700 Subject: [PATCH 10/10] Handle missing booleans --- dist/index.js | 9 ++++++++- src/main.ts | 10 +++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/dist/index.js b/dist/index.js index fb024eb..fbb83c3 100644 --- a/dist/index.js +++ b/dist/index.js @@ -13667,6 +13667,13 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); const core = __importStar(__nccwpck_require__(2186)); const setup_haskell_1 = __importDefault(__nccwpck_require__(9351)); const getToggleInput = (name) => core.getInput(name) !== ''; +const getBooleanInput = (name) => { + // https://github.com/actions/toolkit/issues/844 + if (!process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`]) { + return undefined; + } + return core.getBooleanInput(name); +}; (0, setup_haskell_1.default)({ ghcVersion: core.getInput('ghc-version'), cabalVersion: core.getInput('cabal-version'), @@ -13674,7 +13681,7 @@ const getToggleInput = (name) => core.getInput(name) !== ''; enableStack: getToggleInput('enable-stack'), stackNoGlobal: getToggleInput('stack-no-global'), stackSetupGhc: getToggleInput('stack-setup-ghc'), - cabalUpdate: core.getBooleanInput('cabal-update'), + cabalUpdate: getBooleanInput('cabal-update'), ghcupReleaseChannels: core.getMultilineInput('ghcup-release-channels'), ghcupReleaseChannel: core.getInput('ghcup-release-channel'), disableMatcher: getToggleInput('disable-matcher') diff --git a/src/main.ts b/src/main.ts index 66b23c0..16a9b56 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,6 +3,14 @@ import run from './setup-haskell'; const getToggleInput = (name: string) => core.getInput(name) !== ''; +const getBooleanInput = (name: string): boolean | undefined => { + // https://github.com/actions/toolkit/issues/844 + if (!process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`]) { + return undefined; + } + return core.getBooleanInput(name); +}; + run({ ghcVersion: core.getInput('ghc-version'), cabalVersion: core.getInput('cabal-version'), @@ -10,7 +18,7 @@ run({ enableStack: getToggleInput('enable-stack'), stackNoGlobal: getToggleInput('stack-no-global'), stackSetupGhc: getToggleInput('stack-setup-ghc'), - cabalUpdate: core.getBooleanInput('cabal-update'), + cabalUpdate: getBooleanInput('cabal-update'), ghcupReleaseChannels: core.getMultilineInput('ghcup-release-channels'), ghcupReleaseChannel: core.getInput('ghcup-release-channel'), disableMatcher: getToggleInput('disable-matcher')