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

Allow changing default cache file size limit #1933

Open
wants to merge 1 commit 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ packages/*/__tests__/_temp/
.DS_Store
*.xar
packages/*/audit.json
.idea
41 changes: 39 additions & 2 deletions packages/cache/__tests__/saveCache.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import * as core from '@actions/core'
import * as path from 'path'
import {saveCache} from '../src/cache'
import {saveCache, setFileSizeLimit} from '../src/cache'
import * as cacheHttpClient from '../src/internal/cacheHttpClient'
import * as cacheUtils from '../src/internal/cacheUtils'
import * as config from '../src/internal/config'
import {CacheFilename, CompressionMethod} from '../src/internal/constants'
import {CacheFilename, CacheFileSizeLimit, CompressionMethod} from '../src/internal/constants'
import * as tar from '../src/internal/tar'
import {TypedResponse} from '@actions/http-client/lib/interfaces'
import {
Expand All @@ -19,6 +19,7 @@ jest.mock('../src/internal/config')
jest.mock('../src/internal/tar')

beforeAll(() => {
setFileSizeLimit(CacheFileSizeLimit)
jest.spyOn(console, 'log').mockImplementation(() => {})
jest.spyOn(core, 'debug').mockImplementation(() => {})
jest.spyOn(core, 'info').mockImplementation(() => {})
Expand Down Expand Up @@ -79,6 +80,42 @@ test('save with large cache outputs should fail', async () => {
expect(getCompressionMock).toHaveBeenCalledTimes(1)
})

test('save with small cache outputs should fail on changed limit', async () => {
setFileSizeLimit(100 * 1024 * 1024) // set default limit to 100 MB
const filePath = 'node_modules'
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
const cachePaths = [path.resolve(filePath)]

const createTarMock = jest.spyOn(tar, 'createTar')
const logWarningMock = jest.spyOn(core, 'warning')

const cacheSize = 1024 * 1024 * 1024 //1GB, over the 100MB limit
jest
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
.mockReturnValueOnce(cacheSize)
const compression = CompressionMethod.Gzip
const getCompressionMock = jest
.spyOn(cacheUtils, 'getCompressionMethod')
.mockReturnValueOnce(Promise.resolve(compression))

const cacheId = await saveCache([filePath], primaryKey)
expect(cacheId).toBe(-1)
expect(logWarningMock).toHaveBeenCalledTimes(1)
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to save: Cache size of ~1024 MB (1073741824 B) is over the 100MB limit, not saving cache.'
)

const archiveFolder = '/foo/bar'

expect(createTarMock).toHaveBeenCalledTimes(1)
expect(createTarMock).toHaveBeenCalledWith(
archiveFolder,
cachePaths,
compression
)
expect(getCompressionMock).toHaveBeenCalledTimes(1)
})

test('save with large cache outputs should fail in GHES with error message', async () => {
const filePath = 'node_modules'
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
Expand Down
26 changes: 22 additions & 4 deletions packages/cache/src/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,24 @@ function checkKey(key: string): void {
}
}

let fileSizeLimit = CacheFileSizeLimit // default 10GB per repo limit
let fileSizeLimitStr = formatBytes(fileSizeLimit)

export function setFileSizeLimit(newFileSizeLimit: number){
fileSizeLimit = newFileSizeLimit
fileSizeLimitStr = formatBytes(newFileSizeLimit)
}

export function formatBytes(bytes: number): string {
if (bytes === 0) return "0 Bytes";

const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB"];
const i = Math.floor(Math.log(bytes) / Math.log(1024));
const value = bytes / Math.pow(1024, i);

return `${value.toFixed(0)}${sizes[i]}`;
}

/**
* isFeatureAvailable to check the presence of Actions cache service
*
Expand Down Expand Up @@ -385,7 +403,7 @@ async function saveCacheV1(
if (core.isDebug()) {
await listTar(archivePath, compressionMethod)
}
const fileSizeLimit = 10 * 1024 * 1024 * 1024 // 10GB per repo limit

const archiveFileSize = utils.getArchiveFileSizeInBytes(archivePath)
core.debug(`File Size: ${archiveFileSize}`)

Expand All @@ -394,7 +412,7 @@ async function saveCacheV1(
throw new Error(
`Cache size of ~${Math.round(
archiveFileSize / (1024 * 1024)
)} MB (${archiveFileSize} B) is over the 10GB limit, not saving cache.`
)} MB (${archiveFileSize} B) is over the ${fileSizeLimitStr} limit, not saving cache.`
)
}

Expand Down Expand Up @@ -503,11 +521,11 @@ async function saveCacheV2(
core.debug(`File Size: ${archiveFileSize}`)

// For GHES, this check will take place in ReserveCache API with enterprise file size limit
if (archiveFileSize > CacheFileSizeLimit && !isGhes()) {
if (archiveFileSize > fileSizeLimit && !isGhes()) {
throw new Error(
`Cache size of ~${Math.round(
archiveFileSize / (1024 * 1024)
)} MB (${archiveFileSize} B) is over the 10GB limit, not saving cache.`
)} MB (${archiveFileSize} B) is over the ${fileSizeLimitStr} limit, not saving cache.`
)
}

Expand Down