Support toml rust-toolchain & working-directory

Closes #126
This commit is contained in:
Boaz Berman 2021-04-05 19:12:59 +03:00
parent 88dc235639
commit 00a8bf2bdc
21 changed files with 231 additions and 138 deletions

2
.eslintignore Normal file
View file

@ -0,0 +1,2 @@
node_modules
dist

View file

@ -1,19 +1,19 @@
{ {
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"parserOptions": { "parserOptions": {
"project": "./tsconfig.eslint.json" "project": "./tsconfig.eslint.json"
}, },
"plugins": ["@typescript-eslint"], "plugins": ["@typescript-eslint"],
"extends": [ "extends": [
"eslint:recommended", "eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking", "plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended", "plugin:prettier/recommended",
"prettier", "prettier",
"prettier/@typescript-eslint" "prettier/@typescript-eslint"
], ],
"rules": { "rules": {
"@typescript-eslint/ban-ts-ignore": "off" "@typescript-eslint/ban-ts-ignore": "off"
} }
} }

View file

@ -13,8 +13,7 @@ jobs:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- run: npm ci - run: npm ci
# Temporary disabling in order to release urgent fix - run: npm run lint
# - run: npm run lint
- run: npm run build - run: npm run build
- run: npm run test - run: npm run test
@ -56,7 +55,7 @@ jobs:
install_stable_in_docker: install_stable_in_docker:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ubuntu:latest # Docker image, not the GitHub Actions VM container: ubuntu:latest # Docker image, not the GitHub Actions VM
steps: steps:
# `rustup` will need `curl` or `wget` later # `rustup` will need `curl` or `wget` later
- run: apt-get update && apt-get install -y curl - run: apt-get update && apt-get install -y curl

2
.gitignore vendored
View file

@ -92,3 +92,5 @@ typings/
# IntelliJ IDEs # IntelliJ IDEs
.idea .idea
.npmrc

3
.prettierignore Normal file
View file

@ -0,0 +1,3 @@
# Ignore artifacts:
node_modules
dist

1
.prettierrc.json Normal file
View file

@ -0,0 +1 @@
{}

View file

@ -1,4 +1,5 @@
# Changelog # Changelog
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
@ -8,42 +9,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Pass `allow-downgrade` flag to `rustup` if `nightly` toolchain with components requested - Pass `allow-downgrade` flag to `rustup` if `nightly` toolchain with components requested
## [1.0.5] - 2020-01-26 ## [1.0.5] - 2020-01-26
### Fixed ### Fixed
- `rustup` version parser does not fail Action execution on `macOS-latest` VM images anymore - `rustup` version parser does not fail Action execution on `macOS-latest` VM images anymore
## [1.0.4] - 2020-01-26 ## [1.0.4] - 2020-01-26
### Added ### Added
- Support for the `rust-toolchain` file: If the toolchain input is not given, we will try and install the version specified in the `rust-toolchain` file. - Support for the `rust-toolchain` file: If the toolchain input is not given, we will try and install the version specified in the `rust-toolchain` file.
- Action outputs with `rustc`, `cargo` and `rustup` versions installed - Action outputs with `rustc`, `cargo` and `rustup` versions installed
## [1.0.3] - 2019-10-19 ## [1.0.3] - 2019-10-19
### Added ### Added
- Support for `rustup set profile` command - Support for `rustup set profile` command
- Support for `--component` flag for the `rustup toolchain install` command - Support for `--component` flag for the `rustup toolchain install` command
## [1.0.2] - 2019-10-14 ## [1.0.2] - 2019-10-14
### Changed ### Changed
- Missing `rustup` executable will not raise an annotating warning before the installation anymore (#13) - Missing `rustup` executable will not raise an annotating warning before the installation anymore (#13)
## [1.0.1] - 2019-10-05 ## [1.0.1] - 2019-10-05
### Changed ### Changed
- `target` input is not used as a `--default-target` argument for `rustup` anymore (#8) - `target` input is not used as a `--default-target` argument for `rustup` anymore (#8)
## [1.0.0] - 2019-09-15 ## [1.0.0] - 2019-09-15
### Added ### Added
- First public version - First public version

View file

@ -14,14 +14,14 @@ these small papercuts for you.
**Table of Contents** **Table of Contents**
* [Example workflow](#example-workflow) - [Example workflow](#example-workflow)
* [Inputs](#inputs) - [Inputs](#inputs)
* [Outputs](#outputs) - [Outputs](#outputs)
* [Profiles](#profiles) - [Profiles](#profiles)
* [Components](#components) - [Components](#components)
* [The toolchain file](#the-toolchain-file) - [The toolchain file](#the-toolchain-file)
* [License](#license) - [License](#license)
* [Contribute and support](#contribute-and-support) - [Contribute and support](#contribute-and-support)
## Example workflow ## Example workflow
@ -31,25 +31,25 @@ on: [push]
name: build name: build
jobs: jobs:
check: check:
name: Rust project name: Rust project
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install latest nightly - name: Install latest nightly
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: nightly toolchain: nightly
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
# `cargo check` command here will use installed `nightly` # `cargo check` command here will use installed `nightly`
# as it is set as an "override" for current directory # as it is set as an "override" for current directory
- name: Run cargo check - name: Run cargo check
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: check command: check
``` ```
See [additional recipes here](https://github.com/actions-rs/meta). See [additional recipes here](https://github.com/actions-rs/meta).
@ -57,7 +57,7 @@ See [additional recipes here](https://github.com/actions-rs/meta).
## Inputs ## Inputs
| Name | Required | Description | Type | Default | | Name | Required | Description | Type | Default |
| ------------ | :------: | ----------------------------------------------------------------------------------------------------------------------------------------------------| ------ | --------| | ------------ | :------: | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- |
| `toolchain` | | [Toolchain](https://github.com/rust-lang/rustup.rs#toolchain-specification) name to use, ex. `stable`, `nightly`, `nightly-2019-04-20`, or `1.32.0` | string | stable | | `toolchain` | | [Toolchain](https://github.com/rust-lang/rustup.rs#toolchain-specification) name to use, ex. `stable`, `nightly`, `nightly-2019-04-20`, or `1.32.0` | string | stable |
| `target` | | Additionally install specified target for this toolchain, ex. `x86_64-apple-darwin` | string | | | `target` | | Additionally install specified target for this toolchain, ex. `x86_64-apple-darwin` | string | |
| `default` | | Set installed toolchain as a default toolchain | bool | false | | `default` | | Set installed toolchain as a default toolchain | bool | false |
@ -72,12 +72,12 @@ in order to support toolchain files. See the details [below](#the-toolchain-file
Installed `rustc`, `cargo` and `rustup` versions can be fetched from the Action outputs: Installed `rustc`, `cargo` and `rustup` versions can be fetched from the Action outputs:
| Name | Description | Example | | Name | Description | Example |
| ------------ | --------------------- | ------------------------------- | | ------------ | ------------------ | ------------------------------- |
| `rustc` | Rustc version | `1.40.0 (73528e339 2019-12-16)` | | `rustc` | Rustc version | `1.40.0 (73528e339 2019-12-16)` |
| `rustc_hash` | Rustc version hash | `73528e339` | | `rustc_hash` | Rustc version hash | `73528e339` |
| `cargo` | Cargo version | `1.40.0 (bc8e4c8be 2019-11-22)` | | `cargo` | Cargo version | `1.40.0 (bc8e4c8be 2019-11-22)` |
| `rustup` | rustup version | `1.21.1 (7832b2ebe 2019-12-20)` | | `rustup` | rustup version | `1.21.1 (7832b2ebe 2019-12-20)` |
Note: `rustc_hash` output value can be used with [actions/cache](https://github.com/actions/cache) Action Note: `rustc_hash` output value can be used with [actions/cache](https://github.com/actions/cache) Action
to store cache for different Rust versions, as it is unique across different Rust versions and builds (including `nightly`). to store cache for different Rust versions, as it is unique across different Rust versions and builds (including `nightly`).
@ -92,8 +92,8 @@ minimally required set of components, for example:
- name: Install minimal nightly - name: Install minimal nightly
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: nightly toolchain: nightly
``` ```
This Action will automatically run `rustup self update` if `profile` input is set This Action will automatically run `rustup self update` if `profile` input is set
@ -114,9 +114,9 @@ and in combination with the [profiles](#profiles) input it allows to install onl
- name: Install minimal stable with clippy and rustfmt - name: Install minimal stable with clippy and rustfmt
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: stable toolchain: stable
components: rustfmt, clippy components: rustfmt, clippy
``` ```
As an extra perk, `rustup >= 1.20.0` is able to find the most recent `nightly` toolchain As an extra perk, `rustup >= 1.20.0` is able to find the most recent `nightly` toolchain
@ -127,9 +127,9 @@ to install the minimal set of `nightly` toolchain components with the `rustfmt`
- name: Install minimal nightly with clippy and rustfmt - name: Install minimal nightly with clippy and rustfmt
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: nightly toolchain: nightly
components: rustfmt, clippy components: rustfmt, clippy
``` ```
In case if `nightly` toolchain is requested and one of the components is missing in In case if `nightly` toolchain is requested and one of the components is missing in
@ -137,8 +137,8 @@ latest `nightly` release, this Action will attempt the downgrade till it find
the most recent `nightly` with all components needed.\ the most recent `nightly` with all components needed.\
Note that this behavior will work only if the following two conditions apply: Note that this behavior will work only if the following two conditions apply:
1. `toolchain` input is `nightly` exactly. 1. `toolchain` input is `nightly` exactly.
2. At least one component is provided in `components` input. 2. At least one component is provided in `components` input.
Same to the `profile` input, if installed `rustup` does not supports "components", Same to the `profile` input, if installed `rustup` does not supports "components",
it will be automatically upgraded by this Action. it will be automatically upgraded by this Action.

View file

@ -62,6 +62,37 @@ describe("actions-rs/toolchain", () => {
expect(args.name).toBe("1.39.0"); expect(args.name).toBe("1.39.0");
}); });
it("uses new style rust-toolchain file if input does not exist", function () {
const rustToolchainFile = tempWriteSync(
'[toolchain]\nchannel = "1.51.0"\ncomponents = [ "rustfmt", "clippy" ]\nprofile = "minimal"\ntargets = [ "wasm32-unknown-unknown", "thumbv2-none-eabi" ]'
);
const args = morph(() => {
return getToolchainArgs(rustToolchainFile);
}, {});
expect(args.name).toBe("1.51.0");
expect(args.components).toStrictEqual(["rustfmt", "clippy"]);
expect(args.profile).toBe("minimal");
expect(args.target).toBe("wasm32-unknown-unknown");
});
it("uses new style rust-toolchain file with toml ending if input and rust-toolchain file does not exist", function () {
const rustToolchainFile = tempWriteSync(
'[toolchain]\nchannel = "1.51.0"\ncomponents = [ "rustfmt", "clippy" ]\nprofile = "minimal"\ntargets = [ "wasm32-unknown-unknown", "thumbv2-none-eabi" ]',
"./rust-toolchain.toml"
);
const args = morph(() => {
return getToolchainArgs(rustToolchainFile.replace(/\.toml^/, ""));
}, {});
expect(args.name).toBe("1.51.0");
expect(args.components).toStrictEqual(["rustfmt", "clippy"]);
expect(args.profile).toBe("minimal");
expect(args.target).toBe("wasm32-unknown-unknown");
});
it("trims content of the override file", function () { it("trims content of the override file", function () {
const rustToolchainFile = tempWriteSync("\n 1.39.0\n\n\n\n"); const rustToolchainFile = tempWriteSync("\n 1.39.0\n\n\n\n");

View file

@ -1,10 +1,13 @@
name: 'rust-toolchain' name: "rust-toolchain"
description: 'Install the Rust toolchain' description: "Install the Rust toolchain"
author: 'actions-rs team' author: "actions-rs team"
branding: branding:
icon: play-circle icon: play-circle
color: black color: black
inputs: inputs:
working-directory:
description: The working directory to find the rust-toolchain in.
required: false
toolchain: toolchain:
description: | description: |
Rust toolchain name. Rust toolchain name.
@ -40,5 +43,5 @@ outputs:
description: Installed rustup version description: Installed rustup version
runs: runs:
using: 'node12' using: "node12"
main: 'dist/index.js' main: "dist/index.js"

2
dist/index.js vendored

File diff suppressed because one or more lines are too long

View file

@ -1,11 +1,11 @@
{ {
"clearMocks": true, "clearMocks": true,
"moduleFileExtensions": ["js", "ts"], "moduleFileExtensions": ["js", "ts"],
"testEnvironment": "node", "testEnvironment": "node",
"testMatch": ["**/*.test.ts"], "testMatch": ["**/*.test.ts"],
"testRunner": "jest-circus/runner", "testRunner": "jest-circus/runner",
"transform": { "transform": {
"^.+\\.ts$": "ts-jest" "^.+\\.ts$": "ts-jest"
}, },
"verbose": true "verbose": true
} }

5
package-lock.json generated
View file

@ -764,6 +764,11 @@
} }
} }
}, },
"@iarna/toml": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz",
"integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg=="
},
"@istanbuljs/load-nyc-config": { "@istanbuljs/load-nyc-config": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",

View file

@ -10,8 +10,8 @@
}, },
"scripts": { "scripts": {
"build": "rm -rf ./dist/* && ncc build src/main.ts --minify", "build": "rm -rf ./dist/* && ncc build src/main.ts --minify",
"format": "prettier --write 'src/**/*.ts' '__tests__/**/*.ts'", "format": "prettier --write .",
"lint": "tsc --noEmit && eslint 'src/**/*.ts' '__tests__/**/*.ts'", "lint": "tsc --noEmit && eslint .",
"watch": "rm -rf ./dist/* && ncc build src/main.ts --watch", "watch": "rm -rf ./dist/* && ncc build src/main.ts --watch",
"test": "jest -c jest.config.json", "test": "jest -c jest.config.json",
"pretest": "git config core.hooksPath .githooks" "pretest": "git config core.hooksPath .githooks"
@ -35,7 +35,8 @@
"@actions-rs/core": "^0.1.6", "@actions-rs/core": "^0.1.6",
"@actions/core": "^1.2.6", "@actions/core": "^1.2.6",
"@actions/exec": "^1.0.4", "@actions/exec": "^1.0.4",
"@actions/io": "^1.0.2" "@actions/io": "^1.0.2",
"@iarna/toml": "^2.2.5"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^26.0.15", "@types/jest": "^26.0.15",

View file

@ -1,52 +1,36 @@
import { input } from "@actions-rs/core"; import { input } from "@actions-rs/core";
import { debug } from "@actions/core"; import { parseToolchainFile } from "./toolchain_file";
import { existsSync, readFileSync } from "fs";
export interface ToolchainOptions { export interface ToolchainOptions {
name: string; name: string;
target: string | undefined; target?: string | undefined;
default: boolean; default?: boolean;
override: boolean; override?: boolean;
profile: string | undefined; profile?: string | undefined;
components: string[] | undefined; components?: string[] | undefined;
}
function determineToolchain(overrideFile: string): string {
const toolchainInput = input.getInput("toolchain", { required: false });
if (toolchainInput) {
debug(`using toolchain from input: ${toolchainInput}`);
return toolchainInput;
}
if (!existsSync(overrideFile)) {
throw new Error(
"toolchain input was not given and repository does not have a rust-toolchain file"
);
}
const rustToolchainFile = readFileSync(overrideFile, {
encoding: "utf-8",
flag: "r",
}).trim();
debug(`using toolchain from rust-toolchain file: ${rustToolchainFile}`);
return rustToolchainFile;
} }
export function getToolchainArgs(overrideFile: string): ToolchainOptions { export function getToolchainArgs(overrideFile: string): ToolchainOptions {
const toolchainInput = input.getInput("toolchain", { required: false });
let components: string[] | undefined = input.getInputList("components"); let components: string[] | undefined = input.getInputList("components");
if (components && components.length === 0) { if (components && components.length === 0) {
components = undefined; components = undefined;
} }
const toolchainFromFile = parseToolchainFile(overrideFile);
if (!toolchainInput && !toolchainFromFile) {
throw new Error(
"toolchain input was not given and repository does not have a rust-toolchain file"
);
}
return { return {
name: determineToolchain(overrideFile), name: toolchainInput || toolchainFromFile?.name || "",
target: input.getInput("target") || undefined, target: input.getInput("target") || toolchainFromFile?.target,
default: input.getInputBool("default"), default: input.getInputBool("default"),
override: input.getInputBool("override"), override: input.getInputBool("override"),
profile: input.getInput("profile") || undefined, profile: input.getInput("profile") || toolchainFromFile?.profile,
components: components, components: components || toolchainFromFile?.components,
}; };
} }

View file

@ -5,9 +5,15 @@ import * as args from "./args";
import * as versions from "./versions"; import * as versions from "./versions";
import { RustUp, ToolchainOptions } from "@actions-rs/core"; import { RustUp, ToolchainOptions } from "@actions-rs/core";
type Profile = "minimal" | "default" | "full";
async function run(): Promise<void> { async function run(): Promise<void> {
// we use path.join to make sure this works on Windows, Linux and MacOS // we use path.join to make sure this works on Windows, Linux and MacOS
const toolchainOverridePath = path.join(process.cwd(), "rust-toolchain"); const toolchainOverridePath = path.join(
process.cwd(),
core.getInput("working-directory"),
"rust-toolchain"
);
const opts = args.getToolchainArgs(toolchainOverridePath); const opts = args.getToolchainArgs(toolchainOverridePath);
const rustup = await RustUp.getOrInstall(); const rustup = await RustUp.getOrInstall();
@ -30,8 +36,7 @@ async function run(): Promise<void> {
} }
if (opts.profile) { if (opts.profile) {
// @ts-ignore: TS2345 await rustup.setProfile(opts.profile as Profile);
await rustup.setProfile(opts.profile);
} }
const installOptions: ToolchainOptions = { const installOptions: ToolchainOptions = {
@ -90,8 +95,9 @@ async function main(): Promise<void> {
try { try {
await run(); await run();
} catch (error) { } catch (error) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
core.setFailed(error.message); core.setFailed(error.message);
} }
} }
main(); void main();

60
src/toolchain_file.ts Normal file
View file

@ -0,0 +1,60 @@
import TOML from "@iarna/toml";
import { ToolchainOptions } from "./args";
import { existsSync, readFileSync } from "fs";
import { debug } from "@actions/core";
interface RustToolchainFileToolchain {
channel: string;
targets: string[] | undefined;
profile: string | undefined;
components?: string[] | undefined;
}
interface RustToolchainFile {
toolchain: RustToolchainFileToolchain;
}
export function parseToolchainFile(
overrideFile: string
): ToolchainOptions | null {
if (!existsSync(overrideFile)) {
if (existsSync(`${overrideFile}.toml`)) {
overrideFile = `${overrideFile}.toml`;
} else {
debug("Repository does not have a rust-toolchain file");
return null;
}
}
const rustToolchainFile = readFileSync(overrideFile, {
encoding: "utf-8",
flag: "r",
}).trim();
try {
debug(`using toolchain from rust-toolchain file: ${rustToolchainFile}`);
// eslint-disable-next-line
const parsedToolchain = (TOML.parse(
rustToolchainFile
) as unknown) as RustToolchainFile;
return {
name: parsedToolchain.toolchain.channel,
target: parsedToolchain.toolchain.targets?.[0],
profile: parsedToolchain.toolchain.profile,
components: parsedToolchain.toolchain.components,
};
} catch (err) {
debug(
`using toolchain from old style rust-toolchain file: ${rustToolchainFile}`
);
return {
name: rustToolchainFile,
default: true,
override: false,
};
}
}

View file

@ -45,7 +45,7 @@ function parseShort(stdout: string): string {
async function getStdout( async function getStdout(
exe: string, exe: string,
args: string[], args: string[],
options?: {} options?: Record<string, unknown>
): Promise<string> { ): Promise<string> {
let stdout = ""; let stdout = "";
const resOptions = Object.assign({}, options, { const resOptions = Object.assign({}, options, {

View file

@ -1,7 +1,4 @@
{ {
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"include": [ "include": ["src/**/*.ts", "__tests__/**/*.ts"]
"src/**/*.ts",
"__tests__/**/*.ts"
]
} }

View file

@ -26,7 +26,5 @@
"sourceMap": false, "sourceMap": false,
"typeRoots": ["./types", "./node_modules/@types"] "typeRoots": ["./types", "./node_modules/@types"]
}, },
"include": [ "include": ["src", "__tests__"]
"src/**/*.ts"
]
} }

View file

@ -1,7 +1,7 @@
declare module "mock-env" { declare module "mock-env" {
function morph<T>( function morph<T>(
callback: () => T, callback: () => T,
vars: object, vars: Record<string, unknown>,
toRemove?: string[] toRemove?: string[]
): any; ): T;
} }