Compare commits

..

1 Commits

Author SHA1 Message Date
Sascha Mann
0a6460c824 Add production dependencies & build 2020-07-27 22:13:03 +02:00
21 changed files with 371 additions and 5849 deletions

1
.github/CODEOWNERS vendored
View File

@@ -1 +0,0 @@
* @julia-actions/reviewers

View File

@@ -1,33 +0,0 @@
name: Backup
on:
schedule:
- cron: '5 4 * * 0'
workflow_dispatch:
jobs:
backup:
runs-on: ubuntu-20.04
steps:
- name: Configure cache
uses: actions/cache@v2
with:
path: |
${{ env.GITHUB_WORKSPACE }}
~/.cache/restic
key: ${{ runner.os }}
- name: Install the correct Python version
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Run backup action
uses: julia-actions/restic-action@main
env: # Options: https://restic.readthedocs.io/en/latest/040_backup.html#environment-variables
RESTIC_REPOSITORY: b2:${{ secrets.B2_BUCKET }}:${{ github.repository }}
RESTIC_PASSWORD: ${{ secrets.RESTIC_PASSWORD }}
B2_ACCOUNT_ID: ${{ secrets.B2_ACCOUNT_ID }}
B2_ACCOUNT_KEY: ${{ secrets.B2_ACCOUNT_KEY }}

View File

@@ -1,67 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master, releases/* ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '32 22 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@@ -4,7 +4,7 @@ on:
push:
pull_request:
schedule:
- cron: '37 17 * * *'
- cron: '59 * * * *'
jobs:
test:
@@ -22,6 +22,9 @@ jobs:
steps:
- uses: actions/checkout@v1.0.0
- name: "Debugging info"
run: curl ifconfig.me
- name: "Install dependencies"
run: |
npm install
@@ -33,5 +36,4 @@ jobs:
with:
version: nightly
arch: ${{ matrix.julia-arch }}
show-versioninfo: 'true'
- run: julia --version

View File

@@ -26,10 +26,8 @@ jobs:
npm run pack
- name: "Set up Julia"
id: setup-julia
uses: ./
with:
version: ${{ matrix.julia-version }}
arch: ${{ matrix.julia-arch }}
show-versioninfo: 'true'
- run: julia --version

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "bin"]
path = bin
url = git@github.com:julia-actions/bin.git

View File

@@ -7,64 +7,18 @@ This action sets up a Julia environment for use in actions by downloading a spec
## Table of Contents
- [Table of Contents](#table-of-contents)
- [Usage](#usage)
- [Inputs](#inputs)
- [Outputs](#outputs)
- [Basic](#basic)
- [Julia Versions](#julia-versions)
- [Matrix Testing](#matrix-testing)
- [versioninfo](#versioninfo)
- [Versioning](#versioning)
- [Debug logs](#debug-logs)
- [Privacy Info](#privacy-info)
- [Third party information](#third-party-information)
## Usage
### Inputs
See [action.yml](action.yml).
```yaml
- uses: julia-actions/setup-julia@v1
with:
# The Julia version that will be installed and added as `julia` to the PATH.
# See "Julia Versions" below for a list of valid values.
#
# Warning: It is strongly recommended to wrap this value in quotes.
# Otherwise, the YAML parser used by GitHub Actions parses certain
# versions as numbers which causes the wrong version to be selected.
# For example, `1.0` may be parsed as `1`.
#
# Default: '1'
version: ''
# The architecture of the Julia binaries.
#
# Supported values: x64 | x86
#
# Default: x64
arch: ''
# If true, display the output of InteractiveUtils.versioninfo() after installing.
# See "versioninfo" below for example usage.
#
# Default: false
show-versioninfo: ''
```
### Outputs
```yaml
outputs:
# The installed Julia version.
# May vary from the version input if a version range was given as input.
#
# Example output: '1.5.3'
julia-version: ''
# Path to the directory containing the Julia executable.
# Equivalent to JULIA_BINDIR: https://docs.julialang.org/en/v1/manual/environment-variables/#JULIA_BINDIR
#
# Example output: '/opt/hostedtoolcache/julia/1.5.3/x64/bin'
julia-bindir: ''
```
You can find a list of example workflows making use of this action here: [julia-actions/example-workflows](https://github.com/julia-actions/example-workflows).
### Basic
@@ -81,7 +35,7 @@ steps:
You can either specify specific Julia versions or version ranges. If you specify a version range, the **highest** available Julia version that matches the range will be selected.
**Warning:** It is strongly recommended to wrap versions in quotes. Otherwise, the YAML parser used by GitHub Actions parses certain versions as numbers which causes the wrong version to be selected. For example, `1.0` may be parsed as `1`.
**Warning:** It is strongly recommended to wrap versions in quotes. Otherwise, the YAML parser used by GitHub Actions parses certain versions as numbers which causes the wrong version to be selected. For example, `1.0` is parsed as `1`.
#### Examples
@@ -95,7 +49,9 @@ You can either specify specific Julia versions or version ranges. If you specify
Internally the action uses node's semver package to resolve version ranges. Its [documentation](https://github.com/npm/node-semver#advanced-range-syntax) contains more details on the version range syntax. You can test what version will be selected for a given input in this JavaScript [REPL](https://repl.it/@SaschaMann/setup-julia-version-logic).
The available Julia versions are pulled from [`versions.json`](https://julialang-s3.julialang.org/bin/versions.json). This file is automatically updated once a day. Therefore it may take up to 24 hours until a newly released Julia version is available in the action.
#### WARNING: Version ranges are experimental and potentially out of date
Currently the list of available versions is hardcoded. You have to use the latest version of the action to be able to install the latest Julia versions. Once available we will use a list of versions provided on julialang.org.
### Matrix Testing
@@ -175,21 +131,6 @@ jobs:
shell: bash
```
### versioninfo
By default, only a brief version identifier is printed in the run log. You can display the full `versioninfo` by adding `show-versioninfo`.
Here's an example that prints this information just for `nightly`:
```yaml
- uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.version }}
arch: ${{ matrix.arch }}
show-versioninfo: ${{ matrix.version == 'nightly' }}
```
You use `'true'` if you want it printed for all Julia versions.
## Versioning
This action follows [GitHub's advice](https://help.github.com/en/articles/about-actions#versioning-your-action) on versioning actions, with an additional `latest` tag.
@@ -202,22 +143,13 @@ You can specify commits, branches or tags in your workflows as follows:
```yaml
steps:
- uses: julia-actions/setup-julia@d3ce119a16594ea9e5d7974813970c73b6ab9e94 # commit SHA of the tagged 1.4.1 commit
- uses: julia-actions/setup-julia@6ae948d # commit SHA
- uses: julia-actions/setup-julia@master # branch
- uses: julia-actions/setup-julia@latest # latest version tag (may break existing workflows)
- uses: julia-actions/setup-julia@v1 # major version tag
- uses: julia-actions/setup-julia@v1.4 # minor version tag
- uses: julia-actions/setup-julia@v1.4.1 # specific version tag
- uses: julia-actions/setup-julia@v0.1.0 # specific version tag
```
If your workflow requires access to secrets, you should always pin it to a commit SHA instead of a tag.
This will protect you in case a bad actor gains access to the setup-julia repo.
You can find more information in [GitHub's security hardening guide](https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions).
## Debug logs
You can enable [Step Debug Logs](https://github.com/actions/toolkit/blob/main/docs/action-debugging.md#step-debug-logs) for more detailed logs.
Note that when debug logs are enabled, a request will be sent to `https://httpbin.julialang.org/ip` and the runner's IP will be printed to the debug logs.
## Third party information
Parts of this software have been derived from other open source software.
See [THIRD_PARTY_NOTICE.md](THIRD_PARTY_NOTICE.md) for details.

File diff suppressed because it is too large Load Diff

View File

@@ -1,113 +0,0 @@
// The testing setup has been derived from the actions/setup-go@bc6edb5 action.
// Check README.md for licence information.
import * as path from 'path'
import * as io from '@actions/io'
import nock = require('nock')
import * as semver from 'semver'
const testVersions = [
'0.1.2', '0.2.0', '0.2.1', '0.3.0',
'0.3.1', '0.3.10', '0.3.11', '0.3.12',
'0.3.2', '0.3.3', '0.3.4', '0.3.5',
'0.3.6', '0.3.7', '0.3.8', '0.3.9',
'0.4.0', '0.4.0-rc1', '0.4.0-rc2', '0.4.0-rc3',
'0.4.0-rc4', '0.4.1', '0.4.2', '0.4.3',
'0.4.4', '0.4.5', '0.4.6', '0.4.7',
'0.5.0', '0.5.0-rc0', '0.5.0-rc1', '0.5.0-rc2',
'0.5.0-rc3', '0.5.0-rc4', '0.5.1', '0.5.2',
'0.6.0', '0.6.0-pre.alpha', '0.6.0-pre.beta', '0.6.0-rc1',
'0.6.0-rc2', '0.6.0-rc3', '0.6.1', '0.6.2',
'0.6.3', '0.6.4', '0.7.0', '0.7.0-alpha',
'0.7.0-beta', '0.7.0-beta2', '0.7.0-rc1', '0.7.0-rc2',
'0.7.0-rc3', '1.0.0', '1.0.0-rc1', '1.0.1',
'1.0.2', '1.0.3', '1.0.4', '1.0.5',
'1.1.0', '1.1.0-rc1', '1.1.0-rc2', '1.1.1',
'1.2.0', '1.2.0-rc1', '1.2.0-rc2', '1.2.0-rc3',
'1.3.0-alpha', '1.3.0-rc1', '1.3.0-rc2', '1.3.0-rc3',
'1.3.0-rc4'
]
const toolDir = path.join(__dirname, 'runner', 'tools')
const tempDir = path.join(__dirname, 'runner', 'temp')
const fixtureDir = path.join(__dirname, 'fixtures')
process.env['RUNNER_TOOL_CACHE'] = toolDir
process.env['RUNNER_TEMP'] = tempDir
import * as installer from '../src/installer'
describe('version matching tests', () => {
describe('specific versions', () => {
it('Doesn\'t change the version when given a valid semver version', () => {
expect(installer.getJuliaVersion([], '1.0.5')).toEqual('1.0.5')
expect(installer.getJuliaVersion(['v1.0.5', 'v1.0.6'], '1.0.5')).toEqual('1.0.5')
expect(installer.getJuliaVersion(['v1.0.4', 'v1.0.5'], '1.0.5')).toEqual('1.0.5')
expect(installer.getJuliaVersion(['v1.0.4'], '1.0.5')).toEqual('1.0.5')
expect(installer.getJuliaVersion([], '1.3.0-alpha')).toEqual('1.3.0-alpha')
expect(installer.getJuliaVersion(['v1.2.0', 'v1.3.0-alpha', 'v1.3.0-rc1', 'v1.3.0'], '1.3.0-alpha')).toEqual('1.3.0-alpha')
expect(installer.getJuliaVersion([], '1.3.0-rc2')).toEqual('1.3.0-rc2')
})
it('Doesn\'t change the version when given `nightly`', () => {
expect(installer.getJuliaVersion([], 'nightly')).toEqual('nightly')
expect(installer.getJuliaVersion(testVersions, 'nightly')).toEqual('nightly')
})
})
describe('version ranges', () => {
it('Chooses the highest available version that matches the input', () => {
expect(installer.getJuliaVersion(testVersions, '1')).toEqual('1.2.0')
expect(installer.getJuliaVersion(testVersions, '1.0')).toEqual('1.0.5')
expect(installer.getJuliaVersion(testVersions, '^1.3.0-rc1')).toEqual('1.3.0-rc4')
expect(installer.getJuliaVersion(testVersions, '^1.2.0-rc1')).toEqual('1.2.0')
})
})
describe('node-semver behaviour', () => {
describe('Windows installer change', () => {
it('Correctly understands >1.4.0', () => {
expect(semver.gtr('1.4.0-rc1', '1.3', {includePrerelease: true})).toBeTruthy()
expect(semver.gtr('1.4.0-DEV', '1.3', {includePrerelease: true})).toBeTruthy()
expect(semver.gtr('1.3.1', '1.3', {includePrerelease: true})).toBeFalsy()
expect(semver.gtr('1.3.2-rc1', '1.3', {includePrerelease: true})).toBeFalsy()
})
})
})
})
describe('installer tests', () => {
beforeAll(async () => {
await io.rmRF(toolDir)
await io.rmRF(tempDir)
}, 100000)
afterAll(async () => {
try {
await io.rmRF(toolDir)
await io.rmRF(tempDir)
} catch {
console.log('Failed to remove test directories')
}
}, 100000)
describe('versions.json parsing', () => {
// Instead of downloading versions.json, use fixtures/versions.json
beforeEach(() => {
nock('https://julialang-s3.julialang.org').persist()
.get('/bin/versions.json')
.replyWithFile(200, path.join(fixtureDir, 'versions.json'))
})
afterEach(() => {
nock.cleanAll()
nock.enableNetConnect()
})
it('Extracts the list of available versions', async () => {
expect(await (await installer.getJuliaVersions(await installer.getJuliaVersionInfo())).sort()).toEqual(testVersions.sort())
})
})
})

50
__tests__/main.test.ts Normal file
View File

@@ -0,0 +1,50 @@
import * as installer from '../src/installer'
import * as semver from 'semver'
const testVersions = ['v1.3.0-rc4', 'v1.3.0-rc3', 'v1.3.0-rc2', 'v1.0.5', 'v1.2.0', 'v1.3.0-rc1', 'v1.2.0-rc3', 'v1.3.0-alpha', 'v1.2.0-rc2', 'v1.2.0-rc1', 'v1.1.1', 'v1.0.4', 'v1.1.0', 'v1.1.0-rc2', 'v1.1.0-rc1', 'v1.0.3', 'v1.0.2', 'v1.0.1', 'v1.0.0']
describe('installer tests', () => {
describe('version matching', () => {
describe('specific versions', () => {
it('Doesn\'t change the version when given a valid semver version', async () => {
expect(await installer.getJuliaVersion([], '1.0.5')).toEqual('1.0.5')
expect(await installer.getJuliaVersion(['v1.0.5', 'v1.0.6'], '1.0.5')).toEqual('1.0.5')
expect(await installer.getJuliaVersion(['v1.0.4', 'v1.0.5'], '1.0.5')).toEqual('1.0.5')
expect(await installer.getJuliaVersion(['v1.0.4'], '1.0.5')).toEqual('1.0.5')
expect(await installer.getJuliaVersion([], '1.3.0-alpha')).toEqual('1.3.0-alpha')
expect(await installer.getJuliaVersion(['v1.2.0', 'v1.3.0-alpha', 'v1.3.0-rc1', 'v1.3.0'], '1.3.0-alpha')).toEqual('1.3.0-alpha')
expect(await installer.getJuliaVersion([], '1.3.0-rc2')).toEqual('1.3.0-rc2')
})
it('Doesn\'t change the version when given `nightly`', async () => {
expect(await installer.getJuliaVersion([], 'nightly')).toEqual('nightly')
expect(await installer.getJuliaVersion(testVersions, 'nightly')).toEqual('nightly')
})
})
describe('version ranges', () => {
it('Chooses the highest available version that matches the input', async () => {
expect(await installer.getJuliaVersion(testVersions, '1')).toEqual('1.2.0')
expect(await installer.getJuliaVersion(testVersions, '1.0')).toEqual('1.0.5')
expect(await installer.getJuliaVersion(testVersions, '^1.3.0-rc1')).toEqual('1.3.0-rc4')
expect(await installer.getJuliaVersion(testVersions, '^1.2.0-rc1')).toEqual('1.2.0')
})
})
describe('invalid version range (#38)', () => {
it('Throws an error if a version range does not match any available version', () => {
expect(() => {
installer.getJuliaVersion(['v1.5.0-rc1', 'v1.5.0-beta1', 'v1.4.2', 'v1.4.1', 'v1.4.0', 'v1.4.0-rc2', 'v1.4.0-rc1'], '1.6')
}).toThrowError()
})
})
})
describe('node-semver behaviour', () => {
describe('Windows installer change', () => {
it('Correctly understands >1.4.0', () => {
expect(semver.gtr('1.4.0-rc1', '1.3', {includePrerelease: true})).toBeTruthy()
expect(semver.gtr('1.4.0-DEV', '1.3', {includePrerelease: true})).toBeTruthy()
expect(semver.gtr('1.3.1', '1.3', {includePrerelease: true})).toBeFalsy()
expect(semver.gtr('1.3.2-rc1', '1.3', {includePrerelease: true})).toBeFalsy()
})
})
})
})

View File

@@ -13,11 +13,6 @@ inputs:
description: 'Display InteractiveUtils.versioninfo() after installing'
required: false
default: 'false'
outputs:
julia-version:
description: 'The installed Julia version. May vary from the version input if a version range was given as input.'
julia-bindir:
description: 'Path to the directory containing the Julia executable. Equivalent to JULIA_BINDIR: https://docs.julialang.org/en/v1/manual/environment-variables/#JULIA_BINDIR'
runs:
using: 'node12'
main: 'dist/index.js'

1
bin

Submodule bin deleted from 9ceca17c9c

44
bin/build-release Normal file
View File

@@ -0,0 +1,44 @@
#!/bin/sh
branch_name="$(git symbolic-ref --short -q HEAD)"
version="v$(jq -r .version package.json)"
repo="$1"
if [ -z "$repo" ]; then
echo "ERROR: must specify repository"
exit 1
fi
echo "=== debug info ==="
echo "branch: $branch_name"
echo "version: $version"
echo "repo: $repo"
echo "=================="
echo ""
# Check that the version doesn't exist yet
version_exists="$(curl -s https://api.github.com/repos/"$repo"/tags -H "Accept: application/vnd.github.v3.full+json" | jq -r '.[] | select(.name == "'"$version"'") | .name')"
if [ -n "$version_exists" ]; then
echo "ERROR: version $version already exists"
exit 1
fi
git checkout -b releases/"$version"
npm install
npm run build
npm test
npm run pack
sed -i 's/dist/!dist/g' .gitignore
git add dist
git commit -a -m "Add production dependencies & build"
# Tags
major_minor="$(sed 's/\.[^.]*$//' <<< "$version")"
major="$(sed 's/\.[^.]*$//' <<< "$major_minor")"
git tag "$version"
git tag -f "$major_minor"
git tag -f "$major"
git tag -f "latest"

36
bin/build-test-release Normal file
View File

@@ -0,0 +1,36 @@
#!/bin/sh
branch_name="$(git symbolic-ref --short -q HEAD)"
version="v$(jq -r .version package.json)"
repo="$1"
if [ -z "$repo" ]; then
echo "ERROR: must specify repository"
exit 1
fi
echo "=== debug info ==="
echo "branch: $branch_name"
echo "version: $version"
echo "repo: $repo"
echo "=================="
echo ""
# Check that the version doesn't exist yet
version_exists="$(curl -s https://api.github.com/repos/"$repo"/tags -H "Accept: application/vnd.github.v3.full+json" | jq -r '.[] | select(.name == "'"$version"'") | .name')"
if [ -n "$version_exists" ]; then
echo "ERROR: version $version already exists"
exit 1
fi
git checkout -B test/"$branch_name"/releases/"$version"
npm install
npm run build
npm test
npm run pack
# Add dist/ to git and commit it
sed -i 's/dist/!dist/g' .gitignore
git add dist
git commit -a -m "Add production dependencies & build"

473
dist/index.js vendored
View File

@@ -926,32 +926,6 @@ module.exports = require("tls");
/***/ }),
/***/ 82:
/***/ (function(__unusedmodule, exports) {
"use strict";
// We use any as a valid input type
/* eslint-disable @typescript-eslint/no-explicit-any */
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Sanitizes an input into a string so it can be passed into issueCommand safely
* @param input input to sanitize into a string
*/
function toCommandValue(input) {
if (input === null || input === undefined) {
return '';
}
else if (typeof input === 'string' || input instanceof String) {
return input;
}
return JSON.stringify(input);
}
exports.toCommandValue = toCommandValue;
//# sourceMappingURL=utils.js.map
/***/ }),
/***/ 87:
/***/ (function(module) {
@@ -959,42 +933,6 @@ module.exports = require("os");
/***/ }),
/***/ 102:
/***/ (function(__unusedmodule, exports, __webpack_require__) {
"use strict";
// For internal use, subject to change.
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
// We use any as a valid input type
/* eslint-disable @typescript-eslint/no-explicit-any */
const fs = __importStar(__webpack_require__(747));
const os = __importStar(__webpack_require__(87));
const utils_1 = __webpack_require__(82);
function issueCommand(command, message) {
const filePath = process.env[`GITHUB_${command}`];
if (!filePath) {
throw new Error(`Unable to find environment variable for file command ${command}`);
}
if (!fs.existsSync(filePath)) {
throw new Error(`Missing file at path: ${filePath}`);
}
fs.appendFileSync(filePath, `${utils_1.toCommandValue(message)}${os.EOL}`, {
encoding: 'utf8'
});
}
exports.issueCommand = issueCommand;
//# sourceMappingURL=file-command.js.map
/***/ }),
/***/ 129:
/***/ (function(module) {
@@ -2909,36 +2847,28 @@ module.exports = require("crypto");
"use strict";
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const os = __importStar(__webpack_require__(87));
const utils_1 = __webpack_require__(82);
const os = __webpack_require__(87);
/**
* Commands
*
* Command Format:
* ::name key=value,key=value::message
* ##[name key=value;key=value]message
*
* Examples:
* ::warning::This is the message
* ::set-env name=MY_VAR::some value
* ##[warning]This is the user warning message
* ##[set-secret name=mypassword]definatelyNotAPassword!
*/
function issueCommand(command, properties, message) {
const cmd = new Command(command, properties, message);
process.stdout.write(cmd.toString() + os.EOL);
}
exports.issueCommand = issueCommand;
function issue(name, message = '') {
function issue(name, message) {
issueCommand(name, {}, message);
}
exports.issue = issue;
const CMD_STRING = '::';
const CMD_PREFIX = '##[';
class Command {
constructor(command, properties, message) {
if (!command) {
@@ -2949,42 +2879,37 @@ class Command {
this.message = message;
}
toString() {
let cmdStr = CMD_STRING + this.command;
let cmdStr = CMD_PREFIX + this.command;
if (this.properties && Object.keys(this.properties).length > 0) {
cmdStr += ' ';
let first = true;
for (const key in this.properties) {
if (this.properties.hasOwnProperty(key)) {
const val = this.properties[key];
if (val) {
if (first) {
first = false;
}
else {
cmdStr += ',';
}
cmdStr += `${key}=${escapeProperty(val)}`;
// safely append the val - avoid blowing up when attempting to
// call .replace() if message is not a string for some reason
cmdStr += `${key}=${escape(`${val || ''}`)};`;
}
}
}
}
cmdStr += `${CMD_STRING}${escapeData(this.message)}`;
cmdStr += ']';
// safely append the message - avoid blowing up when attempting to
// call .replace() if message is not a string for some reason
const message = `${this.message || ''}`;
cmdStr += escapeData(message);
return cmdStr;
}
}
function escapeData(s) {
return utils_1.toCommandValue(s)
.replace(/%/g, '%25')
.replace(/\r/g, '%0D')
.replace(/\n/g, '%0A');
return s.replace(/\r/g, '%0D').replace(/\n/g, '%0A');
}
function escapeProperty(s) {
return utils_1.toCommandValue(s)
.replace(/%/g, '%25')
function escape(s) {
return s
.replace(/\r/g, '%0D')
.replace(/\n/g, '%0A')
.replace(/:/g, '%3A')
.replace(/,/g, '%2C');
.replace(/]/g, '%5D')
.replace(/;/g, '%3B');
}
//# sourceMappingURL=command.js.map
@@ -2995,28 +2920,9 @@ function escapeProperty(s) {
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
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 step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const command_1 = __webpack_require__(431);
const file_command_1 = __webpack_require__(102);
const utils_1 = __webpack_require__(82);
const os = __importStar(__webpack_require__(87));
const path = __importStar(__webpack_require__(622));
const path = __webpack_require__(622);
/**
* The code to exit an action
*/
@@ -3035,45 +2941,31 @@ var ExitCode;
// Variables
//-----------------------------------------------------------------------
/**
* Sets env variable for this action and future actions in the job
* sets env variable for this action and future actions in the job
* @param name the name of the variable to set
* @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify
* @param val the value of the variable
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function exportVariable(name, val) {
const convertedVal = utils_1.toCommandValue(val);
process.env[name] = convertedVal;
const filePath = process.env['GITHUB_ENV'] || '';
if (filePath) {
const delimiter = '_GitHubActionsFileCommandDelimeter_';
const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}`;
file_command_1.issueCommand('ENV', commandValue);
}
else {
command_1.issueCommand('set-env', { name }, convertedVal);
}
process.env[name] = val;
command_1.issueCommand('set-env', { name }, val);
}
exports.exportVariable = exportVariable;
/**
* Registers a secret which will get masked from logs
* @param secret value of the secret
* exports the variable and registers a secret which will get masked from logs
* @param name the name of the variable to set
* @param val value of the secret
*/
function setSecret(secret) {
command_1.issueCommand('add-mask', {}, secret);
function exportSecret(name, val) {
exportVariable(name, val);
command_1.issueCommand('set-secret', {}, val);
}
exports.setSecret = setSecret;
exports.exportSecret = exportSecret;
/**
* Prepends inputPath to the PATH (for this action and future actions)
* @param inputPath
*/
function addPath(inputPath) {
const filePath = process.env['GITHUB_PATH'] || '';
if (filePath) {
file_command_1.issueCommand('PATH', inputPath);
}
else {
command_1.issueCommand('add-path', {}, inputPath);
}
command_1.issueCommand('add-path', {}, inputPath);
process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`;
}
exports.addPath = addPath;
@@ -3085,7 +2977,7 @@ exports.addPath = addPath;
* @returns string
*/
function getInput(name, options) {
const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || '';
const val = process.env[`INPUT_${name.replace(' ', '_').toUpperCase()}`] || '';
if (options && options.required && !val) {
throw new Error(`Input required and not supplied: ${name}`);
}
@@ -3096,22 +2988,12 @@ exports.getInput = getInput;
* Sets the value of an output.
*
* @param name name of the output to set
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
* @param value value to store
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function setOutput(name, value) {
command_1.issueCommand('set-output', { name }, value);
}
exports.setOutput = setOutput;
/**
* Enables or disables the echoing of commands into stdout for the rest of the step.
* Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set.
*
*/
function setCommandEcho(enabled) {
command_1.issue('echo', enabled ? 'on' : 'off');
}
exports.setCommandEcho = setCommandEcho;
//-----------------------------------------------------------------------
// Results
//-----------------------------------------------------------------------
@@ -3128,13 +3010,6 @@ exports.setFailed = setFailed;
//-----------------------------------------------------------------------
// Logging Commands
//-----------------------------------------------------------------------
/**
* Gets whether Actions Step Debug is on or not
*/
function isDebug() {
return process.env['RUNNER_DEBUG'] === '1';
}
exports.isDebug = isDebug;
/**
* Writes debug message to user log
* @param message debug message
@@ -3145,92 +3020,20 @@ function debug(message) {
exports.debug = debug;
/**
* Adds an error issue
* @param message error issue message. Errors will be converted to string via toString()
* @param message error issue message
*/
function error(message) {
command_1.issue('error', message instanceof Error ? message.toString() : message);
command_1.issue('error', message);
}
exports.error = error;
/**
* Adds an warning issue
* @param message warning issue message. Errors will be converted to string via toString()
* @param message warning issue message
*/
function warning(message) {
command_1.issue('warning', message instanceof Error ? message.toString() : message);
command_1.issue('warning', message);
}
exports.warning = warning;
/**
* Writes info to log with console.log.
* @param message info message
*/
function info(message) {
process.stdout.write(message + os.EOL);
}
exports.info = info;
/**
* Begin an output group.
*
* Output until the next `groupEnd` will be foldable in this group
*
* @param name The name of the output group
*/
function startGroup(name) {
command_1.issue('group', name);
}
exports.startGroup = startGroup;
/**
* End an output group.
*/
function endGroup() {
command_1.issue('endgroup');
}
exports.endGroup = endGroup;
/**
* Wrap an asynchronous function call in a group.
*
* Returns the same type as the function itself.
*
* @param name The name of the group
* @param fn The function to wrap in the group
*/
function group(name, fn) {
return __awaiter(this, void 0, void 0, function* () {
startGroup(name);
let result;
try {
result = yield fn();
}
finally {
endGroup();
}
return result;
});
}
exports.group = group;
//-----------------------------------------------------------------------
// Wrapper action state
//-----------------------------------------------------------------------
/**
* Saves state for current action, the state can only be retrieved by this action's post job execution.
*
* @param name name of the state to store
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function saveState(name, value) {
command_1.issueCommand('save-state', { name }, value);
}
exports.saveState = saveState;
/**
* Gets the value of an state set by this action's main execution.
*
* @param name name of the state to get
* @returns string
*/
function getState(name) {
return process.env[`STATE_${name}`] || '';
}
exports.getState = getState;
//# sourceMappingURL=core.js.map
/***/ }),
@@ -3969,66 +3772,31 @@ Object.defineProperty(exports, "__esModule", { value: true });
const core = __importStar(__webpack_require__(470));
const exec = __importStar(__webpack_require__(986));
const tc = __importStar(__webpack_require__(533));
const fs = __importStar(__webpack_require__(747));
const https = __importStar(__webpack_require__(211));
const path = __importStar(__webpack_require__(622));
const installer = __importStar(__webpack_require__(749));
function run() {
return __awaiter(this, void 0, void 0, function* () {
try {
// Debugging info
if (core.isDebug()) {
// Log Runner IP Address
https.get('https://httpbin.julialang.org/ip', resp => {
let data = '';
resp.on('data', chunk => {
data += chunk;
});
resp.on('end', () => {
core.debug(`Runner IP address: ${JSON.parse(data).origin}`);
});
}).on('error', err => {
core.debug(`ERROR: Could not retrieve runner IP: ${err}`);
});
}
// Inputs
const versionInput = core.getInput('version');
const arch = core.getInput('arch');
// It can easily happen that, for example, a workflow file contains an input `version: ${{ matrix.julia-version }}`
// while the strategy matrix only contains a key `${{ matrix.version }}`.
// In that case, we want the action to fail, rather than trying to download julia from an URL that's missing parts and 404ing.
// We _could_ fall back to the default but that means that builds silently do things differently than they're meant to, which
// is worse than failing the build.
if (!versionInput) {
throw new Error('Version input must not be null');
}
if (!arch) {
throw new Error(`Arch input must not be null`);
}
const versionInfo = yield installer.getJuliaVersionInfo();
const availableReleases = yield installer.getJuliaVersions(versionInfo);
const availableReleases = installer.juliaVersions;
const version = installer.getJuliaVersion(availableReleases, versionInput);
core.debug(`selected Julia version: ${arch}/${version}`);
core.setOutput('julia-version', version);
// Search in cache
let juliaPath;
juliaPath = tc.find('julia', version, arch);
if (!juliaPath) {
core.debug(`could not find Julia ${arch}/${version} in cache`);
const juliaInstallationPath = yield installer.installJulia(versionInfo, version, arch);
core.debug(`could not find Julia ${version} in cache`);
const juliaInstallationPath = yield installer.installJulia(version, arch);
// Add it to cache
juliaPath = yield tc.cacheDir(juliaInstallationPath, 'julia', version, arch);
core.debug(`added Julia to cache: ${juliaPath}`);
// Remove temporary dir
fs.rmdirSync(juliaInstallationPath, { recursive: true });
}
else {
core.debug(`using cached version of Julia: ${juliaPath}`);
}
// Add it to PATH
core.addPath(path.join(juliaPath, 'bin'));
// Set output
core.setOutput('julia-bindir', path.join(juliaPath, 'bin'));
// Test if Julia has been installed
exec.exec('julia', ['--version']);
// If enabled, also show the full version info
@@ -4077,65 +3845,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
const core = __importStar(__webpack_require__(470));
const exec = __importStar(__webpack_require__(986));
const tc = __importStar(__webpack_require__(533));
const crypto = __importStar(__webpack_require__(417));
const fs = __importStar(__webpack_require__(747));
const os = __importStar(__webpack_require__(87));
const path = __importStar(__webpack_require__(622));
const semver = __importStar(__webpack_require__(280));
// Translations between actions input and Julia arch names
const osMap = {
'win32': 'winnt',
'darwin': 'mac',
'linux': 'linux'
};
const archMap = {
'x86': 'i686',
'x64': 'x86_64'
};
// Store information about the environment
const osPlat = os.platform(); // possible values: win32 (Windows), linux (Linux), darwin (macOS)
core.debug(`platform: ${osPlat}`);
/**
* @returns The SHA256 checksum of a given file.
*/
function calculateChecksum(file) {
return __awaiter(this, void 0, void 0, function* () {
const hash = crypto.createHash('sha256');
const input = fs.createReadStream(file);
return new Promise((resolve, reject) => {
input.on('data', (chunk) => {
hash.update(chunk);
});
input.on('end', () => {
const digest = hash.digest('hex');
digest ? resolve(digest) : reject(new Error(`Could not calculate checksum of file ${file}: digest was empty.`));
});
});
});
}
/**
* @returns The content of the downloaded versions.json file as object.
*/
function getJuliaVersionInfo() {
return __awaiter(this, void 0, void 0, function* () {
const versionsFile = yield tc.downloadTool('https://julialang-s3.julialang.org/bin/versions.json');
return JSON.parse(fs.readFileSync(versionsFile).toString());
});
}
exports.getJuliaVersionInfo = getJuliaVersionInfo;
/**
* @returns An array of all Julia versions available for download
*/
function getJuliaVersions(versionInfo) {
return __awaiter(this, void 0, void 0, function* () {
let versions = [];
for (let version in versionInfo) {
versions.push(version);
}
return versions;
});
}
exports.getJuliaVersions = getJuliaVersions;
// This is temporary until we have a better way of fetching releases (see #1, #4 for details)
exports.juliaVersions = ['v1.5.0-rc2', 'v1.5.0-rc1', 'v1.5.0-beta1', 'v1.4.2', 'v1.4.1', 'v1.4.0', 'v1.4.0-rc2', 'v1.4.0-rc1', 'v1.3.1', 'v1.3.0', 'v1.3.0-rc5', 'v1.3.0-rc4', 'v1.3.0-rc3', 'v1.3.0-rc2', 'v1.0.5', 'v1.2.0', 'v1.3.0-rc1', 'v1.2.0-rc3', 'v1.3.0-alpha', 'v1.2.0-rc2', 'v1.2.0-rc1', 'v1.1.1', 'v1.0.4', 'v1.1.0', 'v1.1.0-rc2', 'v1.1.0-rc1', 'v1.0.3', 'v1.0.2', 'v1.0.1', 'v1.0.0', 'v0.7.0', 'v1.0.0-rc1', 'v0.7.0-rc3', 'v0.7.0-rc2', 'v0.7.0-rc1', 'v0.7.0-beta2', 'v0.6.4', 'v0.7.0-beta', 'v0.7.0-alpha', 'v0.6.3', 'v0.6.2', 'v0.6.1', 'v0.6.0', 'v0.6.0-rc3', 'v0.6.0-rc2', 'v0.5.2', 'v0.6.0-rc1', 'v0.6.0-pre.beta', 'v0.5.1', 'v0.6.0-pre.alpha', 'v0.5.0', 'v0.4.7', 'v0.5.0-rc4', 'v0.5.0-rc3', 'v0.5.0-rc2', 'v0.5.0-rc1', 'v0.5.0-rc0', 'v0.4.6', 'v0.4.5', 'v0.4.4', 'v0.4.3', 'v0.4.2', 'v0.4.1', 'v0.3.12', 'v0.4.0', 'v0.4.0-rc4', 'v0.4.0-rc3', 'v0.4.0-rc2', 'v0.4.0-rc1', 'v0.3.11', 'v0.3.10', 'v0.3.9', 'v0.3.8', 'v0.3.7', 'v0.3.6', 'v0.3.5', 'v0.3.4', 'v0.3.3', 'v0.3.2', 'v0.3.1', 'v0.3.0', 'v0.3.0-rc4', 'v0.3.0-rc3', 'v0.3.0-rc2', 'v0.3.0-rc1', 'v0.2.0-rc1', 'v0.2.0-rc3', 'v0.2.0-rc4', 'v0.2.0', 'v0.2.0-rc2'];
function getJuliaVersion(availableReleases, versionInput) {
if (semver.valid(versionInput) == versionInput) {
// versionInput is a valid version, use it directly
@@ -4155,87 +3872,91 @@ function getJuliaVersion(availableReleases, versionInput) {
return version;
}
exports.getJuliaVersion = getJuliaVersion;
function getNightlyFileName(arch) {
function getMajorMinorVersion(version) {
return version.split('.').slice(0, 2).join('.');
}
function getDownloadURL(version, arch) {
let platform;
if (osPlat === 'win32') { // Windows
platform = 'winnt';
}
else if (osPlat === 'darwin') { // macOS
if (arch == 'x86') {
throw new Error('32-bit Julia is not available on macOS');
}
platform = 'mac';
}
else if (osPlat === 'linux') { // Linux
platform = 'linux';
}
else {
throw new Error(`Platform ${osPlat} is not supported`);
}
// nightlies
if (version == 'nightly') {
const baseURL = 'https://julialangnightlies-s3.julialang.org/bin';
return `${baseURL}/${platform}/${arch}/${getFileName('latest', arch)}`;
}
// normal versions
const baseURL = 'https://julialang-s3.julialang.org/bin';
const versionDir = getMajorMinorVersion(version);
return `${baseURL}/${platform}/${arch}/${versionDir}/${getFileName(version, arch)}`;
}
function getFileName(version, arch) {
let versionExt, ext;
if (osPlat == 'win32') {
if (osPlat === 'win32') { // Windows
versionExt = arch == 'x64' ? '-win64' : '-win32';
ext = 'exe';
}
else if (osPlat == 'darwin') {
else if (osPlat === 'darwin') { // macOS
if (arch == 'x86') {
throw new Error('32-bit Julia is not available on macOS');
}
versionExt = '-mac64';
ext = 'dmg';
}
else if (osPlat === 'linux') {
versionExt = arch == 'x64' ? '-linux64' : '-linux32';
else if (osPlat === 'linux') { // Linux
if (version == 'latest') { // nightly version
versionExt = arch == 'x64' ? '-linux64' : '-linux32';
}
else {
versionExt = arch == 'x64' ? '-linux-x86_64' : '-linux-i686';
}
ext = 'tar.gz';
}
else {
throw new Error(`Platform ${osPlat} is not supported`);
}
return `julia-latest${versionExt}.${ext}`;
return `julia-${version}${versionExt}.${ext}`;
}
function getFileInfo(versionInfo, version, arch) {
if (version == 'nightly') {
return null;
}
for (let file of versionInfo[version].files) {
if (file.os == osMap[osPlat] && file.arch == archMap[arch]) {
return file;
}
}
throw `Could not find ${archMap[arch]}/${version} binaries`;
}
exports.getFileInfo = getFileInfo;
function getDownloadURL(fileInfo, version, arch) {
// nightlies
if (version == 'nightly') {
const baseURL = 'https://julialangnightlies-s3.julialang.org/bin';
return `${baseURL}/${osMap[osPlat]}/${arch}/${getNightlyFileName(arch)}`;
}
return fileInfo.url;
}
exports.getDownloadURL = getDownloadURL;
function installJulia(versionInfo, version, arch) {
function installJulia(version, arch) {
return __awaiter(this, void 0, void 0, function* () {
// Download Julia
const fileInfo = getFileInfo(versionInfo, version, arch);
const downloadURL = getDownloadURL(fileInfo, version, arch);
const downloadURL = getDownloadURL(version, arch);
core.debug(`downloading Julia from ${downloadURL}`);
const juliaDownloadPath = yield tc.downloadTool(downloadURL);
// Verify checksum
if (version != 'nightly') {
const checkSum = yield calculateChecksum(juliaDownloadPath);
if (fileInfo.sha256 != checkSum) {
throw new Error(`Checksum of downloaded file does not match the expected checksum from versions.json.\nExpected: ${fileInfo.sha256}\nGot: ${checkSum}`);
}
core.debug(`Checksum of downloaded file matches expected checksum: ${checkSum}`);
}
else {
core.debug('Skipping checksum check for nightly binaries.');
}
const tempInstallDir = fs.mkdtempSync(`julia-${arch}-${version}-`);
// Install it
switch (osPlat) {
case 'linux':
// tc.extractTar doesn't support stripping components, so we have to call tar manually
yield exec.exec('tar', ['xf', juliaDownloadPath, '--strip-components=1', '-C', tempInstallDir]);
return tempInstallDir;
yield exec.exec('mkdir', [`${process.env.HOME}/julia`]);
yield exec.exec('tar', ['xf', juliaDownloadPath, '--strip-components=1', '-C', `${process.env.HOME}/julia`]);
return `${process.env.HOME}/julia`;
case 'win32':
const juliaInstallationPath = path.join('C:', 'Julia');
if (version == 'nightly' || semver.gtr(version, '1.3', { includePrerelease: true })) {
// The installer changed in 1.4: https://github.com/JuliaLang/julia/blob/ef0c9108b12f3ae177c51037934351ffa703b0b5/NEWS.md#build-system-changes
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/SILENT /dir=${path.join(process.cwd(), tempInstallDir)}" -NoNewWindow -Wait`]);
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/SILENT /dir=${juliaInstallationPath}" -NoNewWindow -Wait`]);
}
else {
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/S /D=${path.join(process.cwd(), tempInstallDir)}" -NoNewWindow -Wait`]);
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/S /D=${juliaInstallationPath}" -NoNewWindow -Wait`]);
}
return tempInstallDir;
return juliaInstallationPath;
case 'darwin':
yield exec.exec('hdiutil', ['attach', juliaDownloadPath]);
yield exec.exec('/bin/bash', ['-c', `cp -a /Volumes/Julia-*/Julia-*.app/Contents/Resources/julia ${tempInstallDir}`]);
return path.join(tempInstallDir, 'julia');
yield exec.exec('mkdir', [`${process.env.HOME}/julia`]);
yield exec.exec('/bin/bash', ['-c', `cp -a /Volumes/Julia-*/Julia-*.app/Contents/Resources/julia ${process.env.HOME}`]);
return `${process.env.HOME}/julia`;
default:
throw new Error(`Platform ${osPlat} is not supported`);
}

157
lib/installer.js generated
View File

@@ -18,65 +18,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
const core = __importStar(require("@actions/core"));
const exec = __importStar(require("@actions/exec"));
const tc = __importStar(require("@actions/tool-cache"));
const crypto = __importStar(require("crypto"));
const fs = __importStar(require("fs"));
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const semver = __importStar(require("semver"));
// Translations between actions input and Julia arch names
const osMap = {
'win32': 'winnt',
'darwin': 'mac',
'linux': 'linux'
};
const archMap = {
'x86': 'i686',
'x64': 'x86_64'
};
// Store information about the environment
const osPlat = os.platform(); // possible values: win32 (Windows), linux (Linux), darwin (macOS)
core.debug(`platform: ${osPlat}`);
/**
* @returns The SHA256 checksum of a given file.
*/
function calculateChecksum(file) {
return __awaiter(this, void 0, void 0, function* () {
const hash = crypto.createHash('sha256');
const input = fs.createReadStream(file);
return new Promise((resolve, reject) => {
input.on('data', (chunk) => {
hash.update(chunk);
});
input.on('end', () => {
const digest = hash.digest('hex');
digest ? resolve(digest) : reject(new Error(`Could not calculate checksum of file ${file}: digest was empty.`));
});
});
});
}
/**
* @returns The content of the downloaded versions.json file as object.
*/
function getJuliaVersionInfo() {
return __awaiter(this, void 0, void 0, function* () {
const versionsFile = yield tc.downloadTool('https://julialang-s3.julialang.org/bin/versions.json');
return JSON.parse(fs.readFileSync(versionsFile).toString());
});
}
exports.getJuliaVersionInfo = getJuliaVersionInfo;
/**
* @returns An array of all Julia versions available for download
*/
function getJuliaVersions(versionInfo) {
return __awaiter(this, void 0, void 0, function* () {
let versions = [];
for (let version in versionInfo) {
versions.push(version);
}
return versions;
});
}
exports.getJuliaVersions = getJuliaVersions;
// This is temporary until we have a better way of fetching releases (see #1, #4 for details)
exports.juliaVersions = ['v1.5.0-rc2', 'v1.5.0-rc1', 'v1.5.0-beta1', 'v1.4.2', 'v1.4.1', 'v1.4.0', 'v1.4.0-rc2', 'v1.4.0-rc1', 'v1.3.1', 'v1.3.0', 'v1.3.0-rc5', 'v1.3.0-rc4', 'v1.3.0-rc3', 'v1.3.0-rc2', 'v1.0.5', 'v1.2.0', 'v1.3.0-rc1', 'v1.2.0-rc3', 'v1.3.0-alpha', 'v1.2.0-rc2', 'v1.2.0-rc1', 'v1.1.1', 'v1.0.4', 'v1.1.0', 'v1.1.0-rc2', 'v1.1.0-rc1', 'v1.0.3', 'v1.0.2', 'v1.0.1', 'v1.0.0', 'v0.7.0', 'v1.0.0-rc1', 'v0.7.0-rc3', 'v0.7.0-rc2', 'v0.7.0-rc1', 'v0.7.0-beta2', 'v0.6.4', 'v0.7.0-beta', 'v0.7.0-alpha', 'v0.6.3', 'v0.6.2', 'v0.6.1', 'v0.6.0', 'v0.6.0-rc3', 'v0.6.0-rc2', 'v0.5.2', 'v0.6.0-rc1', 'v0.6.0-pre.beta', 'v0.5.1', 'v0.6.0-pre.alpha', 'v0.5.0', 'v0.4.7', 'v0.5.0-rc4', 'v0.5.0-rc3', 'v0.5.0-rc2', 'v0.5.0-rc1', 'v0.5.0-rc0', 'v0.4.6', 'v0.4.5', 'v0.4.4', 'v0.4.3', 'v0.4.2', 'v0.4.1', 'v0.3.12', 'v0.4.0', 'v0.4.0-rc4', 'v0.4.0-rc3', 'v0.4.0-rc2', 'v0.4.0-rc1', 'v0.3.11', 'v0.3.10', 'v0.3.9', 'v0.3.8', 'v0.3.7', 'v0.3.6', 'v0.3.5', 'v0.3.4', 'v0.3.3', 'v0.3.2', 'v0.3.1', 'v0.3.0', 'v0.3.0-rc4', 'v0.3.0-rc3', 'v0.3.0-rc2', 'v0.3.0-rc1', 'v0.2.0-rc1', 'v0.2.0-rc3', 'v0.2.0-rc4', 'v0.2.0', 'v0.2.0-rc2'];
function getJuliaVersion(availableReleases, versionInput) {
if (semver.valid(versionInput) == versionInput) {
// versionInput is a valid version, use it directly
@@ -96,87 +45,91 @@ function getJuliaVersion(availableReleases, versionInput) {
return version;
}
exports.getJuliaVersion = getJuliaVersion;
function getNightlyFileName(arch) {
function getMajorMinorVersion(version) {
return version.split('.').slice(0, 2).join('.');
}
function getDownloadURL(version, arch) {
let platform;
if (osPlat === 'win32') { // Windows
platform = 'winnt';
}
else if (osPlat === 'darwin') { // macOS
if (arch == 'x86') {
throw new Error('32-bit Julia is not available on macOS');
}
platform = 'mac';
}
else if (osPlat === 'linux') { // Linux
platform = 'linux';
}
else {
throw new Error(`Platform ${osPlat} is not supported`);
}
// nightlies
if (version == 'nightly') {
const baseURL = 'https://julialangnightlies-s3.julialang.org/bin';
return `${baseURL}/${platform}/${arch}/${getFileName('latest', arch)}`;
}
// normal versions
const baseURL = 'https://julialang-s3.julialang.org/bin';
const versionDir = getMajorMinorVersion(version);
return `${baseURL}/${platform}/${arch}/${versionDir}/${getFileName(version, arch)}`;
}
function getFileName(version, arch) {
let versionExt, ext;
if (osPlat == 'win32') {
if (osPlat === 'win32') { // Windows
versionExt = arch == 'x64' ? '-win64' : '-win32';
ext = 'exe';
}
else if (osPlat == 'darwin') {
else if (osPlat === 'darwin') { // macOS
if (arch == 'x86') {
throw new Error('32-bit Julia is not available on macOS');
}
versionExt = '-mac64';
ext = 'dmg';
}
else if (osPlat === 'linux') {
versionExt = arch == 'x64' ? '-linux64' : '-linux32';
else if (osPlat === 'linux') { // Linux
if (version == 'latest') { // nightly version
versionExt = arch == 'x64' ? '-linux64' : '-linux32';
}
else {
versionExt = arch == 'x64' ? '-linux-x86_64' : '-linux-i686';
}
ext = 'tar.gz';
}
else {
throw new Error(`Platform ${osPlat} is not supported`);
}
return `julia-latest${versionExt}.${ext}`;
return `julia-${version}${versionExt}.${ext}`;
}
function getFileInfo(versionInfo, version, arch) {
if (version == 'nightly') {
return null;
}
for (let file of versionInfo[version].files) {
if (file.os == osMap[osPlat] && file.arch == archMap[arch]) {
return file;
}
}
throw `Could not find ${archMap[arch]}/${version} binaries`;
}
exports.getFileInfo = getFileInfo;
function getDownloadURL(fileInfo, version, arch) {
// nightlies
if (version == 'nightly') {
const baseURL = 'https://julialangnightlies-s3.julialang.org/bin';
return `${baseURL}/${osMap[osPlat]}/${arch}/${getNightlyFileName(arch)}`;
}
return fileInfo.url;
}
exports.getDownloadURL = getDownloadURL;
function installJulia(versionInfo, version, arch) {
function installJulia(version, arch) {
return __awaiter(this, void 0, void 0, function* () {
// Download Julia
const fileInfo = getFileInfo(versionInfo, version, arch);
const downloadURL = getDownloadURL(fileInfo, version, arch);
const downloadURL = getDownloadURL(version, arch);
core.debug(`downloading Julia from ${downloadURL}`);
const juliaDownloadPath = yield tc.downloadTool(downloadURL);
// Verify checksum
if (version != 'nightly') {
const checkSum = yield calculateChecksum(juliaDownloadPath);
if (fileInfo.sha256 != checkSum) {
throw new Error(`Checksum of downloaded file does not match the expected checksum from versions.json.\nExpected: ${fileInfo.sha256}\nGot: ${checkSum}`);
}
core.debug(`Checksum of downloaded file matches expected checksum: ${checkSum}`);
}
else {
core.debug('Skipping checksum check for nightly binaries.');
}
const tempInstallDir = fs.mkdtempSync(`julia-${arch}-${version}-`);
// Install it
switch (osPlat) {
case 'linux':
// tc.extractTar doesn't support stripping components, so we have to call tar manually
yield exec.exec('tar', ['xf', juliaDownloadPath, '--strip-components=1', '-C', tempInstallDir]);
return tempInstallDir;
yield exec.exec('mkdir', [`${process.env.HOME}/julia`]);
yield exec.exec('tar', ['xf', juliaDownloadPath, '--strip-components=1', '-C', `${process.env.HOME}/julia`]);
return `${process.env.HOME}/julia`;
case 'win32':
const juliaInstallationPath = path.join('C:', 'Julia');
if (version == 'nightly' || semver.gtr(version, '1.3', { includePrerelease: true })) {
// The installer changed in 1.4: https://github.com/JuliaLang/julia/blob/ef0c9108b12f3ae177c51037934351ffa703b0b5/NEWS.md#build-system-changes
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/SILENT /dir=${path.join(process.cwd(), tempInstallDir)}" -NoNewWindow -Wait`]);
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/SILENT /dir=${juliaInstallationPath}" -NoNewWindow -Wait`]);
}
else {
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/S /D=${path.join(process.cwd(), tempInstallDir)}" -NoNewWindow -Wait`]);
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/S /D=${juliaInstallationPath}" -NoNewWindow -Wait`]);
}
return tempInstallDir;
return juliaInstallationPath;
case 'darwin':
yield exec.exec('hdiutil', ['attach', juliaDownloadPath]);
yield exec.exec('/bin/bash', ['-c', `cp -a /Volumes/Julia-*/Julia-*.app/Contents/Resources/julia ${tempInstallDir}`]);
return path.join(tempInstallDir, 'julia');
yield exec.exec('mkdir', [`${process.env.HOME}/julia`]);
yield exec.exec('/bin/bash', ['-c', `cp -a /Volumes/Julia-*/Julia-*.app/Contents/Resources/julia ${process.env.HOME}`]);
return `${process.env.HOME}/julia`;
default:
throw new Error(`Platform ${osPlat} is not supported`);
}

41
lib/setup-julia.js generated
View File

@@ -18,66 +18,31 @@ Object.defineProperty(exports, "__esModule", { value: true });
const core = __importStar(require("@actions/core"));
const exec = __importStar(require("@actions/exec"));
const tc = __importStar(require("@actions/tool-cache"));
const fs = __importStar(require("fs"));
const https = __importStar(require("https"));
const path = __importStar(require("path"));
const installer = __importStar(require("./installer"));
function run() {
return __awaiter(this, void 0, void 0, function* () {
try {
// Debugging info
if (core.isDebug()) {
// Log Runner IP Address
https.get('https://httpbin.julialang.org/ip', resp => {
let data = '';
resp.on('data', chunk => {
data += chunk;
});
resp.on('end', () => {
core.debug(`Runner IP address: ${JSON.parse(data).origin}`);
});
}).on('error', err => {
core.debug(`ERROR: Could not retrieve runner IP: ${err}`);
});
}
// Inputs
const versionInput = core.getInput('version');
const arch = core.getInput('arch');
// It can easily happen that, for example, a workflow file contains an input `version: ${{ matrix.julia-version }}`
// while the strategy matrix only contains a key `${{ matrix.version }}`.
// In that case, we want the action to fail, rather than trying to download julia from an URL that's missing parts and 404ing.
// We _could_ fall back to the default but that means that builds silently do things differently than they're meant to, which
// is worse than failing the build.
if (!versionInput) {
throw new Error('Version input must not be null');
}
if (!arch) {
throw new Error(`Arch input must not be null`);
}
const versionInfo = yield installer.getJuliaVersionInfo();
const availableReleases = yield installer.getJuliaVersions(versionInfo);
const availableReleases = installer.juliaVersions;
const version = installer.getJuliaVersion(availableReleases, versionInput);
core.debug(`selected Julia version: ${arch}/${version}`);
core.setOutput('julia-version', version);
// Search in cache
let juliaPath;
juliaPath = tc.find('julia', version, arch);
if (!juliaPath) {
core.debug(`could not find Julia ${arch}/${version} in cache`);
const juliaInstallationPath = yield installer.installJulia(versionInfo, version, arch);
core.debug(`could not find Julia ${version} in cache`);
const juliaInstallationPath = yield installer.installJulia(version, arch);
// Add it to cache
juliaPath = yield tc.cacheDir(juliaInstallationPath, 'julia', version, arch);
core.debug(`added Julia to cache: ${juliaPath}`);
// Remove temporary dir
fs.rmdirSync(juliaInstallationPath, { recursive: true });
}
else {
core.debug(`using cached version of Julia: ${juliaPath}`);
}
// Add it to PATH
core.addPath(path.join(juliaPath, 'bin'));
// Set output
core.setOutput('julia-bindir', path.join(juliaPath, 'bin'));
// Test if Julia has been installed
exec.exec('julia', ['--version']);
// If enabled, also show the full version info

57
package-lock.json generated
View File

@@ -1,13 +1,13 @@
{
"name": "setup-julia",
"version": "1.5.0",
"version": "1.1.10",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@actions/core": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz",
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.0.0.tgz",
"integrity": "sha512-aMIlkx96XH4E/2YZtEOeyrYQfhlas9jIRkfGPqMwXD095Rdkzo4lB6ZmbxPQSzD+e1M+Xsm98ZhuSMYGv/AlqA=="
},
"@actions/exec": {
"version": "1.0.0",
@@ -2861,6 +2861,12 @@
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
"bundled": true,
"dev": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
@@ -3443,13 +3449,6 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"ini": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz",
"integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==",
"dev": true,
"optional": true
},
"invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@@ -5462,36 +5461,6 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
"nock": {
"version": "11.7.2",
"resolved": "https://registry.npmjs.org/nock/-/nock-11.7.2.tgz",
"integrity": "sha512-7swr5bL1xBZ5FctyubjxEVySXOSebyqcL7Vy1bx1nS9IUqQWj81cmKjVKJLr8fHhtzI1MV8nyCdENA/cGcY1+Q==",
"dev": true,
"requires": {
"debug": "^4.1.0",
"json-stringify-safe": "^5.0.1",
"lodash": "^4.17.13",
"mkdirp": "^0.5.0",
"propagate": "^2.0.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
}
}
},
"node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@@ -5852,12 +5821,6 @@
"sisteransi": "^1.0.4"
}
},
"propagate": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz",
"integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==",
"dev": true
},
"psl": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "setup-julia",
"version": "1.5.0",
"version": "1.1.10",
"private": true,
"description": "setup Julia action",
"main": "lib/setup-julia.js",
@@ -21,7 +21,7 @@
"author": "Sascha Mann <git@mail.saschamann.eu>",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.2.6",
"@actions/core": "^1.0.0",
"@actions/exec": "^1.0.0",
"@actions/io": "^1.0.0",
"@actions/tool-cache": "^1.0.0",
@@ -34,7 +34,6 @@
"@zeit/ncc": "^0.22.0",
"jest": "^24.8.0",
"jest-circus": "^24.7.1",
"nock": "^11.7.2",
"prettier": "^1.17.1",
"ts-jest": "^26.0.0",
"typescript": "^3.5.1"

View File

@@ -2,68 +2,17 @@ import * as core from '@actions/core'
import * as exec from '@actions/exec'
import * as tc from '@actions/tool-cache'
import * as crypto from 'crypto'
import * as fs from 'fs'
import * as os from 'os'
import * as path from 'path'
import * as semver from 'semver'
// Translations between actions input and Julia arch names
const osMap = {
'win32': 'winnt',
'darwin': 'mac',
'linux': 'linux'
}
const archMap = {
'x86': 'i686',
'x64': 'x86_64'
}
// Store information about the environment
const osPlat = os.platform() // possible values: win32 (Windows), linux (Linux), darwin (macOS)
core.debug(`platform: ${osPlat}`)
/**
* @returns The SHA256 checksum of a given file.
*/
async function calculateChecksum(file: string): Promise<string> {
const hash = crypto.createHash('sha256')
const input = fs.createReadStream(file)
return new Promise((resolve, reject) => {
input.on('data', (chunk) => {
hash.update(chunk)
})
input.on('end', () => {
const digest = hash.digest('hex')
digest ? resolve(digest) : reject(new Error(`Could not calculate checksum of file ${file}: digest was empty.`))
})
})
}
/**
* @returns The content of the downloaded versions.json file as object.
*/
export async function getJuliaVersionInfo(): Promise<object> {
const versionsFile = await tc.downloadTool('https://julialang-s3.julialang.org/bin/versions.json')
return JSON.parse(fs.readFileSync(versionsFile).toString())
}
/**
* @returns An array of all Julia versions available for download
*/
export async function getJuliaVersions(versionInfo): Promise<string[]> {
let versions: string[] = []
for (let version in versionInfo) {
versions.push(version)
}
return versions
}
// This is temporary until we have a better way of fetching releases (see #1, #4 for details)
export const juliaVersions = ['v1.5.0-rc2', 'v1.5.0-rc1', 'v1.5.0-beta1', 'v1.4.2', 'v1.4.1', 'v1.4.0', 'v1.4.0-rc2', 'v1.4.0-rc1', 'v1.3.1', 'v1.3.0', 'v1.3.0-rc5', 'v1.3.0-rc4', 'v1.3.0-rc3', 'v1.3.0-rc2', 'v1.0.5', 'v1.2.0', 'v1.3.0-rc1', 'v1.2.0-rc3', 'v1.3.0-alpha', 'v1.2.0-rc2', 'v1.2.0-rc1', 'v1.1.1', 'v1.0.4', 'v1.1.0', 'v1.1.0-rc2', 'v1.1.0-rc1', 'v1.0.3', 'v1.0.2', 'v1.0.1', 'v1.0.0', 'v0.7.0', 'v1.0.0-rc1', 'v0.7.0-rc3', 'v0.7.0-rc2', 'v0.7.0-rc1', 'v0.7.0-beta2', 'v0.6.4', 'v0.7.0-beta', 'v0.7.0-alpha', 'v0.6.3', 'v0.6.2', 'v0.6.1', 'v0.6.0', 'v0.6.0-rc3', 'v0.6.0-rc2', 'v0.5.2', 'v0.6.0-rc1', 'v0.6.0-pre.beta', 'v0.5.1', 'v0.6.0-pre.alpha', 'v0.5.0', 'v0.4.7', 'v0.5.0-rc4', 'v0.5.0-rc3', 'v0.5.0-rc2', 'v0.5.0-rc1', 'v0.5.0-rc0', 'v0.4.6', 'v0.4.5', 'v0.4.4', 'v0.4.3', 'v0.4.2', 'v0.4.1', 'v0.3.12', 'v0.4.0', 'v0.4.0-rc4', 'v0.4.0-rc3', 'v0.4.0-rc2', 'v0.4.0-rc1', 'v0.3.11', 'v0.3.10', 'v0.3.9', 'v0.3.8', 'v0.3.7', 'v0.3.6', 'v0.3.5', 'v0.3.4', 'v0.3.3', 'v0.3.2', 'v0.3.1', 'v0.3.0', 'v0.3.0-rc4', 'v0.3.0-rc3', 'v0.3.0-rc2', 'v0.3.0-rc1', 'v0.2.0-rc1', 'v0.2.0-rc3', 'v0.2.0-rc4', 'v0.2.0', 'v0.2.0-rc2']
export function getJuliaVersion(availableReleases: string[], versionInput: string): string {
if (semver.valid(versionInput) == versionInput) {
@@ -88,90 +37,92 @@ export function getJuliaVersion(availableReleases: string[], versionInput: strin
return version
}
function getNightlyFileName(arch: string): string {
function getMajorMinorVersion(version: string): string {
return version.split('.').slice(0, 2).join('.')
}
function getDownloadURL(version: string, arch: string): string {
let platform: string
if (osPlat === 'win32') { // Windows
platform = 'winnt'
} else if (osPlat === 'darwin') { // macOS
if (arch == 'x86') {
throw new Error('32-bit Julia is not available on macOS')
}
platform = 'mac'
} else if (osPlat === 'linux') { // Linux
platform = 'linux'
} else {
throw new Error(`Platform ${osPlat} is not supported`)
}
// nightlies
if (version == 'nightly') {
const baseURL = 'https://julialangnightlies-s3.julialang.org/bin'
return `${baseURL}/${platform}/${arch}/${getFileName('latest', arch)}`
}
// normal versions
const baseURL = 'https://julialang-s3.julialang.org/bin'
const versionDir = getMajorMinorVersion(version)
return `${baseURL}/${platform}/${arch}/${versionDir}/${getFileName(version, arch)}`
}
function getFileName(version: string, arch: string): string {
let versionExt: string, ext: string
if (osPlat == 'win32') {
if (osPlat === 'win32') { // Windows
versionExt = arch == 'x64' ? '-win64' : '-win32'
ext = 'exe'
} else if (osPlat == 'darwin') {
} else if (osPlat === 'darwin') { // macOS
if (arch == 'x86') {
throw new Error('32-bit Julia is not available on macOS')
}
versionExt = '-mac64'
ext = 'dmg'
} else if (osPlat === 'linux') {
versionExt = arch == 'x64' ? '-linux64' : '-linux32'
} else if (osPlat === 'linux') { // Linux
if (version == 'latest') { // nightly version
versionExt = arch == 'x64' ? '-linux64' : '-linux32'
} else {
versionExt = arch == 'x64' ? '-linux-x86_64' : '-linux-i686'
}
ext = 'tar.gz'
} else {
throw new Error(`Platform ${osPlat} is not supported`)
}
return `julia-latest${versionExt}.${ext}`
return `julia-${version}${versionExt}.${ext}`
}
export function getFileInfo(versionInfo, version: string, arch: string) {
if (version == 'nightly') {
return null
}
for (let file of versionInfo[version].files) {
if (file.os == osMap[osPlat] && file.arch == archMap[arch]) {
return file
}
}
throw `Could not find ${archMap[arch]}/${version} binaries`
}
export function getDownloadURL(fileInfo, version: string, arch: string): string {
// nightlies
if (version == 'nightly') {
const baseURL = 'https://julialangnightlies-s3.julialang.org/bin'
return `${baseURL}/${osMap[osPlat]}/${arch}/${getNightlyFileName(arch)}`
}
return fileInfo.url
}
export async function installJulia(versionInfo, version: string, arch: string): Promise<string> {
export async function installJulia(version: string, arch: string): Promise<string> {
// Download Julia
const fileInfo = getFileInfo(versionInfo, version, arch)
const downloadURL = getDownloadURL(fileInfo, version, arch)
const downloadURL = getDownloadURL(version, arch)
core.debug(`downloading Julia from ${downloadURL}`)
const juliaDownloadPath = await tc.downloadTool(downloadURL)
// Verify checksum
if (version != 'nightly') {
const checkSum = await calculateChecksum(juliaDownloadPath)
if (fileInfo.sha256 != checkSum) {
throw new Error(`Checksum of downloaded file does not match the expected checksum from versions.json.\nExpected: ${fileInfo.sha256}\nGot: ${checkSum}`)
}
core.debug(`Checksum of downloaded file matches expected checksum: ${checkSum}`)
} else {
core.debug('Skipping checksum check for nightly binaries.')
}
const tempInstallDir = fs.mkdtempSync(`julia-${arch}-${version}-`)
// Install it
switch (osPlat) {
case 'linux':
// tc.extractTar doesn't support stripping components, so we have to call tar manually
await exec.exec('tar', ['xf', juliaDownloadPath, '--strip-components=1', '-C', tempInstallDir])
return tempInstallDir
await exec.exec('mkdir', [`${process.env.HOME}/julia`])
await exec.exec('tar', ['xf', juliaDownloadPath, '--strip-components=1', '-C', `${process.env.HOME}/julia`])
return `${process.env.HOME}/julia`
case 'win32':
const juliaInstallationPath = path.join('C:', 'Julia')
if (version == 'nightly' || semver.gtr(version, '1.3', {includePrerelease: true})) {
// The installer changed in 1.4: https://github.com/JuliaLang/julia/blob/ef0c9108b12f3ae177c51037934351ffa703b0b5/NEWS.md#build-system-changes
await exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/SILENT /dir=${path.join(process.cwd(), tempInstallDir)}" -NoNewWindow -Wait`])
await exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/SILENT /dir=${juliaInstallationPath}" -NoNewWindow -Wait`])
} else {
await exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/S /D=${path.join(process.cwd(), tempInstallDir)}" -NoNewWindow -Wait`])
await exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/S /D=${juliaInstallationPath}" -NoNewWindow -Wait`])
}
return tempInstallDir
return juliaInstallationPath
case 'darwin':
await exec.exec('hdiutil', ['attach', juliaDownloadPath])
await exec.exec('/bin/bash', ['-c', `cp -a /Volumes/Julia-*/Julia-*.app/Contents/Resources/julia ${tempInstallDir}`])
return path.join(tempInstallDir, 'julia')
await exec.exec('mkdir', [`${process.env.HOME}/julia`])
await exec.exec('/bin/bash', ['-c', `cp -a /Volumes/Julia-*/Julia-*.app/Contents/Resources/julia ${process.env.HOME}`])
return `${process.env.HOME}/julia`
default:
throw new Error(`Platform ${osPlat} is not supported`)
}

View File

@@ -2,77 +2,35 @@ import * as core from '@actions/core'
import * as exec from '@actions/exec'
import * as tc from '@actions/tool-cache'
import * as fs from 'fs'
import * as https from 'https'
import * as path from 'path'
import * as installer from './installer'
async function run() {
try {
// Debugging info
if (core.isDebug()) {
// Log Runner IP Address
https.get('https://httpbin.julialang.org/ip', resp => {
let data = ''
resp.on('data', chunk => {
data += chunk
})
resp.on('end', () => {
core.debug(`Runner IP address: ${JSON.parse(data).origin}`)
})
}).on('error', err => {
core.debug(`ERROR: Could not retrieve runner IP: ${err}`)
})
}
// Inputs
const versionInput = core.getInput('version')
const arch = core.getInput('arch')
// It can easily happen that, for example, a workflow file contains an input `version: ${{ matrix.julia-version }}`
// while the strategy matrix only contains a key `${{ matrix.version }}`.
// In that case, we want the action to fail, rather than trying to download julia from an URL that's missing parts and 404ing.
// We _could_ fall back to the default but that means that builds silently do things differently than they're meant to, which
// is worse than failing the build.
if (!versionInput) {
throw new Error('Version input must not be null')
}
if (!arch) {
throw new Error(`Arch input must not be null`)
}
const versionInfo = await installer.getJuliaVersionInfo()
const availableReleases = await installer.getJuliaVersions(versionInfo)
const availableReleases = installer.juliaVersions
const version = installer.getJuliaVersion(availableReleases, versionInput)
core.debug(`selected Julia version: ${arch}/${version}`)
core.setOutput('julia-version', version)
// Search in cache
let juliaPath: string;
juliaPath = tc.find('julia', version, arch)
if (!juliaPath) {
core.debug(`could not find Julia ${arch}/${version} in cache`)
const juliaInstallationPath = await installer.installJulia(versionInfo, version, arch)
core.debug(`could not find Julia ${version} in cache`)
const juliaInstallationPath = await installer.installJulia(version, arch);
// Add it to cache
juliaPath = await tc.cacheDir(juliaInstallationPath, 'julia', version, arch)
core.debug(`added Julia to cache: ${juliaPath}`)
// Remove temporary dir
fs.rmdirSync(juliaInstallationPath, {recursive: true})
} else {
core.debug(`using cached version of Julia: ${juliaPath}`)
}
// Add it to PATH
core.addPath(path.join(juliaPath, 'bin'))
// Set output
core.setOutput('julia-bindir', path.join(juliaPath, 'bin'))
// Test if Julia has been installed
exec.exec('julia', ['--version'])