├── .prettierignore ├── dist ├── package.json └── matchers │ ├── tsc.json │ ├── eslint-compact.json │ └── eslint-stylish.json ├── .prettierrc ├── .gitattributes ├── .github └── workflows │ ├── versioning.yml │ └── CI.yml ├── jest.config.js ├── tests ├── log-info.sh ├── check-registry.sh └── check-version.sh ├── src ├── matchers.ts ├── registry.test.ts ├── matchers.test.ts ├── registry.ts ├── index.ts ├── installer.test.ts └── installer.ts ├── matchers ├── tsc.json ├── eslint-compact.json └── eslint-stylish.json ├── LICENSE ├── tsconfig.json ├── eslint.config.mjs ├── action.yml ├── .gitignore ├── RELEASE.md ├── package.json ├── README.md └── CHANGELOG.md /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | lib/ 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /dist/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "es5", 4 | "printWidth": 100 5 | } 6 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. Uses 2 | # `eol=lf` in order to ensure that linting can pass properly for windows users 3 | * text=auto eol=lf 4 | -------------------------------------------------------------------------------- /.github/workflows/versioning.yml: -------------------------------------------------------------------------------- 1 | name: Keep the versions up-to-date 2 | 3 | on: 4 | release: 5 | types: [published, edited] 6 | 7 | jobs: 8 | actions-tagger: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: Actions-R-Us/actions-tagger@v2 12 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | clearMocks: true, 3 | moduleFileExtensions: ['js', 'ts'], 4 | testEnvironment: 'node', 5 | testMatch: ['**/*.test.ts'], 6 | testRunner: 'jest-circus/runner', 7 | transform: { 8 | '^.+\\.ts$': 'ts-jest', 9 | }, 10 | verbose: true, 11 | }; 12 | -------------------------------------------------------------------------------- /tests/log-info.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # exit when any command fails 4 | set -e 5 | 6 | echo "Current PATH: $PATH" 7 | echo "Current VOLTA_HOME: $VOLTA_HOME" 8 | 9 | voltaBinContents="$(ls $VOLTA_HOME/bin)" 10 | echo "Current contents of $VOLTA_HOME\n$voltaBinContents" 11 | echo "Path to volta: $(which volta)" 12 | echo "Path to node: $(which node)" 13 | echo "Path to yarn: $(which yarn)" 14 | -------------------------------------------------------------------------------- /src/matchers.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as glob from '@actions/glob'; 3 | 4 | export default async function addMatchers( 5 | matchersPath = path.join(__dirname, '..', 'matchers') 6 | ): Promise { 7 | const globber = await glob.create(path.join(matchersPath, '*.json')); 8 | 9 | for await (const file of globber.globGenerator()) { 10 | console.log(`##[add-matcher]${file}`); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/check-registry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # exit when any command fails 4 | set -e 5 | 6 | expectedRegistry=$1 7 | 8 | # Dummy auth token so that the registry can be read 9 | export NODE_AUTH_TOKEN="test-123" 10 | 11 | actualRegistry="$(npm config get registry)" 12 | 13 | if [[ $expectedRegistry == $actualRegistry ]]; then 14 | echo "npm registry was set to \"$expectedRegistry\"" 15 | exit 0 16 | else 17 | echo "npm registry was set to \"$actualRegistry\" which was incorrect, expected \"$expectedRegistry\"" 18 | exit 1 19 | fi 20 | -------------------------------------------------------------------------------- /tests/check-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # exit when any command fails 4 | set -e 5 | 6 | command=$1 7 | expectedVersion=$2 8 | 9 | if [[ "$expectedVersion" == "current" ]]; then 10 | scriptPath="$(dirname "$BASH_SOURCE")/latest-version.js" 11 | expectedVersion="$(curl --silent "https://volta.sh/latest-version")" 12 | fi 13 | 14 | actualVersion="$($command --version)" 15 | echo "$command found at $(which $command)" 16 | echo "Expected $expectedVersion; found $actualVersion" 17 | 18 | if [[ "$actualVersion" != "$expectedVersion" ]]; then 19 | exit 1 20 | fi 21 | -------------------------------------------------------------------------------- /matchers/tsc.json: -------------------------------------------------------------------------------- 1 | { 2 | "problemMatcher": [ 3 | { 4 | "owner": "tsc", 5 | "pattern": [ 6 | { 7 | "regexp": "^([^\\s].*)[\\(:](\\d+)[,:](\\d+)(?:\\):\\s+|\\s+-\\s+)(error|warning|info)\\s+TS(\\d+)\\s*:\\s*(.*)$", 8 | "file": 1, 9 | "line": 2, 10 | "column": 3, 11 | "severity": 4, 12 | "code": 5, 13 | "message": 6 14 | } 15 | ] 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /dist/matchers/tsc.json: -------------------------------------------------------------------------------- 1 | { 2 | "problemMatcher": [ 3 | { 4 | "owner": "tsc", 5 | "pattern": [ 6 | { 7 | "regexp": "^([^\\s].*)[\\(:](\\d+)[,:](\\d+)(?:\\):\\s+|\\s+-\\s+)(error|warning|info)\\s+TS(\\d+)\\s*:\\s*(.*)$", 8 | "file": 1, 9 | "line": 2, 10 | "column": 3, 11 | "severity": 4, 12 | "code": 5, 13 | "message": 6 14 | } 15 | ] 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /matchers/eslint-compact.json: -------------------------------------------------------------------------------- 1 | { 2 | "problemMatcher": [ 3 | { 4 | "owner": "eslint-compact", 5 | "pattern": [ 6 | { 7 | "regexp": "^(.+):\\sline\\s(\\d+),\\scol\\s(\\d+),\\s(Error|Warning|Info)\\s-\\s(.+)\\s\\((.+)\\)$", 8 | "file": 1, 9 | "line": 2, 10 | "column": 3, 11 | "severity": 4, 12 | "message": 5, 13 | "code": 6 14 | } 15 | ] 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /dist/matchers/eslint-compact.json: -------------------------------------------------------------------------------- 1 | { 2 | "problemMatcher": [ 3 | { 4 | "owner": "eslint-compact", 5 | "pattern": [ 6 | { 7 | "regexp": "^(.+):\\sline\\s(\\d+),\\scol\\s(\\d+),\\s(Error|Warning|Info)\\s-\\s(.+)\\s\\((.+)\\)$", 8 | "file": 1, 9 | "line": 2, 10 | "column": 3, 11 | "severity": 4, 12 | "message": 5, 13 | "code": 6 14 | } 15 | ] 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /matchers/eslint-stylish.json: -------------------------------------------------------------------------------- 1 | { 2 | "problemMatcher": [ 3 | { 4 | "owner": "eslint-stylish", 5 | "pattern": [ 6 | { 7 | "regexp": "^([^\\s].*)$", 8 | "file": 1 9 | }, 10 | { 11 | "regexp": "^\\s+(\\d+):(\\d+)\\s+(error|warning|info)\\s+(.*)\\s\\s+(.*)$", 12 | "line": 1, 13 | "column": 2, 14 | "severity": 3, 15 | "message": 4, 16 | "code": 5, 17 | "loop": true 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /dist/matchers/eslint-stylish.json: -------------------------------------------------------------------------------- 1 | { 2 | "problemMatcher": [ 3 | { 4 | "owner": "eslint-stylish", 5 | "pattern": [ 6 | { 7 | "regexp": "^([^\\s].*)$", 8 | "file": 1 9 | }, 10 | { 11 | "regexp": "^\\s+(\\d+):(\\d+)\\s+(error|warning|info)\\s+(.*)\\s\\s+(.*)$", 12 | "line": 1, 13 | "column": 2, 14 | "severity": 3, 15 | "message": 4, 16 | "code": 5, 17 | "loop": true 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2018 GitHub, Inc. and contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ 4 | "module": "es2020", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 5 | "outDir": "./lib", /* Redirect output structure to the directory. */ 6 | "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 7 | 8 | /* Strict Type-Checking Options */ 9 | "strict": true, /* Enable all strict type-checking options. */ 10 | "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 11 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 12 | "moduleResolution": "node" 13 | }, 14 | "exclude": ["node_modules", "**/*.test.ts"] 15 | } 16 | -------------------------------------------------------------------------------- /src/registry.test.ts: -------------------------------------------------------------------------------- 1 | import { afterEach, describe, test, expect } from 'vitest'; 2 | import * as path from 'path'; 3 | import { writeRegistryToFile } from './registry'; 4 | import { createTempDir } from 'broccoli-test-helper'; 5 | 6 | const ORIGNAL_CONSOLE = Object.assign({}, console); 7 | 8 | describe('registry', () => { 9 | afterEach(() => { 10 | Object.assign(console, ORIGNAL_CONSOLE); 11 | }); 12 | 13 | test('creates an .npmrc with the proper registry url', async () => { 14 | const tmpdir = await createTempDir(); 15 | 16 | await writeRegistryToFile(path.join(tmpdir.path(), '.npmrc'), 'some.registry.url', 'false'); 17 | 18 | expect(tmpdir.read()).toMatchInlineSnapshot(` 19 | { 20 | ".npmrc": "some.registry.url:_authToken=\${NODE_AUTH_TOKEN} 21 | registry=some.registry.url 22 | always-auth=false", 23 | } 24 | `); 25 | }); 26 | 27 | test('includes existing npmrc', async () => { 28 | const tmpdir = await createTempDir(); 29 | 30 | tmpdir.write({ 31 | '.npmrc': 'some-scope:registry=https://npm.pkg.github.com', 32 | }); 33 | 34 | await writeRegistryToFile(path.join(tmpdir.path(), '.npmrc'), 'some.registry.url', 'false'); 35 | 36 | expect(tmpdir.read()).toMatchInlineSnapshot(` 37 | { 38 | ".npmrc": "some-scope:registry=https://npm.pkg.github.com 39 | some.registry.url:_authToken=\${NODE_AUTH_TOKEN} 40 | registry=some.registry.url 41 | always-auth=false", 42 | } 43 | `); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /src/matchers.test.ts: -------------------------------------------------------------------------------- 1 | import { afterEach, beforeEach, describe, test, expect } from 'vitest'; 2 | import * as path from 'path'; 3 | import addMatchers from './matchers'; 4 | import { createTempDir } from 'broccoli-test-helper'; 5 | import type { TempDir } from 'broccoli-test-helper'; 6 | 7 | const ORIGNAL_CONSOLE = Object.assign({}, console); 8 | 9 | describe('addMatchers', () => { 10 | let output: string[][]; 11 | let tmpdir: TempDir; 12 | 13 | beforeEach(async () => { 14 | output = []; 15 | 16 | console.log = (...args: string[]) => { 17 | output.push(args); 18 | }; 19 | 20 | tmpdir = await createTempDir(); 21 | }); 22 | 23 | afterEach(() => { 24 | Object.assign(console, ORIGNAL_CONSOLE); 25 | }); 26 | 27 | test('adds each of the matchers in the `matchers` directory', async () => { 28 | await addMatchers(); 29 | 30 | expect(output).toEqual([ 31 | [`##[add-matcher]${path.join(__dirname, '..', 'matchers', 'eslint-compact.json')}`], 32 | [`##[add-matcher]${path.join(__dirname, '..', 'matchers', 'eslint-stylish.json')}`], 33 | [`##[add-matcher]${path.join(__dirname, '..', 'matchers', 'tsc.json')}`], 34 | ]); 35 | }); 36 | 37 | test('adds matchers found', async () => { 38 | tmpdir.write({ 39 | 'foo.json': '{}', 40 | 'bar.json': '{}', 41 | }); 42 | await addMatchers(tmpdir.path()); 43 | 44 | expect(output).toEqual([ 45 | [`##[add-matcher]${path.normalize(tmpdir.path('bar.json'))}`], 46 | [`##[add-matcher]${path.normalize(tmpdir.path('foo.json'))}`], 47 | ]); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import prettier from 'eslint-plugin-prettier'; 2 | import globals from 'globals'; 3 | import typescriptEslint from '@typescript-eslint/eslint-plugin'; 4 | import tsParser from '@typescript-eslint/parser'; 5 | import path from 'node:path'; 6 | import { fileURLToPath } from 'node:url'; 7 | import js from '@eslint/js'; 8 | import { FlatCompat } from '@eslint/eslintrc'; 9 | 10 | const __filename = fileURLToPath(import.meta.url); 11 | const __dirname = path.dirname(__filename); 12 | const compat = new FlatCompat({ 13 | baseDirectory: __dirname, 14 | recommendedConfig: js.configs.recommended, 15 | allConfig: js.configs.all, 16 | }); 17 | 18 | export default [ 19 | { 20 | ignores: ['!**/.*', 'lib/', 'dist/', 'node_modules/'], 21 | }, 22 | ...compat.extends('eslint:recommended', 'plugin:prettier/recommended'), 23 | { 24 | plugins: { 25 | prettier, 26 | }, 27 | 28 | languageOptions: { 29 | globals: { 30 | ...globals.node, 31 | }, 32 | 33 | ecmaVersion: 2020, 34 | sourceType: 'module', 35 | }, 36 | 37 | rules: {}, 38 | }, 39 | ...compat.extends('plugin:@typescript-eslint/recommended').map((config) => ({ 40 | ...config, 41 | files: ['**/*.ts'], 42 | })), 43 | { 44 | files: ['**/*.ts'], 45 | 46 | plugins: { 47 | '@typescript-eslint': typescriptEslint, 48 | }, 49 | 50 | languageOptions: { 51 | parser: tsParser, 52 | ecmaVersion: 2020, 53 | sourceType: 'module', 54 | }, 55 | }, 56 | { 57 | files: ['__tests__/**/*.[jt]s', '**/*.test.[jt]s'], 58 | 59 | languageOptions: { 60 | globals: { 61 | ...globals.jest, 62 | }, 63 | }, 64 | }, 65 | ]; 66 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: '@volta-cli/action' 2 | description: 'Setup a Node.js environment with Volta' 3 | author: 'Robert Jackson ' 4 | inputs: 5 | volta-version: 6 | description: 'Version of `volta` to fetch and setup. Examples: 0.6.0, 10.15.1, >=10.15.0' 7 | default: '' 8 | node-version: 9 | description: 'Version Spec of the node version to use. Examples: 10.6.x, 10.15.1, >=10.15.0' 10 | default: '' 11 | npm-version: 12 | description: 'Version Spec of the npm version to use. Examples: 7.5.x, 7.5.3, >=7.5.3' 13 | default: '' 14 | yarn-version: 15 | description: 'Version Spec of the yarn version to use. Examples: 1.6.x, 10.15.1, >=10.15.0' 16 | default: '' 17 | package-json-path: 18 | description: 'The path to the package.json to update when using an explicit `node-version` | `yarn-version` | `npm-version` override. By default, we will use `package.json` in the checkout root.' 19 | default: '' 20 | variant: 21 | description: 'Specific variant to install. Example: providing the variant "linux-openssl-rhel", which will target installing the volta-${version}-linux-openssl-rhel.tar.gz tarball' 22 | default: '' 23 | registry-url: 24 | description: 'Optional registry to set up for auth. Will set the registry in a project level .npmrc file, and set up auth to read in from env.NODE_AUTH_TOKEN' 25 | scope: 26 | description: 'Optional scope for authenticating against scoped registries. Will fall back to the repository owner when using the GitHub Packages registry (https://npm.pkg.github.com/).' 27 | token: 28 | description: Used to avoid low rate limiting for cached tool downloads. Since there's a default, this is typically not supplied by the user. 29 | default: ${{ github.token }} 30 | always-auth: 31 | description: 'Set always-auth in npmrc' 32 | default: 'false' 33 | branding: 34 | icon: 'zap' 35 | color: 'yellow' 36 | runs: 37 | using: 'node20' 38 | main: 'dist/index.js' 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directory 2 | node_modules/ 3 | 4 | # Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | jspm_packages/ 46 | 47 | # TypeScript v1 declaration files 48 | typings/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Optional REPL history 60 | .node_repl_history 61 | 62 | # Output of 'npm pack' 63 | *.tgz 64 | 65 | # Yarn Integrity file 66 | .yarn-integrity 67 | 68 | # dotenv environment variables file 69 | .env 70 | .env.test 71 | 72 | # parcel-bundler cache (https://parceljs.org/) 73 | .cache 74 | 75 | # next.js build output 76 | .next 77 | 78 | # nuxt.js build output 79 | .nuxt 80 | 81 | # vuepress build output 82 | .vuepress/dist 83 | 84 | # Serverless directories 85 | .serverless/ 86 | 87 | # FuseBox cache 88 | .fusebox/ 89 | 90 | # DynamoDB Local files 91 | .dynamodb/ 92 | 93 | # OS metadata 94 | .DS_Store 95 | Thumbs.db 96 | 97 | # Ignore built ts files 98 | __tests__/runner/* 99 | lib/**/* 100 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | Releases are mostly automated using 4 | [release-it](https://github.com/release-it/release-it/) and 5 | [lerna-changelog](https://github.com/lerna/lerna-changelog/). 6 | 7 | ## Preparation 8 | 9 | Since the majority of the actual release process is automated, the primary 10 | remaining task prior to releasing is confirming that all pull requests that 11 | have been merged since the last release have been labeled with the appropriate 12 | `lerna-changelog` labels and the titles have been updated to ensure they 13 | represent something that would make sense to our users. Some great information 14 | on why this is important can be found at 15 | [keepachangelog.com](https://keepachangelog.com/en/1.0.0/), but the overall 16 | guiding principle here is that changelogs are for humans, not machines. 17 | 18 | When reviewing merged PR's the labels to be used are: 19 | 20 | * breaking - Used when the PR is considered a breaking change. 21 | * enhancement - Used when the PR adds a new feature or enhancement. 22 | * bug - Used when the PR fixes a bug included in a previous release. 23 | * documentation - Used when the PR adds or updates documentation. 24 | * internal - Used for internal changes that still require a mention in the 25 | changelog/release notes. 26 | 27 | ## Release 28 | 29 | Once the prep work is completed, the actual release is straight forward: 30 | 31 | * First, ensure that you have installed your projects dependencies: 32 | 33 | ```sh 34 | npm install 35 | ``` 36 | 37 | * Second, ensure that you have obtained a 38 | [GitHub personal access token][generate-token] with the `repo` scope (no 39 | other permissions are needed). Make sure the token is available as the 40 | `GITHUB_AUTH` environment variable. 41 | 42 | For instance: 43 | 44 | ```bash 45 | export GITHUB_AUTH=abc123def456 46 | ``` 47 | 48 | [generate-token]: https://github.com/settings/tokens/new?scopes=repo&description=GITHUB_AUTH+env+variable 49 | 50 | * And last (but not least 😁) do your release. 51 | 52 | ```sh 53 | npx release-it 54 | ``` 55 | 56 | [release-it](https://github.com/release-it/release-it/) manages the actual 57 | release process. It will prompt you to to choose the version number after which 58 | you will have the chance to hand tweak the changelog to be used (for the 59 | `CHANGELOG.md` and GitHub release), then `release-it` continues on to tagging, 60 | pushing the tag and commits, etc. 61 | -------------------------------------------------------------------------------- /src/registry.ts: -------------------------------------------------------------------------------- 1 | import { promises as fs } from 'fs'; 2 | import * as os from 'os'; 3 | import * as path from 'path'; 4 | import * as core from '@actions/core'; 5 | import * as github from '@actions/github'; 6 | 7 | // Mostly copied from https://github.com/actions/setup-node/blob/main/src/authutil.ts 8 | 9 | export async function configAuthentication(registryUrl: string, alwaysAuth: string): Promise { 10 | const npmrc: string = path.resolve(process.env['RUNNER_TEMP'] || process.cwd(), '.npmrc'); 11 | 12 | if (!registryUrl.endsWith('/')) { 13 | registryUrl += '/'; 14 | } 15 | 16 | await writeRegistryToFile(npmrc, registryUrl, alwaysAuth); 17 | } 18 | 19 | export async function writeRegistryToFile( 20 | fileLocation: string, 21 | registryUrl: string, 22 | alwaysAuth: string 23 | ): Promise { 24 | let scope: string = core.getInput('scope'); 25 | 26 | if (!scope && registryUrl.indexOf('npm.pkg.github.com') > -1) { 27 | scope = github.context.repo.owner; 28 | } 29 | if (scope && scope[0] != '@') { 30 | scope = '@' + scope; 31 | } 32 | if (scope) { 33 | scope = scope.toLowerCase(); 34 | } 35 | 36 | core.debug(`Setting auth in ${fileLocation}`); 37 | let newContents = ''; 38 | 39 | try { 40 | const curContents = await fs.readFile(fileLocation, 'utf8'); 41 | 42 | curContents.split(os.EOL).forEach((line: string) => { 43 | // Add current contents unless they are setting the registry 44 | if (!line.toLowerCase().startsWith('registry')) { 45 | newContents += line + os.EOL; 46 | } 47 | }); 48 | } catch { 49 | // do nothing... 50 | } 51 | 52 | // Remove http: or https: from front of registry. 53 | const authString: string = 54 | registryUrl.replace(/(^\w+:|^)/, '') + ':_authToken=${NODE_AUTH_TOKEN}'; 55 | 56 | const registryString: string = scope 57 | ? `${scope}:registry=${registryUrl}` 58 | : `registry=${registryUrl}`; 59 | const alwaysAuthString = `always-auth=${alwaysAuth}`; 60 | 61 | newContents += `${authString}${os.EOL}${registryString}${os.EOL}${alwaysAuthString}`; 62 | 63 | await fs.writeFile(fileLocation, newContents, { flag: 'w' }); 64 | 65 | core.exportVariable('NPM_CONFIG_USERCONFIG', fileLocation); 66 | 67 | // Export empty node_auth_token if didn't exist so npm doesn't complain about not being able to find it 68 | core.exportVariable('NODE_AUTH_TOKEN', process.env.NODE_AUTH_TOKEN || 'XXXXX-XXXXX-XXXXX-XXXXX'); 69 | } 70 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@volta-cli/action", 3 | "version": "4.2.1", 4 | "private": true, 5 | "description": "Setup volta for usage in your CI runs", 6 | "keywords": [ 7 | "actions", 8 | "node", 9 | "setup" 10 | ], 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/volta-cli/action.git" 14 | }, 15 | "license": "MIT", 16 | "author": "Robert Jackson ", 17 | "type": "module", 18 | "main": "dist/index.js", 19 | "scripts": { 20 | "build": "npm-run-all build:clean build:ts build:dist build:docs", 21 | "build:clean": "rimraf dist lib", 22 | "build:dist": "ncc build src/index.ts", 23 | "build:ts": "tsc", 24 | "build:docs": "action-docs --update-readme", 25 | "lint": "npm-run-all lint:*", 26 | "lint:files": "eslint --cache .", 27 | "lint:types": "tsc --noEmit", 28 | "test": "vitest" 29 | }, 30 | "devDependencies": { 31 | "@actions/core": "^1.10.1", 32 | "@actions/exec": "^1.1.1", 33 | "@actions/github": "^6.0.0", 34 | "@actions/glob": "^0.4.0", 35 | "@actions/http-client": "^2.2.1", 36 | "@actions/io": "^1.1.3", 37 | "@actions/tool-cache": "^2.0.1", 38 | "@eslint/eslintrc": "^3.1.0", 39 | "@eslint/js": "^9.8.0", 40 | "@release-it-plugins/lerna-changelog": "^7.0.0", 41 | "@types/node": "^18.7.15", 42 | "@types/semver": "^7.5.8", 43 | "@types/uuid": "^10.0.0", 44 | "@typescript-eslint/eslint-plugin": "^8.0.1", 45 | "@typescript-eslint/parser": "^8.0.1", 46 | "@vercel/ncc": "^0.38.1", 47 | "action-docs": "^2.4.2", 48 | "broccoli-test-helper": "^2.0.0", 49 | "eslint": "^9.8.0", 50 | "eslint-config-prettier": "^9.1.0", 51 | "eslint-plugin-prettier": "^5.2.1", 52 | "globals": "^15.9.0", 53 | "nock": "^13.5.4", 54 | "npm-run-all": "^4.1.5", 55 | "prettier": "^3.3.3", 56 | "release-it": "^17.6.0", 57 | "rimraf": "^6.0.1", 58 | "semver": "^7.6.3", 59 | "typescript": "^5.0.4", 60 | "uuid": "^10.0.0", 61 | "vitest": "^2.0.5" 62 | }, 63 | "publishConfig": { 64 | "registry": "https://registry.npmjs.org" 65 | }, 66 | "release-it": { 67 | "hooks": { 68 | "after:bump": "npm run build" 69 | }, 70 | "plugins": { 71 | "@release-it-plugins/lerna-changelog": { 72 | "infile": "CHANGELOG.md", 73 | "launchEditor": true 74 | } 75 | }, 76 | "git": { 77 | "tagName": "v${version}" 78 | }, 79 | "github": { 80 | "release": true, 81 | "tokenRef": "GITHUB_AUTH" 82 | }, 83 | "npm": { 84 | "publish": false 85 | } 86 | }, 87 | "volta": { 88 | "node": "20.11.0", 89 | "npm": "10.4.0" 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core'; 2 | import { existsSync } from 'fs'; 3 | import { dirname } from 'path'; 4 | import * as installer from './installer'; 5 | import * as registry from './registry'; 6 | import addMatchers from './matchers'; 7 | 8 | async function run(): Promise { 9 | try { 10 | const authToken = core.getInput('token', { required: false }); 11 | const voltaVersion = core.getInput('volta-version', { required: false }); 12 | const variant = core.getInput('variant', { required: false }); 13 | let packageJSONPath = core.getInput('package-json-path', { required: false }); 14 | const hasPackageJSONPath = packageJSONPath !== ''; 15 | 16 | if (hasPackageJSONPath && !existsSync(packageJSONPath)) { 17 | core.setFailed( 18 | `custom \`package-json-path: ${packageJSONPath}\` was specified, but a file was not found at \`${packageJSONPath}\`` 19 | ); 20 | return; 21 | } else if (!hasPackageJSONPath) { 22 | packageJSONPath = 'package.json'; 23 | } 24 | 25 | const hasPackageJSON = existsSync(packageJSONPath); 26 | const workingDirectory = dirname(packageJSONPath); 27 | 28 | await installer.getVolta({ versionSpec: voltaVersion, authToken, variant }); 29 | 30 | const nodeVersion = core.getInput('node-version', { required: false }); 31 | if (nodeVersion !== '') { 32 | core.info(`installing Node ${nodeVersion === 'true' ? '' : nodeVersion}`); 33 | await installer.installNode(nodeVersion); 34 | 35 | if (hasPackageJSON) { 36 | await installer.pinNode(workingDirectory, nodeVersion); 37 | } else { 38 | core.info( 39 | `no \`package.json\` file found, if your \`package.json\` is located somewhere other than the root of the working directory you can specify \`package-json-path\` to provide that location. ` 40 | ); 41 | } 42 | } 43 | 44 | const npmVersion = core.getInput('npm-version', { required: false }); 45 | if (npmVersion !== '') { 46 | core.info(`installing NPM ${npmVersion.toUpperCase() === 'TRUE' ? '' : npmVersion}`); 47 | await installer.installNpm(npmVersion); 48 | 49 | // cannot pin `npm` when `node` is not pinned as well 50 | if (nodeVersion !== '' && hasPackageJSON) { 51 | await installer.pinNpm(workingDirectory, npmVersion); 52 | } 53 | } 54 | 55 | const yarnVersion = core.getInput('yarn-version', { required: false }); 56 | if (yarnVersion !== '') { 57 | core.info(`installing Yarn ${yarnVersion.toUpperCase() === 'TRUE' ? '' : yarnVersion}`); 58 | await installer.installYarn(yarnVersion); 59 | 60 | // cannot pin `yarn` when `node` is not pinned as well 61 | if (nodeVersion !== '' && hasPackageJSON) { 62 | await installer.pinYarn(workingDirectory, yarnVersion); 63 | } 64 | } 65 | 66 | const registryUrl = core.getInput('registry-url', { required: false }); 67 | const alwaysAuth = core.getInput('always-auth', { required: false }); 68 | if (registryUrl !== '') { 69 | core.info(`setting up registry url: ${registryUrl}`); 70 | await registry.configAuthentication(registryUrl, alwaysAuth); 71 | } 72 | 73 | await addMatchers(); 74 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 75 | } catch (error: any) { 76 | core.setFailed(error.message); 77 | } 78 | } 79 | 80 | run(); 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHub Action to Setup Volta 2 | 3 |

4 | GitHub Actions status 5 |

6 | 7 | This action installs [volta](https://volta.sh) by: 8 | 9 | - downloading and caching volta (adding it to your $PATH) 10 | - optionally downloading and caching a version of node - npm by version spec and add to PATH 11 | 12 | 13 | ## Inputs 14 | 15 | | name | description | required | default | 16 | | --- | --- | --- | --- | 17 | | `volta-version` |

Version of volta to fetch and setup. Examples: 0.6.0, 10.15.1, >=10.15.0

| `false` | `""` | 18 | | `node-version` |

Version Spec of the node version to use. Examples: 10.6.x, 10.15.1, >=10.15.0

| `false` | `""` | 19 | | `npm-version` |

Version Spec of the npm version to use. Examples: 7.5.x, 7.5.3, >=7.5.3

| `false` | `""` | 20 | | `yarn-version` |

Version Spec of the yarn version to use. Examples: 1.6.x, 10.15.1, >=10.15.0

| `false` | `""` | 21 | | `package-json-path` |

The path to the package.json to update when using an explicit node-version | yarn-version | npm-version override. By default, we will use package.json in the checkout root.

| `false` | `""` | 22 | | `variant` |

Specific variant to install. Example: providing the variant "linux-openssl-rhel", which will target installing the volta-${version}-linux-openssl-rhel.tar.gz tarball

| `false` | `""` | 23 | | `registry-url` |

Optional registry to set up for auth. Will set the registry in a project level .npmrc file, and set up auth to read in from env.NODEAUTHTOKEN

| `false` | `""` | 24 | | `scope` |

Optional scope for authenticating against scoped registries. Will fall back to the repository owner when using the GitHub Packages registry (https://npm.pkg.github.com/).

| `false` | `""` | 25 | | `token` |

Used to avoid low rate limiting for cached tool downloads. Since there's a default, this is typically not supplied by the user.

| `false` | `${{ github.token }}` | 26 | | `always-auth` |

Set always-auth in npmrc

| `false` | `false` | 27 | 28 | 29 | ## Usage 30 | 31 | See [action.yml](action.yml) 32 | 33 | Basic (when the project's `package.json` has a `volta` property with `node` and/or `yarn` versions pinned): 34 | 35 | ```yaml 36 | steps: 37 | - uses: actions/checkout@v4 38 | - uses: volta-cli/action@v4 39 | - run: npm install 40 | - run: npm test 41 | ``` 42 | 43 | Manually specifying node and/or yarn versions (e.g. to test a project without `volta` in `package.json`): 44 | 45 | ```yaml 46 | steps: 47 | - uses: actions/checkout@v4 48 | - uses: volta-cli/action@v4 49 | with: 50 | node-version: 18.x 51 | yarn-version: 1.19.1 52 | 53 | - run: yarn install 54 | - run: yarn test 55 | ``` 56 | 57 | Setting up a matrix of node versions: 58 | 59 | ```yaml 60 | strategy: 61 | matrix: 62 | node-version: ['^14.10', '16', '18'] 63 | 64 | steps: 65 | - uses: actions/checkout@v4 66 | - uses: volta-cli/action@v4 67 | with: 68 | node-version: ${{ matrix.node-version }} 69 | 70 | - run: npm install 71 | - run: npm test 72 | ``` 73 | 74 | You can also specify the version of npm: 75 | 76 | ```yaml 77 | strategy: 78 | matrix: 79 | node-version: ['^8.12', '10', '12'] 80 | 81 | steps: 82 | - uses: actions/checkout@v4 83 | - uses: volta-cli/action@v4 84 | with: 85 | node-version: ${{ matrix.node-version }} 86 | npm-version: '7' 87 | 88 | - run: npm install 89 | - run: npm test 90 | ``` 91 | 92 | In some cases, you may know the particular variant of the installer that you want to use for Volta. You can specify the `variant` input to the action to use a specific installer: 93 | 94 | ```yaml 95 | steps: 96 | - uses: actions/checkout@v4 97 | - uses: volta-cli/action@v4 98 | with: 99 | variant: 'linux-openssl-rhel' 100 | 101 | - run: yarn install 102 | - run: yarn test 103 | ``` 104 | 105 | The `variant` fragment corresponds to a portion of the installer filename, and can be found in the [Volta Releases](https://github.com/volta-cli/volta/releases) page. 106 | 107 | ## License 108 | 109 | The scripts and documentation in this project are released under the [MIT License](LICENSE) 110 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: "CI" 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | - "releases/*" 8 | 9 | defaults: 10 | run: 11 | shell: bash 12 | 13 | env: 14 | NODE_OPTIONS: "--unhandled-rejections=strict" 15 | 16 | concurrency: 17 | group: ci-${{ github.head_ref || github.ref }} 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | test: 22 | runs-on: "${{ matrix.os }}-latest" 23 | 24 | strategy: 25 | matrix: 26 | os: [ubuntu, macOS, windows] 27 | 28 | steps: 29 | - uses: actions/checkout@v4 30 | 31 | - run: npm ci 32 | - run: npm run lint 33 | - run: npm run build 34 | - run: npm test 35 | 36 | test-specific-volta: 37 | runs-on: "${{ matrix.os }}-latest" 38 | 39 | strategy: 40 | fail-fast: false 41 | matrix: 42 | volta-version: ["1.0.0", "1.0.8", "1.1.0"] 43 | os: [ubuntu, macOS, windows] 44 | exclude: 45 | - os: ubuntu 46 | volta-version: "1.0.0" 47 | 48 | steps: 49 | - uses: actions/checkout@v4 50 | with: 51 | path: action 52 | - run: npm ci 53 | working-directory: ./action 54 | - run: npm run build 55 | working-directory: ./action 56 | - uses: ./action 57 | with: 58 | volta-version: ${{ matrix.volta-version }} 59 | 60 | - run: ./action/tests/log-info.sh 61 | - run: ./action/tests/check-version.sh 'volta' ${{ matrix.volta-version }} 62 | - run: volta install node@10.17.0 yarn@1.19.0 63 | - run: ./action/tests/check-version.sh 'node' 'v10.17.0' 64 | - run: ./action/tests/check-version.sh 'yarn' '1.19.0' 65 | 66 | test-no-options: 67 | runs-on: "${{ matrix.os }}-latest" 68 | 69 | strategy: 70 | matrix: 71 | os: [ubuntu, macOS, windows] 72 | 73 | steps: 74 | - uses: actions/checkout@v4 75 | with: 76 | path: action 77 | 78 | - run: npm ci 79 | working-directory: ./action 80 | - run: npm run build 81 | working-directory: ./action 82 | - uses: ./action 83 | 84 | - run: ./action/tests/log-info.sh 85 | - run: ./action/tests/check-version.sh 'volta' 'current' 86 | - run: volta install node@12.16.1 npm@7.5.2 yarn@1.19.1 87 | - run: ./action/tests/check-version.sh 'node' 'v12.16.1' 88 | - run: ./action/tests/check-version.sh 'npm' '7.5.2' 89 | - run: ./action/tests/check-version.sh 'yarn' '1.19.1' 90 | 91 | test-specified-node-npm-yarn-overrides-pinned-versions: 92 | runs-on: "${{ matrix.os }}-latest" 93 | 94 | strategy: 95 | matrix: 96 | os: [ubuntu, macOS, windows] 97 | 98 | steps: 99 | - uses: actions/checkout@v4 100 | with: 101 | ref: "branch-for-testing-overriding-pinned-projects-in-ci" 102 | 103 | - uses: actions/checkout@v4 104 | with: 105 | path: action 106 | 107 | - run: npm ci 108 | working-directory: ./action 109 | - run: npm run build 110 | working-directory: ./action 111 | 112 | - uses: ./action 113 | with: 114 | node-version: 12.14.0 115 | npm-version: 7.5.2 116 | yarn-version: 1.22.0 117 | 118 | - run: ./action/tests/log-info.sh 119 | - run: ./action/tests/check-version.sh 'node' 'v12.14.0' 120 | - run: ./action/tests/check-version.sh 'npm' '7.5.2' 121 | - run: ./action/tests/check-version.sh 'yarn' '1.22.0' 122 | 123 | test-specific-volta-node-npm-yarn: 124 | runs-on: "${{ matrix.os }}-latest" 125 | 126 | strategy: 127 | matrix: 128 | os: [ubuntu, macOS, windows] 129 | 130 | steps: 131 | - uses: actions/checkout@v4 132 | with: 133 | path: action 134 | - run: npm ci 135 | working-directory: ./action 136 | - run: npm run build 137 | working-directory: ./action 138 | - uses: ./action 139 | with: 140 | volta-version: 1.0.8 141 | node-version: 12.0.0 142 | npm-version: 7.5.2 143 | yarn-version: 1.22.0 144 | 145 | - run: ./action/tests/log-info.sh 146 | - run: ./action/tests/check-version.sh 'volta' '1.0.8' 147 | - run: ./action/tests/check-version.sh 'node' 'v12.0.0' 148 | - run: ./action/tests/check-version.sh 'npm' '7.5.2' 149 | - run: ./action/tests/check-version.sh 'yarn' '1.22.0' 150 | 151 | test-specified-registry-url: 152 | runs-on: "${{ matrix.os }}-latest" 153 | 154 | strategy: 155 | fail-fast: false 156 | matrix: 157 | os: [ubuntu, macOS, windows] 158 | 159 | steps: 160 | - uses: actions/checkout@v4 161 | with: 162 | path: action 163 | 164 | - run: npm ci 165 | working-directory: ./action 166 | - run: npm run build 167 | working-directory: ./action 168 | - uses: ./action 169 | with: 170 | registry-url: "https://some.path.here.com/lol/" 171 | 172 | - run: ./action/tests/log-info.sh 173 | - run: ./action/tests/check-version.sh 'volta' 'current' 174 | - run: volta install node@10.17.0 yarn@1.19.0 175 | - run: ./action/tests/check-version.sh 'node' 'v10.17.0' 176 | - run: ./action/tests/check-version.sh 'yarn' '1.19.0' 177 | - run: ./action/tests/check-registry.sh 'https://some.path.here.com/lol/' 178 | 179 | test-specific-variant: 180 | runs-on: "ubuntu-latest" 181 | 182 | steps: 183 | - uses: actions/checkout@v4 184 | with: 185 | path: action 186 | 187 | - run: npm ci 188 | working-directory: ./action 189 | - run: npm run build 190 | working-directory: ./action 191 | - uses: ./action 192 | with: 193 | variant: linux 194 | 195 | - run: ./action/tests/log-info.sh 196 | - run: ./action/tests/check-version.sh 'volta' 'current' 197 | - run: volta install node@12.16.1 npm@7.5.2 yarn@1.19.1 198 | - run: ./action/tests/check-version.sh 'node' 'v12.16.1' 199 | - run: ./action/tests/check-version.sh 'npm' '7.5.2' 200 | - run: ./action/tests/check-version.sh 'yarn' '1.19.1' 201 | 202 | test-js-project-in-subdir-no-options: 203 | runs-on: "ubuntu-latest" 204 | 205 | steps: 206 | - uses: actions/checkout@v4 207 | with: 208 | path: action 209 | 210 | - uses: actions/checkout@v4 211 | with: 212 | ref: "branch-for-testing-overriding-pinned-projects-in-ci" 213 | path: "js-stuff" 214 | 215 | - run: npm ci 216 | working-directory: ./action 217 | - run: npm run build 218 | working-directory: ./action 219 | - uses: ./action 220 | 221 | - run: ./action/tests/log-info.sh 222 | - run: ./action/tests/check-version.sh 'volta' 'current' 223 | - run: ../action/tests/check-version.sh 'node' 'v12.16.1' 224 | working-directory: ./js-stuff 225 | - run: ../action/tests/check-version.sh 'yarn' '1.22.4' 226 | working-directory: ./js-stuff 227 | 228 | test-js-project-in-subdir-with-overrides: 229 | runs-on: "ubuntu-latest" 230 | 231 | steps: 232 | - uses: actions/checkout@v4 233 | with: 234 | path: action 235 | 236 | - uses: actions/checkout@v4 237 | with: 238 | ref: "branch-for-testing-overriding-pinned-projects-in-ci" 239 | path: "js-stuff" 240 | 241 | - run: npm ci 242 | working-directory: ./action 243 | - run: npm run build 244 | working-directory: ./action 245 | - uses: ./action 246 | with: 247 | package-json-path: "js-stuff/package.json" 248 | node-version: 12.14.0 249 | npm-version: 7.5.2 250 | yarn-version: 1.22.0 251 | 252 | - run: ./action/tests/log-info.sh 253 | - run: ./action/tests/check-version.sh 'volta' 'current' 254 | - run: ../action/tests/check-version.sh 'node' 'v12.14.0' 255 | working-directory: ./js-stuff 256 | - run: ../action/tests/check-version.sh 'npm' '7.5.2' 257 | working-directory: ./js-stuff 258 | - run: ../action/tests/check-version.sh 'yarn' '1.22.0' 259 | working-directory: ./js-stuff 260 | -------------------------------------------------------------------------------- /src/installer.test.ts: -------------------------------------------------------------------------------- 1 | import { afterAll, describe, test, it, expect } from 'vitest'; 2 | import { buildLayout, buildDownloadUrl, getVoltaVersion, getOpenSSLVersion } from './installer'; 3 | import { createTempDir } from 'broccoli-test-helper'; 4 | import nock from 'nock'; 5 | 6 | describe('buildDownloadUrl', () => { 7 | describe('volta@1.0.0', function () { 8 | test('darwin - x64', async function () { 9 | expect(await buildDownloadUrl('darwin', 'x64', '1.0.0')).toMatchInlineSnapshot( 10 | `"https://github.com/volta-cli/volta/releases/download/v1.0.0/volta-1.0.0-macos.tar.gz"` 11 | ); 12 | }); 13 | 14 | test('darwin - arm64', async function () { 15 | expect(await buildDownloadUrl('darwin', 'arm64', '1.0.0')).toMatchInlineSnapshot( 16 | `"https://github.com/volta-cli/volta/releases/download/v1.0.0/volta-1.0.0-macos.tar.gz"` 17 | ); 18 | }); 19 | 20 | test('linux', async function () { 21 | expect( 22 | await buildDownloadUrl('linux', 'x64', '1.0.0', '', 'OpenSSL 1.0.1e-fips 11 Feb 2013') 23 | ).toMatchInlineSnapshot( 24 | `"https://github.com/volta-cli/volta/releases/download/v1.0.0/volta-1.0.0-linux-openssl-1.0.tar.gz"` 25 | ); 26 | 27 | expect( 28 | await buildDownloadUrl('linux', 'x64', '1.0.0', '', 'OpenSSL 1.1.1e-fips 11 Sep 2018') 29 | ).toMatchInlineSnapshot( 30 | `"https://github.com/volta-cli/volta/releases/download/v1.0.0/volta-1.0.0-linux-openssl-1.1.tar.gz"` 31 | ); 32 | }); 33 | 34 | test('linux with variant input', async function () { 35 | expect( 36 | await buildDownloadUrl('linux', 'x64', '1.0.0', 'linux-openssl-rhel') 37 | ).toMatchInlineSnapshot( 38 | `"https://github.com/volta-cli/volta/releases/download/v1.0.0/volta-1.0.0-linux-openssl-rhel.tar.gz"` 39 | ); 40 | }); 41 | 42 | test('win32', async function () { 43 | expect(await buildDownloadUrl('win32', 'x86-64', '1.0.0')).toMatchInlineSnapshot( 44 | `"https://github.com/volta-cli/volta/releases/download/v1.0.0/volta-1.0.0-windows-x86_64.msi"` 45 | ); 46 | }); 47 | 48 | test('aix', async function () { 49 | expect( 50 | async () => 51 | await buildDownloadUrl('aix', 'hmm, wat?? (I dont know a valid arch for aix)', '1.0.0') 52 | ).rejects.toThrowErrorMatchingInlineSnapshot( 53 | `[Error: your platform aix is not yet supported]` 54 | ); 55 | }); 56 | }); 57 | 58 | describe('volta@1.1.0', function () { 59 | test('darwin - x64', async function () { 60 | expect(await buildDownloadUrl('darwin', 'x64', '1.1.0')).toMatchInlineSnapshot( 61 | `"https://github.com/volta-cli/volta/releases/download/v1.1.0/volta-1.1.0-macos.tar.gz"` 62 | ); 63 | }); 64 | 65 | test('darwin - arm64', async function () { 66 | expect(await buildDownloadUrl('darwin', 'arm64', '1.1.0')).toMatchInlineSnapshot( 67 | `"https://github.com/volta-cli/volta/releases/download/v1.1.0/volta-1.1.0-macos-aarch64.tar.gz"` 68 | ); 69 | }); 70 | 71 | test('linux', async function () { 72 | expect(await buildDownloadUrl('linux', 'x64', '1.1.0')).toMatchInlineSnapshot( 73 | `"https://github.com/volta-cli/volta/releases/download/v1.1.0/volta-1.1.0-linux.tar.gz"` 74 | ); 75 | }); 76 | 77 | test('linux with variant input', async function () { 78 | expect( 79 | await buildDownloadUrl('linux', 'x64', '1.1.0', 'linux-openssl-rhel') 80 | ).toMatchInlineSnapshot( 81 | `"https://github.com/volta-cli/volta/releases/download/v1.1.0/volta-1.1.0-linux-openssl-rhel.tar.gz"` 82 | ); 83 | }); 84 | 85 | test('win32', async function () { 86 | expect(await buildDownloadUrl('win32', 'x86-64', '1.1.0')).toMatchInlineSnapshot( 87 | `"https://github.com/volta-cli/volta/releases/download/v1.1.0/volta-1.1.0-windows-x86_64.msi"` 88 | ); 89 | }); 90 | 91 | test('aix', async function () { 92 | expect( 93 | async () => 94 | await buildDownloadUrl('aix', 'hmm, wat?? (I dont know a valid arch for aix)', '1.1.0') 95 | ).rejects.toThrowErrorMatchingInlineSnapshot( 96 | `[Error: your platform aix is not yet supported]` 97 | ); 98 | }); 99 | }); 100 | 101 | describe('volta@2.0.0', function () { 102 | test('darwin - x64', async function () { 103 | expect(await buildDownloadUrl('darwin', 'x64', '2.0.0')).toMatchInlineSnapshot( 104 | `"https://github.com/volta-cli/volta/releases/download/v2.0.0/volta-2.0.0-macos.tar.gz"` 105 | ); 106 | }); 107 | 108 | test('darwin - arm64', async function () { 109 | expect(await buildDownloadUrl('darwin', 'arm64', '2.0.0')).toMatchInlineSnapshot( 110 | `"https://github.com/volta-cli/volta/releases/download/v2.0.0/volta-2.0.0-macos.tar.gz"` 111 | ); 112 | }); 113 | 114 | test('linux - x64', async function () { 115 | expect(await buildDownloadUrl('linux', 'x64', '2.0.0')).toMatchInlineSnapshot( 116 | `"https://github.com/volta-cli/volta/releases/download/v2.0.0/volta-2.0.0-linux.tar.gz"` 117 | ); 118 | }); 119 | 120 | test('linux - arm64', async function () { 121 | expect(await buildDownloadUrl('linux', 'arm64', '2.0.0')).toMatchInlineSnapshot( 122 | `"https://github.com/volta-cli/volta/releases/download/v2.0.0/volta-2.0.0-linux-arm.tar.gz"` 123 | ); 124 | }); 125 | 126 | test('linux with variant input', async function () { 127 | expect( 128 | await buildDownloadUrl('linux', 'x64', '1.1.0', 'linux-openssl-rhel') 129 | ).toMatchInlineSnapshot( 130 | `"https://github.com/volta-cli/volta/releases/download/v1.1.0/volta-1.1.0-linux-openssl-rhel.tar.gz"` 131 | ); 132 | }); 133 | 134 | test('win32 - x64', async function () { 135 | expect(await buildDownloadUrl('win32', 'x86-64', '2.0.0')).toMatchInlineSnapshot( 136 | `"https://github.com/volta-cli/volta/releases/download/v2.0.0/volta-2.0.0-windows-x86_64.msi"` 137 | ); 138 | }); 139 | 140 | test('win32 - arm64', async function () { 141 | expect(await buildDownloadUrl('win32', 'arm64', '2.0.0')).toMatchInlineSnapshot( 142 | `"https://github.com/volta-cli/volta/releases/download/v2.0.0/volta-2.0.0-windows-arm64.msi"` 143 | ); 144 | }); 145 | 146 | test('aix', async function () { 147 | expect( 148 | async () => 149 | await buildDownloadUrl('aix', 'hmm, wat?? (I dont know a valid arch for aix)', '2.0.0') 150 | ).rejects.toThrowErrorMatchingInlineSnapshot( 151 | `[Error: your platform aix is not yet supported]` 152 | ); 153 | }); 154 | }); 155 | }); 156 | 157 | describe('getOpenSSLVersion', () => { 158 | test('1.0', async function () { 159 | expect(await getOpenSSLVersion('OpenSSL 1.0.1e-fips 11 Feb 2013')).toMatchInlineSnapshot( 160 | `"openssl-1.0"` 161 | ); 162 | }); 163 | 164 | test('1.1', async function () { 165 | expect(await getOpenSSLVersion('OpenSSL 1.1.1e-fips 11 Sep 2018')).toMatchInlineSnapshot( 166 | `"openssl-1.1"` 167 | ); 168 | }); 169 | }); 170 | 171 | describe('buildLayout', () => { 172 | test('creates the rough folder structure', async () => { 173 | const tmpdir = await createTempDir(); 174 | 175 | tmpdir.write({ 176 | bin: { 177 | shim: 'shim-file-here', 178 | }, 179 | }); 180 | 181 | await buildLayout(tmpdir.path()); 182 | 183 | expect(tmpdir.read()).toMatchInlineSnapshot(` 184 | { 185 | "bin": { 186 | "node": "shim-file-here", 187 | "npm": "shim-file-here", 188 | "npx": "shim-file-here", 189 | "shim": "shim-file-here", 190 | "yarn": "shim-file-here", 191 | }, 192 | "cache": { 193 | "node": {}, 194 | }, 195 | "log": {}, 196 | "tmp": {}, 197 | "tools": { 198 | "image": { 199 | "node": {}, 200 | "packages": {}, 201 | "yarn": {}, 202 | }, 203 | "inventory": { 204 | "node": {}, 205 | "packages": {}, 206 | "yarn": {}, 207 | }, 208 | "user": {}, 209 | }, 210 | } 211 | `); 212 | }); 213 | }); 214 | 215 | describe('getVoltaVersion', function () { 216 | afterAll(() => { 217 | nock.restore(); 218 | }); 219 | 220 | it('without user provided volta version', async function () { 221 | try { 222 | const scope = nock('https://api.github.com') 223 | .get('/repos/volta-cli/volta/releases/latest') 224 | .reply(200, '{ "name": "v999.999.999" }'); 225 | 226 | expect(await getVoltaVersion('', 'some-token')).toEqual('999.999.999'); 227 | 228 | scope.done(); 229 | } finally { 230 | nock.cleanAll(); 231 | } 232 | }); 233 | 234 | it('with user provided volta version', async function () { 235 | expect(await getVoltaVersion('1.0.1', 'some-token')).toEqual('1.0.1'); 236 | }); 237 | 238 | it('errors for older volta versions', async function () { 239 | expect( 240 | async () => await getVoltaVersion('0.6.5', 'some-token') 241 | ).rejects.toThrowErrorMatchingInlineSnapshot( 242 | `[Error: volta-cli/action: Volta version must be >= 1.0.0 (you specified 0.6.5)]` 243 | ); 244 | }); 245 | 246 | it('falls back to downloading from volta.sh/latest-version', async function () { 247 | try { 248 | const githubScope = nock('https://api.github.com') 249 | .get('/repos/volta-cli/volta/releases/latest') 250 | .reply(429, 'rate limit exceeded'); 251 | 252 | const voltaSHScope = nock('https://volta.sh') 253 | .get('/latest-version') 254 | .reply(200, '999.999.999'); 255 | 256 | expect(await getVoltaVersion('', 'some-token')).toEqual('999.999.999'); 257 | 258 | voltaSHScope.done(); 259 | githubScope.done(); 260 | } finally { 261 | nock.cleanAll(); 262 | } 263 | }); 264 | }); 265 | -------------------------------------------------------------------------------- /src/installer.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core'; 2 | import { exec, ExecOptions } from '@actions/exec'; 3 | import * as hc from '@actions/http-client'; 4 | import * as io from '@actions/io'; 5 | import * as tc from '@actions/tool-cache'; 6 | import * as fs from 'fs'; 7 | import type { OutgoingHttpHeaders } from 'http'; 8 | import * as os from 'os'; 9 | import * as path from 'path'; 10 | import * as semver from 'semver'; 11 | import { v4 as uuidV4 } from 'uuid'; 12 | 13 | type VoltaInstallOptions = { 14 | versionSpec: string; 15 | authToken: string; 16 | variant: string; 17 | }; 18 | 19 | async function getLatestVolta(authToken: string): Promise { 20 | core.startGroup('Determine the latest volta version'); 21 | 22 | const url = 'https://api.github.com/repos/volta-cli/volta/releases/latest'; 23 | 24 | const http = new hc.HttpClient('volta-cli/action', [], { 25 | allowRetries: true, 26 | maxRetries: 3, 27 | }); 28 | 29 | let headers: OutgoingHttpHeaders | undefined; 30 | if (authToken) { 31 | headers = { 32 | authorization: authToken, 33 | }; 34 | } 35 | 36 | try { 37 | core.info(`Retrieving release info from ${url}`); 38 | const response = await http.getJson<{ name: string }>(url, headers); 39 | if (!response.result) { 40 | throw new Error(`volta-cli/action: Could not download latest release from ${url}`); 41 | } 42 | 43 | const result = semver.clean(response.result.name) as string; 44 | 45 | core.info(`Latest volta version is ${result}`); 46 | 47 | return result; 48 | } catch (error: unknown) { 49 | if ( 50 | error instanceof hc.HttpClientError && 51 | (error.statusCode === 403 || error.statusCode === 429) 52 | ) { 53 | core.info( 54 | `Received HTTP status code ${error.statusCode}. This usually indicates the rate limit has been exceeded` 55 | ); 56 | 57 | const result = await getLatestVoltaFromVoltaSH(); 58 | 59 | core.info(`Latest volta version is ${result}`); 60 | 61 | return result; 62 | } else { 63 | core.info(`Failed to determine latest volta release from ${url}: ${error}`); 64 | 65 | throw error; 66 | } 67 | } finally { 68 | core.endGroup(); 69 | } 70 | } 71 | 72 | async function getLatestVoltaFromVoltaSH(): Promise { 73 | const url = 'https://volta.sh/latest-version'; 74 | 75 | core.info(`Falling back to determine latest volta version from ${url}`); 76 | 77 | const http = new hc.HttpClient('volta-cli/action', [], { 78 | allowRetries: true, 79 | maxRetries: 3, 80 | }); 81 | 82 | let response: hc.HttpClientResponse; 83 | try { 84 | response = await http.get(url); 85 | } catch (error: unknown) { 86 | core.setFailed(`Action failed with error ${error}`); 87 | 88 | throw error; 89 | } 90 | 91 | if (response.message.statusCode !== 200) { 92 | const message = `volta-cli/action: Could not download latest release from ${url}: ${response.message.statusMessage}`; 93 | 94 | core.setFailed(message); 95 | 96 | throw new Error(message); 97 | } 98 | 99 | return semver.clean(await response.readBody()) as string; 100 | } 101 | 102 | function voltaVersionHasSetup(version: string): boolean { 103 | return semver.gte(version, '0.7.0'); 104 | } 105 | 106 | export async function buildDownloadUrl( 107 | platform: string, 108 | arch: string, 109 | version: string, 110 | variant = '', 111 | openSSLVersionForTesting = '' 112 | ): Promise { 113 | let fileName = ''; 114 | 115 | const isOpenSSLDependent = semver.lt(version, '1.1.0'); 116 | const isVolta1 = semver.lt(version, '2.0.0'); 117 | 118 | if (variant) { 119 | fileName = `volta-${version}-${variant}.tar.gz`; 120 | } else if (isOpenSSLDependent) { 121 | // TODO: remove this branch when support for volta < 1.1.0 is dropped 122 | switch (platform) { 123 | case 'darwin': 124 | fileName = `volta-${version}-macos.tar.gz`; 125 | break; 126 | case 'linux': { 127 | const openSSLVersion = await getOpenSSLVersion(openSSLVersionForTesting); 128 | 129 | fileName = `volta-${version}-linux-${openSSLVersion}.tar.gz`; 130 | break; 131 | } 132 | case 'win32': 133 | fileName = `volta-${version}-windows-x86_64.msi`; 134 | break; 135 | default: 136 | throw new Error(`your platform ${platform} is not yet supported`); 137 | } 138 | } else if (isVolta1) { 139 | switch (platform) { 140 | case 'darwin': 141 | fileName = `volta-${version}-macos${arch === 'arm64' ? '-aarch64' : ''}.tar.gz`; 142 | break; 143 | case 'linux': { 144 | fileName = `volta-${version}-linux.tar.gz`; 145 | break; 146 | } 147 | case 'win32': 148 | fileName = `volta-${version}-windows-x86_64.msi`; 149 | break; 150 | default: 151 | throw new Error(`your platform ${platform} is not yet supported`); 152 | } 153 | } else { 154 | switch (platform) { 155 | case 'darwin': { 156 | fileName = `volta-${version}-macos.tar.gz`; 157 | break; 158 | } 159 | case 'linux': { 160 | fileName = `volta-${version}-linux${arch === 'arm64' ? '-arm' : ''}.tar.gz`; 161 | break; 162 | } 163 | case 'win32': { 164 | fileName = `volta-${version}-windows-${arch === 'arm64' ? 'arm64' : 'x86_64'}.msi`; 165 | break; 166 | } 167 | default: 168 | throw new Error(`your platform ${platform} is not yet supported`); 169 | } 170 | } 171 | 172 | return `https://github.com/volta-cli/volta/releases/download/v${version}/${fileName}`; 173 | } 174 | 175 | export async function getOpenSSLVersion(version = ''): Promise { 176 | if (version === '') { 177 | version = await execOpenSSLVersion(); 178 | } 179 | 180 | // typical version string looks like 'OpenSSL 1.0.1e-fips 11 Feb 2013' 181 | const openSSLVersionPattern = /^([^\s]*)\s([0-9]+\.[0-9]+)/; 182 | const match = openSSLVersionPattern.exec(version); 183 | 184 | if (match === null) { 185 | throw new Error( 186 | `No version of OpenSSL was found. @volta-cli/action requires a valid version of OpenSSL. ('openssl version' output: ${version})` 187 | ); 188 | } 189 | 190 | version = match[2]; 191 | 192 | // should return in openssl-1.1 format 193 | return `openssl-${version}`; 194 | } 195 | 196 | async function execOpenSSLVersion() { 197 | core.info('determining openssl version'); 198 | 199 | let output = ''; 200 | const options: ExecOptions = {}; 201 | options.listeners = { 202 | stdout: (data: Buffer) => { 203 | output += data.toString(); 204 | }, 205 | stderr: (data: Buffer) => { 206 | output += data.toString(); 207 | }, 208 | }; 209 | 210 | await exec('openssl version', [], options); 211 | 212 | return output; 213 | } 214 | 215 | /* 216 | * Used to setup a specific shim when running volta < 0.7 217 | */ 218 | async function setupShim(voltaHome: string, name: string): Promise { 219 | const shimSource = path.join(voltaHome, 'bin', 'shim'); 220 | const shimPath = path.join(voltaHome, 'bin', name); 221 | 222 | fs.copyFileSync(shimSource, shimPath); 223 | 224 | // TODO: this is not portable to win32, confirm `volta setup` will take care 225 | // of this for us 226 | await fs.promises.chmod(shimPath, 0o755); 227 | } 228 | 229 | /* 230 | * Used to setup the node/yarn/npm/npx shims when running volta < 0.7 231 | */ 232 | async function setupShims(voltaHome: string): Promise { 233 | // current volta installations (e.g 0.6.x) expect the common shims 234 | // to be setup in $VOLTA_HOME/bin 235 | setupShim(voltaHome, 'node'); 236 | setupShim(voltaHome, 'yarn'); 237 | setupShim(voltaHome, 'npm'); 238 | setupShim(voltaHome, 'npx'); 239 | } 240 | 241 | /* 242 | * Used to build the required folder structure when installing volta < 0.7 243 | */ 244 | export async function buildLayout(voltaHome: string): Promise { 245 | // create the $VOLTA_HOME folder structure (volta doesn't create these 246 | // folders on demand, and errors when installing node/yarn/tools if it 247 | // isn't present) 248 | await io.mkdirP(path.join(voltaHome, 'tmp')); 249 | await io.mkdirP(path.join(voltaHome, 'bin')); 250 | await io.mkdirP(path.join(voltaHome, 'cache/node')); 251 | await io.mkdirP(path.join(voltaHome, 'log')); 252 | await io.mkdirP(path.join(voltaHome, 'tmp')); 253 | await io.mkdirP(path.join(voltaHome, 'tools/image/node')); 254 | await io.mkdirP(path.join(voltaHome, 'tools/image/packages')); 255 | await io.mkdirP(path.join(voltaHome, 'tools/image/yarn')); 256 | await io.mkdirP(path.join(voltaHome, 'tools/inventory/node')); 257 | await io.mkdirP(path.join(voltaHome, 'tools/inventory/packages')); 258 | await io.mkdirP(path.join(voltaHome, 'tools/inventory/yarn')); 259 | await io.mkdirP(path.join(voltaHome, 'tools/user')); 260 | await setupShims(voltaHome); 261 | } 262 | 263 | async function acquireVolta(version: string, options: VoltaInstallOptions): Promise { 264 | // 265 | // Download - a tool installer intimately knows how to get the tool (and construct urls) 266 | // 267 | 268 | core.startGroup(`downloading volta@${version}`); 269 | 270 | try { 271 | const downloadUrl = await buildDownloadUrl(os.platform(), os.arch(), version, options.variant); 272 | 273 | core.info(`downloading volta from \`${downloadUrl}\``); 274 | const downloadPath = await tc.downloadTool(downloadUrl, undefined, options.authToken); 275 | 276 | const voltaHome = path.join( 277 | // `RUNNER_TEMP` is used by @actions/tool-cache 278 | process.env['RUNNER_TEMP'] || '', 279 | uuidV4() 280 | ); 281 | 282 | await io.mkdirP(voltaHome); 283 | 284 | // 285 | // Extract 286 | // 287 | const voltaHomeBin = path.join(voltaHome, 'bin'); 288 | core.debug(`extracting from \`${downloadPath}\` into \`${voltaHomeBin}\``); 289 | if (os.platform() === 'win32') { 290 | const tmpExtractTarget = path.join( 291 | // `RUNNER_TEMP` is used by @actions/tool-cache 292 | process.env['RUNNER_TEMP'] || '', 293 | uuidV4() 294 | ); 295 | const msiexecPath = await io.which('msiexec', true); 296 | 297 | await exec(msiexecPath, ['/a', downloadPath, '/qn', `TARGETDIR=${tmpExtractTarget}`]); 298 | await io.cp(path.join(tmpExtractTarget, 'PFiles', 'volta'), voltaHomeBin, { 299 | recursive: true, 300 | }); 301 | } else { 302 | await tc.extractTar(downloadPath, voltaHomeBin); 303 | } 304 | 305 | core.debug( 306 | `extracted "${fs.readdirSync(voltaHomeBin).join('","')}" from tarball into '${voltaHomeBin}'` 307 | ); 308 | 309 | return voltaHome; 310 | } finally { 311 | core.endGroup(); 312 | } 313 | } 314 | 315 | async function setupVolta(version: string, voltaHome: string): Promise { 316 | if (voltaVersionHasSetup(version)) { 317 | const executable = path.join(voltaHome, 'bin', 'volta'); 318 | core.info(`executing \`${executable} setup\``); 319 | await exec(executable, ['setup'], { 320 | env: { 321 | // VOLTA_HOME needs to be set before calling volta setup 322 | VOLTA_HOME: voltaHome, 323 | }, 324 | }); 325 | } else { 326 | await buildLayout(voltaHome); 327 | } 328 | } 329 | 330 | export async function execVolta(workingDirectory: string, specifiedArgs: string[]): Promise { 331 | const args = [...specifiedArgs]; 332 | const options: ExecOptions = { 333 | cwd: workingDirectory, 334 | }; 335 | 336 | if (core.isDebug()) { 337 | args.unshift('--verbose'); 338 | 339 | options.env = { 340 | VOLTA_LOGLEVEL: 'debug', 341 | RUST_STACKTRACE: 'full', 342 | 343 | // add `process.env` (otherwise specifying `env` will cause us to no 344 | // longer inherit `process.env`) 345 | ...process.env, 346 | }; 347 | } 348 | 349 | await exec('volta', args, options); 350 | } 351 | 352 | export async function installNode(version: string): Promise { 353 | // using `.` here because `volta install` doesn't care about the working directory at all 354 | await execVolta('.', ['install', `node${version === 'true' ? '' : `@${version}`}`]); 355 | } 356 | 357 | export async function installNpm(version: string): Promise { 358 | // using `.` here because `volta install` doesn't care about the working directory at all 359 | await execVolta('.', ['install', `npm${version === 'true' ? '' : `@${version}`}`]); 360 | } 361 | 362 | export async function installYarn(version: string): Promise { 363 | // using `.` here because `volta install` doesn't care about the working directory at all 364 | await execVolta('.', ['install', `yarn${version === 'true' ? '' : `@${version}`}`]); 365 | } 366 | 367 | export async function pinNode(workingDirectory: string, version: string): Promise { 368 | await execVolta(workingDirectory, ['pin', `node${version === 'true' ? '' : `@${version}`}`]); 369 | } 370 | 371 | export async function pinNpm(workingDirectory: string, version: string): Promise { 372 | await execVolta(workingDirectory, ['pin', `npm${version === 'true' ? '' : `@${version}`}`]); 373 | } 374 | 375 | export async function pinYarn(workingDirectory: string, version: string): Promise { 376 | await execVolta(workingDirectory, ['pin', `yarn${version === 'true' ? '' : `@${version}`}`]); 377 | } 378 | 379 | export async function getVoltaVersion(versionSpec: string, authToken: string): Promise { 380 | let version = semver.clean(versionSpec) || ''; 381 | const validVersionProvided = semver.valid(version) !== null; 382 | 383 | if (validVersionProvided && semver.lt(version, '1.0.0')) { 384 | throw new Error( 385 | `volta-cli/action: Volta version must be >= 1.0.0 (you specified ${versionSpec})` 386 | ); 387 | } 388 | 389 | if (validVersionProvided) { 390 | core.info(`using user provided version volta@${version}`); 391 | } else { 392 | core.info(`looking up latest volta version`); 393 | version = await getLatestVolta(authToken); 394 | } 395 | 396 | return version; 397 | } 398 | 399 | export async function getVolta(options: VoltaInstallOptions): Promise { 400 | const version = await getVoltaVersion(options.versionSpec, options.authToken); 401 | 402 | let voltaHome = tc.find('volta', version); 403 | 404 | if (voltaHome === '') { 405 | // download, extract, cache 406 | const toolRoot = await acquireVolta(version, options); 407 | 408 | // Install into the local tool cache - node extracts with a root folder 409 | // that matches the fileName downloaded 410 | voltaHome = await tc.cacheDir(toolRoot, 'volta', version); 411 | 412 | await setupVolta(version, voltaHome); 413 | 414 | core.info(`caching volta@${version} into ${voltaHome}`); 415 | } else { 416 | core.info(`using cached volta@${version}`); 417 | } 418 | 419 | // prepend the tools path. instructs the agent to prepend for future tasks 420 | if (voltaHome !== undefined) { 421 | const binPath = path.join(voltaHome, 'bin'); 422 | 423 | core.info(`adding ${binPath} to $PATH`); 424 | 425 | core.addPath(binPath); 426 | core.exportVariable('VOLTA_HOME', voltaHome); 427 | } 428 | } 429 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ## v4.2.1 (2024-08-06) 16 | 17 | #### :house: Internal 18 | * [#156](https://github.com/volta-cli/action/pull/156) Re-roll package-lock.json ([@rwjblue](https://github.com/rwjblue)) 19 | * [#155](https://github.com/volta-cli/action/pull/155) Update various dependencies to latest ([@rwjblue](https://github.com/rwjblue)) 20 | * [#153](https://github.com/volta-cli/action/pull/153) Update linting related dependencies to latest ([@rwjblue](https://github.com/rwjblue)) 21 | * [#152](https://github.com/volta-cli/action/pull/152) Update in-range dependencies to latest ([@rwjblue](https://github.com/rwjblue)) 22 | 23 | #### Committers: 1 24 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 25 | 26 | 27 | ## v4.2.0 (2024-08-05) 28 | 29 | #### :rocket: Enhancement 30 | * [#151](https://github.com/volta-cli/action/pull/151) Add support for Volta 2.0.0 ([@charlespierce](https://github.com/charlespierce)) 31 | 32 | #### Committers: 1 33 | - Charles Pierce ([@charlespierce](https://github.com/charlespierce)) 34 | 35 | 36 | ## v4.1.1 (2024-03-14) 37 | 38 | #### :house: Internal 39 | * [#148](https://github.com/volta-cli/action/pull/148) Re-roll lockfile. ([@rwjblue](https://github.com/rwjblue)) 40 | 41 | #### Committers: 1 42 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 43 | 44 | 45 | ## v4.1.0 (2024-03-14) 46 | 47 | #### :bug: Bug Fix 48 | * [#143](https://github.com/volta-cli/action/pull/143) Update node to v20 (fix Node 16 deprecation) ([@stijnvn](https://github.com/stijnvn)) 49 | 50 | #### Committers: 1 51 | - Stijn Van Nieuwenhuyse ([@stijnvn](https://github.com/stijnvn)) 52 | 53 | 54 | ## v4.0.1 (2023-05-17) 55 | 56 | #### :memo: Documentation 57 | * [#125](https://github.com/volta-cli/action/pull/125) docs: update examples with v4 release ([@Maxwell2022](https://github.com/Maxwell2022)) 58 | * [#128](https://github.com/volta-cli/action/pull/128) Use v4 in readme examples ([@otahontas](https://github.com/otahontas)) 59 | * [#116](https://github.com/volta-cli/action/pull/116) Update link to Volta releases page ([@alexlafroscia](https://github.com/alexlafroscia)) 60 | 61 | #### :house: Internal 62 | * [#135](https://github.com/volta-cli/action/pull/135) Update dependencies & devDependencies to latest ([@rwjblue](https://github.com/rwjblue)) 63 | * [#134](https://github.com/volta-cli/action/pull/134) Update release-it (and plugins) to latest ([@rwjblue](https://github.com/rwjblue)) 64 | * [#133](https://github.com/volta-cli/action/pull/133) Add more logging (to more easily identify failures) ([@rwjblue](https://github.com/rwjblue)) 65 | * [#132](https://github.com/volta-cli/action/pull/132) Migrate to vitest ([@rwjblue](https://github.com/rwjblue)) 66 | * [#130](https://github.com/volta-cli/action/pull/130) Update in-range dependencies & devDependencies to latest ([@rwjblue](https://github.com/rwjblue)) 67 | * [#131](https://github.com/volta-cli/action/pull/131) Avoid CI errors when testing volta@1.0.0 with OpenSSL 3 ([@rwjblue](https://github.com/rwjblue)) 68 | 69 | #### Committers: 4 70 | - Alex LaFroscia ([@alexlafroscia](https://github.com/alexlafroscia)) 71 | - Maxime ([@Maxwell2022](https://github.com/Maxwell2022)) 72 | - Otto Ahoniemi ([@otahontas](https://github.com/otahontas)) 73 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 74 | 75 | 76 | ## v4.0.0 (2022-10-03) 77 | 78 | #### :boom: Breaking Change 79 | * [#102](https://github.com/volta-cli/action/pull/102) Replace `openssl-version` configuration with `variant` ([@scalvert](https://github.com/scalvert)) 80 | 81 | #### :memo: Documentation 82 | * [#104](https://github.com/volta-cli/action/pull/104) Add action-docs updater ([@rwjblue](https://github.com/rwjblue)) 83 | * [#103](https://github.com/volta-cli/action/pull/103) Remove reference to https://volta.sh/latest-version in logging ([@rwjblue](https://github.com/rwjblue)) 84 | 85 | #### :rocket: Enhancement 86 | * [#107](https://github.com/volta-cli/action/pull/107) Add `package-json-path` input to specify location of `package.json` ([@rwjblue](https://github.com/rwjblue)) 87 | 88 | #### :bug: Bug Fix 89 | * [#110](https://github.com/volta-cli/action/pull/110) Fix for self-hoster runners (instead of relying on `RUNNER_TEMP`) ([@jeevcat](https://github.com/jeevcat)) 90 | * [#111](https://github.com/volta-cli/action/pull/111) Fall back to downloading latest version from volta.sh on rate-limit ([@ZauberNerd](https://github.com/ZauberNerd)) 91 | * [#115](https://github.com/volta-cli/action/pull/115) Add support for Volta 1.1.0 ([@rwjblue](https://github.com/rwjblue)) 92 | 93 | #### Committers: 4 94 | - Björn Brauer ([@ZauberNerd](https://github.com/ZauberNerd)) 95 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 96 | - Sam Jeeves ([@jeevcat](https://github.com/jeevcat)) 97 | - Steve Calvert ([@scalvert](https://github.com/scalvert)) 98 | 99 | 100 | ## v4.0.0-beta.4 (2022-10-03) 101 | 102 | #### :bug: Bug Fix 103 | * [#115](https://github.com/volta-cli/action/pull/115) Add support for Volta 1.1.0 ([@rwjblue](https://github.com/rwjblue)) 104 | 105 | #### Committers: 1 106 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 107 | 108 | 109 | ## v4.0.0-beta.3 (2022-10-03) 110 | 111 | #### :bug: Bug Fix 112 | * [#110](https://github.com/volta-cli/action/pull/110) Fix for self-hoster runners (instead of relying on `RUNNER_TEMP`) ([@jeevcat](https://github.com/jeevcat)) 113 | * [#111](https://github.com/volta-cli/action/pull/111) Fall back to downloading latest version from volta.sh on rate-limit ([@ZauberNerd](https://github.com/ZauberNerd)) 114 | 115 | #### Committers: 2 116 | - Björn Brauer ([@ZauberNerd](https://github.com/ZauberNerd)) 117 | - Sam Jeeves ([@jeevcat](https://github.com/jeevcat)) 118 | 119 | 120 | ## v4.0.0-beta.2 (2022-09-09) 121 | 122 | #### :rocket: Enhancement 123 | * [#107](https://github.com/volta-cli/action/pull/107) Add `package-json-path` input to specify location of `package.json` ([@rwjblue](https://github.com/rwjblue)) 124 | 125 | #### :house: Internal 126 | * [#106](https://github.com/volta-cli/action/pull/106) Update devDependencies to latest ([@rwjblue](https://github.com/rwjblue)) 127 | 128 | #### Committers: 1 129 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 130 | 131 | 132 | ## v4.0.0-beta.1 (2022-09-07) 133 | 134 | #### :boom: Breaking Change 135 | * [#102](https://github.com/volta-cli/action/pull/102) Replace `openssl-version` configuration with `variant` ([@scalvert](https://github.com/scalvert)) 136 | 137 | #### :memo: Documentation 138 | * [#104](https://github.com/volta-cli/action/pull/104) Add action-docs updater ([@rwjblue](https://github.com/rwjblue)) 139 | * [#103](https://github.com/volta-cli/action/pull/103) Remove reference to https://volta.sh/latest-version in logging ([@rwjblue](https://github.com/rwjblue)) 140 | 141 | #### :house: Internal 142 | * [#105](https://github.com/volta-cli/action/pull/105) Add CI scenario acceptance test using `variant` ([@rwjblue](https://github.com/rwjblue)) 143 | 144 | #### Committers: 2 145 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 146 | - Steve Calvert ([@scalvert](https://github.com/scalvert)) 147 | 148 | 149 | ## v3.0.2 (2022-09-01) 150 | 151 | #### :bug: Bug Fix 152 | * [#101](https://github.com/volta-cli/action/pull/101) Use GitHub API to retrieve latest release information. ([@rwjblue](https://github.com/rwjblue)) 153 | 154 | #### :memo: Documentation 155 | * [#100](https://github.com/volta-cli/action/pull/100) Fix changelog heading ([@Turbo87](https://github.com/Turbo87)) 156 | 157 | #### Committers: 2 158 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 159 | - Tobias Bieniek ([@Turbo87](https://github.com/Turbo87)) 160 | 161 | 162 | ## v3.0.1 (2022-08-30) 163 | 164 | #### :memo: Documentation 165 | * [#99](https://github.com/volta-cli/action/pull/99) Update README to include current versions ([@rwjblue](https://github.com/rwjblue)) 166 | 167 | #### Committers: 1 168 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 169 | 170 | 171 | ## v3.0.0 (2022-08-30) 172 | 173 | #### :boom: Breaking Change 174 | * [#93](https://github.com/volta-cli/action/pull/93) Drop support for usage with Volta older than 1.0.0 ([@rwjblue](https://github.com/rwjblue)) 175 | * [#75](https://github.com/volta-cli/action/pull/75) Output ESM into dist/ ([@rwjblue](https://github.com/rwjblue)) 176 | * [#91](https://github.com/volta-cli/action/pull/91) Update action metadata to leverage Node 16 ([@rwjblue](https://github.com/rwjblue)) 177 | 178 | #### :rocket: Enhancement 179 | * [#97](https://github.com/volta-cli/action/pull/97) Use `${{ github.token }}` to authenticate tool cache downloads ([@rwjblue](https://github.com/rwjblue)) 180 | * [#98](https://github.com/volta-cli/action/pull/98) Allow explicitly specifying `openssl-version` (on self-hosted environments the `openssl` command may not be on `$PATH`) ([@scalvert](https://github.com/scalvert)) 181 | 182 | #### :bug: Bug Fix 183 | * [#95](https://github.com/volta-cli/action/pull/95) Add `scope` to list of inputs ([@rwjblue](https://github.com/rwjblue)) 184 | 185 | #### :house: Internal 186 | * [#46](https://github.com/volta-cli/action/pull/46) Update to npm@8 ([@rwjblue](https://github.com/rwjblue)) 187 | * [#96](https://github.com/volta-cli/action/pull/96) Prevent test harness from defaulting to `./action` as default working directory ([@rwjblue](https://github.com/rwjblue)) 188 | * [#92](https://github.com/volta-cli/action/pull/92) Migrate CI jobs to checkout `action` into subdirectory ([@rwjblue](https://github.com/rwjblue)) 189 | 190 | #### Committers: 2 191 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 192 | - Steve Calvert ([@scalvert](https://github.com/scalvert)) 193 | 194 | 195 | ## v3.0.0-beta.2 (2022-08-30) 196 | 197 | #### :rocket: Enhancement 198 | * [#98](https://github.com/volta-cli/action/pull/98) Allow explicitly specifying `openssl-version` (on self-hosted environments the `openssl` command may not be on `$PATH`) ([@scalvert](https://github.com/scalvert)) 199 | 200 | #### Committers: 1 201 | - Steve Calvert ([@scalvert](https://github.com/scalvert)) 202 | 203 | 204 | ## v3.0.0-beta.1 (2022-08-18) 205 | 206 | #### :boom: Breaking Change 207 | * [#93](https://github.com/volta-cli/action/pull/93) Drop support for usage with Volta older than 1.0.0 ([@rwjblue](https://github.com/rwjblue)) 208 | * [#75](https://github.com/volta-cli/action/pull/75) Output ESM into dist/ ([@rwjblue](https://github.com/rwjblue)) 209 | * [#91](https://github.com/volta-cli/action/pull/91) Update action metadata to leverage Node 16 ([@rwjblue](https://github.com/rwjblue)) 210 | 211 | #### :rocket: Enhancement 212 | * [#97](https://github.com/volta-cli/action/pull/97) Use `${{ github.token }}` to authenticate tool cache downloads ([@rwjblue](https://github.com/rwjblue)) 213 | 214 | #### :bug: Bug Fix 215 | * [#95](https://github.com/volta-cli/action/pull/95) Add `scope` to list of inputs ([@rwjblue](https://github.com/rwjblue)) 216 | 217 | #### :house: Internal 218 | * [#46](https://github.com/volta-cli/action/pull/46) Update to npm@8 ([@rwjblue](https://github.com/rwjblue)) 219 | * [#96](https://github.com/volta-cli/action/pull/96) Prevent test harness from defaulting to `./action` as default working directory ([@rwjblue](https://github.com/rwjblue)) 220 | * [#92](https://github.com/volta-cli/action/pull/92) Migrate CI jobs to checkout `action` into subdirectory ([@rwjblue](https://github.com/rwjblue)) 221 | 222 | #### Committers: 1 223 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 224 | 225 | 226 | ## v2.0.1 (2022-08-12) 227 | 228 | #### :house: Internal 229 | * [#86](https://github.com/volta-cli/action/pull/86) Update dependencies / devDependencies to latest ([@rwjblue](https://github.com/rwjblue)) 230 | 231 | #### Committers: 1 232 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 233 | 234 | 235 | ## v2.0.0 (2022-08-10) 236 | 237 | #### :boom: Breaking Change 238 | * [#89](https://github.com/volta-cli/action/pull/89) Fix usage on Linux distributions other than Ubuntu (e.g. CentOS, RHEL, &c) ([@scalvert](https://github.com/scalvert)) 239 | 240 | #### :rocket: Enhancement 241 | * [#64](https://github.com/volta-cli/action/pull/64) Adds registry-url and always-auth parameters ([@pzuraq](https://github.com/pzuraq)) 242 | 243 | #### :bug: Bug Fix 244 | * [#89](https://github.com/volta-cli/action/pull/89) Fix usage on Linux distributions other than Ubuntu (e.g. CentOS, RHEL, &c) ([@scalvert](https://github.com/scalvert)) 245 | 246 | #### Committers: 3 247 | - Chris Garrett ([@pzuraq](https://github.com/pzuraq)) 248 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 249 | - Steve Calvert ([@scalvert](https://github.com/scalvert)) 250 | 251 | 252 | ## v1.7.0 (2021-03-03) 253 | 254 | #### :rocket: Enhancement 255 | * [#53](https://github.com/volta-cli/action/pull/53) Add support for specifying `npm-version` as an option ([@felipecrs](https://github.com/felipecrs)) 256 | 257 | #### :bug: Bug Fix 258 | * [#54](https://github.com/volta-cli/action/pull/54) Update `tsc` matcher to associate failure with correct line/column. ([@rwjblue](https://github.com/rwjblue)) 259 | 260 | #### :house: Internal 261 | * [#55](https://github.com/volta-cli/action/pull/55) Update release setup. ([@rwjblue](https://github.com/rwjblue)) 262 | 263 | #### Committers: 2 264 | - Felipe Santos ([@felipecrs](https://github.com/felipecrs)) 265 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 266 | 267 | 268 | ## v1.6.0 (2020-10-22) 269 | 270 | #### :rocket: Enhancement 271 | * [#42](https://github.com/volta-cli/action/pull/42) Add tsc and eslint matchers. ([@rwjblue](https://github.com/rwjblue)) 272 | 273 | #### :house: Internal 274 | * [#43](https://github.com/volta-cli/action/pull/43) Refactor CI config to simplify testing volta 0.6, 0.7, 0.8, and 0.9. ([@rwjblue](https://github.com/rwjblue)) 275 | * [#45](https://github.com/volta-cli/action/pull/45) Update dependencies to latest. ([@rwjblue](https://github.com/rwjblue)) 276 | * [#44](https://github.com/volta-cli/action/pull/44) Update release packages to latest. ([@rwjblue](https://github.com/rwjblue)) 277 | * [#41](https://github.com/volta-cli/action/pull/41) Remove unused walk-sync devDep. ([@rwjblue](https://github.com/rwjblue)) 278 | 279 | #### Committers: 1 280 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 281 | 282 | 283 | ## v1.5.0 (2020-10-07) 284 | 285 | #### :rocket: Enhancement 286 | * [#30](https://github.com/volta-cli/action/pull/30) Resolve warnings about the `add-path` command being deprecated. Update @actions/core to latest. ([@dependabot[bot]](https://github.com/apps/dependabot)) 287 | 288 | #### :house: Internal 289 | * [#40](https://github.com/volta-cli/action/pull/40) Re-roll package-lock.json. ([@rwjblue](https://github.com/rwjblue)) 290 | * [#28](https://github.com/volta-cli/action/pull/28) Update dependencies to latest. ([@rwjblue](https://github.com/rwjblue)) 291 | * [#39](https://github.com/volta-cli/action/pull/39) Migrate to @vercel/ncc ([@rwjblue](https://github.com/rwjblue)) 292 | * [#38](https://github.com/volta-cli/action/pull/38) Update @actions/tool-cache and @actions/exec to latest. ([@rwjblue](https://github.com/rwjblue)) 293 | * [#37](https://github.com/volta-cli/action/pull/37) Update jest and related packages to latest. ([@rwjblue](https://github.com/rwjblue)) 294 | * [#34](https://github.com/volta-cli/action/pull/34) Ensure all test scripts fail on uncaught exceptions. ([@rwjblue](https://github.com/rwjblue)) 295 | * [#36](https://github.com/volta-cli/action/pull/36) Migrate internal workflow tests to shell scripts. ([@rwjblue](https://github.com/rwjblue)) 296 | * [#35](https://github.com/volta-cli/action/pull/35) Update uuid to latest. ([@rwjblue](https://github.com/rwjblue)) 297 | * [#33](https://github.com/volta-cli/action/pull/33) Update typescript and related @types packages to latest. ([@rwjblue](https://github.com/rwjblue)) 298 | * [#32](https://github.com/volta-cli/action/pull/32) Add more logging to tests/log-info.js ([@rwjblue](https://github.com/rwjblue)) 299 | * [#31](https://github.com/volta-cli/action/pull/31) Update linting configuration and dependencies. ([@rwjblue](https://github.com/rwjblue)) 300 | 301 | #### Committers: 1 302 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 303 | 304 | 305 | ## v1.4.3 (2020-03-27) 306 | 307 | #### :bug: Bug Fix 308 | * [#24](https://github.com/volta-cli/action/pull/24) Ensure specifying a `node-version` updates the pinned node. ([@rwjblue](https://github.com/rwjblue)) 309 | 310 | #### :house: Internal 311 | * [#23](https://github.com/volta-cli/action/pull/23) Update to prettier@2. ([@rwjblue](https://github.com/rwjblue)) 312 | * [#22](https://github.com/volta-cli/action/pull/22) Update dependencies and devDependencies to latest versions. ([@rwjblue](https://github.com/rwjblue)) 313 | * [#19](https://github.com/volta-cli/action/pull/19) Update CI workflow to assert expected versions. ([@rwjblue](https://github.com/rwjblue)) 314 | 315 | #### Committers: 1 316 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 317 | 318 | 319 | ## v1.4.2 (2020-03-11) 320 | 321 | #### :bug: Bug Fix 322 | * [#20](https://github.com/volta-cli/action/pull/20) Ensure shims work properly when used with volta@0.6 ([@rwjblue](https://github.com/rwjblue)) 323 | 324 | #### Committers: 1 325 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 326 | 327 | 328 | ## v1.4.1 (2020-03-11) 329 | 330 | #### :house: Internal 331 | * [#18](https://github.com/volta-cli/action/pull/18) Setup branding for GitHub Marketplace ([@rwjblue](https://github.com/rwjblue)) 332 | 333 | #### Committers: 1 334 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 335 | 336 | 337 | ## v1.4.0 (2020-03-11) 338 | 339 | #### :memo: Documentation 340 | * [#17](https://github.com/volta-cli/action/pull/17) Tweak action.yml name and description. ([@rwjblue](https://github.com/rwjblue)) 341 | 342 | #### :house: Internal 343 | * [#15](https://github.com/volta-cli/action/pull/15) Fix repo references (rwjblue/setup-volta -> volta-cli/action). ([@rwjblue](https://github.com/rwjblue)) 344 | 345 | #### Committers: 1 346 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 347 | 348 | 349 | ## v1.3.0 (2020-03-11) 350 | 351 | #### :rocket: Enhancement 352 | * [#9](https://github.com/volta-cli/action/pull/9) Add Windows support ([@rwjblue](https://github.com/rwjblue)) 353 | * [#12](https://github.com/volta-cli/action/pull/12) When debugging specify `--verbose` when installing default node / yarn. ([@rwjblue](https://github.com/rwjblue)) 354 | 355 | #### :bug: Bug Fix 356 | * [#10](https://github.com/volta-cli/action/pull/10) Extract downloaded files directly into `$VOLTA_HOME/bin`. ([@rwjblue](https://github.com/rwjblue)) 357 | 358 | #### :house: Internal 359 | * [#13](https://github.com/volta-cli/action/pull/13) Avoid GitHub rate limiting when using `volta install yarn@1` ([@rwjblue](https://github.com/rwjblue)) 360 | * [#11](https://github.com/volta-cli/action/pull/11) Run CI against both Ubuntu and macOS. ([@rwjblue](https://github.com/rwjblue)) 361 | 362 | #### Committers: 1 363 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 364 | 365 | 366 | ## v1.2.1 (2020-03-10) 367 | 368 | #### :house: Internal 369 | * [#8](https://github.com/volta-cli/action/pull/8) Update to latest automated release setup. ([@rwjblue](https://github.com/rwjblue)) 370 | 371 | #### Committers: 1 372 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 373 | 374 | 375 | ## v1.2.0 (2020-03-09) 376 | 377 | #### :house: Internal 378 | * [#7](https://github.com/volta-cli/action/pull/7) Add automated release setup (via release-it). ([@rwjblue](https://github.com/rwjblue)) 379 | * [#6](https://github.com/volta-cli/action/pull/6) Update to latest version of actions/typescript-template. ([@rwjblue](https://github.com/rwjblue)) 380 | 381 | #### Committers: 1 382 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 383 | 384 | ## v1.1.0 (2020-03-08) 385 | 386 | #### :rocket: Enhancement 387 | * [#5](https://github.com/volta-cli/action/pull/5) Update to leverage `volta setup` when using Volta 0.7+ ([@rwjblue](https://github.com/rwjblue)) 388 | 389 | #### :house: Internal 390 | * [#4](https://github.com/volta-cli/action/pull/4) Update dependencies to latest versions. ([@rwjblue](https://github.com/rwjblue)) 391 | 392 | #### Committers: 1 393 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue)) 394 | --------------------------------------------------------------------------------