Skip to content

Commit

Permalink
Release v0.0.5
Browse files Browse the repository at this point in the history
  • Loading branch information
svartalf committed Oct 9, 2019
1 parent bb4b4d7 commit c420cc3
Show file tree
Hide file tree
Showing 8 changed files with 958 additions and 385 deletions.
985 changes: 629 additions & 356 deletions package-lock.json

Large diffs are not rendered by default.

23 changes: 15 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
{
"private": false,
"name": "@actions-rs/core",
"version": "0.0.4",
"version": "0.0.5",
"author": "actions-rs",
"license": "MIT",
"description": "Core functionality for the @actions-rs repos",
"main": "lib/core.js",
"main": "dist/core.js",
"files": [
"dist/**/*.js"
],
"scripts": {
"build": "tsc -p .",
"format": "prettier --write 'src/**/*.{js,ts,tsx}'",
"lint": "tsc --noEmit && eslint 'src/**/*.{js,ts,tsx}'",
"refresh": "rm -rf ./lib/* && npm run build",
"refresh": "rm -rf ./dist/* && npm run build",
"test": "jest --passWithNoTests",
"watch": "tsc -p . -w"
},
Expand All @@ -22,15 +25,19 @@
"url": "https://github.com/actions-rs/core/issues"
},
"dependencies": {
"@actions/core": "^1.1.1",
"@actions/core": "^1.1.3",
"@actions/exec": "^1.0.1",
"@actions/io": "^1.0.1"
"@actions/github": "^1.1.0",
"@actions/io": "^1.0.1",
"@actions/tool-cache": "^1.0.1",
"@octokit/graphql": "^2.0.1",
"@octokit/rest": "^16.30.2"
},
"devDependencies": {
"@types/jest": "^24.0.13",
"@types/node": "^12.7.5",
"@typescript-eslint/eslint-plugin": "^2.3.2",
"@typescript-eslint/parser": "^2.3.2",
"@types/node": "^12.7.11",
"@typescript-eslint/eslint-plugin": "^2.3.3",
"@typescript-eslint/parser": "^2.3.3",
"eslint": "^6.5.1",
"eslint-config-prettier": "^6.3.0",
"eslint-plugin-prettier": "^3.1.1",
Expand Down
100 changes: 100 additions & 0 deletions src/checks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import * as github from '@actions/github';

interface Output {
title: string;
summary: string;
text: string;
}

/**
* Thin wrapper around the GitHub Checks API
*/
export class CheckReporter {
private readonly client: github.GitHub;
private readonly checkName: string;
private checkId: undefined | number;

constructor(client: github.GitHub, checkName: string) {
this.client = client;
this.checkName = checkName;
this.checkId = undefined;
}

/**
* Starts a new Check and returns check ID.
*/
public async startCheck(
status?: 'queued' | 'in_progress' | 'completed',
): Promise<number> {
const { owner, repo } = github.context.repo;

const response = await this.client.checks.create({
owner: owner,
repo: repo,
name: this.checkName,
head_sha: github.context.sha, // eslint-disable-line
status: status ? status : 'in_progress',
});
// TODO: Check for errors

this.checkId = response.data.id;
return this.checkId;
}

// TODO:
// public async sendAnnotations(annotations: Array<octokit.ChecksCreateParamsOutputAnnotations>): Promise<void> {
// }

/**
* It is up to caller to call the `startCheck` first!
*/
public async finishCheck(
conclusion:
| 'cancelled'
| 'success'
| 'failure'
| 'neutral'
| 'timed_out'
| 'action_required',
output: Output,
): Promise<void> {
const { owner, repo } = github.context.repo;

// TODO: Check for errors
await this.client.checks.update({
owner: owner,
repo: repo,
name: this.checkName,
check_run_id: this.checkId!, // eslint-disable-line
status: 'completed',
conclusion: conclusion,
completed_at: new Date().toISOString(), // eslint-disable-line
output: output,
});

return;
}

public async cancelCheck(): Promise<void> {
const { owner, repo } = github.context.repo;

// TODO: Check for errors
await this.client.checks.update({
owner: owner,
repo: repo,
name: this.checkName,
check_run_id: this.checkId!, // eslint-disable-line
status: 'completed',
conclusion: 'cancelled',
completed_at: new Date().toISOString(), // eslint-disable-line
output: {
title: this.checkName,
summary: 'Unhandled error',
text:
'Check was cancelled due to unhandled error. Check the Action logs for details.',
},
});

return;
}
}
61 changes: 59 additions & 2 deletions src/commands/cargo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,75 @@ export class Cargo {

return new Cargo(path);
} catch (error) {
core.info(
core.warning(
'cargo is not installed by default for some virtual environments, \
see https://help.github.com/en/articles/software-in-virtual-environments-for-github-actions',
);
core.info(
core.warning(
'To install it, use this action: https://github.com/actions-rs/toolchain',
);

throw error;
}
}

/**
* Executes `cargo install ${program}`.
*
* TODO: We can utilize the `@actions/tool-cache` and cache installed binary.
* As for now it acts just like an stub and simply installs the program
* on each call.
*
* `version` argument could be either actual program version or `"latest"` string,
* which can be provided by user input.
*
* If `version` is `undefined` or `"latest"`, this method could call the Crates.io API,
* fetch the latest version and search for it in cache.
* TODO: Actually implement this.
*
* ## Returns
*
* Path to the installed program.
* As the $PATH should be already tuned properly at this point,
* returned value at the moment is simply equal to the `program` argument.
*/
public async installCached(
program: string,
version?: string,
): Promise<string> {
const args = ['install'];
if (version && version != 'latest') {
args.push('--version');
args.push(version);
}
args.push(program);

try {
core.startGroup(`Installing "${program} = ${version || 'latest'}"`);
await this.call(args);
} finally {
core.endGroup();
}

return program;
}

/**
* Find the cargo sub-command or install it
*/
public async findOrInstall(
program: string,
version?: string,
): Promise<string> {
try {
return await io.which(program, true);
} catch (error) {
core.info(`${program} is not installed, installing it now`);
}

return await this.installCached(program, version);
}

public async call(args: string[], options?: {}): Promise<number> {
return await exec.exec(this.path, args, options);
}
Expand Down
15 changes: 2 additions & 13 deletions src/commands/cross.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,8 @@ export class Cross {
process.chdir(os.tmpdir());

try {
core.startGroup('Installing cross');

const args = ['install'];
if (version && version != 'latest') {
args.push('--version');
args.push(version);
}
args.push('cross');

await cargo.call(args);

// Assuming that `cross` executable is in `$PATH` already
return new Cross('cross');
const crossPath = await cargo.installCached('cross', version);
return new Cross(crossPath);
} finally {
// It is important to chdir back!
process.chdir(cwd);
Expand Down
143 changes: 143 additions & 0 deletions src/commands/rustup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import * as path from 'path';
import * as process from 'process';

import * as io from '@actions/io';
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as tc from '@actions/tool-cache';

export interface ToolchainOptions {
default?: boolean;
override?: boolean;
profile?: 'minimal' | 'default' | 'full';
}

export class RustUp {
private readonly path: string;

private constructor(exePath: string) {
this.path = exePath;
}

public static async getOrInstall(): Promise<RustUp> {
try {
return await RustUp.get();
} catch (error) {
core.debug(
`Unable to find "rustup" executable, installing it now. Reason: ${error}`,
);
return await RustUp.install();
}
}

// Will throw an error if `rustup` is not installed.
public static async get(): Promise<RustUp> {
const exePath = await io.which('rustup', true);

return new RustUp(exePath);
}

public static async install(): Promise<RustUp> {
const args = ['--default-toolchain', 'none'];

switch (process.platform) {
case 'darwin':
case 'linux': {
// eslint-disable-line prettier/prettier
const rustupSh = await tc.downloadTool('https://sh.rustup.rs');
await exec.exec(rustupSh, args);
break;
}

case 'win32': {
const rustupExe = await tc.downloadTool('http://win.rustup.rs');
await exec.exec(rustupExe, args);
break;
}

default:
throw new Error(
`Unknown platform ${process.platform}, can't install rustup`,
);
}

// `$HOME` should always be declared, so it is more to get the linters happy
core.addPath(path.join(process.env.HOME!, '.cargo', 'bin')); // eslint-disable-line @typescript-eslint/no-non-null-assertion

// Assuming it is in the $PATH already
return new RustUp('rustup');
}

public async installToolchain(
name: string,
options?: ToolchainOptions,
): Promise<number> {
await this.call(['toolchain', 'install', name]);

if (options && options.default) {
await this.call(['default', name]);
}

if (options && options.override) {
await this.call(['override', 'set', name]);
}

// TODO: Support profiles

// TODO: Is there smth like Rust' `return Ok(())`?
return 0;
}

public async addTarget(
name: string,
forToolchain?: string,
): Promise<number> {
const args = ['target', 'add'];
if (forToolchain) {
args.push('--toolchain');
args.push(forToolchain);
}
args.push(name);

return await this.call(args);
}

public async activeToolchain(): Promise<string> {
let stdout = '';
await this.call(['show', 'active-toolchain'], {
listeners: {
stdout: (buffer: Buffer) => {
stdout = buffer.toString().trim();
},
},
});

if (stdout) {
return stdout.split(' ', 2)[0];
} else {
throw new Error('Unable to determine active toolchain');
}
}

// rustup which `program`
public async which(program: string): Promise<string> {
let stdout = '';
await this.call(['which', program], {
listeners: {
stdout: (buffer: Buffer) => {
stdout = buffer.toString().trim();
},
},
});

if (stdout) {
return stdout;
} else {
throw new Error(`Unable to find the ${program}`);
}
}

public async call(args: string[], options?: {}): Promise<number> {
return await exec.exec(this.path, args, options);
}
}
Loading

0 comments on commit c420cc3

Please sign in to comment.