Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added option to enable corepack #901

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/e2e-cache.yml
Expand Up @@ -135,6 +135,44 @@ jobs:
run: __tests__/verify-node.sh "${{ matrix.node-version }}"
shell: bash

node-yarn4-corepack-dependencies-caching:
name: Test yarn 4 (Node ${{ matrix.node-version}}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
env:
YARN_ENABLE_IMMUTABLE_INSTALLS: false
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [18, 20]
steps:
- uses: actions/checkout@v4
- name: Update yarn
run: yarn set version 4.1.0
- name: Yarn version
run: yarn --version
- name: Generate simple .yarnrc.yml
run: |
echo "nodeLinker: node-modules" >> .yarnrc.yml
- name: Generate yarn file
run: yarn install
- name: Remove dependencies
shell: pwsh
run: Remove-Item node_modules -Force -Recurse
- name: Clean global cache
run: yarn cache clean --all
- name: Setup Node
uses: ./
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
corepack: true
- name: Install dependencies
run: yarn install
- name: Verify node and yarn
run: __tests__/verify-node.sh "${{ matrix.node-version }}"
shell: bash

yarn-subprojects:
name: Test yarn subprojects
strategy:
Expand Down
23 changes: 12 additions & 11 deletions README.md
Expand Up @@ -26,22 +26,22 @@ See [action.yml](action.yml)
node-version: ''

# File containing the version Spec of the version to use. Examples: package.json, .nvmrc, .node-version, .tool-versions.
# If node-version and node-version-file are both provided the action will use version from node-version.
# If node-version and node-version-file are both provided the action will use version from node-version.
node-version-file: ''

# Set this option if you want the action to check for the latest available version
# Set this option if you want the action to check for the latest available version
# that satisfies the version spec.
# It will only get affect for lts Nodejs versions (12.x, >=10.15.0, lts/Hydrogen).
# It will only get affect for lts Nodejs versions (12.x, >=10.15.0, lts/Hydrogen).
# Default: false
check-latest: false

# Target architecture for Node to use. Examples: x86, x64. Will use system architecture by default.
# Default: ''. The action use system architecture by default
# Default: ''. The action use system architecture by default
architecture: ''

# Used to pull node distributions from https://github.com/actions/node-versions.
# Since there's a default, this is typically not supplied by the user.
# When running this action on github.com, the default value is sufficient.
# Used to pull node distributions from https://github.com/actions/node-versions.
# Since there's a default, this is typically not supplied by the user.
# When running this action on github.com, the default value is sufficient.
# When running on GHES, you can pass a personal access token for github.com if you are experiencing rate limiting.
#
# We recommend using a service account with the least permissions necessary. Also
Expand All @@ -57,18 +57,18 @@ See [action.yml](action.yml)
# Default: ''
cache: ''

# Used to specify the path to a dependency file: package-lock.json, yarn.lock, etc.
# It will generate hash from the target file for primary key. It works only If cache is specified.
# Used to specify the path to a dependency file: package-lock.json, yarn.lock, etc.
# It will generate hash from the target file for primary key. It works only If cache is specified.
# Supports wildcards or a list of file names for caching multiple dependencies.
# Default: ''
cache-dependency-path: ''

# Optional registry to set up for auth. Will set the registry in a project level .npmrc and .yarnrc file,
# Optional registry to set up for auth. Will set the registry in a project level .npmrc and .yarnrc file,
# and set up auth to read in from env.NODE_AUTH_TOKEN.
# Default: ''
registry-url: ''

# Optional scope for authenticating against scoped registries.
# 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/).
# Default: ''
scope: ''
Expand Down Expand Up @@ -203,6 +203,7 @@ If the runner is not able to access github.com, any Nodejs versions requested du
- [Publishing to npmjs and GPR with npm](docs/advanced-usage.md#publish-to-npmjs-and-gpr-with-npm)
- [Publishing to npmjs and GPR with yarn](docs/advanced-usage.md#publish-to-npmjs-and-gpr-with-yarn)
- [Using private packages](docs/advanced-usage.md#use-private-packages)
- [Enabling Corepack](docs/advanced-usage.md#enabling-corepack)

## License

Expand Down
37 changes: 37 additions & 0 deletions __tests__/main.test.ts
Expand Up @@ -11,6 +11,7 @@ import each from 'jest-each';

import * as main from '../src/main';
import * as util from '../src/util';
import * as cacheUtil from '../src/cache-utils';
import OfficialBuilds from '../src/distributions/official_builds/official_builds';

describe('main tests', () => {
Expand All @@ -25,6 +26,7 @@ describe('main tests', () => {
let endGroupSpy: jest.SpyInstance;

let getExecOutputSpy: jest.SpyInstance;
let getCommandOutputSpy: jest.SpyInstance;

let getNodeVersionFromFileSpy: jest.SpyInstance;
let cnSpy: jest.SpyInstance;
Expand Down Expand Up @@ -56,6 +58,7 @@ describe('main tests', () => {
inSpy.mockImplementation(name => inputs[name]);

getExecOutputSpy = jest.spyOn(exec, 'getExecOutput');
getCommandOutputSpy = jest.spyOn(cacheUtil, 'getCommandOutput');

findSpy = jest.spyOn(tc, 'find');

Expand Down Expand Up @@ -269,4 +272,38 @@ describe('main tests', () => {
);
});
});

describe('corepack flag', () => {
it('should not enable corepack when no input', async () => {
inputs['corepack'] = '';
await main.run();
expect(getCommandOutputSpy).not.toHaveBeenCalledWith(expect.stringContaining('corepack'));
});

it('should not enable corepack when input is "false"', async () => {
inputs['corepack'] = 'false';
await main.run();
expect(getCommandOutputSpy).not.toHaveBeenCalledWith(expect.stringContaining('corepack'));
});

it('should enable corepack when input is "true"', async () => {
inputs['corepack'] = 'true';
await main.run();
expect(getCommandOutputSpy).toHaveBeenCalledWith('corepack enable');
});

it('should enable corepack with a single package manager', async () => {
inputs['corepack'] = 'npm';
await main.run();
expect(getCommandOutputSpy).toHaveBeenCalledWith('corepack enable npm');
});

it('should enable corepack with multiple package managers', async () => {
inputs['corepack'] = 'npm yarn';
await main.run();
expect(getCommandOutputSpy).toHaveBeenCalledWith(
'corepack enable npm yarn'
);
});
});
});
5 changes: 4 additions & 1 deletion action.yml
Expand Up @@ -25,10 +25,13 @@ inputs:
description: 'Used to specify a package manager for caching in the default directory. Supported values: npm, yarn, pnpm.'
cache-dependency-path:
description: 'Used to specify the path to a dependency file: package-lock.json, yarn.lock, etc. Supports wildcards or a list of file names for caching multiple dependencies.'
corepack:
description: 'Used to specify whether to enable Corepack. Set to true to enable all package managers or set it to one or more package manager names separated by a space. Supported package manager names: npm, yarn, pnpm.'
default: 'false'
# TODO: add input to control forcing to pull from cloud or dist.
# escape valve for someone having issues or needing the absolute latest which isn't cached yet
outputs:
cache-hit:
cache-hit:
description: 'A boolean value to indicate if a cache was hit.'
node-version:
description: 'The installed node version.'
Expand Down
16 changes: 15 additions & 1 deletion dist/cache-save/index.js
Expand Up @@ -83333,11 +83333,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.unique = exports.printEnvDetailsAndSetOutput = exports.getNodeVersionFromFile = void 0;
exports.enableCorepack = exports.unique = exports.printEnvDetailsAndSetOutput = exports.getNodeVersionFromFile = void 0;
const core = __importStar(__nccwpck_require__(2186));
const exec = __importStar(__nccwpck_require__(1514));
const fs_1 = __importDefault(__nccwpck_require__(7147));
const path_1 = __importDefault(__nccwpck_require__(1017));
const cache_utils_1 = __nccwpck_require__(1678);
function getNodeVersionFromFile(versionFilePath) {
var _a, _b, _c, _d, _e;
if (!fs_1.default.existsSync(versionFilePath)) {
Expand Down Expand Up @@ -83429,6 +83430,19 @@ const unique = () => {
};
};
exports.unique = unique;
function enableCorepack(input) {
return __awaiter(this, void 0, void 0, function* () {
if (input.length && input !== 'false') {
const corepackArgs = ['enable'];
if (input !== 'true') {
const packageManagers = input.split(' ');
corepackArgs.push(...packageManagers);
}
yield (0, cache_utils_1.getCommandOutput)(`corepack ${corepackArgs.join(' ')}`);
}
});
}
exports.enableCorepack = enableCorepack;


/***/ }),
Expand Down
18 changes: 17 additions & 1 deletion dist/setup/index.js
Expand Up @@ -93697,6 +93697,8 @@ function run() {
if (registryUrl) {
auth.configAuthentication(registryUrl, alwaysAuth);
}
const corepack = core.getInput('corepack') || 'false';
yield (0, util_1.enableCorepack)(corepack);
if (cache && (0, cache_utils_1.isCacheFeatureAvailable)()) {
core.saveState(constants_1.State.CachePackageManager, cache);
const cacheDependencyPath = core.getInput('cache-dependency-path');
Expand Down Expand Up @@ -93780,11 +93782,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.unique = exports.printEnvDetailsAndSetOutput = exports.getNodeVersionFromFile = void 0;
exports.enableCorepack = exports.unique = exports.printEnvDetailsAndSetOutput = exports.getNodeVersionFromFile = void 0;
const core = __importStar(__nccwpck_require__(2186));
const exec = __importStar(__nccwpck_require__(1514));
const fs_1 = __importDefault(__nccwpck_require__(7147));
const path_1 = __importDefault(__nccwpck_require__(1017));
const cache_utils_1 = __nccwpck_require__(1678);
function getNodeVersionFromFile(versionFilePath) {
var _a, _b, _c, _d, _e;
if (!fs_1.default.existsSync(versionFilePath)) {
Expand Down Expand Up @@ -93876,6 +93879,19 @@ const unique = () => {
};
};
exports.unique = unique;
function enableCorepack(input) {
return __awaiter(this, void 0, void 0, function* () {
if (input.length && input !== 'false') {
const corepackArgs = ['enable'];
if (input !== 'true') {
const packageManagers = input.split(' ');
corepackArgs.push(...packageManagers);
}
yield (0, cache_utils_1.getCommandOutput)(`corepack ${corepackArgs.join(' ')}`);
}
});
}
exports.enableCorepack = enableCorepack;


/***/ }),
Expand Down
31 changes: 29 additions & 2 deletions docs/advanced-usage.md
Expand Up @@ -159,7 +159,7 @@ jobs:

## Nightly versions

You can specify a nightly version to download it from https://nodejs.org/download/nightly.
You can specify a nightly version to download it from https://nodejs.org/download/nightly.

### Install the nightly build for a major version

Expand Down Expand Up @@ -267,7 +267,7 @@ steps:
- run: pnpm test
```

> **Note**: By default `--frozen-lockfile` option is passed starting from pnpm `6.10.x`. It will be automatically added if you run it on [CI](https://pnpm.io/cli/install#--frozen-lockfile).
> **Note**: By default `--frozen-lockfile` option is passed starting from pnpm `6.10.x`. It will be automatically added if you run it on [CI](https://pnpm.io/cli/install#--frozen-lockfile).
> If the `pnpm-lock.yaml` file changes then pass `--frozen-lockfile` option.


Expand Down Expand Up @@ -418,3 +418,30 @@ Please refer to the [Ensuring workflow access to your package - Configuring a pa

### always-auth input
The always-auth input sets `always-auth=true` in .npmrc file. With this option set [npm](https://docs.npmjs.com/cli/v6/using-npm/config#always-auth)/yarn sends the authentication credentials when making a request to the registries.

## Enabling Corepack
You can enable [Corepack](https://github.com/nodejs/corepack) by using the `corepack` input. You can then use `pnpm` and `yarn` commands in your project.

```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18.x'
corepack: true

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the input corepack is not listed in /action.yml
did you forget to add it there?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

- name: Install dependencies
run: yarn install --immutable
```

You can also pass package manager names separated by a space to enable corepack for specific package managers only.

```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18.x'
corepack: yarn pnpm
- name: Install dependencies
run: yarn install --immutable
```
9 changes: 8 additions & 1 deletion src/main.ts
Expand Up @@ -7,7 +7,11 @@ import * as path from 'path';
import {restoreCache} from './cache-restore';
import {isCacheFeatureAvailable} from './cache-utils';
import {getNodejsDistribution} from './distributions/installer-factory';
import {getNodeVersionFromFile, printEnvDetailsAndSetOutput} from './util';
import {
getNodeVersionFromFile,
printEnvDetailsAndSetOutput,
enableCorepack
} from './util';
import {State} from './constants';

export async function run() {
Expand Down Expand Up @@ -59,6 +63,9 @@ export async function run() {
auth.configAuthentication(registryUrl, alwaysAuth);
}

const corepack = core.getInput('corepack') || 'false';
await enableCorepack(corepack);

if (cache && isCacheFeatureAvailable()) {
core.saveState(State.CachePackageManager, cache);
const cacheDependencyPath = core.getInput('cache-dependency-path');
Expand Down
12 changes: 12 additions & 0 deletions src/util.ts
Expand Up @@ -3,6 +3,7 @@ import * as exec from '@actions/exec';

import fs from 'fs';
import path from 'path';
import {getCommandOutput} from './cache-utils';

export function getNodeVersionFromFile(versionFilePath: string): string | null {
if (!fs.existsSync(versionFilePath)) {
Expand Down Expand Up @@ -105,3 +106,14 @@ export const unique = () => {
return true;
};
};

export async function enableCorepack(input: string): Promise<void> {
if (input.length && input !== 'false') {
const corepackArgs = ['enable'];
if (input !== 'true') {
const packageManagers = input.split(' ');
Copy link

@ranisalt ranisalt Dec 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also trim the input and split by \s+ to avoid issues due to leading, trailing and double-spacing, and also supporting multiline

corepackArgs.push(...packageManagers);
}
await getCommandOutput(`corepack ${corepackArgs.join(' ')}`);
Copy link

@mcmire mcmire Apr 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking back at previous PRs, it was suggested that if Yarn ends up being enabled, any existing Yarn installation (which is evidently present on GitHub runners) should be uninstalled first: #482 (review). Is this is a concern?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought corepack would interop with existing yarn installations (could be wrong)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the existing Yarn installation can be left as is and it won't cause conflict with the installed Yarn from Corepack.

}
}