Skip to content

Commit

Permalink
Install stack if necessary
Browse files Browse the repository at this point in the history
* Add install-stack input
* Add installed/install functions to StackCLI
* Install stack if necessary
* Build
* Update README
* Skip old LTS on MacOS
  • Loading branch information
pbrisbin authored May 6, 2024
1 parent 29d851d commit 94aff10
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ jobs:
- resolver: lts-12.26
ghc: "8.4.4"

exclude:
# Binary distributions for older GHCs don't exist on macOS-latest
- runner: macOS-latest
stack: {ghc: "8.4.4"}

fail-fast: false

runs-on: ${{ matrix.runner }}
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ jobs:
| `stack-build-arguments-test` | <p>Additional arguments passed after <code>stack-build-arguments</code> in <code>stack build</code> invocations on the <em>Test</em> step.</p> | `false` | `""` |
| `cache-prefix` | <p>Prefix applied to all cache keys. This can be any value you like, but teams often use <code>v{N}</code> and bump it to <code>v{N+1}</code> when/if they need to explicitly bust caches.</p> | `false` | `""` |
| `cache-save-always` | <p>Save artifacts to the cache even if the build fails. This may speed up builds in subsequent runs at the expense of slightly-longer builds when a full cache-hit occurs. Since <code>@v4.2.0</code>.</p> | `false` | `false` |
| `install-stack` | <p>Install stack, if necessary</p> | `false` | `true` |
| `upgrade-stack` | <p>Upgrade stack</p> | `false` | `true` |
| `compiler-tools` | <p>A list of packages to install as compiler tools, one per line. This is useful to do here rather than separate <code>run</code> commands so that their installation is incorporated in the dependency cache. Since <code>@v5.2.0</code>.</p> | `false` | `""` |
| `stack-yaml` | <p><strong>Deprecated</strong> use <code>env.STACK_YAML</code> or <code>stack-arguments</code> instead.</p> | `false` | `""` |
Expand Down
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ inputs:
builds in subsequent runs at the expense of slightly-longer builds when a
full cache-hit occurs. Since `@v4.2.0`.
default: false
install-stack:
description: |
Install stack, if necessary
default: true
upgrade-stack:
description: |
Upgrade stack
Expand Down
42 changes: 37 additions & 5 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ function getInputs() {
stackBuildArgumentsTest: getBuildArguments("test"),
cachePrefix: core.getInput("cache-prefix"),
cacheSaveAlways: core.getBooleanInput("cache-save-always"),
installStack: core.getBooleanInput("install-stack"),
upgradeStack: core.getBooleanInput("upgrade-stack"),
compilerTools: core.getMultilineInput("compiler-tools"),
stackYaml: getInputDefault("stack-yaml", null),
Expand Down Expand Up @@ -203,18 +204,35 @@ async function run() {
inputs.stackArguments.unshift("--stack-yaml");
}
const stack = new stack_cli_1.StackCLI(inputs.stackArguments, core.isDebug());
await core.group("Install/upgrade stack", async () => {
const installed = await stack.installed();
if (installed) {
if (inputs.upgradeStack) {
core.info("Upgrading stack");
await stack.upgrade();
}
}
else {
if (inputs.installStack) {
core.info("Installing stack");
await stack.install();
}
else {
throw new Error([
"The executable stack is not present on $PATH",
"Make sure it is installed in a preceding step, or use",
"`install-stack: true` to have it installed for you.",
].join("\n"));
}
}
});
const hashes = await core.group("Calculate hashes", async () => {
const hashes = await (0, hash_project_1.hashProject)(stack.config);
core.info(`Snapshot: ${hashes.snapshot}`);
core.info(`Packages: ${hashes.package}`);
core.info(`Sources: ${hashes.sources}`);
return hashes;
});
if (inputs.upgradeStack) {
await core.group("Upgrade stack", async () => {
await stack.upgrade();
});
}
const { stackYaml, stackDirectories } = await core.group("Determine stack directories", async () => {
const stackYaml = (0, stack_yaml_1.readStackYamlSync)(stack.config);
const stackDirectories = await (0, stack_yaml_1.getStackDirectories)(stackYaml, stack);
Expand Down Expand Up @@ -428,6 +446,20 @@ class StackCLI {
this.globalArgs.push("nightly");
}
}
async installed() {
const ec = await exec.exec("which", ["stack"], {
silent: true,
ignoreReturnCode: true,
});
return ec == 0;
}
async install() {
const url = "https://get.haskellstack.org";
const tmp = "install-stack.sh";
await exec.exec("curl", ["-sSL", "-o", tmp, url]);
await exec.exec("sh", [tmp]);
fs.rmSync(tmp);
}
async upgrade() {
return await exec.exec("stack", ["upgrade"]);
}
Expand Down
2 changes: 2 additions & 0 deletions src/inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type Inputs = {
stackBuildArgumentsTest: string[];
cachePrefix: string;
cacheSaveAlways: boolean;
installStack: boolean;
upgradeStack: boolean;
compilerTools: string[];

Expand All @@ -38,6 +39,7 @@ export function getInputs(): Inputs {
stackBuildArgumentsTest: getBuildArguments("test"),
cachePrefix: core.getInput("cache-prefix"),
cacheSaveAlways: core.getBooleanInput("cache-save-always"),
installStack: core.getBooleanInput("install-stack"),
upgradeStack: core.getBooleanInput("upgrade-stack"),
compilerTools: core.getMultilineInput("compiler-tools"),
stackYaml: getInputDefault("stack-yaml", null),
Expand Down
30 changes: 24 additions & 6 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,30 @@ async function run() {

const stack = new StackCLI(inputs.stackArguments, core.isDebug());

await core.group("Install/upgrade stack", async () => {
const installed = await stack.installed();

if (installed) {
if (inputs.upgradeStack) {
core.info("Upgrading stack");
await stack.upgrade();
}
} else {
if (inputs.installStack) {
core.info("Installing stack");
await stack.install();
} else {
throw new Error(
[
"The executable stack is not present on $PATH",
"Make sure it is installed in a preceding step, or use",
"`install-stack: true` to have it installed for you.",
].join("\n"),
);
}
}
});

const hashes = await core.group("Calculate hashes", async () => {
const hashes = await hashProject(stack.config);
core.info(`Snapshot: ${hashes.snapshot}`);
Expand All @@ -36,12 +60,6 @@ async function run() {
return hashes;
});

if (inputs.upgradeStack) {
await core.group("Upgrade stack", async () => {
await stack.upgrade();
});
}

const { stackYaml, stackDirectories } = await core.group(
"Determine stack directories",
async () => {
Expand Down
16 changes: 16 additions & 0 deletions src/stack-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,22 @@ export class StackCLI {
}
}

async installed(): Promise<boolean> {
const ec = await exec.exec("which", ["stack"], {
silent: true,
ignoreReturnCode: true,
});
return ec == 0;
}

async install(): Promise<void> {
const url = "https://get.haskellstack.org";
const tmp = "install-stack.sh";
await exec.exec("curl", ["-sSL", "-o", tmp, url]);
await exec.exec("sh", [tmp]);
fs.rmSync(tmp);
}

async upgrade(): Promise<number> {
// Avoid this.exec because we don't need/want globalArgs
return await exec.exec("stack", ["upgrade"]);
Expand Down

0 comments on commit 94aff10

Please sign in to comment.