mirror of
https://github.com/MillironX/setup-nextflow.git
synced 2024-11-25 02:39:55 +00:00
Compare commits
41 commits
5fb6055651
...
0aeab8d284
Author | SHA1 | Date | |
---|---|---|---|
|
0aeab8d284 | ||
|
05aef69bc1 | ||
|
57e49670a9 | ||
|
46187cd528 | ||
|
95a4337530 | ||
|
981cd4fc2e | ||
|
7c79f790e0 | ||
|
c3424c52c4 | ||
|
93ff0f7ef2 | ||
|
c19a8b88ef | ||
|
7a0ec2a9b4 | ||
|
955a936296 | ||
|
a14c1ba3a6 | ||
|
edde65cf1e | ||
|
ab89b450a6 | ||
|
3f231d1a10 | ||
|
03b7b3e3d3 | ||
|
0541993f3c | ||
|
205818f4d8 | ||
|
4ad727836d | ||
|
aebdb951b0 | ||
|
ea5ce95ba5 | ||
|
ed6b338f42 | ||
|
6cafaa8e2c | ||
|
40343dfa61 | ||
|
3538f89b6f | ||
|
024f69ce91 | ||
|
8c63dff97b | ||
|
b9a7fb9499 | ||
|
db82c135bd | ||
|
78e7fadd20 | ||
|
c976e6b883 | ||
|
0401be4ed7 | ||
|
147da60f8f | ||
|
9ec3bc304f | ||
|
48ae930859 | ||
|
1b07a3f172 | ||
|
16725d6eeb | ||
|
80fb69cc4f | ||
|
39c8738968 | ||
|
70311f90c6 |
23 changed files with 8366 additions and 218 deletions
3
.eslintignore
Normal file
3
.eslintignore
Normal file
|
@ -0,0 +1,3 @@
|
|||
dist/
|
||||
lib/
|
||||
node_modules/
|
63
.eslintrc.json
Normal file
63
.eslintrc.json
Normal file
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"plugins": ["ava", "@typescript-eslint", "simple-import-sort"],
|
||||
"extends": ["plugin:github/recommended", "plugin:ava/recommended"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 9,
|
||||
"sourceType": "module",
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"rules": {
|
||||
"simple-import-sort/imports": "error",
|
||||
"simple-import-sort/exports": "error",
|
||||
"i18n-text/no-en": "off",
|
||||
"eslint-comments/no-use": "off",
|
||||
"import/no-namespace": "off",
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/explicit-member-accessibility": [
|
||||
"error",
|
||||
{ "accessibility": "no-public" }
|
||||
],
|
||||
"@typescript-eslint/no-require-imports": "error",
|
||||
"@typescript-eslint/array-type": "error",
|
||||
"@typescript-eslint/await-thenable": "error",
|
||||
"@typescript-eslint/ban-ts-comment": "error",
|
||||
"camelcase": "off",
|
||||
"@typescript-eslint/consistent-type-assertions": "error",
|
||||
"@typescript-eslint/explicit-function-return-type": [
|
||||
"error",
|
||||
{ "allowExpressions": true }
|
||||
],
|
||||
"@typescript-eslint/func-call-spacing": ["error", "never"],
|
||||
"@typescript-eslint/no-array-constructor": "error",
|
||||
"@typescript-eslint/no-empty-interface": "error",
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
"@typescript-eslint/no-extraneous-class": "error",
|
||||
"@typescript-eslint/no-for-in-array": "error",
|
||||
"@typescript-eslint/no-inferrable-types": "error",
|
||||
"@typescript-eslint/no-misused-new": "error",
|
||||
"@typescript-eslint/no-namespace": "error",
|
||||
"@typescript-eslint/no-non-null-assertion": "warn",
|
||||
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
"@typescript-eslint/no-useless-constructor": "error",
|
||||
"@typescript-eslint/no-var-requires": "error",
|
||||
"@typescript-eslint/prefer-for-of": "warn",
|
||||
"@typescript-eslint/prefer-function-type": "warn",
|
||||
"@typescript-eslint/prefer-includes": "error",
|
||||
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
||||
"@typescript-eslint/promise-function-async": "error",
|
||||
"@typescript-eslint/require-array-sort-compare": "error",
|
||||
"@typescript-eslint/restrict-plus-operands": "error",
|
||||
"semi": "off",
|
||||
"sort-imports": "off",
|
||||
"@typescript-eslint/semi": ["error", "never"],
|
||||
"@typescript-eslint/type-annotation-spacing": "error",
|
||||
"@typescript-eslint/unbound-method": "error"
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true
|
||||
}
|
||||
}
|
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
dist/** -diff linguist-generated=true
|
9
.github/workflows/example.yml
vendored
9
.github/workflows/example.yml
vendored
|
@ -2,8 +2,12 @@ name: Example builds
|
|||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
@ -30,8 +34,9 @@ jobs:
|
|||
with:
|
||||
node-version: 16
|
||||
cache: "npm"
|
||||
- run: npm i -g @vercel/ncc
|
||||
- run: npm ci && npm run build
|
||||
- run: npm ci
|
||||
- run: npm run build
|
||||
- run: npm run package
|
||||
- uses: ./
|
||||
with:
|
||||
version: ${{ matrix.nextflow_version }}
|
||||
|
|
5
.github/workflows/publish.yml
vendored
5
.github/workflows/publish.yml
vendored
|
@ -13,8 +13,9 @@ jobs:
|
|||
with:
|
||||
node-version: 16
|
||||
cache: "npm"
|
||||
- run: npm i -g @vercel/ncc
|
||||
- run: npm ci && npm run build
|
||||
- run: npm ci
|
||||
- run: npm run build
|
||||
- run: npm run package
|
||||
- uses: JasonEtco/build-and-tag-action@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
|
27
.github/workflows/test.yml
vendored
Normal file
27
.github/workflows/test.yml
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
name: Run tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
cache: "npm"
|
||||
- run: npm ci
|
||||
- run: npm run build
|
||||
- run: npm run format:check
|
||||
- run: npm run lint
|
||||
- run: npm run package
|
||||
# FIXME Token doesn't get passed correctly
|
||||
# - run: npm run test
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -128,3 +128,7 @@ dist
|
|||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
# Ignore built ts files
|
||||
__tests__/runner/*
|
||||
lib/**/*
|
3
.prettierignore
Normal file
3
.prettierignore
Normal file
|
@ -0,0 +1,3 @@
|
|||
dist/
|
||||
lib/
|
||||
node_modules/
|
10
.prettierrc.json
Normal file
10
.prettierrc.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": false,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "none",
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "avoid"
|
||||
}
|
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -37,8 +37,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- GitHub Actions workflow to test Nextflow installation and downstream usage
|
||||
- Documentation and license files
|
||||
|
||||
[unreleased]: https://github.com/MillironX/setup-nextflow/compare/v1.2.0...HEAD
|
||||
[1.2.0]: https://github.com/MillironX/setup-nextflow/compare/v1.1.1...v1.2.0
|
||||
[1.1.0]: https://github.com/MillironX/setup-nextflow/compare/v1.0.1...v1.1.0
|
||||
[1.0.1]: https://github.com/MillironX/setup-nextflow/compare/v1.0.0...v1.0.1
|
||||
[1.0.0]: https://github.com/MillironX/setup-nextflow/releases/tag/v1.0.0
|
||||
[unreleased]: https://github.com/nf-core/setup-nextflow/compare/v1.2.0...HEAD
|
||||
[1.2.0]: https://github.com/nf-core/setup-nextflow/compare/v1.1.1...v1.2.0
|
||||
[1.1.0]: https://github.com/nf-core/setup-nextflow/compare/v1.0.1...v1.1.0
|
||||
[1.0.1]: https://github.com/nf-core/setup-nextflow/compare/v1.0.0...v1.0.1
|
||||
[1.0.0]: https://github.com/nf-core/setup-nextflow/releases/tag/v1.0.0
|
||||
|
|
22
LICENSE
22
LICENSE
|
@ -1,7 +1,21 @@
|
|||
Copyright 2022 Thomas A. Christensen II
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
Copyright (c) 2022 nf-core
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
25
README.md
25
README.md
|
@ -1,8 +1,8 @@
|
|||
# Setup Nextflow for GitHub Actions
|
||||
|
||||
[![Testing](https://github.com/MillironX/setup-nextflow/actions/workflows/example.yml/badge.svg)](https://github.com/MillironX/setup-nextflow/actions/workflows/example.yml)
|
||||
[![MIT License](https://img.shields.io/github/license/MillironX/setup-nextflow?logo=opensourceinitiative)](https://github.com/MillironX/setup-nextflow/blob/master/LICENSE)
|
||||
[![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/MillironX/setup-nextflow?logo=github)](https://github.com/MillironX/setup-nextflow/releases/latest)
|
||||
[![Testing](https://github.com/nf-core/setup-nextflow/actions/workflows/example.yml/badge.svg)](https://github.com/nf-core/setup-nextflow/actions/workflows/example.yml)
|
||||
[![MIT License](https://img.shields.io/github/license/nf-core/setup-nextflow?logo=opensourceinitiative)](https://github.com/nf-core/setup-nextflow/blob/master/LICENSE)
|
||||
[![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/nf-core/setup-nextflow?logo=github)](https://github.com/nf-core/setup-nextflow/releases/latest)
|
||||
[![Get from GitHub Actions](https://img.shields.io/static/v1?label=actions&message=marketplace&color=green&logo=githubactions)](https://github.com/marketplace/actions/setup-nextflow)
|
||||
|
||||
An action to install [Nextflow](https://nextflow.io) into a GitHub Actions workflow and make it available for subsequent steps.
|
||||
|
@ -17,7 +17,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: MillironX/setup-nextflow@v1
|
||||
- uses: nf-core/setup-nextflow@v1.2.0
|
||||
- run: nextflow run ${GITHUB_WORKSPACE}
|
||||
```
|
||||
|
||||
|
@ -73,3 +73,20 @@ This action locates the releases based upon the GitHub API, and requires an acce
|
|||
## Outputs
|
||||
|
||||
There are no outputs from this action.
|
||||
|
||||
## Why was this action made?
|
||||
|
||||
[Slack link](https://nfcore.slack.com/archives/CE56GDKN0/p1655210460795839)
|
||||
|
||||
You may be asking, why not just a few yaml lines?
|
||||
|
||||
```yaml
|
||||
- name: Install Nextflow
|
||||
env:
|
||||
NXF_VER: ${{ matrix.NXF_VER }}
|
||||
run: |
|
||||
wget -qO- get.nextflow.io | bash
|
||||
sudo mv nextflow /usr/local/bin/
|
||||
```
|
||||
|
||||
The versioning. From the Nextflow install script you can't get `latest-edge` or `latest-everything` for example.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: "Setup Nextflow"
|
||||
description: "Install Nextflow and add it to the PATH"
|
||||
author: "Thomas A. Christensen II"
|
||||
author: "nf-core"
|
||||
inputs:
|
||||
version:
|
||||
description: "The Nextflow version to download (if necessary) and use. Example: 21.10.3"
|
||||
|
|
180
index.ts
180
index.ts
|
@ -1,180 +0,0 @@
|
|||
import * as core from "@actions/core";
|
||||
import * as exec from "@actions/exec";
|
||||
import * as fs from "fs";
|
||||
import * as github from "@actions/github";
|
||||
import * as tc from "@actions/tool-cache";
|
||||
import retry = require("async-retry");
|
||||
import semver = require("semver");
|
||||
|
||||
const NEXTFLOW_REPO = { owner: "nextflow-io", repo: "nextflow" };
|
||||
|
||||
async function all_nf_releases(ok) {
|
||||
return await ok.paginate(
|
||||
ok.rest.repos.listReleases,
|
||||
NEXTFLOW_REPO,
|
||||
(response) => response.data
|
||||
);
|
||||
}
|
||||
|
||||
async function latest_stable_release_data(ok) {
|
||||
const { data: stable_release } = await ok.rest.repos.getLatestRelease(
|
||||
NEXTFLOW_REPO
|
||||
);
|
||||
|
||||
return stable_release;
|
||||
}
|
||||
|
||||
async function release_data(version, ok) {
|
||||
// Setup tag-based filtering
|
||||
let filter = (r) => {
|
||||
return semver.satisfies(r.tag_name, version, true);
|
||||
};
|
||||
|
||||
// Check if the user passed a 'latest*' tag, and override filtering
|
||||
// accordingly
|
||||
if (version.includes("latest")) {
|
||||
if (version.includes("-everything")) {
|
||||
// No filtering
|
||||
filter = (r) => {
|
||||
return true;
|
||||
};
|
||||
} else if (version.includes("-edge")) {
|
||||
filter = (r) => {
|
||||
return r.tag_name.endsWith("-edge");
|
||||
};
|
||||
} else {
|
||||
// This is special: passing 'latest' or 'latest-stable' allows us to use
|
||||
// the latest stable GitHub release direct from the API
|
||||
const stable_release = await latest_stable_release_data(ok);
|
||||
return stable_release;
|
||||
}
|
||||
}
|
||||
|
||||
// Get all the releases
|
||||
const all_releases = await all_nf_releases(ok);
|
||||
|
||||
let matching_releases = all_releases.filter(filter);
|
||||
|
||||
matching_releases.sort(function (x, y) {
|
||||
semver.compare(x.tag_name, y.tag_name, true);
|
||||
});
|
||||
|
||||
return matching_releases[0];
|
||||
}
|
||||
|
||||
function nextflow_bin_url(release, get_all) {
|
||||
const release_assets = release.assets;
|
||||
const all_asset = release_assets.filter((a) => {
|
||||
return a.browser_download_url.endsWith("-all");
|
||||
})[0];
|
||||
const regular_asset = release_assets.filter((a) => {
|
||||
return a.name == "nextflow";
|
||||
})[0];
|
||||
|
||||
const dl_asset = get_all ? all_asset : regular_asset;
|
||||
|
||||
return dl_asset.browser_download_url;
|
||||
}
|
||||
|
||||
async function install_nextflow(url, version) {
|
||||
core.debug(`Downloading Nextflow from ${url}`);
|
||||
const nf_dl_path = await retry(
|
||||
async (bail) => {
|
||||
return await tc.downloadTool(url);
|
||||
},
|
||||
{
|
||||
onRetry: (err) => {
|
||||
core.debug(`Download of ${url} failed, trying again. Error ${err}`);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const temp_install_dir = fs.mkdtempSync(`nxf-${version}`);
|
||||
const nf_path = `${temp_install_dir}/nextflow`;
|
||||
|
||||
fs.renameSync(nf_dl_path, nf_path);
|
||||
fs.chmodSync(nf_path, "0711");
|
||||
|
||||
return temp_install_dir;
|
||||
}
|
||||
|
||||
async function run() {
|
||||
// Set environment variables
|
||||
core.exportVariable("CAPSULE_LOG", "none");
|
||||
|
||||
// Read in the arguments
|
||||
const token = core.getInput("token");
|
||||
const version = core.getInput("version");
|
||||
const get_all = core.getBooleanInput("all");
|
||||
|
||||
let resolved_version = "";
|
||||
|
||||
// Setup the API
|
||||
let octokit = {};
|
||||
try {
|
||||
octokit = github.getOctokit(token);
|
||||
} catch (e: any) {
|
||||
core.setFailed(
|
||||
`Could not authenticate to GitHub Releases API with provided token\n${e.message}`
|
||||
);
|
||||
}
|
||||
|
||||
// Get the release info for the desired release
|
||||
let release: any = {};
|
||||
try {
|
||||
release = await release_data(version, octokit);
|
||||
resolved_version = release.tag_name;
|
||||
core.info(
|
||||
`Input version '${version}' resolved to Nextflow ${release.name}`
|
||||
);
|
||||
} catch (e: any) {
|
||||
core.setFailed(
|
||||
`Could not retrieve Nextflow release matching ${version}.\n${e.message}`
|
||||
);
|
||||
}
|
||||
|
||||
// Get the download url for the desired release
|
||||
let url = "";
|
||||
try {
|
||||
url = nextflow_bin_url(release, get_all);
|
||||
core.info(`Preparing to download from ${url}`);
|
||||
} catch (e: any) {
|
||||
core.setFailed(`Could not parse the download URL\n${e.message}`);
|
||||
}
|
||||
try {
|
||||
// Download Nextflow and add it to path
|
||||
let nf_path = "";
|
||||
nf_path = tc.find("nextflow", resolved_version);
|
||||
|
||||
if (!nf_path) {
|
||||
core.debug(`Could not find Nextflow ${resolved_version} in cache`);
|
||||
const nf_install_path = await install_nextflow(url, resolved_version);
|
||||
|
||||
nf_path = await tc.cacheDir(
|
||||
nf_install_path,
|
||||
"nextflow",
|
||||
resolved_version
|
||||
);
|
||||
core.debug(`Added Nextflow to cache: ${nf_path}`);
|
||||
|
||||
fs.rmdirSync(nf_install_path, { recursive: true });
|
||||
} else {
|
||||
core.debug(`Using cached version of Nextflow: ${nf_path}`);
|
||||
}
|
||||
|
||||
core.addPath(nf_path);
|
||||
|
||||
core.info(`Downloaded \`nextflow\` to ${nf_path} and added to PATH`);
|
||||
} catch (e: any) {
|
||||
core.setFailed(e.message);
|
||||
}
|
||||
|
||||
// Run Nextflow so it downloads its dependencies
|
||||
try {
|
||||
const nf_exit_code = await exec.exec("nextflow", ["help"])
|
||||
} catch (e: any) {
|
||||
core.warning("Nextflow appears to have installed correctly, but an error was thrown while running it.")
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
7832
package-lock.json
generated
7832
package-lock.json
generated
File diff suppressed because it is too large
Load diff
62
package.json
62
package.json
|
@ -1,14 +1,49 @@
|
|||
{
|
||||
"name": "install-nextflow-action",
|
||||
"version": "1.2.0",
|
||||
"description": "",
|
||||
"main": "dist/index.js",
|
||||
"description": "An action to install Nextflow into a GitHub Actions workflow and make it available for subsequent steps.",
|
||||
"main": "lib/src/main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "ncc build index.ts --license LICENSE"
|
||||
"build": "tsc",
|
||||
"format": "prettier --write '**/*.{ts,js,yml,md,json}'",
|
||||
"format:check": "prettier --check '**/*.{ts,js,yml,md,json}'",
|
||||
"lint": "eslint {src,test}/**/*.ts",
|
||||
"lint:fix": "eslint --fix {src,test}/**/*.ts",
|
||||
"package": "ncc build --source-map --license LICENSE",
|
||||
"test": "ava",
|
||||
"all": "npm run build && npm run format && npm run lint && npm run package && npm test"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/nf-core/setup-nextflow.git"
|
||||
},
|
||||
"keywords": [
|
||||
"actions",
|
||||
"node",
|
||||
"setup"
|
||||
],
|
||||
"author": "nf-core",
|
||||
"ava": {
|
||||
"extensions": [
|
||||
"ts"
|
||||
],
|
||||
"rewritePaths": {
|
||||
"src/": "lib/"
|
||||
},
|
||||
"require": [
|
||||
"ts-node/register/transpile-only"
|
||||
],
|
||||
"files": [
|
||||
"test/**/*.ts",
|
||||
"!test/utils.ts"
|
||||
],
|
||||
"source": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"concurrency": 1,
|
||||
"serial": true,
|
||||
"powerAssert": true
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.8.2",
|
||||
|
@ -20,7 +55,22 @@
|
|||
"semver": "^7.3.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ava/typescript": "^3.0.1",
|
||||
"@tsconfig/node16": "^1.0.3",
|
||||
"@types/async-retry": "^1.4.5",
|
||||
"@types/node": "^18.11.0",
|
||||
"@types/semver": "^7.3.13",
|
||||
"@typescript-eslint/parser": "^5.42.1",
|
||||
"@vercel/ncc": "^0.34.0",
|
||||
"ava": "^5.0.1",
|
||||
"eslint": "^8.27.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-ava": "^13.2.0",
|
||||
"eslint-plugin-github": "^4.4.1",
|
||||
"eslint-plugin-jest": "^27.1.5",
|
||||
"eslint-plugin-simple-import-sort": "^8.0.0",
|
||||
"prettier": "^2.7.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.7.3"
|
||||
}
|
||||
}
|
||||
|
|
113
src/functions.ts
Normal file
113
src/functions.ts
Normal file
|
@ -0,0 +1,113 @@
|
|||
import * as core from "@actions/core"
|
||||
import { GitHub } from "@actions/github/lib/utils"
|
||||
import * as tc from "@actions/tool-cache"
|
||||
import retry from "async-retry"
|
||||
import * as fs from "fs"
|
||||
import semver from "semver"
|
||||
|
||||
const NEXTFLOW_REPO = { owner: "nextflow-io", repo: "nextflow" }
|
||||
|
||||
// HACK Private but I want to test this
|
||||
export async function all_nf_releases(
|
||||
ok: InstanceType<typeof GitHub>
|
||||
): Promise<object[]> {
|
||||
return await ok.paginate(
|
||||
ok.rest.repos.listReleases,
|
||||
NEXTFLOW_REPO,
|
||||
response => response.data
|
||||
)
|
||||
}
|
||||
|
||||
// HACK Private but I want to test this
|
||||
export async function latest_stable_release_data(
|
||||
ok: InstanceType<typeof GitHub>
|
||||
): Promise<object> {
|
||||
const { data: stable_release } = await ok.rest.repos.getLatestRelease(
|
||||
NEXTFLOW_REPO
|
||||
)
|
||||
|
||||
return stable_release
|
||||
}
|
||||
|
||||
export async function release_data(
|
||||
version: string,
|
||||
ok: InstanceType<typeof GitHub>
|
||||
): Promise<object> {
|
||||
// Setup tag-based filtering
|
||||
let filter = (r: object): boolean => {
|
||||
return semver.satisfies(r["tag_name"], version, true)
|
||||
}
|
||||
|
||||
// Check if the user passed a 'latest*' tag, and override filtering
|
||||
// accordingly
|
||||
if (version.includes("latest")) {
|
||||
if (version.includes("-everything")) {
|
||||
// No filtering
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
filter = (r: object) => {
|
||||
return true
|
||||
}
|
||||
} else if (version.includes("-edge")) {
|
||||
filter = r => {
|
||||
return r["tag_name"].endsWith("-edge")
|
||||
}
|
||||
} else {
|
||||
// This is special: passing 'latest' or 'latest-stable' allows us to use
|
||||
// the latest stable GitHub release direct from the API
|
||||
const stable_release = await latest_stable_release_data(ok)
|
||||
return stable_release
|
||||
}
|
||||
}
|
||||
|
||||
// Get all the releases
|
||||
const all_releases: object[] = await all_nf_releases(ok)
|
||||
|
||||
const matching_releases = all_releases.filter(filter)
|
||||
|
||||
matching_releases.sort((x, y) => {
|
||||
// HACK IDK why the value flip is necessary with the return
|
||||
return semver.compare(x["tag_name"], y["tag_name"], true) * -1
|
||||
})
|
||||
|
||||
return matching_releases[0]
|
||||
}
|
||||
|
||||
export function nextflow_bin_url(release: object, get_all: boolean): string {
|
||||
const release_assets = release["assets"]
|
||||
const all_asset = release_assets.filter((a: object) => {
|
||||
return a["browser_download_url"].endsWith("-all")
|
||||
})[0]
|
||||
const regular_asset = release_assets.filter((a: object) => {
|
||||
return a["name"] === "nextflow"
|
||||
})[0]
|
||||
|
||||
const dl_asset = get_all ? all_asset : regular_asset
|
||||
|
||||
return dl_asset.browser_download_url
|
||||
}
|
||||
|
||||
export async function install_nextflow(
|
||||
url: string,
|
||||
version: string
|
||||
): Promise<string> {
|
||||
core.debug(`Downloading Nextflow from ${url}`)
|
||||
const nf_dl_path = await retry(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async bail => {
|
||||
return await tc.downloadTool(url)
|
||||
},
|
||||
{
|
||||
onRetry: err => {
|
||||
core.debug(`Download of ${url} failed, trying again. Error ${err}`)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const temp_install_dir = fs.mkdtempSync(`nxf-${version}`)
|
||||
const nf_path = `${temp_install_dir}/nextflow`
|
||||
|
||||
fs.renameSync(nf_dl_path, nf_path)
|
||||
fs.chmodSync(nf_path, "0711")
|
||||
|
||||
return temp_install_dir
|
||||
}
|
99
src/main.ts
Normal file
99
src/main.ts
Normal file
|
@ -0,0 +1,99 @@
|
|||
import * as core from "@actions/core"
|
||||
import * as exec from "@actions/exec"
|
||||
import * as github from "@actions/github"
|
||||
import { GitHub } from "@actions/github/lib/utils"
|
||||
import * as tc from "@actions/tool-cache"
|
||||
import * as fs from "fs"
|
||||
|
||||
import { install_nextflow, nextflow_bin_url, release_data } from "./functions"
|
||||
|
||||
async function run(): Promise<void> {
|
||||
// Set environment variables
|
||||
core.exportVariable("CAPSULE_LOG", "none")
|
||||
|
||||
// Read in the arguments
|
||||
const token = core.getInput("token")
|
||||
const version = core.getInput("version")
|
||||
const get_all = core.getBooleanInput("all")
|
||||
|
||||
let resolved_version = ""
|
||||
|
||||
// Setup the API
|
||||
let octokit: InstanceType<typeof GitHub> | undefined
|
||||
try {
|
||||
octokit = github.getOctokit(token)
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
core.setFailed(
|
||||
`Could not authenticate to GitHub Releases API with provided token\n${e.message}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Get the release info for the desired release
|
||||
let release = {}
|
||||
try {
|
||||
if (octokit !== undefined) {
|
||||
release = await release_data(version, octokit)
|
||||
}
|
||||
resolved_version = release["tag_name"]
|
||||
core.info(
|
||||
`Input version '${version}' resolved to Nextflow ${release["name"]}`
|
||||
)
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
core.setFailed(
|
||||
`Could not retrieve Nextflow release matching ${version}.\n${e.message}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Get the download url for the desired release
|
||||
let url = ""
|
||||
try {
|
||||
url = nextflow_bin_url(release, get_all)
|
||||
core.info(`Preparing to download from ${url}`)
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
core.setFailed(`Could not parse the download URL\n${e.message}`)
|
||||
}
|
||||
}
|
||||
try {
|
||||
// Download Nextflow and add it to path
|
||||
let nf_path = ""
|
||||
nf_path = tc.find("nextflow", resolved_version)
|
||||
|
||||
if (!nf_path) {
|
||||
core.debug(`Could not find Nextflow ${resolved_version} in cache`)
|
||||
const nf_install_path = await install_nextflow(url, resolved_version)
|
||||
|
||||
nf_path = await tc.cacheDir(nf_install_path, "nextflow", resolved_version)
|
||||
core.debug(`Added Nextflow to cache: ${nf_path}`)
|
||||
|
||||
fs.rmdirSync(nf_install_path, { recursive: true })
|
||||
} else {
|
||||
core.debug(`Using cached version of Nextflow: ${nf_path}`)
|
||||
}
|
||||
|
||||
core.addPath(nf_path)
|
||||
|
||||
core.info(`Downloaded \`nextflow\` to ${nf_path} and added to PATH`)
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
core.setFailed(e.message)
|
||||
}
|
||||
}
|
||||
|
||||
// Run Nextflow so it downloads its dependencies
|
||||
try {
|
||||
await exec.exec("nextflow", ["help"])
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
core.warning(
|
||||
"Nextflow appears to have installed correctly, but an error was thrown while running it."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
run()
|
36
test/functions.ts
Normal file
36
test/functions.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import * as github from "@actions/github"
|
||||
import { GitHub } from "@actions/github/lib/utils"
|
||||
import anyTest, { TestFn } from "ava" // eslint-disable-line import/no-unresolved
|
||||
|
||||
import * as functions from "../src/functions"
|
||||
import { getToken } from "./utils"
|
||||
|
||||
const test = anyTest as TestFn<{
|
||||
token: string
|
||||
octokit: InstanceType<typeof GitHub>
|
||||
}>
|
||||
|
||||
test.before(t => {
|
||||
const first = true
|
||||
const current_token = getToken(first)
|
||||
t.context = {
|
||||
token: current_token,
|
||||
octokit: github.getOctokit(current_token)
|
||||
}
|
||||
})
|
||||
|
||||
test("all_nf_releases", async t => {
|
||||
const result = await functions.all_nf_releases(t.context["octokit"])
|
||||
t.is(typeof result, "object")
|
||||
})
|
||||
|
||||
test("lastest_stable_release_data", async t => {
|
||||
const result = await functions.latest_stable_release_data(
|
||||
t.context["octokit"]
|
||||
)
|
||||
t.is(typeof result, "object")
|
||||
t.is(result["tag_name"], "v22.10.2")
|
||||
})
|
||||
|
||||
test.todo("nextflow_bin_url")
|
||||
test.todo("install_nextflow")
|
17
test/main.ts
Normal file
17
test/main.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import test from "ava" // eslint-disable-line import/no-unresolved
|
||||
import * as cp from "child_process"
|
||||
import * as path from "path"
|
||||
import * as process from "process"
|
||||
|
||||
// eslint-disable-next-line ava/no-skip-test
|
||||
test.skip("test runs", t => {
|
||||
process.env["INPUT_VERSION"] = "v22.10.2"
|
||||
const np = process.execPath
|
||||
const ip = path.join(__dirname, "..", "lib", "src", "main.js")
|
||||
const options: cp.ExecFileSyncOptions = {
|
||||
env: process.env
|
||||
}
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(cp.execFileSync(np, [ip], options).toString())
|
||||
t.pass()
|
||||
})
|
30
test/releasedata.ts
Normal file
30
test/releasedata.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import * as github from "@actions/github"
|
||||
import { GitHub } from "@actions/github/lib/utils"
|
||||
import anyTest, { TestFn } from "ava" // eslint-disable-line import/no-unresolved
|
||||
|
||||
import { release_data } from "../src/functions"
|
||||
import { getToken } from "./utils"
|
||||
|
||||
const test = anyTest as TestFn<{
|
||||
token: string
|
||||
octokit: InstanceType<typeof GitHub>
|
||||
}>
|
||||
|
||||
test.before(t => {
|
||||
const first = true
|
||||
const current_token = getToken(first)
|
||||
t.context = {
|
||||
token: current_token,
|
||||
octokit: github.getOctokit(current_token)
|
||||
}
|
||||
})
|
||||
|
||||
const macro = test.macro(async (t, version: string, expected: string) => {
|
||||
const result = await release_data(version, t.context["octokit"])
|
||||
t.is(result["tag_name"], expected)
|
||||
})
|
||||
|
||||
test("hard version", macro, "v22.10.2", "v22.10.2")
|
||||
test("latest-stable", macro, "latest-stable", "v22.10.2")
|
||||
test("latest-edge", macro, "latest-edge", "v22.09.7-edge")
|
||||
test("latest-everything", macro, "latest-everything", "v22.10.2")
|
12
test/utils.ts
Normal file
12
test/utils.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
export function getToken(first: boolean): string {
|
||||
const token = process.env["GITHUB_TOKEN"] || ""
|
||||
if (!token && first) {
|
||||
/* eslint-disable-next-line no-console */
|
||||
console.warn(
|
||||
"Skipping GitHub tests. Set $GITHUB_TOKEN to run REST client and GraphQL client tests"
|
||||
)
|
||||
first = false
|
||||
}
|
||||
|
||||
return token
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
{
|
||||
"extends": "@tsconfig/node16/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"strict": true,
|
||||
"noImplicitAny": false,
|
||||
"esModuleInterop": true,
|
||||
}
|
||||
"extends": "@tsconfig/node16/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"outDir": "./lib",
|
||||
"strict": true,
|
||||
"noImplicitAny": false,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["src/**/*", "test/**/*"],
|
||||
"exclude": ["node_modules", "**/*.test.ts"]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue