Skip to content

Commit 029f331

Browse files
committed
fix(pipeline): cache yarn deps with corepack
1 parent 78ac431 commit 029f331

File tree

4 files changed

+126
-13
lines changed

4 files changed

+126
-13
lines changed

packages/@o3r/pipeline/schematics/ng-add/index.spec.ts

+66
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,69 @@ describe('ng-add', () => {
6565
});
6666

6767
});
68+
69+
describe('ng-add with yarn should generate a GitHub workflow', () => {
70+
71+
let initialTree: Tree;
72+
73+
beforeEach(() => {
74+
initialTree = Tree.empty();
75+
initialTree.create('angular.json', fs.readFileSync(path.resolve(__dirname, '..', '..', 'testing', 'mocks', 'angular.mocks.yarn.json')));
76+
});
77+
78+
it('when no yarnrc.yml', async () => {
79+
const runner = new SchematicTestRunner('@o3r/pipeline', collectionPath);
80+
const tree = await runner.runSchematic('ng-add', {
81+
toolchain: 'github'
82+
} as NgAddSchematicsSchema, initialTree);
83+
84+
expect(tree.exists('.github/actions/setup/action.yml')).toBe(true);
85+
expect(tree.exists('.github/workflows/main.yml')).toBe(true);
86+
expect(tree.exists('.npmrc')).toBe(false);
87+
88+
expect(tree.readText('.github/actions/setup/action.yml')).toContain('(yarn cache dir)');
89+
90+
});
91+
92+
it('with yarnrc.yml without yarnPath', async () => {
93+
const runner = new SchematicTestRunner('@o3r/pipeline', collectionPath);
94+
initialTree.create('.yarnrc.yml', '');
95+
const tree = await runner.runSchematic('ng-add', {
96+
toolchain: 'github'
97+
} as NgAddSchematicsSchema, initialTree);
98+
99+
expect(tree.exists('.github/actions/setup/action.yml')).toBe(true);
100+
expect(tree.exists('.github/workflows/main.yml')).toBe(true);
101+
expect(tree.exists('.npmrc')).toBe(false);
102+
103+
expect(tree.readText('.github/actions/setup/action.yml')).toContain('(yarn config get cacheFolder)');
104+
});
105+
106+
it('with yarnrc.yml with yarnPath v1', async () => {
107+
const runner = new SchematicTestRunner('@o3r/pipeline', collectionPath);
108+
initialTree.create('.yarnrc.yml', 'yarnPath: .yarn/releases/yarn-1.2.3.cjs');
109+
const tree = await runner.runSchematic('ng-add', {
110+
toolchain: 'github'
111+
} as NgAddSchematicsSchema, initialTree);
112+
113+
expect(tree.exists('.github/actions/setup/action.yml')).toBe(true);
114+
expect(tree.exists('.github/workflows/main.yml')).toBe(true);
115+
expect(tree.exists('.npmrc')).toBe(false);
116+
117+
expect(tree.readText('.github/actions/setup/action.yml')).toContain('(yarn cache dir)');
118+
});
119+
120+
it('with yarnrc.yml with yarnPath v2', async () => {
121+
const runner = new SchematicTestRunner('@o3r/pipeline', collectionPath);
122+
initialTree.create('.yarnrc.yml', 'yarnPath: .yarn/releases/yarn-3.2.1.cjs');
123+
const tree = await runner.runSchematic('ng-add', {
124+
toolchain: 'github'
125+
} as NgAddSchematicsSchema, initialTree);
126+
127+
expect(tree.exists('.github/actions/setup/action.yml')).toBe(true);
128+
expect(tree.exists('.github/workflows/main.yml')).toBe(true);
129+
expect(tree.exists('.npmrc')).toBe(false);
130+
131+
expect(tree.readText('.github/actions/setup/action.yml')).toContain('(yarn config get cacheFolder)');
132+
});
133+
});

packages/@o3r/pipeline/schematics/ng-add/index.ts

+24-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
1-
import { apply, chain, MergeStrategy, mergeWith, move, Rule, template, url } from '@angular-devkit/schematics';
2-
import type { NgAddSchematicsSchema } from './schema';
3-
import {dump, load} from 'js-yaml';
4-
import * as path from 'node:path';
1+
import { apply, chain, MergeStrategy, mergeWith, move, Rule, template, type Tree, url } from '@angular-devkit/schematics';
2+
import { dump, load } from 'js-yaml';
53
import * as fs from 'node:fs';
4+
import * as path from 'node:path';
65
import type { PackageJson } from 'type-fest';
6+
import type { NgAddSchematicsSchema } from './schema';
7+
8+
/**
9+
* Determines if the Yarn version is 2 or higher based on the contents of the .yarnrc.yml file.
10+
* @param tree tree
11+
*/
12+
function isYarn2(tree: Tree) {
13+
const yarnrcPath = '/.yarnrc.yml';
14+
if (tree.exists(yarnrcPath)) {
15+
const yarnrcContent = load(tree.readText(yarnrcPath)) as any;
16+
const yarnPath = yarnrcContent?.yarnPath;
17+
return !yarnPath || !/yarn-1\./.test(yarnPath);
18+
}
19+
return false;
20+
}
721

822
/**
923
* Add an Otter CI pipeline to an Angular Project
@@ -26,12 +40,15 @@ function ngAddFn(options: NgAddSchematicsSchema): Rule {
2640
}
2741
context.logger.info(`Setting up pipeline for package manager: "${packageManager}" `);
2842
const setupCommand = packageManager === 'yarn' ? 'yarn install --immutable' : 'npm ci';
43+
const yarn2 = packageManager === 'yarn' && isYarn2(tree);
44+
const yarnCacheFolder = yarn2 ? 'yarn config get cacheFolder' : 'yarn cache dir';
2945
const baseTemplateSource = apply(url(`./templates/${options.toolchain}`), [
3046
template({
3147
...options,
3248
packageManager,
3349
setupCommand,
3450
actionVersionString,
51+
yarnCacheFolder,
3552
dot: '.'
3653
}),
3754
move(tree.root.path)
@@ -41,7 +58,7 @@ function ngAddFn(options: NgAddSchematicsSchema): Rule {
4158
if (!options.npmRegistry) {
4259
return tree;
4360
}
44-
if (packageManager === 'yarn') {
61+
if (yarn2) {
4562
const yarnrcPath = '/.yarnrc.yml';
4663
if (!tree.exists(yarnrcPath)) {
4764
tree.create(yarnrcPath, dump({'npmRegistryServer': options.npmRegistry}, {indent: 2}));
@@ -50,7 +67,8 @@ function ngAddFn(options: NgAddSchematicsSchema): Rule {
5067
yarnrcContent.npmRegistryServer = options.npmRegistry;
5168
tree.overwrite(yarnrcPath, dump(yarnrcContent, {indent: 2}));
5269
}
53-
} else if (packageManager === 'npm') {
70+
} else {
71+
// both npm and yarn 1 use .npmrc for the registry
5472
const npmrcPath = '/.npmrc';
5573
if (!tree.exists(npmrcPath)) {
5674
tree.create(npmrcPath, `registry=${options.npmRegistry}`);

packages/@o3r/pipeline/schematics/ng-add/templates/github/__dot__github/actions/setup/action.yml

+17-7
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,26 @@ runs:
66
steps:
77
- uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
88
with:
9-
node-version: 20
10-
cache: <%= packageManager %>
9+
node-version: 20<% if (packageManager !== 'yarn') { %>
10+
cache: <%= packageManager %><% } %>
1111
- name: Enable Corepack
1212
shell: bash
13-
run: corepack enable
14-
- name: Install
15-
<% if (npmRegistry) { %>
13+
run: corepack enable<% if (packageManager === 'yarn') { %>
14+
- name: Get yarn cache directory path
15+
shell: bash
16+
id: yarn-cache-dir-path
17+
run: echo "dir=$(<%= yarnCacheFolder %>)" >> $GITHUB_OUTPUT
18+
- name: Cache dependencies
19+
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2
20+
with:
21+
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
22+
key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
23+
restore-keys: |
24+
${{ runner.os }}-yarn
25+
${{ runner.os }}<% } %>
26+
- name: Install<% if (npmRegistry) { %>
1627
env:
1728
COREPACK_NPM_REGISTRY: <%= npmRegistry %>
18-
COREPACK_INTEGRITY_KEYS: ""
19-
<% } %>
29+
COREPACK_INTEGRITY_KEYS: ""<% } %>
2030
shell: bash
2131
run: <%= setupCommand %>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/angular/angular-cli/master/packages/angular/cli/lib/config/workspace-schema.json",
3+
"version": 1,
4+
"newProjectRoot": ".",
5+
"cli": {
6+
"packageManager": "yarn"
7+
},
8+
"projects": {
9+
"test-project": {
10+
"projectType": "application",
11+
"root": ".",
12+
"sourceRoot": "./src",
13+
"prefix": "tst",
14+
"architect": {
15+
16+
}
17+
}
18+
}
19+
}

0 commit comments

Comments
 (0)