Compare commits

..

28 Commits

Author SHA1 Message Date
Alif Rachmawadi
b6f5cc2b39 bump version
Some checks failed
Main workflow / Run (macos-latest) (push) Failing after 4s
Main workflow / Run (ubuntu-latest) (push) Failing after 33s
Main workflow / Run (windows-latest) (push) Has been cancelled
2019-08-26 11:54:54 +07:00
Alif Rachmawadi
ad07e49913 removed unused file 2019-08-26 11:54:54 +07:00
Alif Rachmawadi
8f119fb49d Merge pull request #2 from subosito/tool-cache-110
tool-cache 1.1.0
2019-08-26 11:49:37 +07:00
Alif Rachmawadi
1dedc0776a remove unused hacks 2019-08-26 10:59:10 +07:00
Alif Rachmawadi
e4b52bc94d update tool-cache 1.1.0 2019-08-26 10:58:41 +07:00
Alif Rachmawadi
9267b2d4d1 updated user agent 2019-08-19 22:26:44 +07:00
Alif Rachmawadi
0fdcd6ee16 updated usage
Some checks failed
Main workflow / Run (macos-latest) (push) Failing after 2s
Main workflow / Run (ubuntu-latest) (push) Failing after 1m33s
Main workflow / Run (windows-latest) (push) Has been cancelled
2019-08-18 21:25:10 +07:00
Alif Rachmawadi
828493a231 added more tests 2019-08-18 21:23:51 +07:00
Alif Rachmawadi
a1e481922d handle 1.7 as 1.7.x 2019-08-18 21:23:37 +07:00
Alif Rachmawadi
5fe8a7cf47 rename 2019-08-16 19:33:37 +07:00
Alif Rachmawadi
e0ee719d54 bump version 2019-08-16 19:18:34 +07:00
Alif Rachmawadi
9fcb2724bc use flutter-version 2019-08-16 19:15:18 +07:00
Alif Rachmawadi
ad169ccdaa use flutter-version instead of version 2019-08-16 19:14:55 +07:00
Alif Rachmawadi
01ee38751a added semver 2019-08-16 19:04:23 +07:00
Alif Rachmawadi
1f3ea86f20 updated usage 2019-08-16 19:03:08 +07:00
Alif Rachmawadi
944fac1f62 added test fox .x version syntax 2019-08-16 19:03:08 +07:00
Alif Rachmawadi
be0241570a handle .x version syntax 2019-08-16 18:59:11 +07:00
Alif Rachmawadi
9421912880 allow unmocked 2019-08-16 18:40:47 +07:00
Alif Rachmawadi
858e055b72 added test for fetching latest release 2019-08-16 18:31:13 +07:00
Alif Rachmawadi
62ca43375c set version as optional 2019-08-16 18:30:45 +07:00
Alif Rachmawadi
fc54c01d84 added nock 2019-08-16 18:30:30 +07:00
Alif Rachmawadi
39e54cc1e6 get latest release automatically 2019-08-16 18:30:17 +07:00
Alif Rachmawadi
b14481040a updated lib
Some checks failed
Main workflow / Run (macos-latest) (push) Failing after 3s
Main workflow / Run (ubuntu-latest) (push) Failing after 19m41s
Main workflow / Run (windows-latest) (push) Has been cancelled
2019-08-16 15:36:09 +07:00
Alif Rachmawadi
88fdaa7568 added test for invalid version 2019-08-16 15:34:20 +07:00
Alif Rachmawadi
9b82c25a31 use version; fixes #1 2019-08-16 09:28:18 +07:00
Alif Rachmawadi
e15318b1da bump version 2019-08-16 09:16:46 +07:00
Alif Rachmawadi
fc32c521f1 update cache path 2019-08-15 12:44:24 +07:00
Alif Rachmawadi
126ac36d04 updated usage 2019-08-14 08:13:02 +07:00
21 changed files with 5605 additions and 812 deletions

View File

@@ -6,13 +6,46 @@ This action sets up a flutter environment for use in actions. It works on Linux,
```yaml ```yaml
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@v1
- uses: actions/setup-java@v1 - uses: actions/setup-java@v1
with: with:
java-version: '12.x' java-version: '12.x'
- uses: subosito/flutter-action@master - uses: subosito/flutter-action@v1
with: with:
version: '1.7.8+hotfix.4' flutter-version: '1.7.8+hotfix.4'
- run: flutter pub get
- run: flutter test
- run: flutter build apk
```
Use latest release for particular channel:
```yaml
steps:
- uses: actions/checkout@v1
- uses: actions/setup-java@v1
with:
java-version: '12.x'
- uses: subosito/flutter-action@v1
with:
channel: 'stable' # or: 'dev' or 'beta'
- run: flutter pub get
- run: flutter test
- run: flutter build apk
```
Use latest release for particular version and/or channel:
```yaml
steps:
- uses: actions/checkout@v1
- uses: actions/setup-java@v1
with:
java-version: '12.x'
- uses: subosito/flutter-action@v1
with:
flutter-version: '1.7.x' # you can use 1.7
channel: 'dev' # optional, default to: 'stable'
- run: flutter pub get - run: flutter pub get
- run: flutter test - run: flutter test
- run: flutter build apk - run: flutter build apk
@@ -29,13 +62,14 @@ jobs:
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest] os: [ubuntu-latest, windows-latest, macos-latest]
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@v1
- uses: actions/setup-java@v1.0.1 - uses: actions/setup-java@v1
with: with:
java-version: '12.x' java-version: '12.x'
- uses: subosito/flutter-action@master - uses: subosito/flutter-action@v1
with: with:
version: '1.7.8+hotfix.4' flutter-version: '1.8.4'
channel: 'beta'
- run: flutter pub get - run: flutter pub get
- run: flutter test - run: flutter test
- run: flutter build apk - run: flutter build apk

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,28 @@
import io = require('@actions/io'); import io = require('@actions/io');
import fs = require('fs'); import fs = require('fs');
import path = require('path'); import path = require('path');
import nock = require('nock');
const toolDir = path.join(__dirname, 'runner', 'tools'); const toolDir = path.join(__dirname, 'runner', 'tools');
const tempDir = path.join(__dirname, 'runner', 'temp'); const tempDir = path.join(__dirname, 'runner', 'temp');
const dataDir = path.join(__dirname, 'data');
process.env['RUNNER_TOOL_CACHE'] = toolDir; process.env['RUNNER_TOOL_CACHE'] = toolDir;
process.env['RUNNER_TEMP'] = tempDir; process.env['RUNNER_TEMP'] = tempDir;
import * as installer from '../src/installer'; import * as installer from '../src/installer';
function osName(): string {
switch (process.platform) {
case 'win32':
return 'windows';
case 'darwin':
return 'macos';
default:
return process.platform;
}
}
describe('installer tests', () => { describe('installer tests', () => {
beforeAll(async () => { beforeAll(async () => {
await io.rmRF(toolDir); await io.rmRF(toolDir);
@@ -26,13 +39,8 @@ describe('installer tests', () => {
}, 100000); }, 100000);
it('Downloads flutter', async () => { it('Downloads flutter', async () => {
await installer.getFlutter('1.7.8+hotfix.4', 'stable'); await installer.getFlutter('1.0.0', 'stable');
const sdkDir = path.join( const sdkDir = path.join(toolDir, 'flutter', '1.0.0-stable', 'x64');
toolDir,
'Flutter',
'1.7.8-hotfix.4-stable',
'x64'
);
expect(fs.existsSync(`${sdkDir}.complete`)).toBe(true); expect(fs.existsSync(`${sdkDir}.complete`)).toBe(true);
expect(fs.existsSync(path.join(sdkDir, 'bin'))).toBe(true); expect(fs.existsSync(path.join(sdkDir, 'bin'))).toBe(true);
@@ -40,9 +48,62 @@ describe('installer tests', () => {
it('Downloads flutter from beta channel', async () => { it('Downloads flutter from beta channel', async () => {
await installer.getFlutter('1.8.3', 'beta'); await installer.getFlutter('1.8.3', 'beta');
const sdkDir = path.join(toolDir, 'Flutter', '1.8.3-beta', 'x64'); const sdkDir = path.join(toolDir, 'flutter', '1.8.3-beta', 'x64');
expect(fs.existsSync(`${sdkDir}.complete`)).toBe(true); expect(fs.existsSync(`${sdkDir}.complete`)).toBe(true);
expect(fs.existsSync(path.join(sdkDir, 'bin'))).toBe(true); expect(fs.existsSync(path.join(sdkDir, 'bin'))).toBe(true);
}, 100000); }, 100000);
describe('get the latest release of a flutter version', () => {
beforeEach(() => {
const platform = osName();
nock('https://storage.googleapis.com', {allowUnmocked: true})
.get(`/flutter_infra/releases/releases_${platform}.json`)
.replyWithFile(200, path.join(dataDir, `releases_${platform}.json`));
});
afterEach(() => {
nock.cleanAll();
nock.enableNetConnect();
});
it('Downloads latest flutter release from stable channel', async () => {
await installer.getFlutter('', 'stable');
const sdkDir = path.join(
toolDir,
'flutter',
'1.7.8-hotfix.4-stable',
'x64'
);
expect(fs.existsSync(`${sdkDir}.complete`)).toBe(true);
expect(fs.existsSync(path.join(sdkDir, 'bin'))).toBe(true);
}, 100000);
it('Downloads latest flutter release of 1.7 when using version 1.7 from dev channel', async () => {
await installer.getFlutter('1.7', 'dev');
const sdkDir = path.join(toolDir, 'flutter', '1.7.11-dev', 'x64');
expect(fs.existsSync(`${sdkDir}.complete`)).toBe(true);
expect(fs.existsSync(path.join(sdkDir, 'bin'))).toBe(true);
}, 100000);
it('Downloads latest flutter release of 1.7 when using version 1.7.x from dev channel', async () => {
await installer.getFlutter('1.7.x', 'dev');
const sdkDir = path.join(toolDir, 'flutter', '1.7.11-dev', 'x64');
expect(fs.existsSync(`${sdkDir}.complete`)).toBe(true);
expect(fs.existsSync(path.join(sdkDir, 'bin'))).toBe(true);
}, 100000);
});
it('Throws if no location contains correct flutter version', async () => {
let thrown = false;
try {
await installer.getFlutter('1000.0', 'dev');
} catch {
thrown = true;
}
expect(thrown).toBe(true);
});
}); });

View File

@@ -1,14 +1,17 @@
name: 'Flutter Action' name: 'Flutter action'
description: 'Setup your runner with Flutter environment' description: 'Setup your runner with Flutter environment'
author: 'Alif Rachmawadi' author: 'Alif Rachmawadi'
inputs: inputs:
version: flutter-version:
description: 'The Flutter version to make available on the path' description: 'The Flutter version to make available on the path'
required: true required: false
channel: channel:
description: 'The Flutter build release channel' description: 'The Flutter build release channel'
required: false required: false
default: 'stable' default: 'stable'
# Deprecated option, do not use. Will not be supported after October 1, 2019
version:
description: 'Deprecated. Use flutter-version instead. Will not be supported after October 1, 2019'
runs: runs:
using: 'node12' using: 'node12'
main: 'lib/index.js' main: 'lib/index.js'

View File

@@ -20,8 +20,8 @@ const installer = __importStar(require("./installer"));
function run() { function run() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
try { try {
const version = core.getInput('version', { required: true }); const version = core.getInput('version') || core.getInput('flutter-version') || '';
const channel = core.getInput('channel', { required: false }) || 'stable'; const channel = core.getInput('channel') || 'stable';
yield installer.getFlutter(version, channel); yield installer.getFlutter(version, channel);
} }
catch (error) { catch (error) {

View File

@@ -14,20 +14,18 @@ var __importStar = (this && this.__importStar) || function (mod) {
result["default"] = mod; result["default"] = mod;
return result; return result;
}; };
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const core = __importStar(require("@actions/core")); const core = __importStar(require("@actions/core"));
const io = __importStar(require("@actions/io")); const io = __importStar(require("@actions/io"));
const tc = __importStar(require("@actions/tool-cache")); const tc = __importStar(require("@actions/tool-cache"));
const fs = __importStar(require("fs")); const fs = __importStar(require("fs"));
const path = __importStar(require("path")); const path = __importStar(require("path"));
const v4_1 = __importDefault(require("uuid/v4")); const restm = __importStar(require("typed-rest-client/RestClient"));
const exec_1 = require("@actions/exec/lib/exec"); const semver = __importStar(require("semver"));
const IS_WINDOWS = process.platform === 'win32'; const IS_WINDOWS = process.platform === 'win32';
const IS_DARWIN = process.platform === 'darwin'; const IS_DARWIN = process.platform === 'darwin';
const IS_LINUX = process.platform === 'linux'; const IS_LINUX = process.platform === 'linux';
const storageUrl = 'https://storage.googleapis.com/flutter_infra/releases';
let tempDirectory = process.env['RUNNER_TEMP'] || ''; let tempDirectory = process.env['RUNNER_TEMP'] || '';
if (!tempDirectory) { if (!tempDirectory) {
let baseLocation; let baseLocation;
@@ -46,10 +44,13 @@ if (!tempDirectory) {
} }
function getFlutter(version, channel) { function getFlutter(version, channel) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
// make semver compatible, eg: 1.7.8+hotfix.4 -> 1.7.8-hotfix.4 const versionPart = version.split('.');
const semver = version.replace('+', '-'); if (versionPart[1] == null || versionPart[2] == null) {
const cleanver = `${semver}-${channel}`; version = version.concat('.x');
let toolPath = tc.find('Flutter', cleanver); }
version = yield determineVersion(version, channel);
let cleanver = `${version.replace('+', '-')}-${channel}`;
let toolPath = tc.find('flutter', cleanver);
if (toolPath) { if (toolPath) {
core.debug(`Tool found in cache ${toolPath}`); core.debug(`Tool found in cache ${toolPath}`);
} }
@@ -60,7 +61,7 @@ function getFlutter(version, channel) {
let tempDir = generateTempDir(); let tempDir = generateTempDir();
const sdkDir = yield extractDownload(sdkFile, tempDir); const sdkDir = yield extractDownload(sdkFile, tempDir);
core.debug(`Flutter sdk extracted to ${sdkDir}`); core.debug(`Flutter sdk extracted to ${sdkDir}`);
toolPath = yield tc.cacheDir(sdkDir, 'Flutter', cleanver); toolPath = yield tc.cacheDir(sdkDir, 'flutter', cleanver);
} }
core.exportVariable('FLUTTER_HOME', toolPath); core.exportVariable('FLUTTER_HOME', toolPath);
core.addPath(path.join(toolPath, 'bin')); core.addPath(path.join(toolPath, 'bin'));
@@ -82,7 +83,7 @@ function extName() {
function getDownloadInfo(version, channel) { function getDownloadInfo(version, channel) {
const os = osName(); const os = osName();
const ext = extName(); const ext = extName();
const url = `https://storage.googleapis.com/flutter_infra/releases/${channel}/${os}/flutter_${os}_v${version}-${channel}.${ext}`; const url = `${storageUrl}/${channel}/${os}/flutter_${os}_v${version}-${channel}.${ext}`;
return { return {
version, version,
url url
@@ -116,49 +117,44 @@ function extractFile(file, destDir) {
throw new Error(`Failed to extract ${file} - it is a directory`); throw new Error(`Failed to extract ${file} - it is a directory`);
} }
if ('tar.xz' === extName()) { if ('tar.xz' === extName()) {
yield extractTarXz(file, destDir); yield tc.extractTar(file, destDir, 'x');
} }
else { else {
if (IS_DARWIN) { yield tc.extractZip(file, destDir);
yield extractZipDarwin(file, destDir);
}
else {
yield tc.extractZip(file, destDir);
}
} }
}); });
} }
/** function determineVersion(version, channel) {
* Extract a tar.xz
*
* @param file path to the tar.xz
* @param dest destination directory. Optional.
* @returns path to the destination directory
*/
function extractTarXz(file, dest) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
if (!file) { if (version.endsWith('.x') || version === '') {
throw new Error("parameter 'file' is required"); return yield getLatestVersion(version, channel);
} }
dest = dest || (yield _createExtractFolder(dest)); return version;
const tarPath = yield io.which('tar', true);
yield exec_1.exec(`"${tarPath}"`, ['xC', dest, '-f', file]);
return dest;
}); });
} }
exports.extractTarXz = extractTarXz; function getLatestVersion(version, channel) {
function _createExtractFolder(dest) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
if (!dest) { const releasesUrl = `${storageUrl}/releases_${osName()}.json`;
dest = path.join(tempDirectory, v4_1.default()); const rest = new restm.RestClient('flutter-action');
const storage = (yield rest.get(releasesUrl)).result;
if (!storage) {
throw new Error('unable to get latest version');
} }
yield io.mkdirP(dest); if (version.endsWith('.x')) {
return dest; const sver = version.slice(0, version.length - 2);
}); const releases = storage.releases.filter(release => release.version.startsWith(`v${sver}`) && release.channel === channel);
} const versions = releases.map(release => release.version.slice(1, release.version.length));
function extractZipDarwin(file, dest) { const sortedVersions = versions.sort(semver.rcompare);
return __awaiter(this, void 0, void 0, function* () { core.debug(`latest version of ${version} from channel ${channel} is ${sortedVersions[0]}`);
const unzipPath = path.join(__dirname, '..', 'scripts', 'externals', 'unzip-darwin'); return sortedVersions[0];
yield exec_1.exec(`"${unzipPath}"`, [file], { cwd: dest }); }
const channelVersion = storage.releases.find(release => release.hash === storage.current_release[channel]);
if (!channelVersion) {
throw new Error(`unable to get latest version from channel ${channel}`);
}
let cver = channelVersion.version;
cver = cver.slice(1, cver.length);
core.debug(`latest version from channel ${channel} is ${cver}`);
return cver;
}); });
} }

View File

@@ -1,7 +0,0 @@
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,82 +1,82 @@
# `@actions/tool-cache` # `@actions/tool-cache`
> Functions necessary for downloading and caching tools. > Functions necessary for downloading and caching tools.
## Usage ## Usage
#### Download #### Download
You can use this to download tools (or other files) from a download URL: You can use this to download tools (or other files) from a download URL:
``` ```js
const tc = require('@actions/tool-cache'); const tc = require('@actions/tool-cache');
const node12Path = await tc.downloadTool('http://nodejs.org/dist/v12.7.0/node-v12.7.0-linux-x64.tar.gz'); const node12Path = await tc.downloadTool('http://nodejs.org/dist/v12.7.0/node-v12.7.0-linux-x64.tar.gz');
``` ```
#### Extract #### Extract
These can then be extracted in platform specific ways: These can then be extracted in platform specific ways:
``` ```js
const tc = require('@actions/tool-cache'); const tc = require('@actions/tool-cache');
if (process.platform === 'win32') { if (process.platform === 'win32') {
tc.downloadTool('http://nodejs.org/dist/v12.7.0/node-v12.7.0-win-x64.zip'); tc.downloadTool('http://nodejs.org/dist/v12.7.0/node-v12.7.0-win-x64.zip');
const node12ExtractedFolder = await tc.extractZip(node12Path, 'path/to/extract/to'); const node12ExtractedFolder = await tc.extractZip(node12Path, 'path/to/extract/to');
// Or alternately // Or alternately
tc.downloadTool('http://nodejs.org/dist/v12.7.0/node-v12.7.0-win-x64.7z'); tc.downloadTool('http://nodejs.org/dist/v12.7.0/node-v12.7.0-win-x64.7z');
const node12ExtractedFolder = await tc.extract7z(node12Path, 'path/to/extract/to'); const node12ExtractedFolder = await tc.extract7z(node12Path, 'path/to/extract/to');
} }
else { else {
const node12Path = await tc.downloadTool('http://nodejs.org/dist/v12.7.0/node-v12.7.0-linux-x64.tar.gz'); const node12Path = await tc.downloadTool('http://nodejs.org/dist/v12.7.0/node-v12.7.0-linux-x64.tar.gz');
const node12ExtractedFolder = await tc.extractTar(node12Path, 'path/to/extract/to'); const node12ExtractedFolder = await tc.extractTar(node12Path, 'path/to/extract/to');
} }
``` ```
#### Cache #### Cache
Finally, you can cache these directories in our tool-cache. This is useful if you want to switch back and forth between versions of a tool, or save a tool between runs for private runners (private runners are still in development but are on the roadmap). Finally, you can cache these directories in our tool-cache. This is useful if you want to switch back and forth between versions of a tool, or save a tool between runs for private runners (private runners are still in development but are on the roadmap).
You'll often want to add it to the path as part of this step: You'll often want to add it to the path as part of this step:
``` ```js
const tc = require('@actions/tool-cache'); const tc = require('@actions/tool-cache');
const core = require('@actions/core'); const core = require('@actions/core');
const node12Path = await tc.downloadTool('http://nodejs.org/dist/v12.7.0/node-v12.7.0-linux-x64.tar.gz'); const node12Path = await tc.downloadTool('http://nodejs.org/dist/v12.7.0/node-v12.7.0-linux-x64.tar.gz');
const node12ExtractedFolder = await tc.extractTar(node12Path, 'path/to/extract/to'); const node12ExtractedFolder = await tc.extractTar(node12Path, 'path/to/extract/to');
const cachedPath = await tc.cacheDir(node12ExtractedFolder, 'node', '12.7.0'); const cachedPath = await tc.cacheDir(node12ExtractedFolder, 'node', '12.7.0');
core.addPath(cachedPath); core.addPath(cachedPath);
``` ```
You can also cache files for reuse. You can also cache files for reuse.
``` ```js
const tc = require('@actions/tool-cache'); const tc = require('@actions/tool-cache');
tc.cacheFile('path/to/exe', 'destFileName.exe', 'myExeName', '1.1.0'); tc.cacheFile('path/to/exe', 'destFileName.exe', 'myExeName', '1.1.0');
``` ```
#### Find #### Find
Finally, you can find directories and files you've previously cached: Finally, you can find directories and files you've previously cached:
``` ```js
const tc = require('@actions/tool-cache'); const tc = require('@actions/tool-cache');
const core = require('@actions/core'); const core = require('@actions/core');
const nodeDirectory = tc.find('node', '12.x', 'x64'); const nodeDirectory = tc.find('node', '12.x', 'x64');
core.addPath(nodeDirectory); core.addPath(nodeDirectory);
``` ```
You can even find all cached versions of a tool: You can even find all cached versions of a tool:
``` ```js
const tc = require('@actions/tool-cache'); const tc = require('@actions/tool-cache');
const allNodeVersions = tc.findAllVersions('node'); const allNodeVersions = tc.findAllVersions('node');
console.log(`Versions of node available: ${allNodeVersions}`); console.log(`Versions of node available: ${allNodeVersions}`);
``` ```

View File

@@ -1,78 +1,79 @@
export declare class HTTPError extends Error { export declare class HTTPError extends Error {
readonly httpStatusCode: number | undefined; readonly httpStatusCode: number | undefined;
constructor(httpStatusCode: number | undefined); constructor(httpStatusCode: number | undefined);
} }
/** /**
* Download a tool from an url and stream it into a file * Download a tool from an url and stream it into a file
* *
* @param url url of tool to download * @param url url of tool to download
* @returns path to downloaded tool * @returns path to downloaded tool
*/ */
export declare function downloadTool(url: string): Promise<string>; export declare function downloadTool(url: string): Promise<string>;
/** /**
* Extract a .7z file * Extract a .7z file
* *
* @param file path to the .7z file * @param file path to the .7z file
* @param dest destination directory. Optional. * @param dest destination directory. Optional.
* @param _7zPath path to 7zr.exe. Optional, for long path support. Most .7z archives do not have this * @param _7zPath path to 7zr.exe. Optional, for long path support. Most .7z archives do not have this
* problem. If your .7z archive contains very long paths, you can pass the path to 7zr.exe which will * problem. If your .7z archive contains very long paths, you can pass the path to 7zr.exe which will
* gracefully handle long paths. By default 7zdec.exe is used because it is a very small program and is * gracefully handle long paths. By default 7zdec.exe is used because it is a very small program and is
* bundled with the tool lib. However it does not support long paths. 7zr.exe is the reduced command line * bundled with the tool lib. However it does not support long paths. 7zr.exe is the reduced command line
* interface, it is smaller than the full command line interface, and it does support long paths. At the * interface, it is smaller than the full command line interface, and it does support long paths. At the
* time of this writing, it is freely available from the LZMA SDK that is available on the 7zip website. * time of this writing, it is freely available from the LZMA SDK that is available on the 7zip website.
* Be sure to check the current license agreement. If 7zr.exe is bundled with your action, then the path * Be sure to check the current license agreement. If 7zr.exe is bundled with your action, then the path
* to 7zr.exe can be pass to this function. * to 7zr.exe can be pass to this function.
* @returns path to the destination directory * @returns path to the destination directory
*/ */
export declare function extract7z(file: string, dest?: string, _7zPath?: string): Promise<string>; export declare function extract7z(file: string, dest?: string, _7zPath?: string): Promise<string>;
/** /**
* Extract a tar * Extract a tar
* *
* @param file path to the tar * @param file path to the tar
* @param dest destination directory. Optional. * @param dest destination directory. Optional.
* @returns path to the destination directory * @param flags flags for the tar. Optional.
*/ * @returns path to the destination directory
export declare function extractTar(file: string, dest?: string): Promise<string>; */
/** export declare function extractTar(file: string, dest?: string, flags?: string): Promise<string>;
* Extract a zip /**
* * Extract a zip
* @param file path to the zip *
* @param dest destination directory. Optional. * @param file path to the zip
* @returns path to the destination directory * @param dest destination directory. Optional.
*/ * @returns path to the destination directory
export declare function extractZip(file: string, dest?: string): Promise<string>; */
/** export declare function extractZip(file: string, dest?: string): Promise<string>;
* Caches a directory and installs it into the tool cacheDir /**
* * Caches a directory and installs it into the tool cacheDir
* @param sourceDir the directory to cache into tools *
* @param tool tool name * @param sourceDir the directory to cache into tools
* @param version version of the tool. semver format * @param tool tool name
* @param arch architecture of the tool. Optional. Defaults to machine architecture * @param version version of the tool. semver format
*/ * @param arch architecture of the tool. Optional. Defaults to machine architecture
export declare function cacheDir(sourceDir: string, tool: string, version: string, arch?: string): Promise<string>; */
/** export declare function cacheDir(sourceDir: string, tool: string, version: string, arch?: string): Promise<string>;
* Caches a downloaded file (GUID) and installs it /**
* into the tool cache with a given targetName * Caches a downloaded file (GUID) and installs it
* * into the tool cache with a given targetName
* @param sourceFile the file to cache into tools. Typically a result of downloadTool which is a guid. *
* @param targetFile the name of the file name in the tools directory * @param sourceFile the file to cache into tools. Typically a result of downloadTool which is a guid.
* @param tool tool name * @param targetFile the name of the file name in the tools directory
* @param version version of the tool. semver format * @param tool tool name
* @param arch architecture of the tool. Optional. Defaults to machine architecture * @param version version of the tool. semver format
*/ * @param arch architecture of the tool. Optional. Defaults to machine architecture
export declare function cacheFile(sourceFile: string, targetFile: string, tool: string, version: string, arch?: string): Promise<string>; */
/** export declare function cacheFile(sourceFile: string, targetFile: string, tool: string, version: string, arch?: string): Promise<string>;
* Finds the path to a tool version in the local installed tool cache /**
* * Finds the path to a tool version in the local installed tool cache
* @param toolName name of the tool *
* @param versionSpec version of the tool * @param toolName name of the tool
* @param arch optional arch. defaults to arch of computer * @param versionSpec version of the tool
*/ * @param arch optional arch. defaults to arch of computer
export declare function find(toolName: string, versionSpec: string, arch?: string): string; */
/** export declare function find(toolName: string, versionSpec: string, arch?: string): string;
* Finds the paths to all versions of a tool that are installed in the local tool cache /**
* * Finds the paths to all versions of a tool that are installed in the local tool cache
* @param toolName name of the tool *
* @param arch optional arch. defaults to arch of computer * @param toolName name of the tool
*/ * @param arch optional arch. defaults to arch of computer
export declare function findAllVersions(toolName: string, arch?: string): string[]; */
export declare function findAllVersions(toolName: string, arch?: string): string[];

View File

@@ -1,436 +1,448 @@
"use strict"; "use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) { return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next()); step((generator = generator.apply(thisArg, _arguments || [])).next());
}); });
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const core = require("@actions/core"); const core = require("@actions/core");
const io = require("@actions/io"); const io = require("@actions/io");
const fs = require("fs"); const fs = require("fs");
const os = require("os"); const os = require("os");
const path = require("path"); const path = require("path");
const httpm = require("typed-rest-client/HttpClient"); const httpm = require("typed-rest-client/HttpClient");
const semver = require("semver"); const semver = require("semver");
const uuidV4 = require("uuid/v4"); const uuidV4 = require("uuid/v4");
const exec_1 = require("@actions/exec/lib/exec"); const exec_1 = require("@actions/exec/lib/exec");
const assert_1 = require("assert"); const assert_1 = require("assert");
class HTTPError extends Error { class HTTPError extends Error {
constructor(httpStatusCode) { constructor(httpStatusCode) {
super(`Unexpected HTTP response: ${httpStatusCode}`); super(`Unexpected HTTP response: ${httpStatusCode}`);
this.httpStatusCode = httpStatusCode; this.httpStatusCode = httpStatusCode;
Object.setPrototypeOf(this, new.target.prototype); Object.setPrototypeOf(this, new.target.prototype);
} }
} }
exports.HTTPError = HTTPError; exports.HTTPError = HTTPError;
const IS_WINDOWS = process.platform === 'win32'; const IS_WINDOWS = process.platform === 'win32';
const userAgent = 'actions/tool-cache'; const userAgent = 'actions/tool-cache';
// On load grab temp directory and cache directory and remove them from env (currently don't want to expose this) // On load grab temp directory and cache directory and remove them from env (currently don't want to expose this)
let tempDirectory = process.env['RUNNER_TEMP'] || ''; let tempDirectory = process.env['RUNNER_TEMP'] || '';
let cacheRoot = process.env['RUNNER_TOOL_CACHE'] || ''; let cacheRoot = process.env['RUNNER_TOOL_CACHE'] || '';
// If directories not found, place them in common temp locations // If directories not found, place them in common temp locations
if (!tempDirectory || !cacheRoot) { if (!tempDirectory || !cacheRoot) {
let baseLocation; let baseLocation;
if (IS_WINDOWS) { if (IS_WINDOWS) {
// On windows use the USERPROFILE env variable // On windows use the USERPROFILE env variable
baseLocation = process.env['USERPROFILE'] || 'C:\\'; baseLocation = process.env['USERPROFILE'] || 'C:\\';
} }
else { else {
if (process.platform === 'darwin') { if (process.platform === 'darwin') {
baseLocation = '/Users'; baseLocation = '/Users';
} }
else { else {
baseLocation = '/home'; baseLocation = '/home';
} }
} }
if (!tempDirectory) { if (!tempDirectory) {
tempDirectory = path.join(baseLocation, 'actions', 'temp'); tempDirectory = path.join(baseLocation, 'actions', 'temp');
} }
if (!cacheRoot) { if (!cacheRoot) {
cacheRoot = path.join(baseLocation, 'actions', 'cache'); cacheRoot = path.join(baseLocation, 'actions', 'cache');
} }
} }
/** /**
* Download a tool from an url and stream it into a file * Download a tool from an url and stream it into a file
* *
* @param url url of tool to download * @param url url of tool to download
* @returns path to downloaded tool * @returns path to downloaded tool
*/ */
function downloadTool(url) { function downloadTool(url) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
// Wrap in a promise so that we can resolve from within stream callbacks // Wrap in a promise so that we can resolve from within stream callbacks
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
try { try {
const http = new httpm.HttpClient(userAgent, [], { const http = new httpm.HttpClient(userAgent, [], {
allowRetries: true, allowRetries: true,
maxRetries: 3 maxRetries: 3
}); });
const destPath = path.join(tempDirectory, uuidV4()); const destPath = path.join(tempDirectory, uuidV4());
yield io.mkdirP(tempDirectory); yield io.mkdirP(tempDirectory);
core.debug(`Downloading ${url}`); core.debug(`Downloading ${url}`);
core.debug(`Downloading ${destPath}`); core.debug(`Downloading ${destPath}`);
if (fs.existsSync(destPath)) { if (fs.existsSync(destPath)) {
throw new Error(`Destination file path ${destPath} already exists`); throw new Error(`Destination file path ${destPath} already exists`);
} }
const response = yield http.get(url); const response = yield http.get(url);
if (response.message.statusCode !== 200) { if (response.message.statusCode !== 200) {
const err = new HTTPError(response.message.statusCode); const err = new HTTPError(response.message.statusCode);
core.debug(`Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`); core.debug(`Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`);
throw err; throw err;
} }
const file = fs.createWriteStream(destPath); const file = fs.createWriteStream(destPath);
file.on('open', () => __awaiter(this, void 0, void 0, function* () { file.on('open', () => __awaiter(this, void 0, void 0, function* () {
try { try {
const stream = response.message.pipe(file); const stream = response.message.pipe(file);
stream.on('close', () => { stream.on('close', () => {
core.debug('download complete'); core.debug('download complete');
resolve(destPath); resolve(destPath);
}); });
} }
catch (err) { catch (err) {
core.debug(`Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`); core.debug(`Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`);
reject(err); reject(err);
} }
})); }));
file.on('error', err => { file.on('error', err => {
file.end(); file.end();
reject(err); reject(err);
}); });
} }
catch (err) { catch (err) {
reject(err); reject(err);
} }
})); }));
}); });
} }
exports.downloadTool = downloadTool; exports.downloadTool = downloadTool;
/** /**
* Extract a .7z file * Extract a .7z file
* *
* @param file path to the .7z file * @param file path to the .7z file
* @param dest destination directory. Optional. * @param dest destination directory. Optional.
* @param _7zPath path to 7zr.exe. Optional, for long path support. Most .7z archives do not have this * @param _7zPath path to 7zr.exe. Optional, for long path support. Most .7z archives do not have this
* problem. If your .7z archive contains very long paths, you can pass the path to 7zr.exe which will * problem. If your .7z archive contains very long paths, you can pass the path to 7zr.exe which will
* gracefully handle long paths. By default 7zdec.exe is used because it is a very small program and is * gracefully handle long paths. By default 7zdec.exe is used because it is a very small program and is
* bundled with the tool lib. However it does not support long paths. 7zr.exe is the reduced command line * bundled with the tool lib. However it does not support long paths. 7zr.exe is the reduced command line
* interface, it is smaller than the full command line interface, and it does support long paths. At the * interface, it is smaller than the full command line interface, and it does support long paths. At the
* time of this writing, it is freely available from the LZMA SDK that is available on the 7zip website. * time of this writing, it is freely available from the LZMA SDK that is available on the 7zip website.
* Be sure to check the current license agreement. If 7zr.exe is bundled with your action, then the path * Be sure to check the current license agreement. If 7zr.exe is bundled with your action, then the path
* to 7zr.exe can be pass to this function. * to 7zr.exe can be pass to this function.
* @returns path to the destination directory * @returns path to the destination directory
*/ */
function extract7z(file, dest, _7zPath) { function extract7z(file, dest, _7zPath) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
assert_1.ok(IS_WINDOWS, 'extract7z() not supported on current OS'); assert_1.ok(IS_WINDOWS, 'extract7z() not supported on current OS');
assert_1.ok(file, 'parameter "file" is required'); assert_1.ok(file, 'parameter "file" is required');
dest = dest || (yield _createExtractFolder(dest)); dest = dest || (yield _createExtractFolder(dest));
const originalCwd = process.cwd(); const originalCwd = process.cwd();
process.chdir(dest); process.chdir(dest);
if (_7zPath) { if (_7zPath) {
try { try {
const args = [ const args = [
'x', 'x',
'-bb1', '-bb1',
'-bd', '-bd',
'-sccUTF-8', '-sccUTF-8',
file file
]; ];
const options = { const options = {
silent: true silent: true
}; };
yield exec_1.exec(`"${_7zPath}"`, args, options); yield exec_1.exec(`"${_7zPath}"`, args, options);
} }
finally { finally {
process.chdir(originalCwd); process.chdir(originalCwd);
} }
} }
else { else {
const escapedScript = path const escapedScript = path
.join(__dirname, '..', 'scripts', 'Invoke-7zdec.ps1') .join(__dirname, '..', 'scripts', 'Invoke-7zdec.ps1')
.replace(/'/g, "''") .replace(/'/g, "''")
.replace(/"|\n|\r/g, ''); // double-up single quotes, remove double quotes and newlines .replace(/"|\n|\r/g, ''); // double-up single quotes, remove double quotes and newlines
const escapedFile = file.replace(/'/g, "''").replace(/"|\n|\r/g, ''); const escapedFile = file.replace(/'/g, "''").replace(/"|\n|\r/g, '');
const escapedTarget = dest.replace(/'/g, "''").replace(/"|\n|\r/g, ''); const escapedTarget = dest.replace(/'/g, "''").replace(/"|\n|\r/g, '');
const command = `& '${escapedScript}' -Source '${escapedFile}' -Target '${escapedTarget}'`; const command = `& '${escapedScript}' -Source '${escapedFile}' -Target '${escapedTarget}'`;
const args = [ const args = [
'-NoLogo', '-NoLogo',
'-Sta', '-Sta',
'-NoProfile', '-NoProfile',
'-NonInteractive', '-NonInteractive',
'-ExecutionPolicy', '-ExecutionPolicy',
'Unrestricted', 'Unrestricted',
'-Command', '-Command',
command command
]; ];
const options = { const options = {
silent: true silent: true
}; };
try { try {
const powershellPath = yield io.which('powershell', true); const powershellPath = yield io.which('powershell', true);
yield exec_1.exec(`"${powershellPath}"`, args, options); yield exec_1.exec(`"${powershellPath}"`, args, options);
} }
finally { finally {
process.chdir(originalCwd); process.chdir(originalCwd);
} }
} }
return dest; return dest;
}); });
} }
exports.extract7z = extract7z; exports.extract7z = extract7z;
/** /**
* Extract a tar * Extract a tar
* *
* @param file path to the tar * @param file path to the tar
* @param dest destination directory. Optional. * @param dest destination directory. Optional.
* @returns path to the destination directory * @param flags flags for the tar. Optional.
*/ * @returns path to the destination directory
function extractTar(file, dest) { */
return __awaiter(this, void 0, void 0, function* () { function extractTar(file, dest, flags = 'xz') {
if (!file) { return __awaiter(this, void 0, void 0, function* () {
throw new Error("parameter 'file' is required"); if (!file) {
} throw new Error("parameter 'file' is required");
dest = dest || (yield _createExtractFolder(dest)); }
const tarPath = yield io.which('tar', true); dest = dest || (yield _createExtractFolder(dest));
yield exec_1.exec(`"${tarPath}"`, ['xzC', dest, '-f', file]); const tarPath = yield io.which('tar', true);
return dest; yield exec_1.exec(`"${tarPath}"`, [flags, '-C', dest, '-f', file]);
}); return dest;
} });
exports.extractTar = extractTar; }
/** exports.extractTar = extractTar;
* Extract a zip /**
* * Extract a zip
* @param file path to the zip *
* @param dest destination directory. Optional. * @param file path to the zip
* @returns path to the destination directory * @param dest destination directory. Optional.
*/ * @returns path to the destination directory
function extractZip(file, dest) { */
return __awaiter(this, void 0, void 0, function* () { function extractZip(file, dest) {
if (!file) { return __awaiter(this, void 0, void 0, function* () {
throw new Error("parameter 'file' is required"); if (!file) {
} throw new Error("parameter 'file' is required");
dest = dest || (yield _createExtractFolder(dest)); }
if (IS_WINDOWS) { dest = dest || (yield _createExtractFolder(dest));
yield extractZipWin(file, dest); if (IS_WINDOWS) {
} yield extractZipWin(file, dest);
else { }
yield extractZipNix(file, dest); else {
} if (process.platform === 'darwin') {
return dest; yield extractZipDarwin(file, dest);
}); }
} else {
exports.extractZip = extractZip; yield extractZipNix(file, dest);
function extractZipWin(file, dest) { }
return __awaiter(this, void 0, void 0, function* () { }
// build the powershell command return dest;
const escapedFile = file.replace(/'/g, "''").replace(/"|\n|\r/g, ''); // double-up single quotes, remove double quotes and newlines });
const escapedDest = dest.replace(/'/g, "''").replace(/"|\n|\r/g, ''); }
const command = `$ErrorActionPreference = 'Stop' ; try { Add-Type -AssemblyName System.IO.Compression.FileSystem } catch { } ; [System.IO.Compression.ZipFile]::ExtractToDirectory('${escapedFile}', '${escapedDest}')`; exports.extractZip = extractZip;
// run powershell function extractZipWin(file, dest) {
const powershellPath = yield io.which('powershell'); return __awaiter(this, void 0, void 0, function* () {
const args = [ // build the powershell command
'-NoLogo', const escapedFile = file.replace(/'/g, "''").replace(/"|\n|\r/g, ''); // double-up single quotes, remove double quotes and newlines
'-Sta', const escapedDest = dest.replace(/'/g, "''").replace(/"|\n|\r/g, '');
'-NoProfile', const command = `$ErrorActionPreference = 'Stop' ; try { Add-Type -AssemblyName System.IO.Compression.FileSystem } catch { } ; [System.IO.Compression.ZipFile]::ExtractToDirectory('${escapedFile}', '${escapedDest}')`;
'-NonInteractive', // run powershell
'-ExecutionPolicy', const powershellPath = yield io.which('powershell');
'Unrestricted', const args = [
'-Command', '-NoLogo',
command '-Sta',
]; '-NoProfile',
yield exec_1.exec(`"${powershellPath}"`, args); '-NonInteractive',
}); '-ExecutionPolicy',
} 'Unrestricted',
function extractZipNix(file, dest) { '-Command',
return __awaiter(this, void 0, void 0, function* () { command
const unzipPath = path.join(__dirname, '..', 'scripts', 'externals', 'unzip'); ];
yield exec_1.exec(`"${unzipPath}"`, [file], { cwd: dest }); yield exec_1.exec(`"${powershellPath}"`, args);
}); });
} }
/** function extractZipNix(file, dest) {
* Caches a directory and installs it into the tool cacheDir return __awaiter(this, void 0, void 0, function* () {
* const unzipPath = path.join(__dirname, '..', 'scripts', 'externals', 'unzip');
* @param sourceDir the directory to cache into tools yield exec_1.exec(`"${unzipPath}"`, [file], { cwd: dest });
* @param tool tool name });
* @param version version of the tool. semver format }
* @param arch architecture of the tool. Optional. Defaults to machine architecture function extractZipDarwin(file, dest) {
*/ return __awaiter(this, void 0, void 0, function* () {
function cacheDir(sourceDir, tool, version, arch) { const unzipPath = path.join(__dirname, '..', 'scripts', 'externals', 'unzip-darwin');
return __awaiter(this, void 0, void 0, function* () { yield exec_1.exec(`"${unzipPath}"`, [file], { cwd: dest });
version = semver.clean(version) || version; });
arch = arch || os.arch(); }
core.debug(`Caching tool ${tool} ${version} ${arch}`); /**
core.debug(`source dir: ${sourceDir}`); * Caches a directory and installs it into the tool cacheDir
if (!fs.statSync(sourceDir).isDirectory()) { *
throw new Error('sourceDir is not a directory'); * @param sourceDir the directory to cache into tools
} * @param tool tool name
// Create the tool dir * @param version version of the tool. semver format
const destPath = yield _createToolPath(tool, version, arch); * @param arch architecture of the tool. Optional. Defaults to machine architecture
// copy each child item. do not move. move can fail on Windows */
// due to anti-virus software having an open handle on a file. function cacheDir(sourceDir, tool, version, arch) {
for (const itemName of fs.readdirSync(sourceDir)) { return __awaiter(this, void 0, void 0, function* () {
const s = path.join(sourceDir, itemName); version = semver.clean(version) || version;
yield io.cp(s, destPath, { recursive: true }); arch = arch || os.arch();
} core.debug(`Caching tool ${tool} ${version} ${arch}`);
// write .complete core.debug(`source dir: ${sourceDir}`);
_completeToolPath(tool, version, arch); if (!fs.statSync(sourceDir).isDirectory()) {
return destPath; throw new Error('sourceDir is not a directory');
}); }
} // Create the tool dir
exports.cacheDir = cacheDir; const destPath = yield _createToolPath(tool, version, arch);
/** // copy each child item. do not move. move can fail on Windows
* Caches a downloaded file (GUID) and installs it // due to anti-virus software having an open handle on a file.
* into the tool cache with a given targetName for (const itemName of fs.readdirSync(sourceDir)) {
* const s = path.join(sourceDir, itemName);
* @param sourceFile the file to cache into tools. Typically a result of downloadTool which is a guid. yield io.cp(s, destPath, { recursive: true });
* @param targetFile the name of the file name in the tools directory }
* @param tool tool name // write .complete
* @param version version of the tool. semver format _completeToolPath(tool, version, arch);
* @param arch architecture of the tool. Optional. Defaults to machine architecture return destPath;
*/ });
function cacheFile(sourceFile, targetFile, tool, version, arch) { }
return __awaiter(this, void 0, void 0, function* () { exports.cacheDir = cacheDir;
version = semver.clean(version) || version; /**
arch = arch || os.arch(); * Caches a downloaded file (GUID) and installs it
core.debug(`Caching tool ${tool} ${version} ${arch}`); * into the tool cache with a given targetName
core.debug(`source file: ${sourceFile}`); *
if (!fs.statSync(sourceFile).isFile()) { * @param sourceFile the file to cache into tools. Typically a result of downloadTool which is a guid.
throw new Error('sourceFile is not a file'); * @param targetFile the name of the file name in the tools directory
} * @param tool tool name
// create the tool dir * @param version version of the tool. semver format
const destFolder = yield _createToolPath(tool, version, arch); * @param arch architecture of the tool. Optional. Defaults to machine architecture
// copy instead of move. move can fail on Windows due to */
// anti-virus software having an open handle on a file. function cacheFile(sourceFile, targetFile, tool, version, arch) {
const destPath = path.join(destFolder, targetFile); return __awaiter(this, void 0, void 0, function* () {
core.debug(`destination file ${destPath}`); version = semver.clean(version) || version;
yield io.cp(sourceFile, destPath); arch = arch || os.arch();
// write .complete core.debug(`Caching tool ${tool} ${version} ${arch}`);
_completeToolPath(tool, version, arch); core.debug(`source file: ${sourceFile}`);
return destFolder; if (!fs.statSync(sourceFile).isFile()) {
}); throw new Error('sourceFile is not a file');
} }
exports.cacheFile = cacheFile; // create the tool dir
/** const destFolder = yield _createToolPath(tool, version, arch);
* Finds the path to a tool version in the local installed tool cache // copy instead of move. move can fail on Windows due to
* // anti-virus software having an open handle on a file.
* @param toolName name of the tool const destPath = path.join(destFolder, targetFile);
* @param versionSpec version of the tool core.debug(`destination file ${destPath}`);
* @param arch optional arch. defaults to arch of computer yield io.cp(sourceFile, destPath);
*/ // write .complete
function find(toolName, versionSpec, arch) { _completeToolPath(tool, version, arch);
if (!toolName) { return destFolder;
throw new Error('toolName parameter is required'); });
} }
if (!versionSpec) { exports.cacheFile = cacheFile;
throw new Error('versionSpec parameter is required'); /**
} * Finds the path to a tool version in the local installed tool cache
arch = arch || os.arch(); *
// attempt to resolve an explicit version * @param toolName name of the tool
if (!_isExplicitVersion(versionSpec)) { * @param versionSpec version of the tool
const localVersions = findAllVersions(toolName, arch); * @param arch optional arch. defaults to arch of computer
const match = _evaluateVersions(localVersions, versionSpec); */
versionSpec = match; function find(toolName, versionSpec, arch) {
} if (!toolName) {
// check for the explicit version in the cache throw new Error('toolName parameter is required');
let toolPath = ''; }
if (versionSpec) { if (!versionSpec) {
versionSpec = semver.clean(versionSpec) || ''; throw new Error('versionSpec parameter is required');
const cachePath = path.join(cacheRoot, toolName, versionSpec, arch); }
core.debug(`checking cache: ${cachePath}`); arch = arch || os.arch();
if (fs.existsSync(cachePath) && fs.existsSync(`${cachePath}.complete`)) { // attempt to resolve an explicit version
core.debug(`Found tool in cache ${toolName} ${versionSpec} ${arch}`); if (!_isExplicitVersion(versionSpec)) {
toolPath = cachePath; const localVersions = findAllVersions(toolName, arch);
} const match = _evaluateVersions(localVersions, versionSpec);
else { versionSpec = match;
core.debug('not found'); }
} // check for the explicit version in the cache
} let toolPath = '';
return toolPath; if (versionSpec) {
} versionSpec = semver.clean(versionSpec) || '';
exports.find = find; const cachePath = path.join(cacheRoot, toolName, versionSpec, arch);
/** core.debug(`checking cache: ${cachePath}`);
* Finds the paths to all versions of a tool that are installed in the local tool cache if (fs.existsSync(cachePath) && fs.existsSync(`${cachePath}.complete`)) {
* core.debug(`Found tool in cache ${toolName} ${versionSpec} ${arch}`);
* @param toolName name of the tool toolPath = cachePath;
* @param arch optional arch. defaults to arch of computer }
*/ else {
function findAllVersions(toolName, arch) { core.debug('not found');
const versions = []; }
arch = arch || os.arch(); }
const toolPath = path.join(cacheRoot, toolName); return toolPath;
if (fs.existsSync(toolPath)) { }
const children = fs.readdirSync(toolPath); exports.find = find;
for (const child of children) { /**
if (_isExplicitVersion(child)) { * Finds the paths to all versions of a tool that are installed in the local tool cache
const fullPath = path.join(toolPath, child, arch || ''); *
if (fs.existsSync(fullPath) && fs.existsSync(`${fullPath}.complete`)) { * @param toolName name of the tool
versions.push(child); * @param arch optional arch. defaults to arch of computer
} */
} function findAllVersions(toolName, arch) {
} const versions = [];
} arch = arch || os.arch();
return versions; const toolPath = path.join(cacheRoot, toolName);
} if (fs.existsSync(toolPath)) {
exports.findAllVersions = findAllVersions; const children = fs.readdirSync(toolPath);
function _createExtractFolder(dest) { for (const child of children) {
return __awaiter(this, void 0, void 0, function* () { if (_isExplicitVersion(child)) {
if (!dest) { const fullPath = path.join(toolPath, child, arch || '');
// create a temp dir if (fs.existsSync(fullPath) && fs.existsSync(`${fullPath}.complete`)) {
dest = path.join(tempDirectory, uuidV4()); versions.push(child);
} }
yield io.mkdirP(dest); }
return dest; }
}); }
} return versions;
function _createToolPath(tool, version, arch) { }
return __awaiter(this, void 0, void 0, function* () { exports.findAllVersions = findAllVersions;
const folderPath = path.join(cacheRoot, tool, semver.clean(version) || version, arch || ''); function _createExtractFolder(dest) {
core.debug(`destination ${folderPath}`); return __awaiter(this, void 0, void 0, function* () {
const markerPath = `${folderPath}.complete`; if (!dest) {
yield io.rmRF(folderPath); // create a temp dir
yield io.rmRF(markerPath); dest = path.join(tempDirectory, uuidV4());
yield io.mkdirP(folderPath); }
return folderPath; yield io.mkdirP(dest);
}); return dest;
} });
function _completeToolPath(tool, version, arch) { }
const folderPath = path.join(cacheRoot, tool, semver.clean(version) || version, arch || ''); function _createToolPath(tool, version, arch) {
const markerPath = `${folderPath}.complete`; return __awaiter(this, void 0, void 0, function* () {
fs.writeFileSync(markerPath, ''); const folderPath = path.join(cacheRoot, tool, semver.clean(version) || version, arch || '');
core.debug('finished caching tool'); core.debug(`destination ${folderPath}`);
} const markerPath = `${folderPath}.complete`;
function _isExplicitVersion(versionSpec) { yield io.rmRF(folderPath);
const c = semver.clean(versionSpec) || ''; yield io.rmRF(markerPath);
core.debug(`isExplicit: ${c}`); yield io.mkdirP(folderPath);
const valid = semver.valid(c) != null; return folderPath;
core.debug(`explicit? ${valid}`); });
return valid; }
} function _completeToolPath(tool, version, arch) {
function _evaluateVersions(versions, versionSpec) { const folderPath = path.join(cacheRoot, tool, semver.clean(version) || version, arch || '');
let version = ''; const markerPath = `${folderPath}.complete`;
core.debug(`evaluating ${versions.length} versions`); fs.writeFileSync(markerPath, '');
versions = versions.sort((a, b) => { core.debug('finished caching tool');
if (semver.gt(a, b)) { }
return 1; function _isExplicitVersion(versionSpec) {
} const c = semver.clean(versionSpec) || '';
return -1; core.debug(`isExplicit: ${c}`);
}); const valid = semver.valid(c) != null;
for (let i = versions.length - 1; i >= 0; i--) { core.debug(`explicit? ${valid}`);
const potential = versions[i]; return valid;
const satisfied = semver.satisfies(potential, versionSpec); }
if (satisfied) { function _evaluateVersions(versions, versionSpec) {
version = potential; let version = '';
break; core.debug(`evaluating ${versions.length} versions`);
} versions = versions.sort((a, b) => {
} if (semver.gt(a, b)) {
if (version) { return 1;
core.debug(`matched: ${version}`); }
} return -1;
else { });
core.debug('match not found'); for (let i = versions.length - 1; i >= 0; i--) {
} const potential = versions[i];
return version; const satisfied = semver.satisfies(potential, versionSpec);
} if (satisfied) {
version = potential;
break;
}
}
if (version) {
core.debug(`matched: ${version}`);
}
else {
core.debug('match not found');
}
return version;
}
//# sourceMappingURL=tool-cache.js.map //# sourceMappingURL=tool-cache.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,36 +1,32 @@
{ {
"_args": [ "_from": "@actions/tool-cache@^1.1.0",
[ "_id": "@actions/tool-cache@1.1.0",
"@actions/tool-cache@1.0.0",
"/Users/subosito/Code/playground/flutter-actions"
]
],
"_from": "@actions/tool-cache@1.0.0",
"_id": "@actions/tool-cache@1.0.0",
"_inBundle": false, "_inBundle": false,
"_integrity": "sha512-l3zT0IfDfi5Ik5aMpnXqGHGATxN8xa9ls4ue+X/CBXpPhRMRZS4vcuh5Q9T98WAGbkysRCfhpbksTPHIcKnNwQ==", "_integrity": "sha512-Oe/R1Gxv0G699OUL9ypxk9cTwHf1uXHhpcK7kpZt8d/Sbw915ktMkfxXt9+awOfLDwyl54sLi86KGCuSvnRuIQ==",
"_location": "/@actions/tool-cache", "_location": "/@actions/tool-cache",
"_phantomChildren": {}, "_phantomChildren": {},
"_requested": { "_requested": {
"type": "version", "type": "range",
"registry": true, "registry": true,
"raw": "@actions/tool-cache@1.0.0", "raw": "@actions/tool-cache@^1.1.0",
"name": "@actions/tool-cache", "name": "@actions/tool-cache",
"escapedName": "@actions%2ftool-cache", "escapedName": "@actions%2ftool-cache",
"scope": "@actions", "scope": "@actions",
"rawSpec": "1.0.0", "rawSpec": "^1.1.0",
"saveSpec": null, "saveSpec": null,
"fetchSpec": "1.0.0" "fetchSpec": "^1.1.0"
}, },
"_requiredBy": [ "_requiredBy": [
"/" "/"
], ],
"_resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.0.0.tgz", "_resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.1.0.tgz",
"_spec": "1.0.0", "_shasum": "1a0e29f244f2b5c6989fc264581068689f9c219e",
"_where": "/Users/subosito/Code/playground/flutter-actions", "_spec": "@actions/tool-cache@^1.1.0",
"_where": "/Users/subosito/Code/subosito/flutter-action",
"bugs": { "bugs": {
"url": "https://github.com/actions/toolkit/issues" "url": "https://github.com/actions/toolkit/issues"
}, },
"bundleDependencies": false,
"dependencies": { "dependencies": {
"@actions/core": "^1.0.0", "@actions/core": "^1.0.0",
"@actions/exec": "^1.0.0", "@actions/exec": "^1.0.0",
@@ -39,6 +35,7 @@
"typed-rest-client": "^1.4.0", "typed-rest-client": "^1.4.0",
"uuid": "^3.3.2" "uuid": "^3.3.2"
}, },
"deprecated": false,
"description": "Actions tool-cache lib", "description": "Actions tool-cache lib",
"devDependencies": { "devDependencies": {
"@types/nock": "^10.0.3", "@types/nock": "^10.0.3",
@@ -54,7 +51,6 @@
"lib", "lib",
"scripts" "scripts"
], ],
"gitHead": "a40bce7c8d382aa3dbadaa327acbc696e9390e55",
"homepage": "https://github.com/actions/toolkit/tree/master/packages/exec", "homepage": "https://github.com/actions/toolkit/tree/master/packages/exec",
"keywords": [ "keywords": [
"exec", "exec",
@@ -74,5 +70,5 @@
"test": "echo \"Error: run tests from root\" && exit 1", "test": "echo \"Error: run tests from root\" && exit 1",
"tsc": "tsc" "tsc": "tsc"
}, },
"version": "1.0.0" "version": "1.1.0"
} }

View File

@@ -1,60 +1,60 @@
[CmdletBinding()] [CmdletBinding()]
param( param(
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string]$Source, [string]$Source,
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string]$Target) [string]$Target)
# This script translates the output from 7zdec into UTF8. Node has limited # This script translates the output from 7zdec into UTF8. Node has limited
# built-in support for encodings. # built-in support for encodings.
# #
# 7zdec uses the system default code page. The system default code page varies # 7zdec uses the system default code page. The system default code page varies
# depending on the locale configuration. On an en-US box, the system default code # depending on the locale configuration. On an en-US box, the system default code
# page is Windows-1252. # page is Windows-1252.
# #
# Note, on a typical en-US box, testing with the 'ç' character is a good way to # Note, on a typical en-US box, testing with the 'ç' character is a good way to
# determine whether data is passed correctly between processes. This is because # determine whether data is passed correctly between processes. This is because
# the 'ç' character has a different code point across each of the common encodings # the 'ç' character has a different code point across each of the common encodings
# on a typical en-US box, i.e. # on a typical en-US box, i.e.
# 1) the default console-output code page (IBM437) # 1) the default console-output code page (IBM437)
# 2) the system default code page (i.e. CP_ACP) (Windows-1252) # 2) the system default code page (i.e. CP_ACP) (Windows-1252)
# 3) UTF8 # 3) UTF8
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
# Redefine the wrapper over STDOUT to use UTF8. Node expects UTF8 by default. # Redefine the wrapper over STDOUT to use UTF8. Node expects UTF8 by default.
$stdout = [System.Console]::OpenStandardOutput() $stdout = [System.Console]::OpenStandardOutput()
$utf8 = New-Object System.Text.UTF8Encoding($false) # do not emit BOM $utf8 = New-Object System.Text.UTF8Encoding($false) # do not emit BOM
$writer = New-Object System.IO.StreamWriter($stdout, $utf8) $writer = New-Object System.IO.StreamWriter($stdout, $utf8)
[System.Console]::SetOut($writer) [System.Console]::SetOut($writer)
# All subsequent output must be written using [System.Console]::WriteLine(). In # All subsequent output must be written using [System.Console]::WriteLine(). In
# PowerShell 4, Write-Host and Out-Default do not consider the updated stream writer. # PowerShell 4, Write-Host and Out-Default do not consider the updated stream writer.
Set-Location -LiteralPath $Target Set-Location -LiteralPath $Target
# Print the ##command. # Print the ##command.
$_7zdec = Join-Path -Path "$PSScriptRoot" -ChildPath "externals/7zdec.exe" $_7zdec = Join-Path -Path "$PSScriptRoot" -ChildPath "externals/7zdec.exe"
[System.Console]::WriteLine("##[command]$_7zdec x `"$Source`"") [System.Console]::WriteLine("##[command]$_7zdec x `"$Source`"")
# The $OutputEncoding variable instructs PowerShell how to interpret the output # The $OutputEncoding variable instructs PowerShell how to interpret the output
# from the external command. # from the external command.
$OutputEncoding = [System.Text.Encoding]::Default $OutputEncoding = [System.Text.Encoding]::Default
# Note, the output from 7zdec.exe needs to be iterated over. Otherwise PowerShell.exe # Note, the output from 7zdec.exe needs to be iterated over. Otherwise PowerShell.exe
# will launch the external command in such a way that it inherits the streams. # will launch the external command in such a way that it inherits the streams.
& $_7zdec x $Source 2>&1 | & $_7zdec x $Source 2>&1 |
ForEach-Object { ForEach-Object {
if ($_ -is [System.Management.Automation.ErrorRecord]) { if ($_ -is [System.Management.Automation.ErrorRecord]) {
[System.Console]::WriteLine($_.Exception.Message) [System.Console]::WriteLine($_.Exception.Message)
} }
else { else {
[System.Console]::WriteLine($_) [System.Console]::WriteLine($_)
} }
} }
[System.Console]::WriteLine("##[debug]7zdec.exe exit code '$LASTEXITCODE'") [System.Console]::WriteLine("##[debug]7zdec.exe exit code '$LASTEXITCODE'")
[System.Console]::Out.Flush() [System.Console]::Out.Flush()
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }

25
node_modules/semver/package.json generated vendored
View File

@@ -1,39 +1,38 @@
{ {
"_args": [ "_from": "semver",
[
"semver@6.3.0",
"/Users/subosito/Code/playground/flutter-actions"
]
],
"_from": "semver@6.3.0",
"_id": "semver@6.3.0", "_id": "semver@6.3.0",
"_inBundle": false, "_inBundle": false,
"_integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "_integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"_location": "/semver", "_location": "/semver",
"_phantomChildren": {}, "_phantomChildren": {},
"_requested": { "_requested": {
"type": "version", "type": "tag",
"registry": true, "registry": true,
"raw": "semver@6.3.0", "raw": "semver",
"name": "semver", "name": "semver",
"escapedName": "semver", "escapedName": "semver",
"rawSpec": "6.3.0", "rawSpec": "",
"saveSpec": null, "saveSpec": null,
"fetchSpec": "6.3.0" "fetchSpec": "latest"
}, },
"_requiredBy": [ "_requiredBy": [
"#USER",
"/",
"/@actions/tool-cache", "/@actions/tool-cache",
"/istanbul-lib-instrument" "/istanbul-lib-instrument"
], ],
"_resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "_resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"_spec": "6.3.0", "_shasum": "ee0a64c8af5e8ceea67687b133761e1becbd1d3d",
"_where": "/Users/subosito/Code/playground/flutter-actions", "_spec": "semver",
"_where": "/Users/subosito/Code/subosito/flutter-action",
"bin": { "bin": {
"semver": "./bin/semver.js" "semver": "./bin/semver.js"
}, },
"bugs": { "bugs": {
"url": "https://github.com/npm/node-semver/issues" "url": "https://github.com/npm/node-semver/issues"
}, },
"bundleDependencies": false,
"deprecated": false,
"description": "The semantic version parser used by npm.", "description": "The semantic version parser used by npm.",
"devDependencies": { "devDependencies": {
"tap": "^14.3.1" "tap": "^14.3.1"

122
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "flutter-action", "name": "flutter-action",
"version": "1.0.1", "version": "1.1.1",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -20,9 +20,9 @@
"integrity": "sha512-ezrJSRdqtXtdx1WXlfYL85+40F7gB39jCK9P0jZVODW3W6xUYmu6ZOEc/UmmElUwhRyDRm1R4yNZu1Joq2kuQg==" "integrity": "sha512-ezrJSRdqtXtdx1WXlfYL85+40F7gB39jCK9P0jZVODW3W6xUYmu6ZOEc/UmmElUwhRyDRm1R4yNZu1Joq2kuQg=="
}, },
"@actions/tool-cache": { "@actions/tool-cache": {
"version": "1.0.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.1.0.tgz",
"integrity": "sha512-l3zT0IfDfi5Ik5aMpnXqGHGATxN8xa9ls4ue+X/CBXpPhRMRZS4vcuh5Q9T98WAGbkysRCfhpbksTPHIcKnNwQ==", "integrity": "sha512-Oe/R1Gxv0G699OUL9ypxk9cTwHf1uXHhpcK7kpZt8d/Sbw915ktMkfxXt9+awOfLDwyl54sLi86KGCuSvnRuIQ==",
"requires": { "requires": {
"@actions/core": "^1.0.0", "@actions/core": "^1.0.0",
"@actions/exec": "^1.0.0", "@actions/exec": "^1.0.0",
@@ -530,6 +530,15 @@
"integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==",
"dev": true "dev": true
}, },
"@types/nock": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@types/nock/-/nock-10.0.3.tgz",
"integrity": "sha512-OthuN+2FuzfZO3yONJ/QVjKmLEuRagS9TV9lEId+WHL9KhftYG+/2z+pxlr0UgVVXSpVD8woie/3fzQn8ft/Ow==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/node": { "@types/node": {
"version": "12.6.8", "version": "12.6.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.6.8.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.6.8.tgz",
@@ -702,6 +711,12 @@
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true "dev": true
}, },
"assertion-error": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
"dev": true
},
"assign-symbols": { "assign-symbols": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
@@ -1052,6 +1067,20 @@
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
"dev": true "dev": true
}, },
"chai": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
"integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==",
"dev": true,
"requires": {
"assertion-error": "^1.1.0",
"check-error": "^1.0.2",
"deep-eql": "^3.0.1",
"get-func-name": "^2.0.0",
"pathval": "^1.1.0",
"type-detect": "^4.0.5"
}
},
"chalk": { "chalk": {
"version": "2.4.2", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@@ -1063,6 +1092,12 @@
"supports-color": "^5.3.0" "supports-color": "^5.3.0"
} }
}, },
"check-error": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
"dev": true
},
"ci-info": { "ci-info": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
@@ -1308,6 +1343,21 @@
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
"dev": true "dev": true
}, },
"deep-eql": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
"integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
"dev": true,
"requires": {
"type-detect": "^4.0.0"
}
},
"deep-equal": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
"integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
"dev": true
},
"deep-is": { "deep-is": {
"version": "0.1.3", "version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
@@ -2321,6 +2371,12 @@
"integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
"dev": true "dev": true
}, },
"get-func-name": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
"integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
"dev": true
},
"get-stdin": { "get-stdin": {
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz",
@@ -3817,6 +3873,46 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true "dev": true
}, },
"nock": {
"version": "10.0.6",
"resolved": "https://registry.npmjs.org/nock/-/nock-10.0.6.tgz",
"integrity": "sha512-b47OWj1qf/LqSQYnmokNWM8D88KvUl2y7jT0567NB3ZBAZFz2bWp2PC81Xn7u8F2/vJxzkzNZybnemeFa7AZ2w==",
"dev": true,
"requires": {
"chai": "^4.1.2",
"debug": "^4.1.0",
"deep-equal": "^1.0.0",
"json-stringify-safe": "^5.0.1",
"lodash": "^4.17.5",
"mkdirp": "^0.5.0",
"propagate": "^1.0.0",
"qs": "^6.5.1",
"semver": "^5.5.0"
},
"dependencies": {
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
}
}
},
"node-int64": { "node-int64": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@@ -4149,6 +4245,12 @@
"pify": "^3.0.0" "pify": "^3.0.0"
} }
}, },
"pathval": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
"dev": true
},
"performance-now": { "performance-now": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@@ -4240,6 +4342,12 @@
"sisteransi": "^1.0.0" "sisteransi": "^1.0.0"
} }
}, },
"propagate": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/propagate/-/propagate-1.0.0.tgz",
"integrity": "sha1-AMLa7t2iDofjeCs0Stuhzd1q1wk=",
"dev": true
},
"psl": { "psl": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.2.0.tgz", "resolved": "https://registry.npmjs.org/psl/-/psl-1.2.0.tgz",
@@ -5177,6 +5285,12 @@
"prelude-ls": "~1.1.2" "prelude-ls": "~1.1.2"
} }
}, },
"type-detect": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
"dev": true
},
"type-fest": { "type-fest": {
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",

View File

@@ -1,8 +1,8 @@
{ {
"name": "flutter-action", "name": "flutter-action",
"version": "1.0.1", "version": "1.1.1",
"private": true, "private": true,
"description": "flutter action", "description": "Flutter environment for use in actions",
"main": "lib/index.js", "main": "lib/index.js",
"scripts": { "scripts": {
"build": "tsc", "build": "tsc",
@@ -26,17 +26,20 @@
"@actions/core": "^1.0.0", "@actions/core": "^1.0.0",
"@actions/exec": "^1.0.0", "@actions/exec": "^1.0.0",
"@actions/io": "^1.0.0", "@actions/io": "^1.0.0",
"@actions/tool-cache": "^1.0.0", "@actions/tool-cache": "^1.1.0",
"semver": "^6.3.0",
"uuid": "^3.3.2" "uuid": "^3.3.2"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^24.0.13", "@types/jest": "^24.0.13",
"@types/nock": "^10.0.3",
"@types/node": "^12.0.4", "@types/node": "^12.0.4",
"@types/semver": "^6.0.0", "@types/semver": "^6.0.1",
"@types/uuid": "^3.4.5", "@types/uuid": "^3.4.5",
"husky": "^3.0.0", "husky": "^3.0.0",
"jest": "^24.8.0", "jest": "^24.8.0",
"jest-circus": "^24.7.1", "jest-circus": "^24.7.1",
"nock": "^10.0.6",
"prettier": "^1.17.1", "prettier": "^1.17.1",
"ts-jest": "^24.0.2", "ts-jest": "^24.0.2",
"typescript": "^3.5.1" "typescript": "^3.5.1"

View File

@@ -3,8 +3,9 @@ import * as installer from './installer';
async function run() { async function run() {
try { try {
const version = core.getInput('version', {required: true}); const version =
const channel = core.getInput('channel', {required: false}) || 'stable'; core.getInput('version') || core.getInput('flutter-version') || '';
const channel = core.getInput('channel') || 'stable';
await installer.getFlutter(version, channel); await installer.getFlutter(version, channel);
} catch (error) { } catch (error) {

View File

@@ -3,13 +3,15 @@ import * as io from '@actions/io';
import * as tc from '@actions/tool-cache'; import * as tc from '@actions/tool-cache';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import uuidV4 from 'uuid/v4'; import * as restm from 'typed-rest-client/RestClient';
import {exec} from '@actions/exec/lib/exec'; import * as semver from 'semver';
const IS_WINDOWS = process.platform === 'win32'; const IS_WINDOWS = process.platform === 'win32';
const IS_DARWIN = process.platform === 'darwin'; const IS_DARWIN = process.platform === 'darwin';
const IS_LINUX = process.platform === 'linux'; const IS_LINUX = process.platform === 'linux';
const storageUrl = 'https://storage.googleapis.com/flutter_infra/releases';
let tempDirectory = process.env['RUNNER_TEMP'] || ''; let tempDirectory = process.env['RUNNER_TEMP'] || '';
if (!tempDirectory) { if (!tempDirectory) {
@@ -32,10 +34,16 @@ export async function getFlutter(
version: string, version: string,
channel: string channel: string
): Promise<void> { ): Promise<void> {
// make semver compatible, eg: 1.7.8+hotfix.4 -> 1.7.8-hotfix.4 const versionPart = version.split('.');
const semver = version.replace('+', '-');
const cleanver = `${semver}-${channel}`; if (versionPart[1] == null || versionPart[2] == null) {
let toolPath = tc.find('Flutter', cleanver); version = version.concat('.x');
}
version = await determineVersion(version, channel);
let cleanver = `${version.replace('+', '-')}-${channel}`;
let toolPath = tc.find('flutter', cleanver);
if (toolPath) { if (toolPath) {
core.debug(`Tool found in cache ${toolPath}`); core.debug(`Tool found in cache ${toolPath}`);
@@ -49,7 +57,7 @@ export async function getFlutter(
const sdkDir = await extractDownload(sdkFile, tempDir); const sdkDir = await extractDownload(sdkFile, tempDir);
core.debug(`Flutter sdk extracted to ${sdkDir}`); core.debug(`Flutter sdk extracted to ${sdkDir}`);
toolPath = await tc.cacheDir(sdkDir, 'Flutter', cleanver); toolPath = await tc.cacheDir(sdkDir, 'flutter', cleanver);
} }
core.exportVariable('FLUTTER_HOME', toolPath); core.exportVariable('FLUTTER_HOME', toolPath);
@@ -75,7 +83,7 @@ function getDownloadInfo(
): {version: string; url: string} { ): {version: string; url: string} {
const os = osName(); const os = osName();
const ext = extName(); const ext = extName();
const url = `https://storage.googleapis.com/flutter_infra/releases/${channel}/${os}/flutter_${os}_v${version}-${channel}.${ext}`; const url = `${storageUrl}/${channel}/${os}/flutter_${os}_v${version}-${channel}.${ext}`;
return { return {
version, version,
@@ -120,54 +128,84 @@ async function extractFile(file: string, destDir: string): Promise<void> {
} }
if ('tar.xz' === extName()) { if ('tar.xz' === extName()) {
await extractTarXz(file, destDir); await tc.extractTar(file, destDir, 'x');
} else { } else {
if (IS_DARWIN) { await tc.extractZip(file, destDir);
await extractZipDarwin(file, destDir);
} else {
await tc.extractZip(file, destDir);
}
} }
} }
/** async function determineVersion(
* Extract a tar.xz version: string,
* channel: string
* @param file path to the tar.xz
* @param dest destination directory. Optional.
* @returns path to the destination directory
*/
export async function extractTarXz(
file: string,
dest?: string
): Promise<string> { ): Promise<string> {
if (!file) { if (version.endsWith('.x') || version === '') {
throw new Error("parameter 'file' is required"); return await getLatestVersion(version, channel);
} }
dest = dest || (await _createExtractFolder(dest)); return version;
const tarPath: string = await io.which('tar', true);
await exec(`"${tarPath}"`, ['xC', dest, '-f', file]);
return dest;
} }
async function _createExtractFolder(dest?: string): Promise<string> { interface IFlutterChannel {
if (!dest) { [key: string]: string;
dest = path.join(tempDirectory, uuidV4()); beta: string;
dev: string;
stable: string;
}
interface IFlutterRelease {
hash: string;
channel: string;
version: string;
}
interface IFlutterStorage {
current_release: IFlutterChannel;
releases: IFlutterRelease[];
}
async function getLatestVersion(
version: string,
channel: string
): Promise<string> {
const releasesUrl: string = `${storageUrl}/releases_${osName()}.json`;
const rest: restm.RestClient = new restm.RestClient('flutter-action');
const storage: IFlutterStorage | null = (await rest.get<IFlutterStorage | null>(
releasesUrl
)).result;
if (!storage) {
throw new Error('unable to get latest version');
} }
await io.mkdirP(dest); if (version.endsWith('.x')) {
return dest; const sver = version.slice(0, version.length - 2);
} const releases = storage.releases.filter(
release =>
release.version.startsWith(`v${sver}`) && release.channel === channel
);
const versions = releases.map(release =>
release.version.slice(1, release.version.length)
);
const sortedVersions = versions.sort(semver.rcompare);
async function extractZipDarwin(file: string, dest: string): Promise<void> { core.debug(
const unzipPath = path.join( `latest version of ${version} from channel ${channel} is ${sortedVersions[0]}`
__dirname, );
'..',
'scripts', return sortedVersions[0];
'externals', }
'unzip-darwin'
const channelVersion = storage.releases.find(
release => release.hash === storage.current_release[channel]
); );
await exec(`"${unzipPath}"`, [file], {cwd: dest});
if (!channelVersion) {
throw new Error(`unable to get latest version from channel ${channel}`);
}
let cver = channelVersion.version;
cver = cver.slice(1, cver.length);
core.debug(`latest version from channel ${channel} is ${cver}`);
return cver;
} }