From 930ff22596a105b03477b98dc518407f85424f8b Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Tue, 11 Jul 2023 16:37:50 +0200 Subject: [PATCH 01/16] Fix Install on Windows is very slow --- dist/setup/index.js | 27 +++++++++++++++++++++++---- src/installer.ts | 43 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index 378197f56..eef32c092 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -61441,6 +61441,14 @@ function resolveVersionFromManifest(versionSpec, stable, auth, arch, manifest) { } }); } +function addExecutablesToCache(extPath, info, arch) { + return __awaiter(this, void 0, void 0, function* () { + core.info('Adding to the cache ...'); + const cachedDir = yield tc.cacheDir(extPath, 'go', makeSemver(info.resolvedVersion), arch); + core.info(`Successfully cached go to ${cachedDir}`); + return cachedDir; + }); +} function installGoVersion(info, auth, arch) { return __awaiter(this, void 0, void 0, function* () { core.info(`Acquiring ${info.resolvedVersion} from ${info.downloadUrl}`); @@ -61455,10 +61463,21 @@ function installGoVersion(info, auth, arch) { if (info.type === 'dist') { extPath = path.join(extPath, 'go'); } - core.info('Adding to the cache ...'); - const cachedDir = yield tc.cacheDir(extPath, 'go', makeSemver(info.resolvedVersion), arch); - core.info(`Successfully cached go to ${cachedDir}`); - return cachedDir; + if (isWindows) { + const oldCacheDir = process.env['RUNNER_TOOL_CACHE'] || ''; + const tempCacheDir = oldCacheDir.replace('C:', 'D:').replace('c:', 'd:'); + process.env['RUNNER_TOOL_CACHE'] = tempCacheDir; + const cachedDir = yield addExecutablesToCache(extPath, info, arch); + const lnkDest = cachedDir; + const lnkSrc = lnkDest.replace(tempCacheDir, oldCacheDir); + const lnkSrcDir = path.dirname(lnkSrc); + fs_1.default.mkdirSync(lnkSrcDir, { recursive: true }); + fs_1.default.symlinkSync(lnkDest, lnkSrc, 'junction'); + core.info(`Created link ${lnkSrc} => ${lnkDest}`); + process.env['RUNNER_TOOL_CACHE'] = oldCacheDir; + return cachedDir.replace(tempCacheDir, oldCacheDir); + } + return yield addExecutablesToCache(extPath, info, arch); }); } function extractGoArchive(archivePath) { diff --git a/src/installer.ts b/src/installer.ts index 013fb6405..16afd241c 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -164,6 +164,22 @@ async function resolveVersionFromManifest( } } +async function addExecutablesToCache( + extPath: string, + info: IGoVersionInfo, + arch: string +): Promise { + core.info('Adding to the cache ...'); + const cachedDir = await tc.cacheDir( + extPath, + 'go', + makeSemver(info.resolvedVersion), + arch + ); + core.info(`Successfully cached go to ${cachedDir}`); + return cachedDir; +} + async function installGoVersion( info: IGoVersionInfo, auth: string | undefined, @@ -185,15 +201,24 @@ async function installGoVersion( extPath = path.join(extPath, 'go'); } - core.info('Adding to the cache ...'); - const cachedDir = await tc.cacheDir( - extPath, - 'go', - makeSemver(info.resolvedVersion), - arch - ); - core.info(`Successfully cached go to ${cachedDir}`); - return cachedDir; + if (isWindows) { + const oldCacheDir = process.env['RUNNER_TOOL_CACHE'] || ''; + const tempCacheDir = oldCacheDir.replace('C:', 'D:').replace('c:', 'd:'); + process.env['RUNNER_TOOL_CACHE'] = tempCacheDir; + + const cachedDir = await addExecutablesToCache(extPath, info, arch); + + const lnkDest = cachedDir; + const lnkSrc = lnkDest.replace(tempCacheDir, oldCacheDir); + const lnkSrcDir = path.dirname(lnkSrc); + fs.mkdirSync(lnkSrcDir, {recursive: true}); + fs.symlinkSync(lnkDest, lnkSrc, 'junction'); + core.info(`Created link ${lnkSrc} => ${lnkDest}`); + process.env['RUNNER_TOOL_CACHE'] = oldCacheDir; + return cachedDir.replace(tempCacheDir, oldCacheDir); + } + + return await addExecutablesToCache(extPath, info, arch); } export async function extractGoArchive(archivePath: string): Promise { From 93ae31f0a4d858c9c98166dba9e98a832a97fbd5 Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Wed, 12 Jul 2023 00:13:32 +0200 Subject: [PATCH 02/16] Add unit test --- __tests__/setup-go.test.ts | 38 +++++++++++++++++++++++++++++++++++++- src/installer.ts | 2 +- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/__tests__/setup-go.test.ts b/__tests__/setup-go.test.ts index cea14f4e8..6a04035d2 100644 --- a/__tests__/setup-go.test.ts +++ b/__tests__/setup-go.test.ts @@ -3,7 +3,7 @@ import * as io from '@actions/io'; import * as tc from '@actions/tool-cache'; import fs from 'fs'; import cp from 'child_process'; -import osm from 'os'; +import osm, {type} from 'os'; import path from 'path'; import * as main from '../src/main'; import * as im from '../src/installer'; @@ -11,6 +11,7 @@ import * as im from '../src/installer'; import goJsonData from './data/golang-dl.json'; import matchers from '../matchers.json'; import goTestManifest from './data/versions-manifest.json'; +import {addExecutablesToCache, IGoVersionInfo} from '../src/installer'; const matcherPattern = matchers.problemMatcher[0].pattern[0]; const matcherRegExp = new RegExp(matcherPattern.regexp); const win32Join = path.win32.join; @@ -957,4 +958,39 @@ use . } ); }); + + describe('Windows performance workaround', () => { + it('addExecutablesToCache should depends on env[RUNNER_TOOL_CACHE]', async () => { + const statSpy = jest.spyOn(fs, 'statSync'); + // @ts-ignore + statSpy.mockImplementation(() => ({ + isDirectory: () => true + })); + const readdirSpy = jest.spyOn(fs, 'readdirSync'); + readdirSpy.mockImplementation(() => []); + const writeFileSpy = jest.spyOn(fs, 'writeFileSync'); + writeFileSpy.mockImplementation(() => {}); + const rmRFSpy = jest.spyOn(io, 'rmRF'); + rmRFSpy.mockImplementation(() => Promise.resolve()); + const mkdirPSpy = jest.spyOn(io, 'mkdirP'); + mkdirPSpy.mockImplementation(() => Promise.resolve()); + const cpSpy = jest.spyOn(io, 'cp'); + cpSpy.mockImplementation(() => Promise.resolve()); + + const info: IGoVersionInfo = { + type: 'dist', + downloadUrl: 'http://nowhere.com', + resolvedVersion: '1.2.3', + fileName: 'ignore' + }; + + process.env['RUNNER_TOOL_CACHE'] = '/faked-hostedtoolcache1'; + const cacheDir1 = await addExecutablesToCache('/qzx', info, 'arch'); + expect(cacheDir1).toBe('/faked-hostedtoolcache1/go/1.2.3/arch'); + + process.env['RUNNER_TOOL_CACHE'] = '/faked-hostedtoolcache2'; + const cacheDir2 = await addExecutablesToCache('/qzx', info, 'arch'); + expect(cacheDir2).toBe('/faked-hostedtoolcache2/go/1.2.3/arch'); + }); + }); }); diff --git a/src/installer.ts b/src/installer.ts index 16afd241c..537d4c217 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -164,7 +164,7 @@ async function resolveVersionFromManifest( } } -async function addExecutablesToCache( +export async function addExecutablesToCache( extPath: string, info: IGoVersionInfo, arch: string From 1c500a441411bb23b12fcc90ff0824316e3dec78 Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Wed, 12 Jul 2023 00:28:42 +0200 Subject: [PATCH 03/16] Improve readability --- dist/setup/index.js | 31 ++++++++++++++++++------------- src/installer.ts | 37 +++++++++++++++++++++++-------------- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index eef32c092..faf0ecd95 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -61338,7 +61338,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.resolveStableVersionInput = exports.parseGoVersionFile = exports.makeSemver = exports.getVersionsDist = exports.findMatch = exports.getInfoFromManifest = exports.getManifest = exports.extractGoArchive = exports.getGo = void 0; +exports.resolveStableVersionInput = exports.parseGoVersionFile = exports.makeSemver = exports.getVersionsDist = exports.findMatch = exports.getInfoFromManifest = exports.getManifest = exports.extractGoArchive = exports.addExecutablesToCache = exports.getGo = void 0; const tc = __importStar(__nccwpck_require__(7784)); const core = __importStar(__nccwpck_require__(2186)); const path = __importStar(__nccwpck_require__(1017)); @@ -61449,6 +61449,7 @@ function addExecutablesToCache(extPath, info, arch) { return cachedDir; }); } +exports.addExecutablesToCache = addExecutablesToCache; function installGoVersion(info, auth, arch) { return __awaiter(this, void 0, void 0, function* () { core.info(`Acquiring ${info.resolvedVersion} from ${info.downloadUrl}`); @@ -61464,18 +61465,22 @@ function installGoVersion(info, auth, arch) { extPath = path.join(extPath, 'go'); } if (isWindows) { - const oldCacheDir = process.env['RUNNER_TOOL_CACHE'] || ''; - const tempCacheDir = oldCacheDir.replace('C:', 'D:').replace('c:', 'd:'); - process.env['RUNNER_TOOL_CACHE'] = tempCacheDir; - const cachedDir = yield addExecutablesToCache(extPath, info, arch); - const lnkDest = cachedDir; - const lnkSrc = lnkDest.replace(tempCacheDir, oldCacheDir); - const lnkSrcDir = path.dirname(lnkSrc); - fs_1.default.mkdirSync(lnkSrcDir, { recursive: true }); - fs_1.default.symlinkSync(lnkDest, lnkSrc, 'junction'); - core.info(`Created link ${lnkSrc} => ${lnkDest}`); - process.env['RUNNER_TOOL_CACHE'] = oldCacheDir; - return cachedDir.replace(tempCacheDir, oldCacheDir); + const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE'] || ''; + const substitutedToolCacheRoot = defaultToolCacheRoot + .replace('C:', 'D:') + .replace('c:', 'd:'); + // make toolcache root to be on drive d: + process.env['RUNNER_TOOL_CACHE'] = substitutedToolCacheRoot; + const actualToolCacheDir = yield addExecutablesToCache(extPath, info, arch); + // create a link from c: to d: + const lnkSrc = actualToolCacheDir.replace(substitutedToolCacheRoot, defaultToolCacheRoot); + fs_1.default.mkdirSync(path.dirname(lnkSrc), { recursive: true }); + fs_1.default.symlinkSync(actualToolCacheDir, lnkSrc, 'junction'); + core.info(`Created link ${lnkSrc} => ${actualToolCacheDir}`); + // restore toolcache root to default drive c: + process.env['RUNNER_TOOL_CACHE'] = defaultToolCacheRoot; + // make outer code to continue using toolcache as if it were installed on c: + return lnkSrc; } return yield addExecutablesToCache(extPath, info, arch); }); diff --git a/src/installer.ts b/src/installer.ts index 537d4c217..8d2eaa765 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -202,20 +202,29 @@ async function installGoVersion( } if (isWindows) { - const oldCacheDir = process.env['RUNNER_TOOL_CACHE'] || ''; - const tempCacheDir = oldCacheDir.replace('C:', 'D:').replace('c:', 'd:'); - process.env['RUNNER_TOOL_CACHE'] = tempCacheDir; - - const cachedDir = await addExecutablesToCache(extPath, info, arch); - - const lnkDest = cachedDir; - const lnkSrc = lnkDest.replace(tempCacheDir, oldCacheDir); - const lnkSrcDir = path.dirname(lnkSrc); - fs.mkdirSync(lnkSrcDir, {recursive: true}); - fs.symlinkSync(lnkDest, lnkSrc, 'junction'); - core.info(`Created link ${lnkSrc} => ${lnkDest}`); - process.env['RUNNER_TOOL_CACHE'] = oldCacheDir; - return cachedDir.replace(tempCacheDir, oldCacheDir); + const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE'] || ''; + const substitutedToolCacheRoot = defaultToolCacheRoot + .replace('C:', 'D:') + .replace('c:', 'd:'); + // make toolcache root to be on drive d: + process.env['RUNNER_TOOL_CACHE'] = substitutedToolCacheRoot; + + const actualToolCacheDir = await addExecutablesToCache(extPath, info, arch); + + // create a link from c: to d: + const lnkSrc = actualToolCacheDir.replace( + substitutedToolCacheRoot, + defaultToolCacheRoot + ); + fs.mkdirSync(path.dirname(lnkSrc), {recursive: true}); + fs.symlinkSync(actualToolCacheDir, lnkSrc, 'junction'); + core.info(`Created link ${lnkSrc} => ${actualToolCacheDir}`); + + // restore toolcache root to default drive c: + process.env['RUNNER_TOOL_CACHE'] = defaultToolCacheRoot; + + // make outer code to continue using toolcache as if it were installed on c: + return lnkSrc; } return await addExecutablesToCache(extPath, info, arch); From c5c2a053c120a181a760ba1d17cc707b97a32217 Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Wed, 12 Jul 2023 00:59:12 +0200 Subject: [PATCH 04/16] Add e2e test --- .github/workflows/windows-validation.yml | 62 ++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 .github/workflows/windows-validation.yml diff --git a/.github/workflows/windows-validation.yml b/.github/workflows/windows-validation.yml new file mode 100644 index 000000000..93bce4f65 --- /dev/null +++ b/.github/workflows/windows-validation.yml @@ -0,0 +1,62 @@ +name: Basic validation + +on: + push: + branches: + - main + paths-ignore: + - '**.md' + pull_request: + paths-ignore: + - '**.md' + +jobs: + create-link-on-windows: + runs-on: windows-latest + strategy: + matrix: + cache: [false, true] + go: [1.20.1] + steps: + - uses: actions/checkout@v3 + + - uses: ./ + with: + go-version: ${{ matrix.go }} + cache: ${{ matrix.cache }} + name: v4-cache-${{ matrix.cache }} + + - run: | + du -m -s 'D:\hostedtoolcache\windows\go\${{ matrix.go }}\x64' + size=$(du -m -s 'D:\hostedtoolcache\windows\go\${{ matrix.go }}\x64'|cut -f1 -d$'\t') + # make sure archive does not take lost of the space + if [ $size -gt 999 ];then + echo 'Size of installed on drive d: go is too big'; + exit 1 + fi + + du -m -s 'C:\hostedtoolcache\windows\go\${{ matrix.go }}\x64' + # make sure drive c: contains only a link + size=$(du -m -s 'C:\hostedtoolcache\windows\go\${{ matrix.go }}\x64'|cut -f1 -d$'\t') + if [ $size -ne 0 ];then + echo 'Size of the link created on drive c: must be 0' + exit 1 + fi + shell: bash + name: Disk usage + + - run: | + echo $PATH + which go + go version + go env + if [ $(which go) != '/c/hostedtoolcache/windows/go/${{ matrix.go }}/x64/bin/go' ];then + echo 'which go should return "/c/hostedtoolcache/windows/go/${{ matrix.go }}/x64/bin/go"' + exit 1 + fi + if [ $(go env GOROOT) != 'C:\hostedtoolcache\windows\go\1.20.1\x64' ];then + echo 'go env GOROOT should return "C:\hostedtoolcache\windows\go\1.20.1\x64"' + exit 1 + fi + shell: bash + name: test paths and environments From 99ea9d4780c05d1b96482b8785bfbbea490bb51d Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Wed, 12 Jul 2023 01:21:11 +0200 Subject: [PATCH 05/16] fix lint --- __tests__/setup-go.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__tests__/setup-go.test.ts b/__tests__/setup-go.test.ts index 6a04035d2..2049b9497 100644 --- a/__tests__/setup-go.test.ts +++ b/__tests__/setup-go.test.ts @@ -962,7 +962,7 @@ use . describe('Windows performance workaround', () => { it('addExecutablesToCache should depends on env[RUNNER_TOOL_CACHE]', async () => { const statSpy = jest.spyOn(fs, 'statSync'); - // @ts-ignore + // @ts-ignore - not implement unused methods statSpy.mockImplementation(() => ({ isDirectory: () => true })); From d4fc9881c530de9958b956f0aa11747b2b82e736 Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Wed, 12 Jul 2023 02:08:24 +0200 Subject: [PATCH 06/16] Fix unit tests --- __tests__/setup-go.test.ts | 42 +++--------------- __tests__/windows-performance.test.ts | 61 +++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 35 deletions(-) create mode 100644 __tests__/windows-performance.test.ts diff --git a/__tests__/setup-go.test.ts b/__tests__/setup-go.test.ts index 2049b9497..ffe8c2e02 100644 --- a/__tests__/setup-go.test.ts +++ b/__tests__/setup-go.test.ts @@ -40,6 +40,8 @@ describe('setup-go', () => { let existsSpy: jest.SpyInstance; let readFileSpy: jest.SpyInstance; let mkdirpSpy: jest.SpyInstance; + let mkdirSpy: jest.SpyInstance; + let symlinkSpy: jest.SpyInstance; let execSpy: jest.SpyInstance; let getManifestSpy: jest.SpyInstance; let getAllVersionsSpy: jest.SpyInstance; @@ -93,6 +95,11 @@ describe('setup-go', () => { readFileSpy = jest.spyOn(fs, 'readFileSync'); mkdirpSpy = jest.spyOn(io, 'mkdirP'); + // fs + mkdirSpy = jest.spyOn(fs, 'mkdir'); + symlinkSpy = jest.spyOn(fs, 'symlinkSync'); + symlinkSpy.mockImplementation(() => {}); + // gets getManifestSpy.mockImplementation(() => goTestManifest); @@ -958,39 +965,4 @@ use . } ); }); - - describe('Windows performance workaround', () => { - it('addExecutablesToCache should depends on env[RUNNER_TOOL_CACHE]', async () => { - const statSpy = jest.spyOn(fs, 'statSync'); - // @ts-ignore - not implement unused methods - statSpy.mockImplementation(() => ({ - isDirectory: () => true - })); - const readdirSpy = jest.spyOn(fs, 'readdirSync'); - readdirSpy.mockImplementation(() => []); - const writeFileSpy = jest.spyOn(fs, 'writeFileSync'); - writeFileSpy.mockImplementation(() => {}); - const rmRFSpy = jest.spyOn(io, 'rmRF'); - rmRFSpy.mockImplementation(() => Promise.resolve()); - const mkdirPSpy = jest.spyOn(io, 'mkdirP'); - mkdirPSpy.mockImplementation(() => Promise.resolve()); - const cpSpy = jest.spyOn(io, 'cp'); - cpSpy.mockImplementation(() => Promise.resolve()); - - const info: IGoVersionInfo = { - type: 'dist', - downloadUrl: 'http://nowhere.com', - resolvedVersion: '1.2.3', - fileName: 'ignore' - }; - - process.env['RUNNER_TOOL_CACHE'] = '/faked-hostedtoolcache1'; - const cacheDir1 = await addExecutablesToCache('/qzx', info, 'arch'); - expect(cacheDir1).toBe('/faked-hostedtoolcache1/go/1.2.3/arch'); - - process.env['RUNNER_TOOL_CACHE'] = '/faked-hostedtoolcache2'; - const cacheDir2 = await addExecutablesToCache('/qzx', info, 'arch'); - expect(cacheDir2).toBe('/faked-hostedtoolcache2/go/1.2.3/arch'); - }); - }); }); diff --git a/__tests__/windows-performance.test.ts b/__tests__/windows-performance.test.ts new file mode 100644 index 000000000..7e7f18ebf --- /dev/null +++ b/__tests__/windows-performance.test.ts @@ -0,0 +1,61 @@ +import fs from 'fs'; +import * as io from '@actions/io'; +import {addExecutablesToCache, IGoVersionInfo} from '../src/installer'; + +describe('Windows performance workaround', () => { + let mkdirSpy: jest.SpyInstance; + let symlinkSpy: jest.SpyInstance; + let statSpy: jest.SpyInstance; + let readdirSpy: jest.SpyInstance; + let writeFileSpy: jest.SpyInstance; + let rmRFSpy: jest.SpyInstance; + let mkdirPSpy: jest.SpyInstance; + let cpSpy: jest.SpyInstance; + + let runnerToolCache: string | undefined; + beforeEach(() => { + mkdirSpy = jest.spyOn(fs, 'mkdir'); + symlinkSpy = jest.spyOn(fs, 'symlinkSync'); + statSpy = jest.spyOn(fs, 'statSync'); + readdirSpy = jest.spyOn(fs, 'readdirSync'); + writeFileSpy = jest.spyOn(fs, 'writeFileSync'); + rmRFSpy = jest.spyOn(io, 'rmRF'); + mkdirPSpy = jest.spyOn(io, 'mkdirP'); + cpSpy = jest.spyOn(io, 'cp'); + + // default implementations + // @ts-ignore - not implement unused methods + statSpy.mockImplementation(() => ({ + isDirectory: () => true + })); + readdirSpy.mockImplementation(() => []); + writeFileSpy.mockImplementation(() => {}); + mkdirSpy.mockImplementation(() => {}); + symlinkSpy.mockImplementation(() => {}); + rmRFSpy.mockImplementation(() => Promise.resolve()); + mkdirPSpy.mockImplementation(() => Promise.resolve()); + cpSpy.mockImplementation(() => Promise.resolve()); + + runnerToolCache = process.env['RUNNER_TOOL_CACHE']; + }); + afterEach(() => { + jest.clearAllMocks(); + process.env['RUNNER_TOOL_CACHE'] = runnerToolCache; + }); + it('addExecutablesToCache should depend on env[RUNNER_TOOL_CACHE]', async () => { + const info: IGoVersionInfo = { + type: 'dist', + downloadUrl: 'http://nowhere.com', + resolvedVersion: '1.2.3', + fileName: 'ignore' + }; + + process.env['RUNNER_TOOL_CACHE'] = '/faked-hostedtoolcache1'; + const cacheDir1 = await addExecutablesToCache('/qzx', info, 'arch'); + expect(cacheDir1).toBe('/faked-hostedtoolcache1/go/1.2.3/arch'); + + process.env['RUNNER_TOOL_CACHE'] = '/faked-hostedtoolcache2'; + const cacheDir2 = await addExecutablesToCache('/qzx', info, 'arch'); + expect(cacheDir2).toBe('/faked-hostedtoolcache2/go/1.2.3/arch'); + }); +}); From 7eefc6eb215d2c70b5fe6aa4ad8dec8e6fcc1d71 Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Wed, 12 Jul 2023 02:14:56 +0200 Subject: [PATCH 07/16] Fix unit tests --- .github/workflows/windows-validation.yml | 2 +- __tests__/windows-performance.test.ts | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/windows-validation.yml b/.github/workflows/windows-validation.yml index 93bce4f65..91e6e5f2c 100644 --- a/.github/workflows/windows-validation.yml +++ b/.github/workflows/windows-validation.yml @@ -29,7 +29,7 @@ jobs: - run: | du -m -s 'D:\hostedtoolcache\windows\go\${{ matrix.go }}\x64' size=$(du -m -s 'D:\hostedtoolcache\windows\go\${{ matrix.go }}\x64'|cut -f1 -d$'\t') - # make sure archive does not take lost of the space + # make sure archive does not take lot of space if [ $size -gt 999 ];then echo 'Size of installed on drive d: go is too big'; exit 1 diff --git a/__tests__/windows-performance.test.ts b/__tests__/windows-performance.test.ts index 7e7f18ebf..451744b67 100644 --- a/__tests__/windows-performance.test.ts +++ b/__tests__/windows-performance.test.ts @@ -1,6 +1,7 @@ import fs from 'fs'; import * as io from '@actions/io'; import {addExecutablesToCache, IGoVersionInfo} from '../src/installer'; +import path from 'path'; describe('Windows performance workaround', () => { let mkdirSpy: jest.SpyInstance; @@ -52,10 +53,14 @@ describe('Windows performance workaround', () => { process.env['RUNNER_TOOL_CACHE'] = '/faked-hostedtoolcache1'; const cacheDir1 = await addExecutablesToCache('/qzx', info, 'arch'); - expect(cacheDir1).toBe('/faked-hostedtoolcache1/go/1.2.3/arch'); + expect(cacheDir1).toBe( + path.join('/', 'faked-hostedtoolcache1', 'go', '1.2.3', 'arch') + ); process.env['RUNNER_TOOL_CACHE'] = '/faked-hostedtoolcache2'; const cacheDir2 = await addExecutablesToCache('/qzx', info, 'arch'); - expect(cacheDir2).toBe('/faked-hostedtoolcache2/go/1.2.3/arch'); + expect(cacheDir2).toBe( + path.join('/', 'faked-hostedtoolcache2', 'go', '1.2.3', 'arch') + ); }); }); From 96a955403c45123272712295720bce565c8666a1 Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Wed, 12 Jul 2023 09:06:59 +0200 Subject: [PATCH 08/16] limit to github hosted runners --- dist/setup/index.js | 5 ++++- src/installer.ts | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index faf0ecd95..0e94fd132 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -61464,7 +61464,10 @@ function installGoVersion(info, auth, arch) { if (info.type === 'dist') { extPath = path.join(extPath, 'go'); } - if (isWindows) { + // for github hosted windows runner handle latency of OS drive + // by avoiding write operations to C: + const isHosted = (process.env['RUNNER_ENVIRONMENT'] = 'github-hosted'); + if (isWindows && isHosted) { const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE'] || ''; const substitutedToolCacheRoot = defaultToolCacheRoot .replace('C:', 'D:') diff --git a/src/installer.ts b/src/installer.ts index 8d2eaa765..bc39e79be 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -189,6 +189,7 @@ async function installGoVersion( // Windows requires that we keep the extension (.zip) for extraction const isWindows = os.platform() === 'win32'; + const tempDir = process.env.RUNNER_TEMP || '.'; const fileName = isWindows ? path.join(tempDir, info.fileName) : undefined; @@ -201,7 +202,10 @@ async function installGoVersion( extPath = path.join(extPath, 'go'); } - if (isWindows) { + // for github hosted windows runner handle latency of OS drive + // by avoiding write operations to C: + const isHosted = (process.env['RUNNER_ENVIRONMENT'] = 'github-hosted'); + if (isWindows && isHosted) { const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE'] || ''; const substitutedToolCacheRoot = defaultToolCacheRoot .replace('C:', 'D:') From 60dde965e006ac9b91caf4ee7be27385536709ca Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Wed, 12 Jul 2023 10:15:20 +0200 Subject: [PATCH 09/16] test hosted version of go --- .github/workflows/windows-validation.yml | 27 ++++++++++++++++++++---- dist/setup/index.js | 4 ++-- src/installer.ts | 5 ++--- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/.github/workflows/windows-validation.yml b/.github/workflows/windows-validation.yml index 91e6e5f2c..b764d0cf8 100644 --- a/.github/workflows/windows-validation.yml +++ b/.github/workflows/windows-validation.yml @@ -1,4 +1,4 @@ -name: Basic validation +name: validate Windows installation on: push: @@ -16,7 +16,8 @@ jobs: strategy: matrix: cache: [false, true] - go: [1.20.1] + go: [1.20.1, 1.20.5] + name: 'Setup ${{ matrix.go }} cache: ${{ matrix.cache }}' steps: - uses: actions/checkout@v3 @@ -26,6 +27,23 @@ jobs: cache: ${{ matrix.cache }} name: v4-cache-${{ matrix.cache }} + - run: | + if [ -e 'D:\hostedtoolcache\windows\go\${{ matrix.go }}\x64' ];then + echo 'D:\hostedtoolcache\windows\go\${{ matrix.go }}\x64 should not exist for hosted version of go'; + exit 1 + fi + + du -m -s 'C:\hostedtoolcache\windows\go\${{ matrix.go }}\x64' + # make sure drive c: contains the folder + size=$(du -m -s 'C:\hostedtoolcache\windows\go\${{ matrix.go }}\x64'|cut -f1 -d$'\t') + if [ $size -eq 0 ];then + echo 'Size of the hosted go installed on drive c: must be above zero' + exit 1 + fi + shell: bash + name: Hosted go should not have link + if: ${{ matrix.go == '1.20.5' }} + - run: | du -m -s 'D:\hostedtoolcache\windows\go\${{ matrix.go }}\x64' size=$(du -m -s 'D:\hostedtoolcache\windows\go\${{ matrix.go }}\x64'|cut -f1 -d$'\t') @@ -44,6 +62,7 @@ jobs: fi shell: bash name: Disk usage + if: ${{ matrix.go != '1.20.5' }} - run: | echo $PATH @@ -54,8 +73,8 @@ jobs: echo 'which go should return "/c/hostedtoolcache/windows/go/${{ matrix.go }}/x64/bin/go"' exit 1 fi - if [ $(go env GOROOT) != 'C:\hostedtoolcache\windows\go\1.20.1\x64' ];then - echo 'go env GOROOT should return "C:\hostedtoolcache\windows\go\1.20.1\x64"' + if [ $(go env GOROOT) != 'C:\hostedtoolcache\windows\go\${{ matrix.go }}\x64' ];then + echo 'go env GOROOT should return "C:\hostedtoolcache\windows\go\${{ matrix.go }}\x64"' exit 1 fi shell: bash diff --git a/dist/setup/index.js b/dist/setup/index.js index 0e94fd132..621fa6520 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -61466,8 +61466,8 @@ function installGoVersion(info, auth, arch) { } // for github hosted windows runner handle latency of OS drive // by avoiding write operations to C: - const isHosted = (process.env['RUNNER_ENVIRONMENT'] = 'github-hosted'); - if (isWindows && isHosted) { + const isHosted = process.env['RUNNER_ENVIRONMENT'] === 'github-hosted'; + if (isWindows && isHosted && fs_1.default.existsSync('d:\\') && fs_1.default.existsSync('c:\\')) { const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE'] || ''; const substitutedToolCacheRoot = defaultToolCacheRoot .replace('C:', 'D:') diff --git a/src/installer.ts b/src/installer.ts index bc39e79be..ea30780b2 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -189,7 +189,6 @@ async function installGoVersion( // Windows requires that we keep the extension (.zip) for extraction const isWindows = os.platform() === 'win32'; - const tempDir = process.env.RUNNER_TEMP || '.'; const fileName = isWindows ? path.join(tempDir, info.fileName) : undefined; @@ -204,8 +203,8 @@ async function installGoVersion( // for github hosted windows runner handle latency of OS drive // by avoiding write operations to C: - const isHosted = (process.env['RUNNER_ENVIRONMENT'] = 'github-hosted'); - if (isWindows && isHosted) { + const isHosted = process.env['RUNNER_ENVIRONMENT'] === 'github-hosted'; + if (isWindows && isHosted && fs.existsSync('d:\\') && fs.existsSync('c:\\')) { const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE'] || ''; const substitutedToolCacheRoot = defaultToolCacheRoot .replace('C:', 'D:') From 90cd2f950f9db2bc38d38883cc05925685cabe87 Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Mon, 17 Jul 2023 14:15:14 +0200 Subject: [PATCH 10/16] AzDev environment --- dist/setup/index.js | 3 ++- src/installer.ts | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index 621fa6520..6783029a6 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -61466,7 +61466,8 @@ function installGoVersion(info, auth, arch) { } // for github hosted windows runner handle latency of OS drive // by avoiding write operations to C: - const isHosted = process.env['RUNNER_ENVIRONMENT'] === 'github-hosted'; + const isHosted = process.env['RUNNER_ENVIRONMENT'] === 'github-hosted' || + process.env['AGENT_ISSELFHOSTED'] === '0'; if (isWindows && isHosted && fs_1.default.existsSync('d:\\') && fs_1.default.existsSync('c:\\')) { const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE'] || ''; const substitutedToolCacheRoot = defaultToolCacheRoot diff --git a/src/installer.ts b/src/installer.ts index ea30780b2..7fc70b8aa 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -203,7 +203,9 @@ async function installGoVersion( // for github hosted windows runner handle latency of OS drive // by avoiding write operations to C: - const isHosted = process.env['RUNNER_ENVIRONMENT'] === 'github-hosted'; + const isHosted = + process.env['RUNNER_ENVIRONMENT'] === 'github-hosted' || + process.env['AGENT_ISSELFHOSTED'] === '0'; if (isWindows && isHosted && fs.existsSync('d:\\') && fs.existsSync('c:\\')) { const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE'] || ''; const substitutedToolCacheRoot = defaultToolCacheRoot From 00f551b2d16e1ecda99eeab266b169ee0215875b Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Mon, 17 Jul 2023 14:42:22 +0200 Subject: [PATCH 11/16] rename lnkSrc --- dist/setup/index.js | 18 +++++++++++------- src/installer.ts | 20 +++++++++++++------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index 6783029a6..37158af04 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -61468,8 +61468,12 @@ function installGoVersion(info, auth, arch) { // by avoiding write operations to C: const isHosted = process.env['RUNNER_ENVIRONMENT'] === 'github-hosted' || process.env['AGENT_ISSELFHOSTED'] === '0'; - if (isWindows && isHosted && fs_1.default.existsSync('d:\\') && fs_1.default.existsSync('c:\\')) { - const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE'] || ''; + const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE']; + if (isWindows && + defaultToolCacheRoot && + isHosted && + fs_1.default.existsSync('d:\\') && + fs_1.default.existsSync('c:\\')) { const substitutedToolCacheRoot = defaultToolCacheRoot .replace('C:', 'D:') .replace('c:', 'd:'); @@ -61477,14 +61481,14 @@ function installGoVersion(info, auth, arch) { process.env['RUNNER_TOOL_CACHE'] = substitutedToolCacheRoot; const actualToolCacheDir = yield addExecutablesToCache(extPath, info, arch); // create a link from c: to d: - const lnkSrc = actualToolCacheDir.replace(substitutedToolCacheRoot, defaultToolCacheRoot); - fs_1.default.mkdirSync(path.dirname(lnkSrc), { recursive: true }); - fs_1.default.symlinkSync(actualToolCacheDir, lnkSrc, 'junction'); - core.info(`Created link ${lnkSrc} => ${actualToolCacheDir}`); + const defaultToolCacheDir = actualToolCacheDir.replace(substitutedToolCacheRoot, defaultToolCacheRoot); + fs_1.default.mkdirSync(path.dirname(defaultToolCacheDir), { recursive: true }); + fs_1.default.symlinkSync(actualToolCacheDir, defaultToolCacheDir, 'junction'); + core.info(`Created link ${defaultToolCacheDir} => ${actualToolCacheDir}`); // restore toolcache root to default drive c: process.env['RUNNER_TOOL_CACHE'] = defaultToolCacheRoot; // make outer code to continue using toolcache as if it were installed on c: - return lnkSrc; + return defaultToolCacheDir; } return yield addExecutablesToCache(extPath, info, arch); }); diff --git a/src/installer.ts b/src/installer.ts index 7fc70b8aa..629d69637 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -206,8 +206,14 @@ async function installGoVersion( const isHosted = process.env['RUNNER_ENVIRONMENT'] === 'github-hosted' || process.env['AGENT_ISSELFHOSTED'] === '0'; - if (isWindows && isHosted && fs.existsSync('d:\\') && fs.existsSync('c:\\')) { - const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE'] || ''; + const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE']; + if ( + isWindows && + defaultToolCacheRoot && + isHosted && + fs.existsSync('d:\\') && + fs.existsSync('c:\\') + ) { const substitutedToolCacheRoot = defaultToolCacheRoot .replace('C:', 'D:') .replace('c:', 'd:'); @@ -217,19 +223,19 @@ async function installGoVersion( const actualToolCacheDir = await addExecutablesToCache(extPath, info, arch); // create a link from c: to d: - const lnkSrc = actualToolCacheDir.replace( + const defaultToolCacheDir = actualToolCacheDir.replace( substitutedToolCacheRoot, defaultToolCacheRoot ); - fs.mkdirSync(path.dirname(lnkSrc), {recursive: true}); - fs.symlinkSync(actualToolCacheDir, lnkSrc, 'junction'); - core.info(`Created link ${lnkSrc} => ${actualToolCacheDir}`); + fs.mkdirSync(path.dirname(defaultToolCacheDir), {recursive: true}); + fs.symlinkSync(actualToolCacheDir, defaultToolCacheDir, 'junction'); + core.info(`Created link ${defaultToolCacheDir} => ${actualToolCacheDir}`); // restore toolcache root to default drive c: process.env['RUNNER_TOOL_CACHE'] = defaultToolCacheRoot; // make outer code to continue using toolcache as if it were installed on c: - return lnkSrc; + return defaultToolCacheDir; } return await addExecutablesToCache(extPath, info, arch); From 8998c6804e4448fb670c93965cdcdb77e3b0d3ae Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Mon, 17 Jul 2023 14:47:01 +0200 Subject: [PATCH 12/16] refactor conditions --- dist/setup/index.js | 45 ++++++++++++++++++----------------- src/installer.ts | 58 ++++++++++++++++++++++----------------------- 2 files changed, 52 insertions(+), 51 deletions(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index 37158af04..befde36b9 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -61466,31 +61466,32 @@ function installGoVersion(info, auth, arch) { } // for github hosted windows runner handle latency of OS drive // by avoiding write operations to C: + if (!isWindows) + return addExecutablesToCache(extPath, info, arch); const isHosted = process.env['RUNNER_ENVIRONMENT'] === 'github-hosted' || process.env['AGENT_ISSELFHOSTED'] === '0'; + if (!isHosted) + return addExecutablesToCache(extPath, info, arch); const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE']; - if (isWindows && - defaultToolCacheRoot && - isHosted && - fs_1.default.existsSync('d:\\') && - fs_1.default.existsSync('c:\\')) { - const substitutedToolCacheRoot = defaultToolCacheRoot - .replace('C:', 'D:') - .replace('c:', 'd:'); - // make toolcache root to be on drive d: - process.env['RUNNER_TOOL_CACHE'] = substitutedToolCacheRoot; - const actualToolCacheDir = yield addExecutablesToCache(extPath, info, arch); - // create a link from c: to d: - const defaultToolCacheDir = actualToolCacheDir.replace(substitutedToolCacheRoot, defaultToolCacheRoot); - fs_1.default.mkdirSync(path.dirname(defaultToolCacheDir), { recursive: true }); - fs_1.default.symlinkSync(actualToolCacheDir, defaultToolCacheDir, 'junction'); - core.info(`Created link ${defaultToolCacheDir} => ${actualToolCacheDir}`); - // restore toolcache root to default drive c: - process.env['RUNNER_TOOL_CACHE'] = defaultToolCacheRoot; - // make outer code to continue using toolcache as if it were installed on c: - return defaultToolCacheDir; - } - return yield addExecutablesToCache(extPath, info, arch); + if (!defaultToolCacheRoot) + return addExecutablesToCache(extPath, info, arch); + if (!fs_1.default.existsSync('d:\\') || !fs_1.default.existsSync('c:\\')) + return addExecutablesToCache(extPath, info, arch); + const substitutedToolCacheRoot = defaultToolCacheRoot + .replace('C:', 'D:') + .replace('c:', 'd:'); + // make toolcache root to be on drive d: + process.env['RUNNER_TOOL_CACHE'] = substitutedToolCacheRoot; + const actualToolCacheDir = yield addExecutablesToCache(extPath, info, arch); + // create a link from c: to d: + const defaultToolCacheDir = actualToolCacheDir.replace(substitutedToolCacheRoot, defaultToolCacheRoot); + fs_1.default.mkdirSync(path.dirname(defaultToolCacheDir), { recursive: true }); + fs_1.default.symlinkSync(actualToolCacheDir, defaultToolCacheDir, 'junction'); + core.info(`Created link ${defaultToolCacheDir} => ${actualToolCacheDir}`); + // restore toolcache root to default drive c: + process.env['RUNNER_TOOL_CACHE'] = defaultToolCacheRoot; + // make outer code to continue using toolcache as if it were installed on c: + return defaultToolCacheDir; }); } function extractGoArchive(archivePath) { diff --git a/src/installer.ts b/src/installer.ts index 629d69637..6557d8655 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -203,42 +203,42 @@ async function installGoVersion( // for github hosted windows runner handle latency of OS drive // by avoiding write operations to C: + + if (!isWindows) return addExecutablesToCache(extPath, info, arch); + const isHosted = process.env['RUNNER_ENVIRONMENT'] === 'github-hosted' || process.env['AGENT_ISSELFHOSTED'] === '0'; + if (!isHosted) return addExecutablesToCache(extPath, info, arch); + const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE']; - if ( - isWindows && - defaultToolCacheRoot && - isHosted && - fs.existsSync('d:\\') && - fs.existsSync('c:\\') - ) { - const substitutedToolCacheRoot = defaultToolCacheRoot - .replace('C:', 'D:') - .replace('c:', 'd:'); - // make toolcache root to be on drive d: - process.env['RUNNER_TOOL_CACHE'] = substitutedToolCacheRoot; - - const actualToolCacheDir = await addExecutablesToCache(extPath, info, arch); - - // create a link from c: to d: - const defaultToolCacheDir = actualToolCacheDir.replace( - substitutedToolCacheRoot, - defaultToolCacheRoot - ); - fs.mkdirSync(path.dirname(defaultToolCacheDir), {recursive: true}); - fs.symlinkSync(actualToolCacheDir, defaultToolCacheDir, 'junction'); - core.info(`Created link ${defaultToolCacheDir} => ${actualToolCacheDir}`); + if (!defaultToolCacheRoot) return addExecutablesToCache(extPath, info, arch); - // restore toolcache root to default drive c: - process.env['RUNNER_TOOL_CACHE'] = defaultToolCacheRoot; + if (!fs.existsSync('d:\\') || !fs.existsSync('c:\\')) + return addExecutablesToCache(extPath, info, arch); - // make outer code to continue using toolcache as if it were installed on c: - return defaultToolCacheDir; - } + const substitutedToolCacheRoot = defaultToolCacheRoot + .replace('C:', 'D:') + .replace('c:', 'd:'); + // make toolcache root to be on drive d: + process.env['RUNNER_TOOL_CACHE'] = substitutedToolCacheRoot; + + const actualToolCacheDir = await addExecutablesToCache(extPath, info, arch); + + // create a link from c: to d: + const defaultToolCacheDir = actualToolCacheDir.replace( + substitutedToolCacheRoot, + defaultToolCacheRoot + ); + fs.mkdirSync(path.dirname(defaultToolCacheDir), {recursive: true}); + fs.symlinkSync(actualToolCacheDir, defaultToolCacheDir, 'junction'); + core.info(`Created link ${defaultToolCacheDir} => ${actualToolCacheDir}`); + + // restore toolcache root to default drive c: + process.env['RUNNER_TOOL_CACHE'] = defaultToolCacheRoot; - return await addExecutablesToCache(extPath, info, arch); + // make outer code to continue using toolcache as if it were installed on c: + return defaultToolCacheDir; } export async function extractGoArchive(archivePath: string): Promise { From 42a70ecdeea737d4ad8cbd37b2028274188ce26f Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Tue, 18 Jul 2023 14:26:06 +0200 Subject: [PATCH 13/16] improve tests --- .github/workflows/windows-validation.yml | 90 ++++++++++++++++-------- __tests__/setup-go.test.ts | 3 +- __tests__/windows-performance.test.ts | 3 + 3 files changed, 66 insertions(+), 30 deletions(-) diff --git a/.github/workflows/windows-validation.yml b/.github/workflows/windows-validation.yml index b764d0cf8..8c8772086 100644 --- a/.github/workflows/windows-validation.yml +++ b/.github/workflows/windows-validation.yml @@ -11,40 +11,36 @@ on: - '**.md' jobs: - create-link-on-windows: + create-link-if-not-default: runs-on: windows-latest + name: 'Setup ${{ matrix.go }}, cache: ${{ matrix.cache }}' strategy: matrix: cache: [false, true] - go: [1.20.1, 1.20.5] - name: 'Setup ${{ matrix.go }} cache: ${{ matrix.cache }}' + go: [1.20.1] steps: - uses: actions/checkout@v3 - - uses: ./ + - name: non-default-cache-${{ matrix.cache }}-${{ matrix.go }} + uses: ./ with: go-version: ${{ matrix.go }} cache: ${{ matrix.cache }} - name: v4-cache-${{ matrix.cache }} - - - run: | - if [ -e 'D:\hostedtoolcache\windows\go\${{ matrix.go }}\x64' ];then - echo 'D:\hostedtoolcache\windows\go\${{ matrix.go }}\x64 should not exist for hosted version of go'; - exit 1 - fi + - name: 'Drive C: should have zero size link' + run: | du -m -s 'C:\hostedtoolcache\windows\go\${{ matrix.go }}\x64' - # make sure drive c: contains the folder + # make sure drive c: contains only a link size=$(du -m -s 'C:\hostedtoolcache\windows\go\${{ matrix.go }}\x64'|cut -f1 -d$'\t') - if [ $size -eq 0 ];then - echo 'Size of the hosted go installed on drive c: must be above zero' + if [ $size -ne 0 ];then + echo 'Size of the link created on drive c: must be 0' exit 1 fi shell: bash - name: Hosted go should not have link - if: ${{ matrix.go == '1.20.5' }} - - run: | + # Drive D: is small, take care the action does not eat up the space + - name: 'Drive D: space usage should be below 1G' + run: | du -m -s 'D:\hostedtoolcache\windows\go\${{ matrix.go }}\x64' size=$(du -m -s 'D:\hostedtoolcache\windows\go\${{ matrix.go }}\x64'|cut -f1 -d$'\t') # make sure archive does not take lot of space @@ -52,19 +48,11 @@ jobs: echo 'Size of installed on drive d: go is too big'; exit 1 fi - - du -m -s 'C:\hostedtoolcache\windows\go\${{ matrix.go }}\x64' - # make sure drive c: contains only a link - size=$(du -m -s 'C:\hostedtoolcache\windows\go\${{ matrix.go }}\x64'|cut -f1 -d$'\t') - if [ $size -ne 0 ];then - echo 'Size of the link created on drive c: must be 0' - exit 1 - fi shell: bash - name: Disk usage - if: ${{ matrix.go != '1.20.5' }} - - run: | + # make sure the Go installation has not been changed to the end user + - name: Test paths and environments + run: | echo $PATH which go go version @@ -78,4 +66,48 @@ jobs: exit 1 fi shell: bash - name: test paths and environments + + find-default-go: + name: 'Find default go version' + runs-on: windows-latest + outputs: + version: ${{ steps.goversion.outputs.version }} + steps: + - run: | + version=`go env GOVERSION|sed s/^go//` + echo "default go version: $version" + echo "version=$version" >> "$GITHUB_OUTPUT" + id: goversion + shell: bash + + dont-create-link-if-default: + name: 'Use default go, cache: ${{ matrix.cache }}' + runs-on: windows-latest + needs: find-default-go + strategy: + matrix: + cache: [false, true] + steps: + - uses: actions/checkout@v3 + + - uses: ./ + with: + go-version: ${{ needs.find-default-go.outputs.version }} + cache: ${{ matrix.cache }} + + - name: 'Drive C: should have Go installation' + run: | + size=$(du -m -s 'C:\hostedtoolcache\windows\go\${{ needs.find-default-go.outputs.version }}\x64'|cut -f1 -d$'\t') + if [ $size -eq 0 ];then + echo 'Size of the hosted go installed on drive c: must be above zero' + exit 1 + fi + shell: bash + + - name: 'Drive D: should not have Go installation' + run: | + if [ -e 'D:\hostedtoolcache\windows\go\${{ needs.find-default-go.outputs.version }}\x64' ];then + echo 'D:\hostedtoolcache\windows\go\${{ needs.find-default-go.outputs.version }}\x64 should not exist for hosted version of go'; + exit 1 + fi + shell: bash diff --git a/__tests__/setup-go.test.ts b/__tests__/setup-go.test.ts index ffe8c2e02..70f2166eb 100644 --- a/__tests__/setup-go.test.ts +++ b/__tests__/setup-go.test.ts @@ -11,12 +11,13 @@ import * as im from '../src/installer'; import goJsonData from './data/golang-dl.json'; import matchers from '../matchers.json'; import goTestManifest from './data/versions-manifest.json'; -import {addExecutablesToCache, IGoVersionInfo} from '../src/installer'; const matcherPattern = matchers.problemMatcher[0].pattern[0]; const matcherRegExp = new RegExp(matcherPattern.regexp); const win32Join = path.win32.join; const posixJoin = path.posix.join; +jest.setTimeout(10000); + describe('setup-go', () => { let inputs = {} as any; let os = {} as any; diff --git a/__tests__/windows-performance.test.ts b/__tests__/windows-performance.test.ts index 451744b67..bfb164480 100644 --- a/__tests__/windows-performance.test.ts +++ b/__tests__/windows-performance.test.ts @@ -43,6 +43,9 @@ describe('Windows performance workaround', () => { jest.clearAllMocks(); process.env['RUNNER_TOOL_CACHE'] = runnerToolCache; }); + // addExecutablesToCache uses 3rd party dependency toolkit.cache under the hood + // that currently is implemented with RUNNER_TOOL_CACHE environment variable + // Make sure the implementation has not been changed it('addExecutablesToCache should depend on env[RUNNER_TOOL_CACHE]', async () => { const info: IGoVersionInfo = { type: 'dist', From d6ad0fa4fe6ac5bfeab8de09f942f2fbc919e1fb Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Thu, 20 Jul 2023 08:48:13 +0200 Subject: [PATCH 14/16] refactoring --- ...ance.test.ts => windows-toolcache.test.ts} | 17 +--- dist/setup/index.js | 77 ++++++++------- src/installer.ts | 99 ++++++++++--------- 3 files changed, 100 insertions(+), 93 deletions(-) rename __tests__/{windows-performance.test.ts => windows-toolcache.test.ts} (78%) diff --git a/__tests__/windows-performance.test.ts b/__tests__/windows-toolcache.test.ts similarity index 78% rename from __tests__/windows-performance.test.ts rename to __tests__/windows-toolcache.test.ts index bfb164480..52fd692cb 100644 --- a/__tests__/windows-performance.test.ts +++ b/__tests__/windows-toolcache.test.ts @@ -1,6 +1,6 @@ import fs from 'fs'; import * as io from '@actions/io'; -import {addExecutablesToCache, IGoVersionInfo} from '../src/installer'; +import * as tc from '@actions/tool-cache'; import path from 'path'; describe('Windows performance workaround', () => { @@ -43,25 +43,18 @@ describe('Windows performance workaround', () => { jest.clearAllMocks(); process.env['RUNNER_TOOL_CACHE'] = runnerToolCache; }); - // addExecutablesToCache uses 3rd party dependency toolkit.cache under the hood - // that currently is implemented with RUNNER_TOOL_CACHE environment variable + // cacheWindowsToolkitDir depends on implementation of tc.cacheDir + // with the assumption that target dir is passed by RUNNER_TOOL_CACHE environment variable // Make sure the implementation has not been changed it('addExecutablesToCache should depend on env[RUNNER_TOOL_CACHE]', async () => { - const info: IGoVersionInfo = { - type: 'dist', - downloadUrl: 'http://nowhere.com', - resolvedVersion: '1.2.3', - fileName: 'ignore' - }; - process.env['RUNNER_TOOL_CACHE'] = '/faked-hostedtoolcache1'; - const cacheDir1 = await addExecutablesToCache('/qzx', info, 'arch'); + const cacheDir1 = await tc.cacheDir('/qzx', 'go', '1.2.3', 'arch'); expect(cacheDir1).toBe( path.join('/', 'faked-hostedtoolcache1', 'go', '1.2.3', 'arch') ); process.env['RUNNER_TOOL_CACHE'] = '/faked-hostedtoolcache2'; - const cacheDir2 = await addExecutablesToCache('/qzx', info, 'arch'); + const cacheDir2 = await tc.cacheDir('/qzx', 'go', '1.2.3', 'arch'); expect(cacheDir2).toBe( path.join('/', 'faked-hostedtoolcache2', 'go', '1.2.3', 'arch') ); diff --git a/dist/setup/index.js b/dist/setup/index.js index befde36b9..3d936115b 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -61338,7 +61338,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.resolveStableVersionInput = exports.parseGoVersionFile = exports.makeSemver = exports.getVersionsDist = exports.findMatch = exports.getInfoFromManifest = exports.getManifest = exports.extractGoArchive = exports.addExecutablesToCache = exports.getGo = void 0; +exports.resolveStableVersionInput = exports.parseGoVersionFile = exports.makeSemver = exports.getVersionsDist = exports.findMatch = exports.getInfoFromManifest = exports.getManifest = exports.extractGoArchive = exports.getGo = void 0; const tc = __importStar(__nccwpck_require__(7784)); const core = __importStar(__nccwpck_require__(2186)); const path = __importStar(__nccwpck_require__(1017)); @@ -61441,59 +61441,66 @@ function resolveVersionFromManifest(versionSpec, stable, auth, arch, manifest) { } }); } -function addExecutablesToCache(extPath, info, arch) { +// for github hosted windows runner handle latency of OS drive +// by avoiding write operations to C: +function cacheWindowsDir(extPath, tool, version, arch) { return __awaiter(this, void 0, void 0, function* () { - core.info('Adding to the cache ...'); - const cachedDir = yield tc.cacheDir(extPath, 'go', makeSemver(info.resolvedVersion), arch); - core.info(`Successfully cached go to ${cachedDir}`); - return cachedDir; - }); -} -exports.addExecutablesToCache = addExecutablesToCache; -function installGoVersion(info, auth, arch) { - return __awaiter(this, void 0, void 0, function* () { - core.info(`Acquiring ${info.resolvedVersion} from ${info.downloadUrl}`); - // Windows requires that we keep the extension (.zip) for extraction - const isWindows = os_1.default.platform() === 'win32'; - const tempDir = process.env.RUNNER_TEMP || '.'; - const fileName = isWindows ? path.join(tempDir, info.fileName) : undefined; - const downloadPath = yield tc.downloadTool(info.downloadUrl, fileName, auth); - core.info('Extracting Go...'); - let extPath = yield extractGoArchive(downloadPath); - core.info(`Successfully extracted go to ${extPath}`); - if (info.type === 'dist') { - extPath = path.join(extPath, 'go'); - } - // for github hosted windows runner handle latency of OS drive - // by avoiding write operations to C: - if (!isWindows) - return addExecutablesToCache(extPath, info, arch); + if (os_1.default.platform() !== 'win32') + return false; const isHosted = process.env['RUNNER_ENVIRONMENT'] === 'github-hosted' || process.env['AGENT_ISSELFHOSTED'] === '0'; if (!isHosted) - return addExecutablesToCache(extPath, info, arch); + return false; const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE']; if (!defaultToolCacheRoot) - return addExecutablesToCache(extPath, info, arch); + return false; if (!fs_1.default.existsSync('d:\\') || !fs_1.default.existsSync('c:\\')) - return addExecutablesToCache(extPath, info, arch); - const substitutedToolCacheRoot = defaultToolCacheRoot + return false; + const actualToolCacheRoot = defaultToolCacheRoot .replace('C:', 'D:') .replace('c:', 'd:'); // make toolcache root to be on drive d: - process.env['RUNNER_TOOL_CACHE'] = substitutedToolCacheRoot; - const actualToolCacheDir = yield addExecutablesToCache(extPath, info, arch); + process.env['RUNNER_TOOL_CACHE'] = actualToolCacheRoot; + const actualToolCacheDir = yield tc.cacheDir(extPath, tool, version, arch); // create a link from c: to d: - const defaultToolCacheDir = actualToolCacheDir.replace(substitutedToolCacheRoot, defaultToolCacheRoot); + const defaultToolCacheDir = actualToolCacheDir.replace(actualToolCacheRoot, defaultToolCacheRoot); fs_1.default.mkdirSync(path.dirname(defaultToolCacheDir), { recursive: true }); fs_1.default.symlinkSync(actualToolCacheDir, defaultToolCacheDir, 'junction'); core.info(`Created link ${defaultToolCacheDir} => ${actualToolCacheDir}`); + // make outer code to continue using toolcache as if it were installed on c: // restore toolcache root to default drive c: process.env['RUNNER_TOOL_CACHE'] = defaultToolCacheRoot; - // make outer code to continue using toolcache as if it were installed on c: return defaultToolCacheDir; }); } +function addExecutablesToToolCache(extPath, info, arch) { + return __awaiter(this, void 0, void 0, function* () { + const tool = 'go'; + const version = makeSemver(info.resolvedVersion); + return ((yield cacheWindowsDir(extPath, tool, version, arch)) || + (yield tc.cacheDir(extPath, tool, version, arch))); + }); +} +function installGoVersion(info, auth, arch) { + return __awaiter(this, void 0, void 0, function* () { + core.info(`Acquiring ${info.resolvedVersion} from ${info.downloadUrl}`); + // Windows requires that we keep the extension (.zip) for extraction + const isWindows = os_1.default.platform() === 'win32'; + const tempDir = process.env.RUNNER_TEMP || '.'; + const fileName = isWindows ? path.join(tempDir, info.fileName) : undefined; + const downloadPath = yield tc.downloadTool(info.downloadUrl, fileName, auth); + core.info('Extracting Go...'); + let extPath = yield extractGoArchive(downloadPath); + core.info(`Successfully extracted go to ${extPath}`); + if (info.type === 'dist') { + extPath = path.join(extPath, 'go'); + } + core.info('Adding to the cache ...'); + const toolCacheDir = yield addExecutablesToToolCache(extPath, info, arch); + core.info(`Successfully cached go to ${toolCacheDir}`); + return toolCacheDir; + }); +} function extractGoArchive(archivePath) { return __awaiter(this, void 0, void 0, function* () { const platform = os_1.default.platform(); diff --git a/src/installer.ts b/src/installer.ts index 6557d8655..9653839be 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -164,20 +164,60 @@ async function resolveVersionFromManifest( } } -export async function addExecutablesToCache( +// for github hosted windows runner handle latency of OS drive +// by avoiding write operations to C: +async function cacheWindowsDir( + extPath: string, + tool: string, + version: string, + arch: string +): Promise { + if (os.platform() !== 'win32') return false; + + const isHosted = + process.env['RUNNER_ENVIRONMENT'] === 'github-hosted' || + process.env['AGENT_ISSELFHOSTED'] === '0'; + if (!isHosted) return false; + + const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE']; + if (!defaultToolCacheRoot) return false; + + if (!fs.existsSync('d:\\') || !fs.existsSync('c:\\')) return false; + + const actualToolCacheRoot = defaultToolCacheRoot + .replace('C:', 'D:') + .replace('c:', 'd:'); + // make toolcache root to be on drive d: + process.env['RUNNER_TOOL_CACHE'] = actualToolCacheRoot; + + const actualToolCacheDir = await tc.cacheDir(extPath, tool, version, arch); + + // create a link from c: to d: + const defaultToolCacheDir = actualToolCacheDir.replace( + actualToolCacheRoot, + defaultToolCacheRoot + ); + fs.mkdirSync(path.dirname(defaultToolCacheDir), {recursive: true}); + fs.symlinkSync(actualToolCacheDir, defaultToolCacheDir, 'junction'); + core.info(`Created link ${defaultToolCacheDir} => ${actualToolCacheDir}`); + + // make outer code to continue using toolcache as if it were installed on c: + // restore toolcache root to default drive c: + process.env['RUNNER_TOOL_CACHE'] = defaultToolCacheRoot; + return defaultToolCacheDir; +} + +async function addExecutablesToToolCache( extPath: string, info: IGoVersionInfo, arch: string ): Promise { - core.info('Adding to the cache ...'); - const cachedDir = await tc.cacheDir( - extPath, - 'go', - makeSemver(info.resolvedVersion), - arch + const tool = 'go'; + const version = makeSemver(info.resolvedVersion); + return ( + (await cacheWindowsDir(extPath, tool, version, arch)) || + (await tc.cacheDir(extPath, tool, version, arch)) ); - core.info(`Successfully cached go to ${cachedDir}`); - return cachedDir; } async function installGoVersion( @@ -201,44 +241,11 @@ async function installGoVersion( extPath = path.join(extPath, 'go'); } - // for github hosted windows runner handle latency of OS drive - // by avoiding write operations to C: - - if (!isWindows) return addExecutablesToCache(extPath, info, arch); - - const isHosted = - process.env['RUNNER_ENVIRONMENT'] === 'github-hosted' || - process.env['AGENT_ISSELFHOSTED'] === '0'; - if (!isHosted) return addExecutablesToCache(extPath, info, arch); - - const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE']; - if (!defaultToolCacheRoot) return addExecutablesToCache(extPath, info, arch); - - if (!fs.existsSync('d:\\') || !fs.existsSync('c:\\')) - return addExecutablesToCache(extPath, info, arch); - - const substitutedToolCacheRoot = defaultToolCacheRoot - .replace('C:', 'D:') - .replace('c:', 'd:'); - // make toolcache root to be on drive d: - process.env['RUNNER_TOOL_CACHE'] = substitutedToolCacheRoot; - - const actualToolCacheDir = await addExecutablesToCache(extPath, info, arch); - - // create a link from c: to d: - const defaultToolCacheDir = actualToolCacheDir.replace( - substitutedToolCacheRoot, - defaultToolCacheRoot - ); - fs.mkdirSync(path.dirname(defaultToolCacheDir), {recursive: true}); - fs.symlinkSync(actualToolCacheDir, defaultToolCacheDir, 'junction'); - core.info(`Created link ${defaultToolCacheDir} => ${actualToolCacheDir}`); - - // restore toolcache root to default drive c: - process.env['RUNNER_TOOL_CACHE'] = defaultToolCacheRoot; + core.info('Adding to the cache ...'); + const toolCacheDir = await addExecutablesToToolCache(extPath, info, arch); + core.info(`Successfully cached go to ${toolCacheDir}`); - // make outer code to continue using toolcache as if it were installed on c: - return defaultToolCacheDir; + return toolCacheDir; } export async function extractGoArchive(archivePath: string): Promise { From 59c54a4b0bd948e7a2b72fafdc5a687868385747 Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Tue, 25 Jul 2023 15:24:49 +0200 Subject: [PATCH 15/16] Fix e2e test --- .github/workflows/windows-validation.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/windows-validation.yml b/.github/workflows/windows-validation.yml index 8c8772086..6890d07bc 100644 --- a/.github/workflows/windows-validation.yml +++ b/.github/workflows/windows-validation.yml @@ -1,4 +1,4 @@ -name: validate Windows installation +name: Validate Windows installation on: push: @@ -13,7 +13,7 @@ on: jobs: create-link-if-not-default: runs-on: windows-latest - name: 'Setup ${{ matrix.go }}, cache: ${{ matrix.cache }}' + name: 'Validate if symlink is created' strategy: matrix: cache: [false, true] @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@v3 - - name: non-default-cache-${{ matrix.cache }}-${{ matrix.go }} + - name: 'Setup ${{ matrix.cache }}, cache: ${{ matrix.go }}' uses: ./ with: go-version: ${{ matrix.go }} @@ -81,7 +81,7 @@ jobs: shell: bash dont-create-link-if-default: - name: 'Use default go, cache: ${{ matrix.cache }}' + name: 'Validate if symlink is not created for default go' runs-on: windows-latest needs: find-default-go strategy: @@ -90,12 +90,13 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: ./ + - name: 'Setup default go, cache: ${{ matrix.cache }}' + uses: ./ with: go-version: ${{ needs.find-default-go.outputs.version }} cache: ${{ matrix.cache }} - - name: 'Drive C: should have Go installation' + - name: 'Drive C: should have Go installation, cache: ${{ matrix.cache}}' run: | size=$(du -m -s 'C:\hostedtoolcache\windows\go\${{ needs.find-default-go.outputs.version }}\x64'|cut -f1 -d$'\t') if [ $size -eq 0 ];then @@ -104,7 +105,7 @@ jobs: fi shell: bash - - name: 'Drive D: should not have Go installation' + - name: 'Drive D: should not have Go installation, cache: ${{ matrix.cache}}' run: | if [ -e 'D:\hostedtoolcache\windows\go\${{ needs.find-default-go.outputs.version }}\x64' ];then echo 'D:\hostedtoolcache\windows\go\${{ needs.find-default-go.outputs.version }}\x64 should not exist for hosted version of go'; From 55bf2e2f650a9be1549d9a6633b4bb7402d59b50 Mon Sep 17 00:00:00 2001 From: Sergey Dolin Date: Tue, 25 Jul 2023 15:51:23 +0200 Subject: [PATCH 16/16] improve isHosted readability --- dist/setup/index.js | 6 +++--- src/installer.ts | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index 3d936115b..fcd931409 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -61447,9 +61447,9 @@ function cacheWindowsDir(extPath, tool, version, arch) { return __awaiter(this, void 0, void 0, function* () { if (os_1.default.platform() !== 'win32') return false; - const isHosted = process.env['RUNNER_ENVIRONMENT'] === 'github-hosted' || - process.env['AGENT_ISSELFHOSTED'] === '0'; - if (!isHosted) + // make sure the action runs in the hosted environment + if (process.env['RUNNER_ENVIRONMENT'] !== 'github-hosted' && + process.env['AGENT_ISSELFHOSTED'] === '1') return false; const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE']; if (!defaultToolCacheRoot) diff --git a/src/installer.ts b/src/installer.ts index 9653839be..be90e101a 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -174,10 +174,12 @@ async function cacheWindowsDir( ): Promise { if (os.platform() !== 'win32') return false; - const isHosted = - process.env['RUNNER_ENVIRONMENT'] === 'github-hosted' || - process.env['AGENT_ISSELFHOSTED'] === '0'; - if (!isHosted) return false; + // make sure the action runs in the hosted environment + if ( + process.env['RUNNER_ENVIRONMENT'] !== 'github-hosted' && + process.env['AGENT_ISSELFHOSTED'] === '1' + ) + return false; const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE']; if (!defaultToolCacheRoot) return false;