Skip to content

Commit a709f1e

Browse files
Add new ghcup-release-channels input
1 parent c5343c2 commit a709f1e

File tree

9 files changed

+131
-86
lines changed

9 files changed

+131
-86
lines changed

.github/workflows/workflow.yml

+18-1
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,29 @@ jobs:
9595
# and of cabal just 2.4, 3.0, 3.2, 3.4
9696
# according to https://launchpad.net/~hvr/+archive/ubuntu/ghc?field.series_filter=focal
9797

98-
# Test ghcup pre-release channel
98+
# Any matrix combinations with latest-nightly should add the appropriate release channel
99+
- plan:
100+
ghc: latest-nightly
101+
ghcup_release_channels: >
102+
https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml
103+
104+
# Test deprecated release channel still works for now
99105
- os: ubuntu-latest
100106
ghcup_release_channel: "https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.7.yaml"
101107
plan:
102108
ghc: "9.6.0.20230111"
103109
cabal: "3.8"
104110

111+
# Test ghcup release channels
112+
- os: ubuntu-latest
113+
ghcup_release_channels: >
114+
https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-0.0.7.yaml,
115+
https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.7.yaml,
116+
https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-vanilla-0.0.7.yaml,
117+
plan:
118+
ghc: "9.6.0.20230111"
119+
cabal: "3.8"
120+
105121
# setup does something special for 7.10.3 (issue #79)
106122
- os: ubuntu-20.04
107123
plan:
@@ -148,6 +164,7 @@ jobs:
148164
with:
149165
ghc-version: ${{ matrix.plan.ghc }}
150166
ghcup-release-channel: ${{ matrix.ghcup_release_channel }}
167+
ghcup-release-channels: ${{ matrix.ghcup_release_channels }}
151168
cabal-version: ${{ matrix.plan.cabal }}
152169
cabal-update: ${{ matrix.cabal_update }}
153170

README.md

+30-17
Original file line numberDiff line numberDiff line change
@@ -184,23 +184,35 @@ jobs:
184184
185185
## Inputs
186186
187-
| Name | Description | Type | Default |
188-
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------- |
189-
| `ghc-version` | GHC version to use, e.g. `9.2` or `9.2.5`. | `string` | `latest` |
190-
| `cabal-version` | Cabal version to use, e.g. `3.6`. | `string` | `latest` |
191-
| `stack-version` | Stack version to use, e.g. `latest`. Stack will only be installed if `enable-stack` is set. | `string` | `latest` |
192-
| `enable-stack` | If set, will setup Stack. | "boolean" | false/unset |
193-
| `stack-no-global` | If set, `enable-stack` must be set. Prevents installing GHC and Cabal globally. | "boolean" | false/unset |
194-
| `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 |
195-
| `disable-matcher` | If set, disables match messages from GHC as GitHub CI annotations. | "boolean" | false/unset |
196-
| `cabal-update` | If set to `false`, skip `cabal update` step. | `boolean` | `true` |
197-
| `ghcup-release-channel` | If set, add a [release channel](https://www.haskell.org/ghcup/guide/#pre-release-channels) to ghcup. | `URL` | none |
198-
199-
Note: "boolean" types are set/unset, not true/false.
200-
That is, setting any "boolean" to a value other than the empty string (`""`) will be considered true/set.
201-
However, to avoid confusion and for forward compatibility, it is still recommended to **only use value `true` to set a "boolean" flag.**
202-
203-
In contrast, a proper `boolean` input like `cabal-update` only accepts values `true` and `false`.
187+
| Name | Description | Type | Default |
188+
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------- |
189+
| `ghc-version` | GHC version to use, e.g. `9.2` or `9.2.5`. | `string` | `latest` |
190+
| `cabal-version` | Cabal version to use, e.g. `3.6`. | `string` | `latest` |
191+
| `stack-version` | Stack version to use, e.g. `latest`. Stack will only be installed if `enable-stack` is set. | `string` | `latest` |
192+
| `enable-stack` | If set, will setup Stack. | "boolean" | false/unset |
193+
| `stack-no-global` | If set, `enable-stack` must be set. Prevents installing GHC and Cabal globally. | "boolean" | false/unset |
194+
| `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 |
195+
| `disable-matcher` | If set, disables match messages from GHC as GitHub CI annotations. | "boolean" | false/unset |
196+
| `cabal-update` | If set to `false`, skip `cabal update` step. | `boolean` | `true` |
197+
| `ghcup-release-channels` | If set, add [release channels](https://www.haskell.org/ghcup/guide/#pre-release-channels) to ghcup. | `URL[]` | none |
198+
199+
Notes:
200+
201+
- "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.
202+
However, to avoid confusion and for forward compatibility, it is still recommended to **only use value `true` to set a "boolean" flag.**
203+
204+
In contrast, a proper `boolean` input like `cabal-update` only accepts values `true` and `false`.
205+
206+
- Inputs that can take multiple values (like `ghcup-release-channels`) should be specified as a comma separated list, e.g.
207+
208+
```yaml
209+
- uses: haskell-actions/setup@v2
210+
with:
211+
ghcup-release-channels: >
212+
https://example.com/channel1,
213+
https://example.com/channel2,
214+
https://example.com/channel3,
215+
```
204216

205217
## Outputs
206218

@@ -237,6 +249,7 @@ E.g., `8.10` will be resolved to `8.10.7`, and so will `8`.
237249
**GHC:**
238250

239251
- `latest-nightly`
252+
- This requires adding https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml to `ghcup-release-channels`
240253
- `latest` (default)
241254
- `9.6.2` `9.6`
242255
- `9.6.1`

action.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@ inputs:
3030
# Note: 'cabal-update' only accepts 'true' and 'false' as values.
3131
# This is different from the other flags ('enable-stack', 'disable-matcher' etc.)
3232
# which are true as soon as they are not null.
33+
ghcup-release-channels:
34+
required: false
35+
description: "Release channel URLs to add to ghcup via `ghcup config add-release-channel`."
3336
ghcup-release-channel:
3437
required: false
35-
description: "A release channel URL to add to ghcup via `ghcup config add-release-channel`."
38+
description: "Deprecated by ghcup-release-channels."
3639
disable-matcher:
3740
required: false
3841
description: 'If specified, disables match messages from GHC as GitHub CI annotations.'

dist/index.js

+24-21
Original file line numberDiff line numberDiff line change
@@ -13665,7 +13665,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
1366513665
return result;
1366613666
};
1366713667
Object.defineProperty(exports, "__esModule", ({ value: true }));
13668-
exports.getOpts = exports.parseURL = exports.parseYAMLBoolean = exports.releaseRevision = exports.getDefaults = exports.yamlInputs = exports.ghcup_version = exports.supported_versions = exports.release_revisions = void 0;
13668+
exports.getOpts = exports.parseYAMLBoolean = exports.releaseRevision = exports.getDefaults = exports.yamlInputs = exports.ghcup_version = exports.supported_versions = exports.release_revisions = void 0;
1366913669
const core = __importStar(__nccwpck_require__(2186));
1367013670
const fs_1 = __nccwpck_require__(7147);
1367113671
const js_yaml_1 = __nccwpck_require__(1917);
@@ -13765,24 +13765,33 @@ function parseYAMLBoolean(name, val) {
1376513765
`Supported boolean values: \`true | True | TRUE | false | False | FALSE\``);
1376613766
}
1376713767
exports.parseYAMLBoolean = parseYAMLBoolean;
13768-
function parseURL(name, val) {
13769-
if (val === '')
13770-
return null;
13771-
try {
13772-
return new URL(val);
13773-
}
13774-
catch (e) {
13775-
throw new TypeError(`Action input "${name}" is not a valid URL`);
13776-
}
13768+
/**
13769+
* Parse a string as a comma-separated list.
13770+
*/
13771+
function parseCSV(val) {
13772+
return val
13773+
.split(',')
13774+
.map(s => s.trim())
13775+
.filter(s => s != '');
1377713776
}
13778-
exports.parseURL = parseURL;
1377913777
function getOpts({ ghc, cabal, stack }, os, inputs) {
1378013778
core.debug(`Inputs are: ${JSON.stringify(inputs)}`);
1378113779
const stackNoGlobal = (inputs['stack-no-global'] || '') !== '';
1378213780
const stackSetupGhc = (inputs['stack-setup-ghc'] || '') !== '';
1378313781
const stackEnable = (inputs['enable-stack'] || '') !== '';
1378413782
const matcherDisable = (inputs['disable-matcher'] || '') !== '';
13785-
const ghcupReleaseChannel = parseURL('ghcup-release-channel', inputs['ghcup-release-channel'] || '');
13783+
if (inputs['ghcup-release-channel']) {
13784+
core.warning('ghcup-release-channel is deprecated in favor of ghcup-release-channels');
13785+
inputs['ghcup-release-channels'] = inputs['ghcup-release-channel'];
13786+
}
13787+
const ghcupReleaseChannels = parseCSV(inputs['ghcup-release-channels'] ?? '').map(v => {
13788+
try {
13789+
return new URL(v);
13790+
}
13791+
catch (e) {
13792+
throw new TypeError(`Not a valid URL: ${v}`);
13793+
}
13794+
});
1378613795
// Andreas, 2023-01-05, issue #29:
1378713796
// 'cabal-update' has a default value, so we should get a proper boolean always.
1378813797
// Andreas, 2023-01-06: This is not true if we use the action as a library.
@@ -13814,7 +13823,7 @@ function getOpts({ ghc, cabal, stack }, os, inputs) {
1381413823
enable: ghcEnable
1381513824
},
1381613825
ghcup: {
13817-
releaseChannel: ghcupReleaseChannel
13826+
releaseChannels: ghcupReleaseChannels
1381813827
},
1381913828
cabal: {
1382013829
raw: verInpt.cabal,
@@ -13898,15 +13907,9 @@ async function run(inputs) {
1389813907
core.debug(`run: inputs = ${JSON.stringify(inputs)}`);
1389913908
core.debug(`run: os = ${JSON.stringify(os)}`);
1390013909
core.debug(`run: opts = ${JSON.stringify(opts)}`);
13901-
const releaseChannels = [
13902-
opts.ghcup.releaseChannel,
13903-
opts.ghc.raw === 'latest-nightly'
13904-
? new URL('https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml')
13905-
: null
13906-
].filter((v) => v !== null);
13907-
if (releaseChannels.length > 0) {
13910+
if (opts.ghcup.releaseChannels.length > 0) {
1390813911
await core.group(`Setting release channels`, async () => {
13909-
for (const channel of releaseChannels) {
13912+
for (const channel of opts.ghcup.releaseChannels) {
1391013913
await (0, installer_1.addGhcupReleaseChannel)(channel, os);
1391113914
}
1391213915
});

lib/opts.d.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export interface ProgramOpt {
1616
export interface Options {
1717
ghc: ProgramOpt;
1818
ghcup: {
19-
releaseChannel: URL | null;
19+
releaseChannels: URL[];
2020
};
2121
cabal: ProgramOpt & {
2222
update: boolean;
@@ -85,6 +85,5 @@ export declare function releaseRevision(version: string, tool: Tool, os: OS): st
8585
* @returns boolean
8686
*/
8787
export declare function parseYAMLBoolean(name: string, val: string): boolean;
88-
export declare function parseURL(name: string, val: string): URL | null;
8988
export declare function getOpts({ ghc, cabal, stack }: Defaults, os: OS, inputs: Record<string, string>): Options;
9089
export {};

lib/opts.js

+22-13
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
2323
return result;
2424
};
2525
Object.defineProperty(exports, "__esModule", { value: true });
26-
exports.getOpts = exports.parseURL = exports.parseYAMLBoolean = exports.releaseRevision = exports.getDefaults = exports.yamlInputs = exports.ghcup_version = exports.supported_versions = exports.release_revisions = void 0;
26+
exports.getOpts = exports.parseYAMLBoolean = exports.releaseRevision = exports.getDefaults = exports.yamlInputs = exports.ghcup_version = exports.supported_versions = exports.release_revisions = void 0;
2727
const core = __importStar(require("@actions/core"));
2828
const fs_1 = require("fs");
2929
const js_yaml_1 = require("js-yaml");
@@ -123,24 +123,33 @@ function parseYAMLBoolean(name, val) {
123123
`Supported boolean values: \`true | True | TRUE | false | False | FALSE\``);
124124
}
125125
exports.parseYAMLBoolean = parseYAMLBoolean;
126-
function parseURL(name, val) {
127-
if (val === '')
128-
return null;
129-
try {
130-
return new URL(val);
131-
}
132-
catch (e) {
133-
throw new TypeError(`Action input "${name}" is not a valid URL`);
134-
}
126+
/**
127+
* Parse a string as a comma-separated list.
128+
*/
129+
function parseCSV(val) {
130+
return val
131+
.split(',')
132+
.map(s => s.trim())
133+
.filter(s => s != '');
135134
}
136-
exports.parseURL = parseURL;
137135
function getOpts({ ghc, cabal, stack }, os, inputs) {
138136
core.debug(`Inputs are: ${JSON.stringify(inputs)}`);
139137
const stackNoGlobal = (inputs['stack-no-global'] || '') !== '';
140138
const stackSetupGhc = (inputs['stack-setup-ghc'] || '') !== '';
141139
const stackEnable = (inputs['enable-stack'] || '') !== '';
142140
const matcherDisable = (inputs['disable-matcher'] || '') !== '';
143-
const ghcupReleaseChannel = parseURL('ghcup-release-channel', inputs['ghcup-release-channel'] || '');
141+
if (inputs['ghcup-release-channel']) {
142+
core.warning('ghcup-release-channel is deprecated in favor of ghcup-release-channels');
143+
inputs['ghcup-release-channels'] = inputs['ghcup-release-channel'];
144+
}
145+
const ghcupReleaseChannels = parseCSV(inputs['ghcup-release-channels'] ?? '').map(v => {
146+
try {
147+
return new URL(v);
148+
}
149+
catch (e) {
150+
throw new TypeError(`Not a valid URL: ${v}`);
151+
}
152+
});
144153
// Andreas, 2023-01-05, issue #29:
145154
// 'cabal-update' has a default value, so we should get a proper boolean always.
146155
// 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) {
172181
enable: ghcEnable
173182
},
174183
ghcup: {
175-
releaseChannel: ghcupReleaseChannel
184+
releaseChannels: ghcupReleaseChannels
176185
},
177186
cabal: {
178187
raw: verInpt.cabal,

lib/setup-haskell.js

+2-8
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,9 @@ async function run(inputs) {
5252
core.debug(`run: inputs = ${JSON.stringify(inputs)}`);
5353
core.debug(`run: os = ${JSON.stringify(os)}`);
5454
core.debug(`run: opts = ${JSON.stringify(opts)}`);
55-
const releaseChannels = [
56-
opts.ghcup.releaseChannel,
57-
opts.ghc.raw === 'latest-nightly'
58-
? new URL('https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml')
59-
: null
60-
].filter((v) => v !== null);
61-
if (releaseChannels.length > 0) {
55+
if (opts.ghcup.releaseChannels.length > 0) {
6256
await core.group(`Setting release channels`, async () => {
63-
for (const channel of releaseChannels) {
57+
for (const channel of opts.ghcup.releaseChannels) {
6458
await (0, installer_1.addGhcupReleaseChannel)(channel, os);
6559
}
6660
});

src/opts.ts

+28-13
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export interface ProgramOpt {
2424

2525
export interface Options {
2626
ghc: ProgramOpt;
27-
ghcup: {releaseChannel: URL | null};
27+
ghcup: {releaseChannels: URL[]};
2828
cabal: ProgramOpt & {update: boolean};
2929
stack: ProgramOpt & {setup: boolean};
3030
general: {matcher: {enable: boolean}};
@@ -138,13 +138,14 @@ export function parseYAMLBoolean(name: string, val: string): boolean {
138138
);
139139
}
140140

141-
export function parseURL(name: string, val: string): URL | null {
142-
if (val === '') return null;
143-
try {
144-
return new URL(val);
145-
} catch (e) {
146-
throw new TypeError(`Action input "${name}" is not a valid URL`);
147-
}
141+
/**
142+
* Parse a string as a comma-separated list.
143+
*/
144+
function parseCSV(val: string): string[] {
145+
return val
146+
.split(',')
147+
.map(s => s.trim())
148+
.filter(s => s != '');
148149
}
149150

150151
export function getOpts(
@@ -157,10 +158,24 @@ export function getOpts(
157158
const stackSetupGhc = (inputs['stack-setup-ghc'] || '') !== '';
158159
const stackEnable = (inputs['enable-stack'] || '') !== '';
159160
const matcherDisable = (inputs['disable-matcher'] || '') !== '';
160-
const ghcupReleaseChannel = parseURL(
161-
'ghcup-release-channel',
162-
inputs['ghcup-release-channel'] || ''
163-
);
161+
162+
if (inputs['ghcup-release-channel']) {
163+
core.warning(
164+
'ghcup-release-channel is deprecated in favor of ghcup-release-channels'
165+
);
166+
inputs['ghcup-release-channels'] = inputs['ghcup-release-channel'];
167+
}
168+
169+
const ghcupReleaseChannels = parseCSV(
170+
inputs['ghcup-release-channels'] ?? ''
171+
).map(v => {
172+
try {
173+
return new URL(v);
174+
} catch (e) {
175+
throw new TypeError(`Not a valid URL: ${v}`);
176+
}
177+
});
178+
164179
// Andreas, 2023-01-05, issue #29:
165180
// 'cabal-update' has a default value, so we should get a proper boolean always.
166181
// Andreas, 2023-01-06: This is not true if we use the action as a library.
@@ -204,7 +219,7 @@ export function getOpts(
204219
enable: ghcEnable
205220
},
206221
ghcup: {
207-
releaseChannel: ghcupReleaseChannel
222+
releaseChannels: ghcupReleaseChannels
208223
},
209224
cabal: {
210225
raw: verInpt.cabal,

src/setup-haskell.ts

+2-10
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,9 @@ export default async function run(
3030
core.debug(`run: os = ${JSON.stringify(os)}`);
3131
core.debug(`run: opts = ${JSON.stringify(opts)}`);
3232

33-
const releaseChannels = [
34-
opts.ghcup.releaseChannel,
35-
opts.ghc.raw === 'latest-nightly'
36-
? new URL(
37-
'https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml'
38-
)
39-
: null
40-
].filter((v): v is URL => v !== null);
41-
if (releaseChannels.length > 0) {
33+
if (opts.ghcup.releaseChannels.length > 0) {
4234
await core.group(`Setting release channels`, async () => {
43-
for (const channel of releaseChannels) {
35+
for (const channel of opts.ghcup.releaseChannels) {
4436
await addGhcupReleaseChannel(channel, os);
4537
}
4638
});

0 commit comments

Comments
 (0)