Skip to content

Commit

Permalink
MultiCI: Abstract Logging behind new type
Browse files Browse the repository at this point in the history
In order to support more environments, we abstract away `@actions/core`'s logging functionality
behind it's own type. This allows replacement with environment-specific versions.

Note: This PR does not replace all, there is a follow-up to finish replacing. The intention is
to have the new content reviewed vs. the "find and replace" PR following.

Part of gradle#502.
  • Loading branch information
Nava2 committed Jan 10, 2025
1 parent fbb6c60 commit 7ce7dd5
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 63 deletions.
26 changes: 25 additions & 1 deletion sources/src/actions/github-actions-env.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as core from '@actions/core'
import {state} from '../env'
import {log, LogLevel, state} from '../env'

function setupState(): void {
state.setImpl({
Expand All @@ -13,6 +13,30 @@ function setupState(): void {
})
}

function setupLogger(): void {
// Redirect the log output to the GitHub Actions logging system.
log.setWriter((level, message) => {
switch (level) {
case LogLevel.DEBUG:
core.debug(message)
break
case LogLevel.INFO:
core.info(message)
break
case LogLevel.NOTICE:
core.notice(message)
break
case LogLevel.WARN:
core.warning(message)
break
case LogLevel.ERROR:
core.error(message)
break
}
})
}

export const configureGithubEnv = (): void => {
setupState()
setupLogger()
}
4 changes: 2 additions & 2 deletions sources/src/caching/cache-cleaner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as exec from '@actions/exec'
import fs from 'fs'
import path from 'path'
import * as provisioner from '../execution/provision'
import {state} from '../env'
import {log, state} from '../env'

export class CacheCleaner {
private readonly gradleUserHome: string
Expand Down Expand Up @@ -60,7 +60,7 @@ export class CacheCleaner {
const executable = await provisioner.provisionGradleAtLeast('8.12')

await core.group('Executing Gradle to clean up caches', async () => {
core.info(`Cleaning up caches last used before ${cleanTimestamp}`)
log.info(`Cleaning up caches last used before ${cleanTimestamp}`)
await this.executeCleanupBuild(executable, cleanupProjectDir)
})
}
Expand Down
32 changes: 8 additions & 24 deletions sources/src/caching/cache-utils.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
import * as core from '@actions/core'
import * as cache from '@actions/cache'
import * as exec from '@actions/exec'

import * as crypto from 'crypto'
import * as path from 'path'
import * as fs from 'fs'

import {state} from '../env'
import {log} from '../env'
import {CacheEntryListener} from './cache-reporting'

const SEGMENT_DOWNLOAD_TIMEOUT_VAR = 'SEGMENT_DOWNLOAD_TIMEOUT_MINS'
const SEGMENT_DOWNLOAD_TIMEOUT_DEFAULT = 10 * 60 * 1000 // 10 minutes

export function isCacheDebuggingEnabled(): boolean {
if (state.isDebug()) {
return true
}
return process.env['GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED'] ? true : false
}

export function hashFileNames(fileNames: string[]): string {
return hashStrings(fileNames.map(x => x.replace(new RegExp(`\\${path.sep}`, 'g'), '/')))
}
Expand Down Expand Up @@ -48,7 +40,7 @@ export async function restoreCache(
if (restoredEntry !== undefined) {
const restoreTime = Date.now() - startTime
listener.markRestored(restoredEntry.key, restoredEntry.size, restoreTime)
core.info(`Restored cache entry with key ${cacheKey} to ${cachePath.join()} in ${restoreTime}ms`)
log.info(`Restored cache entry with key ${cacheKey} to ${cachePath.join()} in ${restoreTime}ms`)
}
return restoredEntry
} catch (error) {
Expand All @@ -64,7 +56,7 @@ export async function saveCache(cachePath: string[], cacheKey: string, listener:
const savedEntry = await cache.saveCache(cachePath, cacheKey)
const saveTime = Date.now() - startTime
listener.markSaved(savedEntry.key, savedEntry.size, saveTime)
core.info(`Saved cache entry with key ${cacheKey} from ${cachePath.join()} in ${saveTime}ms`)
log.info(`Saved cache entry with key ${cacheKey} from ${cachePath.join()} in ${saveTime}ms`)
} catch (error) {
if (error instanceof cache.ReserveCacheError) {
listener.markAlreadyExists(cacheKey)
Expand All @@ -75,27 +67,19 @@ export async function saveCache(cachePath: string[], cacheKey: string, listener:
}
}

export function cacheDebug(message: string): void {
if (isCacheDebuggingEnabled()) {
core.info(message)
} else {
core.debug(message)
}
}

export function handleCacheFailure(error: unknown, message: string): void {
if (error instanceof cache.ValidationError) {
// Fail on cache validation errors
throw error
}
if (error instanceof cache.ReserveCacheError) {
// Reserve cache errors are expected if the artifact has been previously cached
core.info(`${message}: ${error}`)
log.info(`${message}: ${error}`)
} else {
// Warn on all other errors
core.warning(`${message}: ${error}`)
log.warn(`${message}: ${error}`)
if (error instanceof Error && error.stack) {
cacheDebug(error.stack)
log.cacheDebug(error.stack)
}
}
}
Expand All @@ -119,12 +103,12 @@ export async function tryDelete(file: string): Promise<void> {
return
} catch (error) {
if (attempt === maxAttempts) {
core.warning(`Failed to delete ${file}, which will impact caching.
log.warn(`Failed to delete ${file}, which will impact caching.
It is likely locked by another process. Output of 'jps -ml':
${await getJavaProcesses()}`)
throw error
} else {
cacheDebug(`Attempt to delete ${file} failed. Will try again.`)
log.cacheDebug(`Attempt to delete ${file} failed. Will try again.`)
await delay(1000)
}
}
Expand Down
32 changes: 16 additions & 16 deletions sources/src/caching/gradle-home-extry-extractor.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import path from 'path'
import fs from 'fs'
import * as core from '@actions/core'
import * as glob from '@actions/glob'

import {CacheEntryListener, CacheListener} from './cache-reporting'
import {cacheDebug, hashFileNames, isCacheDebuggingEnabled, restoreCache, saveCache, tryDelete} from './cache-utils'
import {hashFileNames, restoreCache, saveCache, tryDelete} from './cache-utils'

import {log, state} from '../env'
import {BuildResult, loadBuildResults} from '../build-results'
import {CacheConfig, ACTION_METADATA_DIR} from '../configuration'
import {getCacheKeyBase} from './cache-key'
Expand Down Expand Up @@ -107,7 +107,7 @@ abstract class AbstractEntryExtractor {
// Handle case where the extracted-cache-entry definitions have been changed
const skipRestore = process.env[SKIP_RESTORE_VAR] || ''
if (skipRestore.includes(artifactType)) {
core.info(`Not restoring extracted cache entry for ${artifactType}`)
log.info(`Not restoring extracted cache entry for ${artifactType}`)
entryListener.markRequested('SKIP_RESTORE')
} else {
processes.push(
Expand Down Expand Up @@ -136,7 +136,7 @@ abstract class AbstractEntryExtractor {
if (restoredEntry) {
return new ExtractedCacheEntry(artifactType, pattern, cacheKey)
} else {
core.info(`Did not restore ${artifactType} with key ${cacheKey} to ${pattern}`)
log.info(`Did not restore ${artifactType} with key ${cacheKey} to ${pattern}`)
return new ExtractedCacheEntry(artifactType, pattern, undefined)
}
}
Expand All @@ -148,7 +148,7 @@ abstract class AbstractEntryExtractor {
async extract(listener: CacheListener): Promise<void> {
// Load the cache entry definitions (from config) and the previously restored entries (from persisted metadata file)
const cacheEntryDefinitions = this.getExtractedCacheEntryDefinitions()
cacheDebug(
log.cacheDebug(
`Extracting cache entries for ${this.extractorName}: ${JSON.stringify(cacheEntryDefinitions, null, 2)}`
)

Expand All @@ -172,7 +172,7 @@ abstract class AbstractEntryExtractor {
const matchingFiles = await globber.glob()

if (matchingFiles.length === 0) {
cacheDebug(`No files found to cache for ${artifactType}`)
log.cacheDebug(`No files found to cache for ${artifactType}`)
continue
}

Expand Down Expand Up @@ -228,7 +228,7 @@ abstract class AbstractEntryExtractor {
)?.cacheKey

if (previouslyRestoredKey === cacheKey) {
cacheDebug(`No change to previously restored ${artifactType}. Not saving.`)
log.cacheDebug(`No change to previously restored ${artifactType}. Not saving.`)
entryListener.markNotSaved('contents unchanged')
} else {
await saveCache(pattern.split('\n'), cacheKey, entryListener)
Expand All @@ -245,22 +245,22 @@ abstract class AbstractEntryExtractor {
const relativeFiles = files.map(x => path.relative(this.gradleUserHome, x))
const key = hashFileNames(relativeFiles)

cacheDebug(`Generating cache key for ${artifactType} from file names: ${relativeFiles}`)
log.cacheDebug(`Generating cache key for ${artifactType} from file names: ${relativeFiles}`)

return `${getCacheKeyBase(artifactType, CACHE_PROTOCOL_VERSION)}-${key}`
}

protected async createCacheKeyFromFileContents(artifactType: string, pattern: string): Promise<string> {
const key = await glob.hashFiles(pattern)

cacheDebug(`Generating cache key for ${artifactType} from files matching: ${pattern}`)
log.cacheDebug(`Generating cache key for ${artifactType} from files matching: ${pattern}`)

return `${getCacheKeyBase(artifactType, CACHE_PROTOCOL_VERSION)}-${key}`
}

// Run actions sequentially if debugging is enabled
private async awaitForDebugging(p: Promise<ExtractedCacheEntry>): Promise<ExtractedCacheEntry> {
if (isCacheDebuggingEnabled()) {
if (state.isCacheDebuggingEnabled()) {
await p
}
return p
Expand All @@ -276,7 +276,7 @@ abstract class AbstractEntryExtractor {
}

const filedata = fs.readFileSync(cacheMetadataFile, 'utf-8')
cacheDebug(`Loaded cache metadata for ${this.extractorName}: ${filedata}`)
log.cacheDebug(`Loaded cache metadata for ${this.extractorName}: ${filedata}`)
const extractedCacheEntryMetadata = JSON.parse(filedata) as ExtractedCacheEntryMetadata
return extractedCacheEntryMetadata.entries
}
Expand All @@ -289,7 +289,7 @@ abstract class AbstractEntryExtractor {
extractedCacheEntryMetadata.entries = results.filter(x => x.cacheKey !== undefined)

const filedata = JSON.stringify(extractedCacheEntryMetadata)
cacheDebug(`Saving cache metadata for ${this.extractorName}: ${filedata}`)
log.cacheDebug(`Saving cache metadata for ${this.extractorName}: ${filedata}`)

fs.writeFileSync(this.getCacheMetadataFile(), filedata, 'utf-8')
}
Expand Down Expand Up @@ -325,7 +325,7 @@ export class GradleHomeEntryExtractor extends AbstractEntryExtractor {
})

for (const wrapperZip of await globber.glob()) {
cacheDebug(`Deleting wrapper zip: ${wrapperZip}`)
log.cacheDebug(`Deleting wrapper zip: ${wrapperZip}`)
await tryDelete(wrapperZip)
}
}
Expand Down Expand Up @@ -389,7 +389,7 @@ export class ConfigurationCacheEntryExtractor extends AbstractEntryExtractor {
private markNotRestored(listener: CacheListener, reason: string): void {
const cacheEntries = this.loadExtractedCacheEntries()
if (cacheEntries.length > 0) {
core.info(`Not restoring configuration-cache state, as ${reason}`)
log.info(`Not restoring configuration-cache state, as ${reason}`)
for (const cacheEntry of cacheEntries) {
listener.entry(cacheEntry.pattern).markNotRestored(reason)
}
Expand All @@ -403,7 +403,7 @@ export class ConfigurationCacheEntryExtractor extends AbstractEntryExtractor {
if (!this.cacheConfig.getCacheEncryptionKey()) {
const cacheEntryDefinitions = this.getExtractedCacheEntryDefinitions()
if (cacheEntryDefinitions.length > 0) {
core.info('Not saving configuration-cache state, as no encryption key was provided')
log.info('Not saving configuration-cache state, as no encryption key was provided')
for (const cacheEntry of cacheEntryDefinitions) {
listener.entry(cacheEntry.pattern).markNotSaved('No encryption key provided')
}
Expand Down Expand Up @@ -435,7 +435,7 @@ export class ConfigurationCacheEntryExtractor extends AbstractEntryExtractor {
return !versionIsAtLeast(result.gradleVersion, '8.6.0')
})
) {
core.info(
log.info(
`Not saving config-cache data for ${configCachePath}. Configuration cache data is only saved for Gradle 8.6+`
)
definition.notCacheableBecause('Configuration cache data only saved for Gradle 8.6+')
Expand Down
Loading

0 comments on commit 7ce7dd5

Please sign in to comment.