Skip to content

Commit

Permalink
Add node's caching implementation (#2)
Browse files Browse the repository at this point in the history
* first iteration for implementation of caching

* add logs

* add debug line

* fix build command

* fix path

* add possible post-if

* remove braces

* test new action post-if variant

* work on built-in caching

* remove post-if

* pass version

* work on yarn support

* fix return value

* change names and remove logs

* worked on resolving comments

* check post-if for null

* add success() condition

* remove primary key field

* work on resolving comments

* remove logs

* resolving comments

* resolving comments

* resolving comments

* resolving comments

* fix getpackageManagerVersion

* run clean for unstaged changes

* fix falling version tests

* work on resolving comments

* resolving comments

* fix comment

* resolve comments

* Add tests to cover node's caching (#3)

* add tests to cover node's caching

* work on fixing tests

* fix e2e tests

* rebuild and fix test

* fixing tests

* change name of describes, it and fix test

* add names for jobs

* fix issue
  • Loading branch information
dmitry-shibanov authored Jun 16, 2021
1 parent 5c355be commit 3d0d4ed
Show file tree
Hide file tree
Showing 20 changed files with 149,068 additions and 21,767 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
- run: npm run build
- run: npm run format-check
- run: npm test
- run: git add .
- name: Verify no unstaged changes
if: runner.os != 'windows'
run: __tests__/verify-no-unstaged-changes.sh
101 changes: 101 additions & 0 deletions .github/workflows/e2e-cache.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: e2e-cache

on:
pull_request:
paths-ignore:
- '**.md'
push:
branches:
- main
- releases/*
paths-ignore:
- '**.md'

jobs:
node-npm-depencies-caching:
name: Test npm (Node ${{ matrix.node-version}}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [10, 12, 14]
steps:
- uses: actions/checkout@v2
- name: Clean global cache
run: npm cache clean --force
- name: Setup Node
uses: ./
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm install
- name: Verify node and npm
run: __tests__/verify-node.sh "${{ matrix.node-version }}"
shell: bash

node-yarn1-depencies-caching:
name: Test yarn 1 (Node ${{ matrix.node-version}}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [10, 12, 14]
steps:
- uses: actions/checkout@v2
- name: Yarn version
run: yarn --version
- 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
- name: Setup Node
uses: ./
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
- name: Install dependencies
run: yarn install
- name: Verify node and yarn
run: __tests__/verify-node.sh "${{ matrix.node-version }}"
shell: bash

node-yarn2-depencies-caching:
name: Test yarn 2 (Node ${{ matrix.node-version}}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [10, 12, 14]
steps:
- uses: actions/checkout@v2
- name: Update yarn
run: yarn set version berry
- 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'
- name: Install dependencies
run: yarn install
- name: Verify node and yarn
run: __tests__/verify-node.sh "${{ matrix.node-version }}"
shell: bash
2 changes: 1 addition & 1 deletion .github/workflows/versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,4 @@ jobs:
architecture: 'x86'
- name: Verify node
run: __tests__/verify-arch.sh "ia32"
shell: bash
shell: bash
168 changes: 168 additions & 0 deletions __tests__/cache-restore.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import * as core from '@actions/core';
import * as cache from '@actions/cache';
import * as path from 'path';
import * as glob from '@actions/glob';

import * as utils from '../src/cache-utils';
import {restoreCache} from '../src/cache-restore';

describe('cache-restore', () => {
process.env['GITHUB_WORKSPACE'] = path.join(__dirname, 'data');
if (!process.env.RUNNER_OS) {
process.env.RUNNER_OS = 'Linux';
}
const platform = process.env.RUNNER_OS;
const commonPath = '/some/random/path';
const npmCachePath = `${commonPath}/npm`;
const yarn1CachePath = `${commonPath}/yarn1`;
const yarn2CachePath = `${commonPath}/yarn2`;
const yarnFileHash =
'b8a0bae5243251f7c07dd52d1f78ff78281dfefaded700a176261b6b54fa245b';
const npmFileHash =
'abf7c9b306a3149dcfba4673e2362755503bcceaab46f0e4e6fee0ade493e20c';
const cachesObject = {
[npmCachePath]: npmFileHash,
[yarn1CachePath]: yarnFileHash,
[yarn2CachePath]: yarnFileHash
};

function findCacheFolder(command: string) {
switch (command) {
case utils.supportedPackageManagers.npm.getCacheFolderCommand:
return npmCachePath;
case utils.supportedPackageManagers.yarn1.getCacheFolderCommand:
return yarn1CachePath;
case utils.supportedPackageManagers.yarn2.getCacheFolderCommand:
return yarn2CachePath;
default:
return 'packge/not/found';
}
}

let saveStateSpy: jest.SpyInstance;
let infoSpy: jest.SpyInstance;
let debugSpy: jest.SpyInstance;
let setOutputSpy: jest.SpyInstance;
let getCommandOutputSpy: jest.SpyInstance;
let restoreCacheSpy: jest.SpyInstance;
let hashFilesSpy: jest.SpyInstance;

beforeEach(() => {
// core
infoSpy = jest.spyOn(core, 'info');
infoSpy.mockImplementation(() => undefined);

debugSpy = jest.spyOn(core, 'debug');
debugSpy.mockImplementation(() => undefined);

setOutputSpy = jest.spyOn(core, 'setOutput');
setOutputSpy.mockImplementation(() => undefined);

saveStateSpy = jest.spyOn(core, 'saveState');
saveStateSpy.mockImplementation(() => undefined);

// glob
hashFilesSpy = jest.spyOn(glob, 'hashFiles');
hashFilesSpy.mockImplementation((pattern: string) => {
if (pattern.includes('package-lock.json')) {
return npmFileHash;
} else if (pattern.includes('yarn.lock')) {
return yarnFileHash;
} else {
return '';
}
});

// cache
restoreCacheSpy = jest.spyOn(cache, 'restoreCache');
restoreCacheSpy.mockImplementation(
(cachePaths: Array<string>, key: string) => {
if (!cachePaths || cachePaths.length === 0) {
return undefined;
}

const cachPath = cachePaths[0];
const fileHash = cachesObject[cachPath];

if (key.includes(fileHash)) {
return key;
}

return undefined;
}
);

// cache-utils
getCommandOutputSpy = jest.spyOn(utils, 'getCommandOutput');
});

describe('Validate provided package manager', () => {
it.each([['npm7'], ['npm6'], ['yarn1'], ['yarn2'], ['random']])(
'Throw an error because %s is not supported',
async packageManager => {
await expect(restoreCache(packageManager)).rejects.toThrowError(
`Caching for '${packageManager}' is not supported`
);
}
);
});

describe('Restore dependencies', () => {
it.each([
['yarn', '2.1.2', yarnFileHash],
['yarn', '1.2.3', yarnFileHash],
['npm', '', npmFileHash]
])(
'restored dependencies for %s',
async (packageManager, toolVersion, fileHash) => {
getCommandOutputSpy.mockImplementation((command: string) => {
if (command.includes('version')) {
return toolVersion;
} else {
return findCacheFolder(command);
}
});

await restoreCache(packageManager);
expect(hashFilesSpy).toHaveBeenCalled();
expect(infoSpy).toHaveBeenCalledWith(
`Cache restored from key: ${platform}-${packageManager}-${fileHash}`
);
expect(infoSpy).not.toHaveBeenCalledWith(
`${packageManager} cache is not found`
);
}
);
});

describe('Dependencies changed', () => {
it.each([
['yarn', '2.1.2', yarnFileHash],
['yarn', '1.2.3', yarnFileHash],
['npm', '', npmFileHash]
])(
'dependencies are changed %s',
async (packageManager, toolVersion, fileHash) => {
getCommandOutputSpy.mockImplementation((command: string) => {
if (command.includes('version')) {
return toolVersion;
} else {
return findCacheFolder(command);
}
});

restoreCacheSpy.mockImplementationOnce(() => undefined);
await restoreCache(packageManager);
expect(hashFilesSpy).toHaveBeenCalled();
expect(infoSpy).toHaveBeenCalledWith(
`${packageManager} cache is not found`
);
}
);
});

afterEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();
});
});
Loading

0 comments on commit 3d0d4ed

Please sign in to comment.