Skip to content
This repository has been archived by the owner on Jan 5, 2024. It is now read-only.

Fix #29: new input cabal-update: false to skip 'cabal update' #146

Merged
merged 10 commits into from Jan 10, 2023
15 changes: 15 additions & 0 deletions .github/workflows/workflow.yml
Expand Up @@ -41,10 +41,13 @@ jobs:
os: [ubuntu-latest, macOS-latest, windows-latest]
ghc: ["latest", "8.4.4"]
cabal: ["latest", "3.2.0.0"]
cabal_update: ["false"]
# The following tests do not set 'cabal-update', which defaults to 'true' then.
include:
- os: ubuntu-latest
ghc: "8.2.2"
cabal: "2.4.1.0"
cabal_update: "false"
- os: ubuntu-18.04
ghc: "7.4.1"
cabal: "3.4"
Expand All @@ -68,24 +71,36 @@ jobs:
cabal: "3.6"
steps:
- uses: actions/checkout@v3

- uses: ./setup
with:
ghc-version: ${{ matrix.ghc }}
cabal-version: ${{ matrix.cabal }}
cabal-update: ${{ matrix.cabal_update }}

- name: Test runghc
run: |
runghc --version
runghc __tests__/hello.hs

- name: Build test project
working-directory: setup/__tests__/project
run: cabal build

- name: Run test project
working-directory: setup/__tests__/project
run: cabal run

- name: Build and run test with Hackage dependency
if: ${{ matrix.cabal_update != 'false' }}
working-directory: setup/__tests__/project-with-hackage-dependency
run: cabal build && cabal run

- name: Show installed versions
run: |
cabal --version
ghc --version

- name: Confirm installed and expected versions match
shell: bash
# check that if given in the matrix, the actual version matches:
Expand Down
22 changes: 13 additions & 9 deletions setup/README.md
Expand Up @@ -98,18 +98,22 @@ jobs:

## Inputs

| Name | Required | Description | Type | Default |
| ----------------- | :------: | ---------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------- |
| `ghc-version` | | GHC version to use, ex. `latest` | string | latest |
| `cabal-version` | | Cabal version to use, ex. `3.4` | string | latest |
| `stack-version` | | Stack version to use, ex. `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 |
| Name | Description | Type | Default |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------- |
| `ghc-version` | GHC version to use, e.g. `9.2` or `9.2.4`. | `string` | `latest` |
| `cabal-version` | Cabal version to use, e.g. `3.4`. | `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` |

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`.

## Outputs

Expand Down
4 changes: 4 additions & 0 deletions setup/__tests__/project-with-hackage-dependency/Main.hs
@@ -0,0 +1,4 @@
module Main where

main :: IO ()
main = putStrLn "Hello, Hackage!"
2 changes: 2 additions & 0 deletions setup/__tests__/project-with-hackage-dependency/Setup.hs
@@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain
@@ -0,0 +1,11 @@
cabal-version: >=1.10
name: project-with-hackage-dependency
version: 0.1.0.0
build-type: Simple

executable project
main-is: Main.hs
build-depends: base
-- Add a package from hackage here to see whether `cabal update` ran.
, base-orphans
default-language: Haskell2010
15 changes: 11 additions & 4 deletions setup/action.yml
Expand Up @@ -16,16 +16,23 @@ inputs:
default: 'latest'
enable-stack:
required: false
description: 'If specified, will setup Stack'
description: 'If specified, will setup Stack.'
stack-no-global:
required: false
description: 'If specified, enable-stack must be set. Prevents installing GHC and Cabal globally'
description: 'If specified, enable-stack must be set. Prevents installing GHC and Cabal globally.'
stack-setup-ghc:
required: false
description: 'If specified, enable-stack must be set. Will run stack setup to install the specified GHC'
description: 'If specified, enable-stack must be set. Will run stack setup to install the specified GHC.'
cabal-update:
required: false
default: true
description: 'Set to `false` to prevent `cabal update` from being run.'
# 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.
disable-matcher:
required: false
description: 'If specified, disables match messages from GHC as GitHub CI annotations'
description: 'If specified, disables match messages from GHC as GitHub CI annotations.'
outputs:
ghc-path:
description: 'The path of the ghc executable _directory_'
Expand Down
33 changes: 30 additions & 3 deletions setup/dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 14 additions & 1 deletion setup/lib/opts.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 29 additions & 2 deletions setup/lib/opts.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion setup/lib/setup-haskell.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 32 additions & 2 deletions setup/src/opts.ts
Expand Up @@ -24,7 +24,7 @@ export interface ProgramOpt {

export interface Options {
ghc: ProgramOpt;
cabal: ProgramOpt;
cabal: ProgramOpt & {update: boolean};
stack: ProgramOpt & {setup: boolean};
general: {matcher: {enable: boolean}};
}
Expand Down Expand Up @@ -83,6 +83,27 @@ 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\``
);
}

export function getOpts(
{ghc, cabal, stack}: Defaults,
os: OS,
Expand All @@ -93,6 +114,14 @@ export function getOpts(
const stackSetupGhc = (inputs['stack-setup-ghc'] || '') !== '';
const stackEnable = (inputs['enable-stack'] || '') !== '';
const matcherDisable = (inputs['disable-matcher'] || '') !== '';
// 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(
andreasabel marked this conversation as resolved.
Show resolved Hide resolved
'cabal-update',
inputs['cabal-update'] || 'true'
);
core.debug(`${stackNoGlobal}/${stackSetupGhc}/${stackEnable}`);
const verInpt = {
ghc: inputs['ghc-version'] || ghc.version,
Expand Down Expand Up @@ -136,7 +165,8 @@ export function getOpts(
os,
cabalEnable // if true: inform user about resolution
),
enable: cabalEnable
enable: cabalEnable,
update: cabalUpdate
},
stack: {
raw: verInpt.stack,
Expand Down
2 changes: 1 addition & 1 deletion setup/src/setup-haskell.ts
Expand Up @@ -73,7 +73,7 @@ export default async function run(
// https://github.com/haskell/cabal/issues/6823
// await exec('cabal user-config update');
}
if (!opts.stack.enable) await exec('cabal update');
if (opts.cabal.update && !opts.stack.enable) await exec('cabal update');
});

core.info(`##[add-matcher]${path.join(__dirname, '..', 'matcher.json')}`);
Expand Down