mirror of
https://github.com/julia-actions/setup-julia.git
synced 2026-02-12 19:16:54 +08:00
Compare commits
1 Commits
releases/v
...
releases/v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4469f5b9da |
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -1 +0,0 @@
|
||||
* @julia-actions/reviewers
|
||||
7
.github/dependabot.yml
vendored
7
.github/dependabot.yml
vendored
@@ -1,7 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: gitsubmodule
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
34
.github/workflows/backup.yml
vendored
34
.github/workflows/backup.yml
vendored
@@ -1,34 +0,0 @@
|
||||
name: Backup
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '5 4 * * 0'
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
backup:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 60
|
||||
|
||||
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 }}
|
||||
9
.github/workflows/checkin.yml
vendored
9
.github/workflows/checkin.yml
vendored
@@ -1,21 +1,14 @@
|
||||
name: "PR Checks"
|
||||
on: [pull_request, push]
|
||||
|
||||
concurrency:
|
||||
# Skip intermediate builds: all builds except for builds on the `master`, `main`, or `release-*` branches
|
||||
# Cancel intermediate builds: only pull request builds
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.ref != 'refs/heads/master' || github.ref != 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-') || github.run_number }}
|
||||
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
|
||||
|
||||
jobs:
|
||||
check_pr:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: "npm ci"
|
||||
run: npm ci --legacy-peer-deps
|
||||
run: npm ci
|
||||
|
||||
- name: "npm run build"
|
||||
run: npm run build
|
||||
|
||||
74
.github/workflows/codeql-analysis.yml
vendored
74
.github/workflows/codeql-analysis.yml
vendored
@@ -1,74 +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"
|
||||
|
||||
concurrency:
|
||||
# Skip intermediate builds: all builds except for builds on the `master`, `main`, or `release-*` branches
|
||||
# Cancel intermediate builds: only pull request builds
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.ref != 'refs/heads/master' || github.ref != 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-') || github.run_number }}
|
||||
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
|
||||
|
||||
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
|
||||
timeout-minutes: 60
|
||||
|
||||
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
|
||||
40
.github/workflows/example-builds-defaultarch.yml
vendored
40
.github/workflows/example-builds-defaultarch.yml
vendored
@@ -1,40 +0,0 @@
|
||||
name: Example builds (default arch)
|
||||
|
||||
concurrency:
|
||||
# Skip intermediate builds: all builds except for builds on the `master`, `main`, or `release-*` branches
|
||||
# Cancel intermediate builds: only pull request builds
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.ref != 'refs/heads/master' || github.ref != 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-') || github.run_number }}
|
||||
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ['main', 'master', 'releases/*']
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
julia-version: ['1']
|
||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1.0.0
|
||||
|
||||
- name: "Install dependencies"
|
||||
run: |
|
||||
npm install --legacy-peer-deps
|
||||
npm run build
|
||||
npm run pack
|
||||
|
||||
- name: "Set up Julia"
|
||||
id: setup-julia
|
||||
uses: ./
|
||||
with:
|
||||
version: ${{ matrix.julia-version }}
|
||||
- run: julia --version
|
||||
- run: julia --compile=min -O0 -e 'import InteractiveUtils; InteractiveUtils.versioninfo()'
|
||||
@@ -1,38 +0,0 @@
|
||||
name: Example builds (nightly, default arch)
|
||||
|
||||
concurrency:
|
||||
# Skip intermediate builds: all builds except for builds on the `master`, `main`, or `release-*` branches
|
||||
# Cancel intermediate builds: only pull request builds
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.ref != 'refs/heads/master' || github.ref != 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-') || github.run_number }}
|
||||
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ['main', 'master', 'releases/*']
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
julia-version: [nightly, 1.8-nightly]
|
||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1.0.0
|
||||
|
||||
- name: "Install dependencies"
|
||||
run: |
|
||||
npm install --legacy-peer-deps
|
||||
npm run build
|
||||
npm run pack
|
||||
|
||||
- name: "Set up Julia (${{ matrix.julia-version }})"
|
||||
uses: ./
|
||||
with:
|
||||
version: ${{ matrix.julia-version }}
|
||||
- run: julia --version
|
||||
- run: julia --compile=min -O0 -e 'import InteractiveUtils; InteractiveUtils.versioninfo()'
|
||||
20
.github/workflows/example-builds-nightly.yml
vendored
20
.github/workflows/example-builds-nightly.yml
vendored
@@ -1,14 +1,7 @@
|
||||
name: Example builds (nightly)
|
||||
|
||||
concurrency:
|
||||
# Skip intermediate builds: all builds except for builds on the `master`, `main`, or `release-*` branches
|
||||
# Cancel intermediate builds: only pull request builds
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.ref != 'refs/heads/master' || github.ref != 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-') || github.run_number }}
|
||||
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ['main', 'master', 'releases/*']
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '37 17 * * *'
|
||||
@@ -16,31 +9,28 @@ on:
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
julia-version: [nightly, 1.8-nightly]
|
||||
julia-arch: [x64, x86]
|
||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||
# 32-bit Julia binaries are not available on macOS
|
||||
exclude:
|
||||
- os: macOS-latest
|
||||
julia-arch: x86
|
||||
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1.0.0
|
||||
|
||||
|
||||
- name: "Install dependencies"
|
||||
run: |
|
||||
npm install --legacy-peer-deps
|
||||
npm install
|
||||
npm run build
|
||||
npm run pack
|
||||
|
||||
- name: "Set up Julia (${{ matrix.julia-version }})"
|
||||
- name: "Set up Julia (nightly)"
|
||||
uses: ./
|
||||
with:
|
||||
version: ${{ matrix.julia-version }}
|
||||
version: nightly
|
||||
arch: ${{ matrix.julia-arch }}
|
||||
- run: julia --version
|
||||
- run: julia --compile=min -O0 -e 'import InteractiveUtils; InteractiveUtils.versioninfo()'
|
||||
|
||||
21
.github/workflows/example-builds.yml
vendored
21
.github/workflows/example-builds.yml
vendored
@@ -1,46 +1,33 @@
|
||||
name: Example builds
|
||||
|
||||
concurrency:
|
||||
# Skip intermediate builds: all builds except for builds on the `master`, `main`, or `release-*` branches
|
||||
# Cancel intermediate builds: only pull request builds
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.ref != 'refs/heads/master' || github.ref != 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-') || github.run_number }}
|
||||
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ['main', 'master', 'releases/*']
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
julia-version: ['1.0.5', '1.2', '^1.5.0-beta1', '1']
|
||||
julia-version: ['1.0.5', '1', '^1.5.0-beta1']
|
||||
julia-arch: [x64, x86]
|
||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||
# 32-bit Julia binaries are not available on macOS
|
||||
exclude:
|
||||
- os: macOS-latest
|
||||
julia-arch: x86
|
||||
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1.0.0
|
||||
|
||||
- name: "Install dependencies"
|
||||
run: |
|
||||
npm install --legacy-peer-deps
|
||||
npm install
|
||||
npm run build
|
||||
npm run pack
|
||||
|
||||
- name: "Set up Julia"
|
||||
id: setup-julia
|
||||
uses: ./
|
||||
with:
|
||||
version: ${{ matrix.julia-version }}
|
||||
arch: ${{ matrix.julia-arch }}
|
||||
- run: julia --version
|
||||
- run: julia --compile=min -O0 -e 'import InteractiveUtils; InteractiveUtils.versioninfo()'
|
||||
|
||||
100
README.md
100
README.md
@@ -1,6 +1,5 @@
|
||||
# setup-julia Action
|
||||
|
||||
[](https://securitylab.github.com/tools/codeql)
|
||||
[](https://dependabot.com)
|
||||
|
||||
This action sets up a Julia environment for use in actions by downloading a specified version of Julia and adding it to PATH.
|
||||
@@ -8,80 +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)
|
||||
- [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.
|
||||
#
|
||||
# Please note that installing aarch64 binaries only makes sense on self-hosted aarch64 runners.
|
||||
# We currently don't run test builds on that architecture, so we cannot guarantee that the input won't break randomly,
|
||||
# although there is no reason why it would.
|
||||
#
|
||||
# Supported values: x64 | x86 | aarch64 (untested)
|
||||
#
|
||||
# Note: you can use X64, X86, and ARM64 as synonyms for x64, x86, and aarch64, respectively.
|
||||
#
|
||||
# Defaults to the architecture of the runner executing the job.
|
||||
arch: ''
|
||||
|
||||
# Set the display setting for printing InteractiveUtils.versioninfo() after installing.
|
||||
#
|
||||
# Starting Julia and running InteractiveUtils.versioninfo() takes a significant amount of time (1s or ~10% of the total build time in testing),
|
||||
# so you may not want to run it in every build, in particular on paid runners, as this cost will add up quickly.
|
||||
#
|
||||
# See "versioninfo" below for example usage and further explanations.
|
||||
#
|
||||
# Supported values: true | false | never
|
||||
#
|
||||
# true: Always print versioninfo
|
||||
# false: Only print versioninfo for nightly Julia
|
||||
# never: Never print versioninfo
|
||||
#
|
||||
# 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
|
||||
|
||||
@@ -98,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
|
||||
|
||||
@@ -109,11 +46,12 @@ You can either specify specific Julia versions or version ranges. If you specify
|
||||
- `^1.3.0-0` is a **caret** version range that includes _all_ pre-releases. It matches all versions `≥ 1.3.0-` and `< 2.0.0`.
|
||||
- `~1.3.0-0` is a **tilde** version range that includes _all_ pre-releases. It matches all versions `≥ 1.3.0-` and `< 1.4.0`.
|
||||
- `nightly` will install the latest nightly build.
|
||||
- `1.7-nightly` will install the latest nightly build for the upcoming 1.7 release. This version will only be available during certain phases of the Julia release cycle.
|
||||
|
||||
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
|
||||
|
||||
@@ -129,7 +67,7 @@ jobs:
|
||||
matrix:
|
||||
julia-version: ['1.0', '1.2.0', '^1.3.0-rc1']
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1.0.0
|
||||
- name: "Set up Julia"
|
||||
@@ -155,7 +93,7 @@ jobs:
|
||||
exclude:
|
||||
- os: macOS-latest
|
||||
julia-arch: x86
|
||||
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1.0.0
|
||||
- name: "Set up Julia"
|
||||
@@ -182,7 +120,7 @@ jobs:
|
||||
- os: windows-latest
|
||||
julia-version: ['1.0.4']
|
||||
julia-arch: x86
|
||||
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1.0.0
|
||||
- name: "Set up Julia"
|
||||
@@ -193,16 +131,6 @@ jobs:
|
||||
shell: bash
|
||||
```
|
||||
|
||||
### versioninfo
|
||||
|
||||
By default, only the output of `julia --version` is printed as verification that Julia has been installed for stable versions of Julia.
|
||||
`InteractiveUtils.versioninfo()` is run by default for nightly builds.
|
||||
|
||||
Starting Julia and printing the full versioninfo takes a significant amount of time (1s or ~10% of the total build time in testing), so you may not want to run it in every build, in particular on paid runners as this cost will add up quickly.
|
||||
However, `julia --version` does not provide sufficient information to know which commit a nightly binary was built from, therefore it is useful to show the full versioninfo on nightly builds regardless.
|
||||
|
||||
You can override this behaviour by changing the input to `never` if you never want to run `InteractiveUtils.versioninfo()` or to `true` if you always want to run `InteractiveUtils.versioninfo()`, even on stable Julia builds.
|
||||
|
||||
## 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.
|
||||
@@ -215,17 +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.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
50
__tests__/main.test.ts
Normal 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()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
11
action.yml
11
action.yml
@@ -6,20 +6,15 @@ inputs:
|
||||
description: 'The Julia version to download (if necessary) and use. Example: 1.0.4'
|
||||
default: '1'
|
||||
arch:
|
||||
description: 'Architecture of the Julia binaries. Defaults to the architecture of the runner executing the job.'
|
||||
description: 'Architecture of the Julia binaries. Defaults to x64.'
|
||||
required: false
|
||||
default: '${{ runner.arch }}'
|
||||
default: 'x64'
|
||||
show-versioninfo:
|
||||
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: 'node16'
|
||||
using: 'node12'
|
||||
main: 'dist/index.js'
|
||||
branding:
|
||||
icon: 'download'
|
||||
|
||||
2
bin
2
bin
Submodule bin updated: 31b4b500a3...9ceca17c9c
3095
dist/index.js
vendored
3095
dist/index.js
vendored
File diff suppressed because it is too large
Load Diff
284
lib/installer.js
generated
284
lib/installer.js
generated
@@ -18,80 +18,23 @@ 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 retry = require("async-retry");
|
||||
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',
|
||||
'aarch64': 'aarch64'
|
||||
};
|
||||
// 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* () {
|
||||
// Occasionally the connection is reset for unknown reasons
|
||||
// In those cases, retry the download
|
||||
const versionsFile = yield retry((bail) => __awaiter(this, void 0, void 0, function* () {
|
||||
return yield tc.downloadTool('https://julialang-s3.julialang.org/bin/versions.json');
|
||||
}), {
|
||||
onRetry: (err) => {
|
||||
core.debug(`Download of versions.json failed, trying again. Error: ${err}`);
|
||||
}
|
||||
});
|
||||
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.2', 'v1.5.1', 'v1.5.0', '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.endsWith('nightly')) {
|
||||
// versionInput is a valid version or a nightly version, use it directly
|
||||
if (semver.valid(versionInput) == versionInput) {
|
||||
// versionInput is a valid version, use it directly
|
||||
return versionInput;
|
||||
}
|
||||
// nightlies
|
||||
if (versionInput == 'nightly') {
|
||||
return 'nightly';
|
||||
}
|
||||
// Use the highest available version that matches versionInput
|
||||
let version = semver.maxSatisfying(availableReleases, versionInput);
|
||||
if (version == null) {
|
||||
@@ -102,195 +45,94 @@ function getJuliaVersion(availableReleases, versionInput) {
|
||||
return version;
|
||||
}
|
||||
exports.getJuliaVersion = getJuliaVersion;
|
||||
function getDesiredFileExts() {
|
||||
let fileExt1;
|
||||
let hasFileExt2;
|
||||
let fileExt2;
|
||||
if (osPlat == 'win32') {
|
||||
fileExt1 = 'exe';
|
||||
hasFileExt2 = false;
|
||||
fileExt2 = '';
|
||||
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') {
|
||||
fileExt1 = 'tar.gz';
|
||||
hasFileExt2 = true;
|
||||
fileExt2 = 'dmg';
|
||||
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') {
|
||||
fileExt1 = 'tar.gz';
|
||||
hasFileExt2 = false;
|
||||
fileExt2 = '';
|
||||
else if (osPlat === 'linux') { // Linux
|
||||
platform = 'linux';
|
||||
}
|
||||
else {
|
||||
throw new Error(`Platform ${osPlat} is not supported`);
|
||||
}
|
||||
return [fileExt1, hasFileExt2, fileExt2];
|
||||
}
|
||||
function getNightlyFileName(arch) {
|
||||
let versionExt;
|
||||
let fileExt1;
|
||||
[fileExt1, ,] = getDesiredFileExts();
|
||||
if (osPlat == 'win32') {
|
||||
versionExt = arch == 'x64' ? '-win64' : '-win32';
|
||||
// nightlies
|
||||
if (version == 'nightly') {
|
||||
const baseURL = 'https://julialangnightlies-s3.julialang.org/bin';
|
||||
return `${baseURL}/${platform}/${arch}/${getFileName('latest', arch)}`;
|
||||
}
|
||||
else if (osPlat == 'darwin') {
|
||||
// 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') { // Windows
|
||||
versionExt = arch == 'x64' ? '-win64' : '-win32';
|
||||
ext = 'exe';
|
||||
}
|
||||
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}.${fileExt1}`;
|
||||
return `julia-${version}${versionExt}.${ext}`;
|
||||
}
|
||||
function getFileInfo(versionInfo, version, arch) {
|
||||
const err = `Could not find ${archMap[arch]}/${version} binaries`;
|
||||
let fileExt1;
|
||||
let hasFileExt2;
|
||||
let fileExt2;
|
||||
[fileExt1, hasFileExt2, fileExt2] = getDesiredFileExts();
|
||||
if (version.endsWith('nightly')) {
|
||||
return null;
|
||||
}
|
||||
if (!versionInfo[version]) {
|
||||
throw err;
|
||||
}
|
||||
for (let file of versionInfo[version].files) {
|
||||
if (file.os == osMap[osPlat] && file.arch == archMap[arch]) {
|
||||
if (file.extension == fileExt1) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasFileExt2) {
|
||||
core.debug(`Could not find ${fileExt1}; trying to find ${fileExt2} instead`);
|
||||
for (let file of versionInfo[version].files) {
|
||||
if (file.os == osMap[osPlat] && file.arch == archMap[arch]) {
|
||||
if (file.extension == fileExt2) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
exports.getFileInfo = getFileInfo;
|
||||
function getDownloadURL(fileInfo, version, arch) {
|
||||
const baseURL = `https://julialangnightlies-s3.julialang.org/bin/${osMap[osPlat]}/${arch}`;
|
||||
// release branch nightlies, e.g. 1.6-nightlies should return .../bin/linux/x64/1.6/julia-latest-linux64.tar.gz
|
||||
const majorMinorMatches = /^(\d*.\d*)-nightly/.exec(version);
|
||||
if (majorMinorMatches) {
|
||||
return `${baseURL}/${majorMinorMatches[1]}/${getNightlyFileName(arch)}`;
|
||||
}
|
||||
// nightlies
|
||||
if (version == 'nightly') {
|
||||
return `${baseURL}/${getNightlyFileName(arch)}`;
|
||||
}
|
||||
// Verify that fileInfo.url points at the official Julia download servers
|
||||
if (!fileInfo.url.startsWith('https://julialang-s3.julialang.org/')) {
|
||||
throw new Error(`versions.json points at a download location outside of Julia's download server: ${fileInfo.url}. Aborting for security reasons.`);
|
||||
}
|
||||
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}`);
|
||||
// Occasionally the connection is reset for unknown reasons
|
||||
// In those cases, retry the download
|
||||
const juliaDownloadPath = yield retry((bail) => __awaiter(this, void 0, void 0, function* () {
|
||||
return yield tc.downloadTool(downloadURL);
|
||||
}), {
|
||||
onRetry: (err) => {
|
||||
core.debug(`Download of ${downloadURL} failed, trying again. Error: ${err}`);
|
||||
}
|
||||
});
|
||||
// Verify checksum
|
||||
if (!version.endsWith('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}-`);
|
||||
const juliaDownloadPath = yield tc.downloadTool(downloadURL);
|
||||
// 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':
|
||||
if (version.endsWith('nightly') || semver.gtr(version, '1.3', { includePrerelease: true })) {
|
||||
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':
|
||||
if (fileInfo !== null && fileInfo.extension == 'dmg') {
|
||||
core.debug(`Support for .dmg files is deprecated and may be removed in a future release`);
|
||||
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');
|
||||
}
|
||||
else {
|
||||
// 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('hdiutil', ['attach', juliaDownloadPath]);
|
||||
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`);
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.installJulia = installJulia;
|
||||
/**
|
||||
* Test if Julia has been installed and print the version.
|
||||
*
|
||||
* true => always show versioninfo
|
||||
* false => only show on nightlies
|
||||
* never => never show it anywhere
|
||||
*
|
||||
* @param showVersionInfoInput
|
||||
*/
|
||||
function showVersionInfo(showVersionInfoInput, version) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
// --compile=min -O0 reduces the time from ~1.8-1.9s to ~0.8-0.9s
|
||||
let exitCode;
|
||||
switch (showVersionInfoInput) {
|
||||
case 'true':
|
||||
exitCode = yield exec.exec('julia', ['--compile=min', '-O0', '-e', 'using InteractiveUtils; versioninfo()']);
|
||||
break;
|
||||
case 'false':
|
||||
if (version.endsWith('nightly')) {
|
||||
exitCode = yield exec.exec('julia', ['--compile=min', '-O0', '-e', 'using InteractiveUtils; versioninfo()']);
|
||||
}
|
||||
else {
|
||||
exitCode = yield exec.exec('julia', ['--version']);
|
||||
}
|
||||
break;
|
||||
case 'never':
|
||||
exitCode = yield exec.exec('julia', ['--version']);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`${showVersionInfoInput} is not a valid value for show-versioninfo. Supported values: true | false | never`);
|
||||
}
|
||||
if (exitCode !== 0) {
|
||||
throw new Error(`Julia could not be installed properly. Exit code: ${exitCode}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.showVersionInfo = showVersionInfo;
|
||||
|
||||
36
lib/setup-julia.js
generated
36
lib/setup-julia.js
generated
@@ -16,19 +16,11 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
||||
};
|
||||
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"));
|
||||
const archSynonyms = {
|
||||
'x86': 'x86',
|
||||
'X86': 'x86',
|
||||
'x64': 'x64',
|
||||
'X64': 'x64',
|
||||
'aarch64': 'aarch64',
|
||||
'ARM64': 'aarch64'
|
||||
};
|
||||
function run() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
@@ -49,7 +41,7 @@ function run() {
|
||||
}
|
||||
// Inputs
|
||||
const versionInput = core.getInput('version');
|
||||
const originalArchInput = core.getInput('arch');
|
||||
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.
|
||||
@@ -58,37 +50,33 @@ function run() {
|
||||
if (!versionInput) {
|
||||
throw new Error('Version input must not be null');
|
||||
}
|
||||
if (!originalArchInput) {
|
||||
if (!arch) {
|
||||
throw new Error(`Arch input must not be null`);
|
||||
}
|
||||
const arch = archSynonyms[originalArchInput];
|
||||
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 and print the version
|
||||
const showVersionInfoInput = core.getInput('show-versioninfo');
|
||||
yield installer.showVersionInfo(showVersionInfoInput, version);
|
||||
// Test if Julia has been installed
|
||||
exec.exec('julia', ['--version']);
|
||||
// If enabled, also show the full version info
|
||||
if (core.getInput('show-versioninfo') == 'true') {
|
||||
exec.exec('julia', ['-e', 'using InteractiveUtils; versioninfo()']);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
core.setFailed(error.message);
|
||||
|
||||
8665
package-lock.json
generated
8665
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "setup-julia",
|
||||
"version": "1.8.3",
|
||||
"version": "1.2.2",
|
||||
"private": true,
|
||||
"description": "setup Julia action",
|
||||
"main": "lib/setup-julia.js",
|
||||
@@ -21,22 +21,19 @@
|
||||
"author": "Sascha Mann <git@mail.saschamann.eu>",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/core": "^1.2.4",
|
||||
"@actions/exec": "^1.0.0",
|
||||
"@actions/io": "^1.0.0",
|
||||
"@actions/tool-cache": "^1.0.0",
|
||||
"async-retry": "^1.3.1",
|
||||
"semver": "^6.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/async-retry": "^1.4.2",
|
||||
"@types/jest": "^24.0.13",
|
||||
"@types/node": "^12.12.7",
|
||||
"@types/semver": "^6.0.0",
|
||||
"@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"
|
||||
|
||||
293
src/installer.ts
293
src/installer.ts
@@ -2,85 +2,29 @@ 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 retry = require('async-retry')
|
||||
|
||||
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',
|
||||
'aarch64': 'aarch64'
|
||||
}
|
||||
|
||||
// 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> {
|
||||
// Occasionally the connection is reset for unknown reasons
|
||||
// In those cases, retry the download
|
||||
const versionsFile = await retry(async (bail: Function) => {
|
||||
return await tc.downloadTool('https://julialang-s3.julialang.org/bin/versions.json')
|
||||
}, {
|
||||
onRetry: (err: Error) => {
|
||||
core.debug(`Download of versions.json failed, trying again. Error: ${err}`)
|
||||
}
|
||||
})
|
||||
|
||||
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.2', 'v1.5.1', 'v1.5.0', '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 || versionInput.endsWith('nightly')) {
|
||||
// versionInput is a valid version or a nightly version, use it directly
|
||||
if (semver.valid(versionInput) == versionInput) {
|
||||
// versionInput is a valid version, use it directly
|
||||
return versionInput
|
||||
}
|
||||
|
||||
// nightlies
|
||||
if (versionInput == 'nightly') {
|
||||
return 'nightly'
|
||||
}
|
||||
|
||||
// Use the highest available version that matches versionInput
|
||||
let version = semver.maxSatisfying(availableReleases, versionInput)
|
||||
if (version == null) {
|
||||
@@ -93,204 +37,93 @@ export function getJuliaVersion(availableReleases: string[], versionInput: strin
|
||||
return version
|
||||
}
|
||||
|
||||
function getDesiredFileExts(): [string, boolean, string] {
|
||||
let fileExt1: string
|
||||
let hasFileExt2: boolean
|
||||
let fileExt2: string
|
||||
|
||||
if (osPlat == 'win32') {
|
||||
fileExt1 = 'exe'
|
||||
hasFileExt2 = false
|
||||
fileExt2 = ''
|
||||
} else if (osPlat == 'darwin') {
|
||||
fileExt1 = 'tar.gz'
|
||||
hasFileExt2 = true
|
||||
fileExt2 = 'dmg'
|
||||
} else if (osPlat === 'linux') {
|
||||
fileExt1 = 'tar.gz'
|
||||
hasFileExt2 = false
|
||||
fileExt2 = ''
|
||||
} else {
|
||||
throw new Error(`Platform ${osPlat} is not supported`)
|
||||
}
|
||||
|
||||
return [fileExt1, hasFileExt2, fileExt2]
|
||||
function getMajorMinorVersion(version: string): string {
|
||||
return version.split('.').slice(0, 2).join('.')
|
||||
}
|
||||
|
||||
function getNightlyFileName(arch: string): string {
|
||||
let versionExt: string
|
||||
let fileExt1: string
|
||||
[fileExt1, , ] = getDesiredFileExts()
|
||||
function getDownloadURL(version: string, arch: string): string {
|
||||
let platform: string
|
||||
|
||||
if (osPlat == 'win32') {
|
||||
versionExt = arch == 'x64' ? '-win64' : '-win32'
|
||||
} else if (osPlat == 'darwin') {
|
||||
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')
|
||||
}
|
||||
versionExt = '-mac64'
|
||||
} else if (osPlat === 'linux') {
|
||||
versionExt = arch == 'x64' ? '-linux64' : '-linux32'
|
||||
platform = 'mac'
|
||||
} else if (osPlat === 'linux') { // Linux
|
||||
platform = 'linux'
|
||||
} else {
|
||||
throw new Error(`Platform ${osPlat} is not supported`)
|
||||
}
|
||||
|
||||
return `julia-latest${versionExt}.${fileExt1}`
|
||||
}
|
||||
|
||||
export function getFileInfo(versionInfo, version: string, arch: string) {
|
||||
const err = `Could not find ${archMap[arch]}/${version} binaries`
|
||||
|
||||
let fileExt1: string
|
||||
let hasFileExt2: boolean
|
||||
let fileExt2: string
|
||||
[fileExt1, hasFileExt2, fileExt2] = getDesiredFileExts()
|
||||
|
||||
if (version.endsWith('nightly')) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (!versionInfo[version]) {
|
||||
throw err
|
||||
}
|
||||
|
||||
for (let file of versionInfo[version].files) {
|
||||
if (file.os == osMap[osPlat] && file.arch == archMap[arch]) {
|
||||
if (file.extension == fileExt1) {
|
||||
return file
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasFileExt2) {
|
||||
core.debug(`Could not find ${fileExt1}; trying to find ${fileExt2} instead`)
|
||||
for (let file of versionInfo[version].files) {
|
||||
if (file.os == osMap[osPlat] && file.arch == archMap[arch]) {
|
||||
if (file.extension == fileExt2) {
|
||||
return file
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw err
|
||||
}
|
||||
|
||||
export function getDownloadURL(fileInfo, version: string, arch: string): string {
|
||||
const baseURL = `https://julialangnightlies-s3.julialang.org/bin/${osMap[osPlat]}/${arch}`
|
||||
|
||||
// release branch nightlies, e.g. 1.6-nightlies should return .../bin/linux/x64/1.6/julia-latest-linux64.tar.gz
|
||||
const majorMinorMatches = /^(\d*.\d*)-nightly/.exec(version)
|
||||
if (majorMinorMatches) {
|
||||
return `${baseURL}/${majorMinorMatches[1]}/${getNightlyFileName(arch)}`
|
||||
}
|
||||
|
||||
// nightlies
|
||||
if (version == 'nightly') {
|
||||
return `${baseURL}/${getNightlyFileName(arch)}`
|
||||
const baseURL = 'https://julialangnightlies-s3.julialang.org/bin'
|
||||
return `${baseURL}/${platform}/${arch}/${getFileName('latest', arch)}`
|
||||
}
|
||||
|
||||
// Verify that fileInfo.url points at the official Julia download servers
|
||||
if (!fileInfo.url.startsWith('https://julialang-s3.julialang.org/')) {
|
||||
throw new Error(`versions.json points at a download location outside of Julia's download server: ${fileInfo.url}. Aborting for security reasons.`)
|
||||
}
|
||||
return fileInfo.url
|
||||
// normal versions
|
||||
const baseURL = 'https://julialang-s3.julialang.org/bin'
|
||||
const versionDir = getMajorMinorVersion(version)
|
||||
|
||||
return `${baseURL}/${platform}/${arch}/${versionDir}/${getFileName(version, arch)}`
|
||||
}
|
||||
|
||||
export async function installJulia(versionInfo, version: string, arch: string): Promise<string> {
|
||||
// Download Julia
|
||||
const fileInfo = getFileInfo(versionInfo, version, arch)
|
||||
const downloadURL = getDownloadURL(fileInfo, version, arch)
|
||||
core.debug(`downloading Julia from ${downloadURL}`)
|
||||
function getFileName(version: string, arch: string): string {
|
||||
let versionExt: string, ext: string
|
||||
|
||||
// Occasionally the connection is reset for unknown reasons
|
||||
// In those cases, retry the download
|
||||
const juliaDownloadPath = await retry(async (bail: Function) => {
|
||||
return await tc.downloadTool(downloadURL)
|
||||
}, {
|
||||
onRetry: (err: Error) => {
|
||||
core.debug(`Download of ${downloadURL} failed, trying again. Error: ${err}`)
|
||||
if (osPlat === 'win32') { // Windows
|
||||
versionExt = arch == 'x64' ? '-win64' : '-win32'
|
||||
ext = 'exe'
|
||||
} else if (osPlat === 'darwin') { // macOS
|
||||
if (arch == 'x86') {
|
||||
throw new Error('32-bit Julia is not available on macOS')
|
||||
}
|
||||
})
|
||||
|
||||
// Verify checksum
|
||||
if (!version.endsWith('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}`)
|
||||
versionExt = '-mac64'
|
||||
ext = 'dmg'
|
||||
} else if (osPlat === 'linux') { // Linux
|
||||
if (version == 'latest') { // nightly version
|
||||
versionExt = arch == 'x64' ? '-linux64' : '-linux32'
|
||||
} else {
|
||||
versionExt = arch == 'x64' ? '-linux-x86_64' : '-linux-i686'
|
||||
}
|
||||
core.debug(`Checksum of downloaded file matches expected checksum: ${checkSum}`)
|
||||
ext = 'tar.gz'
|
||||
} else {
|
||||
core.debug('Skipping checksum check for nightly binaries.')
|
||||
throw new Error(`Platform ${osPlat} is not supported`)
|
||||
}
|
||||
|
||||
const tempInstallDir = fs.mkdtempSync(`julia-${arch}-${version}-`)
|
||||
return `julia-${version}${versionExt}.${ext}`
|
||||
}
|
||||
|
||||
export async function installJulia(version: string, arch: string): Promise<string> {
|
||||
// Download Julia
|
||||
const downloadURL = getDownloadURL(version, arch)
|
||||
core.debug(`downloading Julia from ${downloadURL}`)
|
||||
const juliaDownloadPath = await tc.downloadTool(downloadURL)
|
||||
|
||||
// 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':
|
||||
if (version.endsWith('nightly') || semver.gtr(version, '1.3', {includePrerelease: true})) {
|
||||
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':
|
||||
if (fileInfo !== null && fileInfo.extension == 'dmg') {
|
||||
core.debug(`Support for .dmg files is deprecated and may be removed in a future release`)
|
||||
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')
|
||||
} else {
|
||||
// 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('hdiutil', ['attach', juliaDownloadPath])
|
||||
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`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if Julia has been installed and print the version.
|
||||
*
|
||||
* true => always show versioninfo
|
||||
* false => only show on nightlies
|
||||
* never => never show it anywhere
|
||||
*
|
||||
* @param showVersionInfoInput
|
||||
*/
|
||||
export async function showVersionInfo(showVersionInfoInput: string, version: string): Promise<void> {
|
||||
// --compile=min -O0 reduces the time from ~1.8-1.9s to ~0.8-0.9s
|
||||
let exitCode: number
|
||||
|
||||
switch (showVersionInfoInput) {
|
||||
case 'true':
|
||||
exitCode = await exec.exec('julia', ['--compile=min', '-O0', '-e', 'using InteractiveUtils; versioninfo()'])
|
||||
break
|
||||
|
||||
case 'false':
|
||||
if (version.endsWith('nightly')) {
|
||||
exitCode = await exec.exec('julia', ['--compile=min', '-O0', '-e', 'using InteractiveUtils; versioninfo()'])
|
||||
} else {
|
||||
exitCode = await exec.exec('julia', ['--version'])
|
||||
}
|
||||
break
|
||||
|
||||
case 'never':
|
||||
exitCode = await exec.exec('julia', ['--version'])
|
||||
break
|
||||
|
||||
default:
|
||||
throw new Error(`${showVersionInfoInput} is not a valid value for show-versioninfo. Supported values: true | false | never`)
|
||||
}
|
||||
|
||||
if (exitCode !== 0) {
|
||||
throw new Error(`Julia could not be installed properly. Exit code: ${exitCode}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,21 +2,11 @@ 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'
|
||||
|
||||
const archSynonyms = {
|
||||
'x86': 'x86',
|
||||
'X86': 'x86',
|
||||
'x64': 'x64',
|
||||
'X64': 'x64',
|
||||
'aarch64': 'aarch64',
|
||||
'ARM64': 'aarch64'
|
||||
}
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
// Debugging info
|
||||
@@ -39,7 +29,7 @@ async function run() {
|
||||
|
||||
// Inputs
|
||||
const versionInput = core.getInput('version')
|
||||
const originalArchInput = core.getInput('arch')
|
||||
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 }}`.
|
||||
@@ -49,45 +39,39 @@ async function run() {
|
||||
if (!versionInput) {
|
||||
throw new Error('Version input must not be null')
|
||||
}
|
||||
if (!originalArchInput) {
|
||||
if (!arch) {
|
||||
throw new Error(`Arch input must not be null`)
|
||||
}
|
||||
|
||||
const arch = archSynonyms[originalArchInput]
|
||||
|
||||
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'))
|
||||
|
||||
// Test if Julia has been installed
|
||||
exec.exec('julia', ['--version'])
|
||||
|
||||
// Set output
|
||||
core.setOutput('julia-bindir', path.join(juliaPath, 'bin'))
|
||||
|
||||
// Test if Julia has been installed and print the version
|
||||
const showVersionInfoInput = core.getInput('show-versioninfo')
|
||||
await installer.showVersionInfo(showVersionInfoInput, version)
|
||||
// If enabled, also show the full version info
|
||||
if (core.getInput('show-versioninfo') == 'true') {
|
||||
exec.exec('julia', ['-e', 'using InteractiveUtils; versioninfo()'])
|
||||
}
|
||||
} catch (error) {
|
||||
core.setFailed(error.message)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user