From cfd20ecc0a3d198b556d3737da8cf1d7e8a4830a Mon Sep 17 00:00:00 2001 From: daz Date: Sat, 6 Apr 2024 20:37:46 -0600 Subject: [PATCH] Replace static config methods with config types This will allow different entry points to have different inputs. --- sources/src/build-scan.ts | 22 +- sources/src/cache-base.ts | 24 +- sources/src/cache-extract-entries.ts | 31 +- sources/src/cache-utils.ts | 35 +-- sources/src/caches.ts | 36 +-- sources/src/dependency-graph.ts | 62 +--- sources/src/dependency-submission/main.ts | 9 +- sources/src/dependency-submission/post.ts | 6 +- sources/src/input-params.ts | 330 +++++++++++++-------- sources/src/job-summary.ts | 46 +-- sources/src/provision.ts | 9 +- sources/src/setup-gradle.ts | 13 +- sources/src/setup-gradle/main.ts | 8 +- sources/src/setup-gradle/post.ts | 6 +- sources/test/jest/cache-debug.test.ts | 7 +- sources/test/jest/dependency-graph.test.ts | 16 +- 16 files changed, 337 insertions(+), 323 deletions(-) diff --git a/sources/src/build-scan.ts b/sources/src/build-scan.ts index 2115e78..fbb1771 100644 --- a/sources/src/build-scan.ts +++ b/sources/src/build-scan.ts @@ -1,30 +1,18 @@ import * as core from '@actions/core' -import {getBuildScanPublishEnabled, getBuildScanTermsOfUseUrl, getBuildScanTermsOfUseAgree} from './input-params' +import {BuildScanConfig} from './input-params' -export function setup(): void { +export function setup(config: BuildScanConfig): void { maybeExportVariable('DEVELOCITY_INJECTION_INIT_SCRIPT_NAME', 'gradle-actions.inject-develocity.init.gradle') maybeExportVariable('DEVELOCITY_AUTO_INJECTION_CUSTOM_VALUE', 'gradle-actions') - if (getBuildScanPublishEnabled() && verifyTermsOfUseAgreement()) { + if (config.getBuildScanPublishEnabled()) { maybeExportVariable('DEVELOCITY_INJECTION_ENABLED', 'true') maybeExportVariable('DEVELOCITY_PLUGIN_VERSION', '3.17') maybeExportVariable('DEVELOCITY_CCUD_PLUGIN_VERSION', '1.13') - maybeExportVariable('DEVELOCITY_TERMS_OF_USE_URL', getBuildScanTermsOfUseUrl()) - maybeExportVariable('DEVELOCITY_TERMS_OF_USE_AGREE', getBuildScanTermsOfUseAgree()) + maybeExportVariable('DEVELOCITY_TERMS_OF_USE_URL', config.getBuildScanTermsOfUseUrl()) + maybeExportVariable('DEVELOCITY_TERMS_OF_USE_AGREE', config.getBuildScanTermsOfUseAgree()) } } -function verifyTermsOfUseAgreement(): boolean { - if ( - (getBuildScanTermsOfUseUrl() !== 'https://gradle.com/terms-of-service' && - getBuildScanTermsOfUseUrl() !== 'https://gradle.com/help/legal-terms-of-use') || - getBuildScanTermsOfUseAgree() !== 'yes' - ) { - core.warning(`Terms of use must be agreed in order to publish build scans.`) - return false - } - return true -} - function maybeExportVariable(variableName: string, value: unknown): void { if (!process.env[variableName]) { core.exportVariable(variableName, value) diff --git a/sources/src/cache-base.ts b/sources/src/cache-base.ts index 4a7905c..8cce377 100644 --- a/sources/src/cache-base.ts +++ b/sources/src/cache-base.ts @@ -4,7 +4,7 @@ import * as glob from '@actions/glob' import path from 'path' import fs from 'fs' -import * as params from './input-params' +import {CacheConfig} from './input-params' import {CacheListener} from './cache-reporting' import {saveCache, restoreCache, cacheDebug, isCacheDebuggingEnabled, tryDelete, generateCacheKey} from './cache-utils' import {GradleHomeEntryExtractor, ConfigurationCacheEntryExtractor} from './cache-extract-entries' @@ -14,15 +14,17 @@ const RESTORED_CACHE_KEY_KEY = 'restored-cache-key' export const META_FILE_DIR = '.setup-gradle' export class GradleStateCache { + private cacheConfig: CacheConfig private cacheName: string private cacheDescription: string protected readonly userHome: string protected readonly gradleUserHome: string - constructor(userHome: string, gradleUserHome: string) { + constructor(userHome: string, gradleUserHome: string, cacheConfig: CacheConfig) { this.userHome = userHome this.gradleUserHome = gradleUserHome + this.cacheConfig = cacheConfig this.cacheName = 'gradle' this.cacheDescription = 'Gradle User Home' } @@ -31,7 +33,7 @@ export class GradleStateCache { this.initializeGradleUserHome() // Export the GRADLE_ENCRYPTION_KEY variable if provided - const encryptionKey = params.getCacheEncryptionKey() + const encryptionKey = this.cacheConfig.getCacheEncryptionKey() if (encryptionKey) { core.exportVariable('GRADLE_ENCRYPTION_KEY', encryptionKey) } @@ -52,7 +54,7 @@ export class GradleStateCache { async restore(listener: CacheListener): Promise { const entryListener = listener.entry(this.cacheDescription) - const cacheKey = generateCacheKey(this.cacheName) + const cacheKey = generateCacheKey(this.cacheName, this.cacheConfig) cacheDebug( `Requesting ${this.cacheDescription} with @@ -82,8 +84,8 @@ export class GradleStateCache { */ async afterRestore(listener: CacheListener): Promise { await this.debugReportGradleUserHomeSize('as restored from cache') - await new GradleHomeEntryExtractor(this.gradleUserHome).restore(listener) - await new ConfigurationCacheEntryExtractor(this.gradleUserHome).restore(listener) + await new GradleHomeEntryExtractor(this.gradleUserHome, this.cacheConfig).restore(listener) + await new ConfigurationCacheEntryExtractor(this.gradleUserHome, this.cacheConfig).restore(listener) await this.debugReportGradleUserHomeSize('after restoring common artifacts') } @@ -95,7 +97,7 @@ export class GradleStateCache { * it is saved with the exact key. */ async save(listener: CacheListener): Promise { - const cacheKey = generateCacheKey(this.cacheName).key + const cacheKey = generateCacheKey(this.cacheName, this.cacheConfig).key const restoredCacheKey = core.getState(RESTORED_CACHE_KEY_KEY) const gradleHomeEntryListener = listener.entry(this.cacheDescription) @@ -133,8 +135,8 @@ export class GradleStateCache { await this.debugReportGradleUserHomeSize('before saving common artifacts') await this.deleteExcludedPaths() await Promise.all([ - new GradleHomeEntryExtractor(this.gradleUserHome).extract(listener), - new ConfigurationCacheEntryExtractor(this.gradleUserHome).extract(listener) + new GradleHomeEntryExtractor(this.gradleUserHome, this.cacheConfig).extract(listener), + new ConfigurationCacheEntryExtractor(this.gradleUserHome, this.cacheConfig).extract(listener) ]) await this.debugReportGradleUserHomeSize( "after extracting common artifacts (only 'caches' and 'notifications' will be stored)" @@ -145,7 +147,7 @@ export class GradleStateCache { * Delete any file paths that are excluded by the `gradle-home-cache-excludes` parameter. */ private async deleteExcludedPaths(): Promise { - const rawPaths: string[] = params.getCacheExcludes() + const rawPaths: string[] = this.cacheConfig.getCacheExcludes() rawPaths.push('caches/*/cc-keystore') const resolvedPaths = rawPaths.map(x => path.resolve(this.gradleUserHome, x)) @@ -168,7 +170,7 @@ export class GradleStateCache { * but this can be overridden by the `gradle-home-cache-includes` parameter. */ protected getCachePath(): string[] { - const rawPaths: string[] = params.getCacheIncludes() + const rawPaths: string[] = this.cacheConfig.getCacheIncludes() rawPaths.push(META_FILE_DIR) const resolvedPaths = rawPaths.map(x => this.resolveCachePath(x)) cacheDebug(`Using cache paths: ${resolvedPaths}`) diff --git a/sources/src/cache-extract-entries.ts b/sources/src/cache-extract-entries.ts index dc2dd96..baf03af 100644 --- a/sources/src/cache-extract-entries.ts +++ b/sources/src/cache-extract-entries.ts @@ -4,12 +4,19 @@ import * as core from '@actions/core' import * as glob from '@actions/glob' import * as semver from 'semver' -import * as params from './input-params' - import {META_FILE_DIR} from './cache-base' import {CacheEntryListener, CacheListener} from './cache-reporting' -import {cacheDebug, getCacheKeyPrefix, hashFileNames, restoreCache, saveCache, tryDelete} from './cache-utils' +import { + cacheDebug, + getCacheKeyPrefix, + hashFileNames, + isCacheDebuggingEnabled, + restoreCache, + saveCache, + tryDelete +} from './cache-utils' import {BuildResult, loadBuildResults} from './build-results' +import {CacheConfig} from './input-params' const SKIP_RESTORE_VAR = 'GRADLE_BUILD_ACTION_SKIP_RESTORE' @@ -80,12 +87,14 @@ class ExtractedCacheEntryDefinition { * for more efficient storage. */ abstract class AbstractEntryExtractor { + protected readonly cacheConfig: CacheConfig protected readonly gradleUserHome: string private extractorName: string - constructor(gradleUserHome: string, extractorName: string) { + constructor(gradleUserHome: string, extractorName: string, cacheConfig: CacheConfig) { this.gradleUserHome = gradleUserHome this.extractorName = extractorName + this.cacheConfig = cacheConfig } /** @@ -261,7 +270,7 @@ abstract class AbstractEntryExtractor { // Run actions sequentially if debugging is enabled private async awaitForDebugging(p: Promise): Promise { - if (params.isCacheDebuggingEnabled()) { + if (isCacheDebuggingEnabled()) { await p } return p @@ -306,8 +315,8 @@ abstract class AbstractEntryExtractor { } export class GradleHomeEntryExtractor extends AbstractEntryExtractor { - constructor(gradleUserHome: string) { - super(gradleUserHome, 'gradle-home') + constructor(gradleUserHome: string, cacheConfig: CacheConfig) { + super(gradleUserHome, 'gradle-home', cacheConfig) } async extract(listener: CacheListener): Promise { @@ -363,8 +372,8 @@ export class GradleHomeEntryExtractor extends AbstractEntryExtractor { } export class ConfigurationCacheEntryExtractor extends AbstractEntryExtractor { - constructor(gradleUserHome: string) { - super(gradleUserHome, 'configuration-cache') + constructor(gradleUserHome: string, cacheConfig: CacheConfig) { + super(gradleUserHome, 'configuration-cache', cacheConfig) } /** @@ -377,7 +386,7 @@ export class ConfigurationCacheEntryExtractor extends AbstractEntryExtractor { return } - if (!params.getCacheEncryptionKey()) { + if (!this.cacheConfig.getCacheEncryptionKey()) { this.markNotRestored(listener, 'Encryption Key was not provided') return } @@ -399,7 +408,7 @@ export class ConfigurationCacheEntryExtractor extends AbstractEntryExtractor { } async extract(listener: CacheListener): Promise { - if (!params.getCacheEncryptionKey()) { + 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') diff --git a/sources/src/cache-utils.ts b/sources/src/cache-utils.ts index 953254d..2759b70 100644 --- a/sources/src/cache-utils.ts +++ b/sources/src/cache-utils.ts @@ -7,9 +7,8 @@ import * as crypto from 'crypto' import * as path from 'path' import * as fs from 'fs' -import * as params from './input-params' - import {CacheEntryListener} from './cache-reporting' +import {CacheConfig, getJobMatrix} from './input-params' const CACHE_PROTOCOL_VERSION = 'v9-' @@ -22,31 +21,11 @@ const CACHE_KEY_JOB_EXECUTION_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_JOB_EXECUTION const SEGMENT_DOWNLOAD_TIMEOUT_VAR = 'SEGMENT_DOWNLOAD_TIMEOUT_MINS' const SEGMENT_DOWNLOAD_TIMEOUT_DEFAULT = 10 * 60 * 1000 // 10 minutes -export function isCacheDisabled(): boolean { - if (!cache.isFeatureAvailable()) { +export function isCacheDebuggingEnabled(): boolean { + if (core.isDebug()) { return true } - return params.isCacheDisabled() -} - -export function isCacheReadOnly(): boolean { - return !isCacheWriteOnly() && params.isCacheReadOnly() -} - -export function isCacheWriteOnly(): boolean { - return params.isCacheWriteOnly() -} - -export function isCacheOverwriteExisting(): boolean { - return params.isCacheOverwriteExisting() -} - -export function isCacheDebuggingEnabled(): boolean { - return params.isCacheDebuggingEnabled() -} - -export function isCacheCleanupEnabled(): boolean { - return params.isCacheCleanupEnabled() + return process.env['GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED'] ? true : false } /** @@ -80,7 +59,7 @@ export class CacheKey { * - Any previous key for this Job (any matrix) * - Any previous key for this cache on the current OS */ -export function generateCacheKey(cacheName: string): CacheKey { +export function generateCacheKey(cacheName: string, config: CacheConfig): CacheKey { const cacheKeyBase = `${getCacheKeyPrefix()}${CACHE_PROTOCOL_VERSION}${cacheName}` // At the most general level, share caches for all executions on the same OS @@ -95,7 +74,7 @@ export function generateCacheKey(cacheName: string): CacheKey { // Exact match on Git SHA const cacheKey = `${cacheKeyForJobContext}-${getCacheKeyJobExecution()}` - if (params.isCacheStrictMatch()) { + if (config.isCacheStrictMatch()) { return new CacheKey(cacheKey, [cacheKeyForJobContext]) } @@ -125,7 +104,7 @@ function getCacheKeyJobInstance(): string { // By default, we hash the workflow name and the full `matrix` data for the run, to uniquely identify this job invocation // The only way we can obtain the `matrix` data is via the `workflow-job-context` parameter in action.yml. const workflowName = github.context.workflow - const workflowJobContext = params.getJobMatrix() + const workflowJobContext = getJobMatrix() return hashStrings([workflowName, workflowJobContext]) } diff --git a/sources/src/caches.ts b/sources/src/caches.ts index 2980444..d2b8ebe 100644 --- a/sources/src/caches.ts +++ b/sources/src/caches.ts @@ -1,19 +1,18 @@ import * as core from '@actions/core' -import { - isCacheCleanupEnabled, - isCacheDisabled, - isCacheReadOnly, - isCacheWriteOnly, - isCacheOverwriteExisting -} from './cache-utils' import {CacheListener} from './cache-reporting' import {DaemonController} from './daemon-controller' import {GradleStateCache} from './cache-base' import {CacheCleaner} from './cache-cleaner' +import {CacheConfig} from './input-params' const CACHE_RESTORED_VAR = 'GRADLE_BUILD_ACTION_CACHE_RESTORED' -export async function restore(userHome: string, gradleUserHome: string, cacheListener: CacheListener): Promise { +export async function restore( + userHome: string, + gradleUserHome: string, + cacheListener: CacheListener, + cacheConfig: CacheConfig +): Promise { // Bypass restore cache on all but first action step in workflow. if (process.env[CACHE_RESTORED_VAR]) { core.info('Cache only restored on first action step.') @@ -21,9 +20,9 @@ export async function restore(userHome: string, gradleUserHome: string, cacheLis } core.exportVariable(CACHE_RESTORED_VAR, true) - const gradleStateCache = new GradleStateCache(userHome, gradleUserHome) + const gradleStateCache = new GradleStateCache(userHome, gradleUserHome, cacheConfig) - if (isCacheDisabled()) { + if (cacheConfig.isCacheDisabled()) { core.info('Cache is disabled: will not restore state from previous builds.') // Initialize the Gradle User Home even when caching is disabled. gradleStateCache.init() @@ -32,7 +31,7 @@ export async function restore(userHome: string, gradleUserHome: string, cacheLis } if (gradleStateCache.cacheOutputExists()) { - if (!isCacheOverwriteExisting()) { + if (!cacheConfig.isCacheOverwriteExisting()) { core.info('Gradle User Home already exists: will not restore from cache.') // Initialize pre-existing Gradle User Home. gradleStateCache.init() @@ -47,7 +46,7 @@ export async function restore(userHome: string, gradleUserHome: string, cacheLis // Mark the state as restored so that post-action will perform save. core.saveState(CACHE_RESTORED_VAR, true) - if (isCacheWriteOnly()) { + if (cacheConfig.isCacheWriteOnly()) { core.info('Cache is write-only: will not restore from cache.') cacheListener.cacheWriteOnly = true return @@ -57,7 +56,7 @@ export async function restore(userHome: string, gradleUserHome: string, cacheLis await gradleStateCache.restore(cacheListener) }) - if (isCacheCleanupEnabled() && !isCacheReadOnly()) { + if (cacheConfig.isCacheCleanupEnabled()) { core.info('Preparing cache for cleanup.') const cacheCleaner = new CacheCleaner(gradleUserHome, process.env['RUNNER_TEMP']!) await cacheCleaner.prepare() @@ -68,9 +67,10 @@ export async function save( userHome: string, gradleUserHome: string, cacheListener: CacheListener, - daemonController: DaemonController + daemonController: DaemonController, + cacheConfig: CacheConfig ): Promise { - if (isCacheDisabled()) { + if (cacheConfig.isCacheDisabled()) { core.info('Cache is disabled: will not save state for later builds.') return } @@ -80,7 +80,7 @@ export async function save( return } - if (isCacheReadOnly()) { + if (cacheConfig.isCacheReadOnly()) { core.info('Cache is read-only: will not save state for use in subsequent builds.') cacheListener.cacheReadOnly = true return @@ -88,7 +88,7 @@ export async function save( await daemonController.stopAllDaemons() - if (isCacheCleanupEnabled()) { + if (cacheConfig.isCacheCleanupEnabled()) { core.info('Forcing cache cleanup.') const cacheCleaner = new CacheCleaner(gradleUserHome, process.env['RUNNER_TEMP']!) try { @@ -99,6 +99,6 @@ export async function save( } await core.group('Caching Gradle state', async () => { - return new GradleStateCache(userHome, gradleUserHome).save(cacheListener) + return new GradleStateCache(userHome, gradleUserHome, cacheConfig).save(cacheListener) }) } diff --git a/sources/src/dependency-graph.ts b/sources/src/dependency-graph.ts index a832bd1..a539924 100644 --- a/sources/src/dependency-graph.ts +++ b/sources/src/dependency-graph.ts @@ -11,31 +11,26 @@ import fs from 'fs' import * as layout from './repository-layout' import {PostActionJobFailure} from './errors' -import { - DependencyGraphOption, - getDependencyGraphContinueOnFailure, - getGithubToken, - getJobMatrix, - getArtifactRetentionDays -} from './input-params' +import {DependencyGraphConfig, DependencyGraphOption, getGithubToken} from './input-params' const DEPENDENCY_GRAPH_PREFIX = 'dependency-graph_' -export async function setup(option: DependencyGraphOption): Promise { +export async function setup(config: DependencyGraphConfig): Promise { + const option = config.getDependencyGraphOption() if (option === DependencyGraphOption.Disabled) { core.exportVariable('GITHUB_DEPENDENCY_GRAPH_ENABLED', 'false') return } // Download and submit early, for compatability with dependency review. if (option === DependencyGraphOption.DownloadAndSubmit) { - await downloadAndSubmitDependencyGraphs() + await downloadAndSubmitDependencyGraphs(config) return } core.info('Enabling dependency graph generation') core.exportVariable('GITHUB_DEPENDENCY_GRAPH_ENABLED', 'true') - maybeExportVariable('GITHUB_DEPENDENCY_GRAPH_CONTINUE_ON_FAILURE', getDependencyGraphContinueOnFailure()) - maybeExportVariable('GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR', getJobCorrelator()) + maybeExportVariable('GITHUB_DEPENDENCY_GRAPH_CONTINUE_ON_FAILURE', config.getDependencyGraphContinueOnFailure()) + maybeExportVariable('GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR', config.getJobCorrelator()) maybeExportVariable('GITHUB_DEPENDENCY_GRAPH_JOB_ID', github.context.runId) maybeExportVariable('GITHUB_DEPENDENCY_GRAPH_REF', github.context.ref) maybeExportVariable('GITHUB_DEPENDENCY_GRAPH_SHA', getShaFromContext()) @@ -58,12 +53,13 @@ function maybeExportVariable(variableName: string, value: unknown): void { } } -export async function complete(option: DependencyGraphOption): Promise { +export async function complete(config: DependencyGraphConfig): Promise { if (isRunningInActEnvironment()) { core.info('Dependency graph upload and submit not supported in the ACT environment.') return } + const option = config.getDependencyGraphOption() try { switch (option) { case DependencyGraphOption.Disabled: @@ -75,10 +71,10 @@ export async function complete(option: DependencyGraphOption): Promise { await submitDependencyGraphs(await findGeneratedDependencyGraphFiles()) return case DependencyGraphOption.GenerateAndUpload: - await uploadDependencyGraphs(await findGeneratedDependencyGraphFiles()) + await uploadDependencyGraphs(await findGeneratedDependencyGraphFiles(), config) } } catch (e) { - warnOrFail(option, e) + warnOrFail(config, option, e) } } @@ -87,7 +83,7 @@ async function findGeneratedDependencyGraphFiles(): Promise { return await findDependencyGraphFiles(workspaceDirectory) } -async function uploadDependencyGraphs(dependencyGraphFiles: string[]): Promise { +async function uploadDependencyGraphs(dependencyGraphFiles: string[], config: DependencyGraphConfig): Promise { const workspaceDirectory = layout.workspaceDirectory() const artifactClient = new DefaultArtifactClient() @@ -96,12 +92,12 @@ async function uploadDependencyGraphs(dependencyGraphFiles: string[]): Promise { +async function downloadAndSubmitDependencyGraphs(config: DependencyGraphConfig): Promise { if (isRunningInActEnvironment()) { core.info('Dependency graph download and submit not supported in the ACT environment.') return @@ -110,7 +106,7 @@ async function downloadAndSubmitDependencyGraphs(): Promise { try { await submitDependencyGraphs(await downloadDependencyGraphs()) } catch (e) { - warnOrFail(DependencyGraphOption.DownloadAndSubmit, e) + warnOrFail(config, DependencyGraphOption.DownloadAndSubmit, e) } } @@ -192,8 +188,8 @@ async function findDependencyGraphFiles(dir: string): Promise { return graphFiles } -function warnOrFail(option: String, error: unknown): void { - if (!getDependencyGraphContinueOnFailure()) { +function warnOrFail(config: DependencyGraphConfig, option: String, error: unknown): void { + if (!config.getDependencyGraphContinueOnFailure()) { throw new PostActionJobFailure(error) } @@ -228,32 +224,6 @@ function getShaFromContext(): string { } } -function getJobCorrelator(): string { - return constructJobCorrelator(github.context.workflow, github.context.job, getJobMatrix()) -} - -export function constructJobCorrelator(workflow: string, jobId: string, matrixJson: string): string { - const matrixString = describeMatrix(matrixJson) - const label = matrixString ? `${workflow}-${jobId}-${matrixString}` : `${workflow}-${jobId}` - return sanitize(label) -} - -function describeMatrix(matrixJson: string): string { - core.debug(`Got matrix json: ${matrixJson}`) - const matrix = JSON.parse(matrixJson) - if (matrix) { - return Object.values(matrix).join('-') - } - return '' -} - -function sanitize(value: string): string { - return value - .replace(/[^a-zA-Z0-9_-\s]/g, '') - .replace(/\s+/g, '_') - .toLowerCase() -} - function isRunningInActEnvironment(): boolean { return process.env.ACT !== undefined } diff --git a/sources/src/dependency-submission/main.ts b/sources/src/dependency-submission/main.ts index cfbb688..e9e5110 100644 --- a/sources/src/dependency-submission/main.ts +++ b/sources/src/dependency-submission/main.ts @@ -7,7 +7,7 @@ import * as layout from '../repository-layout' import * as dependencyGraph from '../dependency-graph' import {parseArgsStringToArgv} from 'string-argv' -import {DependencyGraphOption, getDependencyGraphOption} from '../input-params' +import {BuildScanConfig, CacheConfig, DependencyGraphConfig, DependencyGraphOption} from '../input-params' /** * The main entry point for the action, called by Github Actions for the step. @@ -15,12 +15,13 @@ import {DependencyGraphOption, getDependencyGraphOption} from '../input-params' export async function run(): Promise { try { // Configure Gradle environment (Gradle User Home) - await setupGradle.setup() + await setupGradle.setup(new CacheConfig(), new BuildScanConfig()) // Configure the dependency graph submission - await dependencyGraph.setup(getDependencyGraphOption()) + const config = new DependencyGraphConfig() + await dependencyGraph.setup(config) - if (getDependencyGraphOption() === DependencyGraphOption.DownloadAndSubmit) { + if (config.getDependencyGraphOption() === DependencyGraphOption.DownloadAndSubmit) { // No execution to perform return } diff --git a/sources/src/dependency-submission/post.ts b/sources/src/dependency-submission/post.ts index 83efab1..d1b99ba 100644 --- a/sources/src/dependency-submission/post.ts +++ b/sources/src/dependency-submission/post.ts @@ -2,7 +2,7 @@ import * as core from '@actions/core' import * as setupGradle from '../setup-gradle' import * as dependencyGraph from '../dependency-graph' -import {getDependencyGraphOption} from '../input-params' +import {CacheConfig, DependencyGraphConfig, SummaryConfig} from '../input-params' import {PostActionJobFailure} from '../errors' // Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in @@ -15,9 +15,9 @@ process.on('uncaughtException', e => handleFailure(e)) */ export async function run(): Promise { try { - if (await setupGradle.complete()) { + if (await setupGradle.complete(new CacheConfig(), new SummaryConfig())) { // Only submit the dependency graphs once per job - await dependencyGraph.complete(getDependencyGraphOption()) + await dependencyGraph.complete(new DependencyGraphConfig()) } } catch (error) { if (error instanceof PostActionJobFailure) { diff --git a/sources/src/input-params.ts b/sources/src/input-params.ts index cfaff3a..bd9449a 100644 --- a/sources/src/input-params.ts +++ b/sources/src/input-params.ts @@ -1,54 +1,234 @@ import * as core from '@actions/core' +import * as github from '@actions/github' +import * as cache from '@actions/cache' +import {SUMMARY_ENV_VAR} from '@actions/core/lib/summary' + import {parseArgsStringToArgv} from 'string-argv' -export function isCacheDisabled(): boolean { - return getBooleanInput('cache-disabled') +export class DependencyGraphConfig { + getDependencyGraphOption(): DependencyGraphOption { + const val = core.getInput('dependency-graph') + switch (val.toLowerCase().trim()) { + case 'disabled': + return DependencyGraphOption.Disabled + case 'generate': + return DependencyGraphOption.Generate + case 'generate-and-submit': + return DependencyGraphOption.GenerateAndSubmit + case 'generate-and-upload': + return DependencyGraphOption.GenerateAndUpload + case 'download-and-submit': + return DependencyGraphOption.DownloadAndSubmit + case 'clear': + return DependencyGraphOption.Clear + } + throw TypeError( + `The value '${val}' is not valid for 'dependency-graph'. Valid values are: [disabled, generate, generate-and-submit, generate-and-upload, download-and-submit, clear]. The default value is 'disabled'.` + ) + } + + getDependencyGraphContinueOnFailure(): boolean { + return getBooleanInput('dependency-graph-continue-on-failure', true) + } + + getArtifactRetentionDays(): number { + const val = core.getInput('artifact-retention-days') + return parseNumericInput('artifact-retention-days', val, 0) + // Zero indicates that the default repository settings should be used + } + + getJobCorrelator(): string { + return DependencyGraphConfig.constructJobCorrelator(github.context.workflow, github.context.job, getJobMatrix()) + } + + static constructJobCorrelator(workflow: string, jobId: string, matrixJson: string): string { + const matrixString = this.describeMatrix(matrixJson) + const label = matrixString ? `${workflow}-${jobId}-${matrixString}` : `${workflow}-${jobId}` + return this.sanitize(label) + } + + private static describeMatrix(matrixJson: string): string { + core.debug(`Got matrix json: ${matrixJson}`) + const matrix = JSON.parse(matrixJson) + if (matrix) { + return Object.values(matrix).join('-') + } + return '' + } + + private static sanitize(value: string): string { + return value + .replace(/[^a-zA-Z0-9_-\s]/g, '') + .replace(/\s+/g, '_') + .toLowerCase() + } } -export function isCacheReadOnly(): boolean { - return getBooleanInput('cache-read-only') +export enum DependencyGraphOption { + Disabled = 'disabled', + Generate = 'generate', + GenerateAndSubmit = 'generate-and-submit', + GenerateAndUpload = 'generate-and-upload', + DownloadAndSubmit = 'download-and-submit', + Clear = 'clear' } -export function isCacheWriteOnly(): boolean { - return getBooleanInput('cache-write-only') +export class CacheConfig { + isCacheDisabled(): boolean { + if (!cache.isFeatureAvailable()) { + return true + } + + return getBooleanInput('cache-disabled') + } + + isCacheReadOnly(): boolean { + return !this.isCacheWriteOnly() && getBooleanInput('cache-read-only') + } + + isCacheWriteOnly(): boolean { + return getBooleanInput('cache-write-only') + } + + isCacheOverwriteExisting(): boolean { + return getBooleanInput('cache-overwrite-existing') + } + + isCacheStrictMatch(): boolean { + return getBooleanInput('gradle-home-cache-strict-match') + } + + isCacheCleanupEnabled(): boolean { + return getBooleanInput('gradle-home-cache-cleanup') && !this.isCacheReadOnly() + } + + getCacheEncryptionKey(): string { + return core.getInput('cache-encryption-key') + } + + getCacheIncludes(): string[] { + return core.getMultilineInput('gradle-home-cache-includes') + } + + getCacheExcludes(): string[] { + return core.getMultilineInput('gradle-home-cache-excludes') + } } -export function isCacheOverwriteExisting(): boolean { - return getBooleanInput('cache-overwrite-existing') +export class SummaryConfig { + shouldGenerateJobSummary(hasFailure: boolean): boolean { + // Check if Job Summary is supported on this platform + if (!process.env[SUMMARY_ENV_VAR]) { + return false + } + + // Check if Job Summary is disabled using the deprecated input + if (!this.isJobSummaryEnabled()) { + return false + } + + return this.shouldAddJobSummary(this.getJobSummaryOption(), hasFailure) + } + + shouldAddPRComment(hasFailure: boolean): boolean { + return this.shouldAddJobSummary(this.getPRCommentOption(), hasFailure) + } + + private shouldAddJobSummary(option: JobSummaryOption, hasFailure: boolean): boolean { + switch (option) { + case JobSummaryOption.Always: + return true + case JobSummaryOption.Never: + return false + case JobSummaryOption.OnFailure: + return hasFailure + } + } + + private isJobSummaryEnabled(): boolean { + return getBooleanInput('generate-job-summary', true) + } + + private getJobSummaryOption(): JobSummaryOption { + return this.parseJobSummaryOption('add-job-summary') + } + + private getPRCommentOption(): JobSummaryOption { + return this.parseJobSummaryOption('add-job-summary-as-pr-comment') + } + + private parseJobSummaryOption(paramName: string): JobSummaryOption { + const val = core.getInput(paramName) + switch (val.toLowerCase().trim()) { + case 'never': + return JobSummaryOption.Never + case 'always': + return JobSummaryOption.Always + case 'on-failure': + return JobSummaryOption.OnFailure + } + throw TypeError( + `The value '${val}' is not valid for ${paramName}. Valid values are: [never, always, on-failure].` + ) + } } -export function isCacheStrictMatch(): boolean { - return getBooleanInput('gradle-home-cache-strict-match') +export enum JobSummaryOption { + Never = 'never', + Always = 'always', + OnFailure = 'on-failure' } -export function isCacheDebuggingEnabled(): boolean { - return process.env['GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED'] ? true : false -} +export class BuildScanConfig { + getBuildScanPublishEnabled(): boolean { + if (!this.verifyTermsOfUseAgreement()) { + return false + } + return getBooleanInput('build-scan-publish') && this.verifyTermsOfUseAgreement() + } -export function isCacheCleanupEnabled(): boolean { - return getBooleanInput('gradle-home-cache-cleanup') -} + getBuildScanTermsOfUseUrl(): string { + return this.getTermsOfUseProp('build-scan-terms-of-use-url', 'build-scan-terms-of-service-url') + } -export function getCacheEncryptionKey(): string { - return core.getInput('cache-encryption-key') -} + getBuildScanTermsOfUseAgree(): string { + return this.getTermsOfUseProp('build-scan-terms-of-use-agree', 'build-scan-terms-of-service-agree') + } -export function getCacheIncludes(): string[] { - return core.getMultilineInput('gradle-home-cache-includes') -} + private verifyTermsOfUseAgreement(): boolean { + if ( + (this.getBuildScanTermsOfUseUrl() !== 'https://gradle.com/terms-of-service' && + this.getBuildScanTermsOfUseUrl() !== 'https://gradle.com/help/legal-terms-of-use') || + this.getBuildScanTermsOfUseAgree() !== 'yes' + ) { + core.warning( + `Terms of use at 'https://gradle.com/help/legal-terms-of-use' must be agreed in order to publish build scans.` + ) + return false + } + return true + } -export function getCacheExcludes(): string[] { - return core.getMultilineInput('gradle-home-cache-excludes') -} - -export function getBuildRootDirectory(): string { - return core.getInput('build-root-directory') + /** + * TODO @bigdaz: remove support for the deprecated input property in the next major release of the action + */ + private getTermsOfUseProp(newPropName: string, oldPropName: string): string { + const newProp = core.getInput(newPropName) + if (newProp !== '') { + return newProp + } + return core.getInput(oldPropName) + } } export function getGradleVersion(): string { return core.getInput('gradle-version') } +export function getBuildRootDirectory(): string { + return core.getInput('build-root-directory') +} + export function getArguments(): string[] { const input = core.getInput('arguments') return parseArgsStringToArgv(input) @@ -63,85 +243,6 @@ export function getGithubToken(): string { return core.getInput('github-token', {required: true}) } -export function isJobSummaryEnabled(): boolean { - return getBooleanInput('generate-job-summary', true) -} - -export function getJobSummaryOption(): JobSummaryOption { - return parseJobSummaryOption('add-job-summary') -} - -export function getPRCommentOption(): JobSummaryOption { - return parseJobSummaryOption('add-job-summary-as-pr-comment') -} - -export function getBuildScanPublishEnabled(): boolean { - return getBooleanInput('build-scan-publish') -} - -export function getBuildScanTermsOfUseUrl(): string { - return getTermsOfUseProp('build-scan-terms-of-use-url', 'build-scan-terms-of-service-url') -} - -export function getBuildScanTermsOfUseAgree(): string { - return getTermsOfUseProp('build-scan-terms-of-use-agree', 'build-scan-terms-of-service-agree') -} - -/** - * TODO @bigdaz: remove the deprecated input property in the next major release of the action - */ -function getTermsOfUseProp(newPropName: string, oldPropName: string): string { - const newProp = core.getInput(newPropName) - if (newProp !== '') { - return newProp - } - return core.getInput(oldPropName) -} - -function parseJobSummaryOption(paramName: string): JobSummaryOption { - const val = core.getInput(paramName) - switch (val.toLowerCase().trim()) { - case 'never': - return JobSummaryOption.Never - case 'always': - return JobSummaryOption.Always - case 'on-failure': - return JobSummaryOption.OnFailure - } - throw TypeError(`The value '${val}' is not valid for ${paramName}. Valid values are: [never, always, on-failure].`) -} - -export function getDependencyGraphOption(): DependencyGraphOption { - const val = core.getInput('dependency-graph') - switch (val.toLowerCase().trim()) { - case 'disabled': - return DependencyGraphOption.Disabled - case 'generate': - return DependencyGraphOption.Generate - case 'generate-and-submit': - return DependencyGraphOption.GenerateAndSubmit - case 'generate-and-upload': - return DependencyGraphOption.GenerateAndUpload - case 'download-and-submit': - return DependencyGraphOption.DownloadAndSubmit - case 'clear': - return DependencyGraphOption.Clear - } - throw TypeError( - `The value '${val}' is not valid for 'dependency-graph'. Valid values are: [disabled, generate, generate-and-submit, generate-and-upload, download-and-submit, clear]. The default value is 'disabled'.` - ) -} - -export function getDependencyGraphContinueOnFailure(): boolean { - return getBooleanInput('dependency-graph-continue-on-failure', true) -} - -export function getArtifactRetentionDays(): number { - const val = core.getInput('artifact-retention-days') - return parseNumericInput('artifact-retention-days', val, 0) - // Zero indicates that the default repository settings should be used -} - export function parseNumericInput(paramName: string, paramValue: string, paramDefault: number): number { if (paramValue.length === 0) { return paramDefault @@ -165,18 +266,3 @@ function getBooleanInput(paramName: string, paramDefault = false): boolean { } throw TypeError(`The value '${paramValue} is not valid for '${paramName}. Valid values are: [true, false]`) } - -export enum DependencyGraphOption { - Disabled = 'disabled', - Generate = 'generate', - GenerateAndSubmit = 'generate-and-submit', - GenerateAndUpload = 'generate-and-upload', - DownloadAndSubmit = 'download-and-submit', - Clear = 'clear' -} - -export enum JobSummaryOption { - Never = 'never', - Always = 'always', - OnFailure = 'on-failure' -} diff --git a/sources/src/job-summary.ts b/sources/src/job-summary.ts index 1277b6e..2cf95b9 100644 --- a/sources/src/job-summary.ts +++ b/sources/src/job-summary.ts @@ -1,17 +1,21 @@ import * as core from '@actions/core' import * as github from '@actions/github' -import {SUMMARY_ENV_VAR} from '@actions/core/lib/summary' import {RequestError} from '@octokit/request-error' -import * as params from './input-params' import {BuildResult} from './build-results' import {CacheListener, generateCachingReport} from './cache-reporting' +import {SummaryConfig, getGithubToken} from './input-params' -export async function generateJobSummary(buildResults: BuildResult[], cacheListener: CacheListener): Promise { +export async function generateJobSummary( + buildResults: BuildResult[], + cacheListener: CacheListener, + config: SummaryConfig +): Promise { const summaryTable = renderSummaryTable(buildResults) const cachingReport = generateCachingReport(cacheListener) - if (shouldGenerateJobSummary(buildResults)) { + const hasFailure = buildResults.some(result => result.buildFailed) + if (config.shouldGenerateJobSummary(hasFailure)) { core.info('Generating Job Summary') core.summary.addRaw(summaryTable) @@ -25,7 +29,7 @@ export async function generateJobSummary(buildResults: BuildResult[], cacheListe core.info('============================') } - if (shouldAddPRComment(buildResults)) { + if (config.shouldAddPRComment(hasFailure)) { await addPRComment(summaryTable) } } @@ -47,7 +51,7 @@ async function addPRComment(jobSummary: string): Promise { ${jobSummary}` - const github_token = params.getGithubToken() + const github_token = getGithubToken() const octokit = github.getOctokit(github_token) try { await octokit.rest.issues.createComment({ @@ -128,36 +132,6 @@ function renderBuildScanBadge(outcomeText: string, outcomeColor: string, targetU return `${badgeHtml}` } -function shouldGenerateJobSummary(buildResults: BuildResult[]): boolean { - // Check if Job Summary is supported on this platform - if (!process.env[SUMMARY_ENV_VAR]) { - return false - } - - // Check if Job Summary is disabled using the deprecated input - if (!params.isJobSummaryEnabled()) { - return false - } - - return shouldAddJobSummary(params.getJobSummaryOption(), buildResults) -} - -function shouldAddPRComment(buildResults: BuildResult[]): boolean { - return shouldAddJobSummary(params.getPRCommentOption(), buildResults) -} - -function shouldAddJobSummary(option: params.JobSummaryOption, buildResults: BuildResult[]): boolean { - switch (option) { - case params.JobSummaryOption.Always: - return true - case params.JobSummaryOption.Never: - return false - case params.JobSummaryOption.OnFailure: - core.info(`Got these build results: ${JSON.stringify(buildResults)}`) - return buildResults.some(result => result.buildFailed) - } -} - function truncateString(str: string, maxLength: number): string { if (str.length > maxLength) { return `
${str.slice(0, maxLength - 1)}…
` diff --git a/sources/src/provision.ts b/sources/src/provision.ts index f111198..76369ce 100644 --- a/sources/src/provision.ts +++ b/sources/src/provision.ts @@ -8,7 +8,8 @@ import * as toolCache from '@actions/tool-cache' import * as gradlew from './gradlew' import * as params from './input-params' -import {handleCacheFailure, isCacheDisabled, isCacheReadOnly} from './cache-utils' +import {handleCacheFailure} from './cache-utils' +import {CacheConfig} from './input-params' const gradleVersionsBaseUrl = 'https://services.gradle.org/versions' @@ -122,7 +123,9 @@ async function locateGradleAndDownloadIfRequired(versionInfo: GradleVersionInfo) async function downloadAndCacheGradleDistribution(versionInfo: GradleVersionInfo): Promise { const downloadPath = path.join(os.homedir(), `gradle-installations/downloads/gradle-${versionInfo.version}-bin.zip`) - if (isCacheDisabled()) { + // TODO: Convert this to a class and inject config + const cacheConfig = new CacheConfig() + if (cacheConfig.isCacheDisabled()) { await downloadGradleDistribution(versionInfo, downloadPath) return downloadPath } @@ -141,7 +144,7 @@ async function downloadAndCacheGradleDistribution(versionInfo: GradleVersionInfo core.info(`Gradle distribution ${versionInfo.version} not found in cache. Will download.`) await downloadGradleDistribution(versionInfo, downloadPath) - if (!isCacheReadOnly()) { + if (!cacheConfig.isCacheReadOnly()) { try { await cache.saveCache([downloadPath], cacheKey) } catch (error) { diff --git a/sources/src/setup-gradle.ts b/sources/src/setup-gradle.ts index 5c35766..a6fea8f 100644 --- a/sources/src/setup-gradle.ts +++ b/sources/src/setup-gradle.ts @@ -10,13 +10,14 @@ import * as buildScan from './build-scan' import {loadBuildResults} from './build-results' import {CacheListener} from './cache-reporting' import {DaemonController} from './daemon-controller' +import {BuildScanConfig, CacheConfig, SummaryConfig} from './input-params' const GRADLE_SETUP_VAR = 'GRADLE_BUILD_ACTION_SETUP_COMPLETED' const USER_HOME = 'USER_HOME' const GRADLE_USER_HOME = 'GRADLE_USER_HOME' const CACHE_LISTENER = 'CACHE_LISTENER' -export async function setup(): Promise { +export async function setup(cacheConfig: CacheConfig, buildScanConfig: BuildScanConfig): Promise { const userHome = await determineUserHome() const gradleUserHome = await determineGradleUserHome() @@ -35,16 +36,16 @@ export async function setup(): Promise { core.saveState(GRADLE_USER_HOME, gradleUserHome) const cacheListener = new CacheListener() - await caches.restore(userHome, gradleUserHome, cacheListener) + await caches.restore(userHome, gradleUserHome, cacheListener, cacheConfig) core.saveState(CACHE_LISTENER, cacheListener.stringify()) - buildScan.setup() + buildScan.setup(buildScanConfig) return true } -export async function complete(): Promise { +export async function complete(cacheConfig: CacheConfig, summaryConfig: SummaryConfig): Promise { if (!core.getState(GRADLE_SETUP_VAR)) { core.info('Gradle setup post-action only performed for first gradle/actions step in workflow.') return false @@ -58,9 +59,9 @@ export async function complete(): Promise { const cacheListener: CacheListener = CacheListener.rehydrate(core.getState(CACHE_LISTENER)) const daemonController = new DaemonController(buildResults) - await caches.save(userHome, gradleUserHome, cacheListener, daemonController) + await caches.save(userHome, gradleUserHome, cacheListener, daemonController, cacheConfig) - await jobSummary.generateJobSummary(buildResults, cacheListener) + await jobSummary.generateJobSummary(buildResults, cacheListener, summaryConfig) core.info('Completed post-action step') diff --git a/sources/src/setup-gradle/main.ts b/sources/src/setup-gradle/main.ts index f4aafe8..50c7d90 100644 --- a/sources/src/setup-gradle/main.ts +++ b/sources/src/setup-gradle/main.ts @@ -4,8 +4,8 @@ import * as setupGradle from '../setup-gradle' import * as execution from '../execution' import * as provisioner from '../provision' import * as layout from '../repository-layout' -import * as params from '../input-params' import * as dependencyGraph from '../dependency-graph' +import {BuildScanConfig, CacheConfig, DependencyGraphConfig, getArguments} from '../input-params' /** * The main entry point for the action, called by Github Actions for the step. @@ -13,16 +13,16 @@ import * as dependencyGraph from '../dependency-graph' export async function run(): Promise { try { // Configure Gradle environment (Gradle User Home) - await setupGradle.setup() + await setupGradle.setup(new CacheConfig(), new BuildScanConfig()) // Configure the dependency graph submission - await dependencyGraph.setup(params.getDependencyGraphOption()) + await dependencyGraph.setup(new DependencyGraphConfig()) // Download and install Gradle if required const executable = await provisioner.provisionGradle() // Only execute if arguments have been provided - const args: string[] = params.getArguments() + const args: string[] = getArguments() if (args.length > 0) { const buildRootDirectory = layout.buildRootDirectory() await execution.executeGradleBuild(executable, buildRootDirectory, args) diff --git a/sources/src/setup-gradle/post.ts b/sources/src/setup-gradle/post.ts index 83efab1..d1b99ba 100644 --- a/sources/src/setup-gradle/post.ts +++ b/sources/src/setup-gradle/post.ts @@ -2,7 +2,7 @@ import * as core from '@actions/core' import * as setupGradle from '../setup-gradle' import * as dependencyGraph from '../dependency-graph' -import {getDependencyGraphOption} from '../input-params' +import {CacheConfig, DependencyGraphConfig, SummaryConfig} from '../input-params' import {PostActionJobFailure} from '../errors' // Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in @@ -15,9 +15,9 @@ process.on('uncaughtException', e => handleFailure(e)) */ export async function run(): Promise { try { - if (await setupGradle.complete()) { + if (await setupGradle.complete(new CacheConfig(), new SummaryConfig())) { // Only submit the dependency graphs once per job - await dependencyGraph.complete(getDependencyGraphOption()) + await dependencyGraph.complete(new DependencyGraphConfig()) } } catch (error) { if (error instanceof PostActionJobFailure) { diff --git a/sources/test/jest/cache-debug.test.ts b/sources/test/jest/cache-debug.test.ts index 88550f6..f0466a5 100644 --- a/sources/test/jest/cache-debug.test.ts +++ b/sources/test/jest/cache-debug.test.ts @@ -1,6 +1,7 @@ -import {GradleStateCache} from "../../src/cache-base" import * as path from 'path' import * as fs from 'fs' +import {GradleStateCache} from "../../src/cache-base" +import {CacheConfig} from "../../src/input-params" const testTmp = 'test/jest/tmp' fs.rmSync(testTmp, {recursive: true, force: true}) @@ -11,7 +12,7 @@ describe("--info and --stacktrace", () => { const emptyGradleHome = `${testTmp}/empty-gradle-home` fs.mkdirSync(emptyGradleHome, {recursive: true}) - const stateCache = new GradleStateCache("ignored", emptyGradleHome) + const stateCache = new GradleStateCache("ignored", emptyGradleHome, new CacheConfig()) stateCache.configureInfoLogLevel() expect(fs.readFileSync(path.resolve(emptyGradleHome, "gradle.properties"), 'utf-8')) @@ -24,7 +25,7 @@ describe("--info and --stacktrace", () => { fs.mkdirSync(existingGradleHome, {recursive: true}) fs.writeFileSync(path.resolve(existingGradleHome, "gradle.properties"), "org.gradle.logging.level=debug\n") - const stateCache = new GradleStateCache("ignored", existingGradleHome) + const stateCache = new GradleStateCache("ignored", existingGradleHome, new CacheConfig()) stateCache.configureInfoLogLevel() expect(fs.readFileSync(path.resolve(existingGradleHome, "gradle.properties"), 'utf-8')) diff --git a/sources/test/jest/dependency-graph.test.ts b/sources/test/jest/dependency-graph.test.ts index bf1a9a8..5904731 100644 --- a/sources/test/jest/dependency-graph.test.ts +++ b/sources/test/jest/dependency-graph.test.ts @@ -1,33 +1,33 @@ -import * as dependencyGraph from '../../src/dependency-graph' +import { DependencyGraphConfig } from "../../src/input-params" describe('dependency-graph', () => { describe('constructs job correlator', () => { it('removes commas from workflow name', () => { - const id = dependencyGraph.constructJobCorrelator('Workflow, with,commas', 'jobid', '{}') + const id = DependencyGraphConfig.constructJobCorrelator('Workflow, with,commas', 'jobid', '{}') expect(id).toBe('workflow_withcommas-jobid') }) it('removes non word characters', () => { - const id = dependencyGraph.constructJobCorrelator('Workflow!_with()characters', 'job-*id', '{"foo": "bar!@#$%^&*("}') + const id = DependencyGraphConfig.constructJobCorrelator('Workflow!_with()characters', 'job-*id', '{"foo": "bar!@#$%^&*("}') expect(id).toBe('workflow_withcharacters-job-id-bar') }) it('replaces spaces', () => { - const id = dependencyGraph.constructJobCorrelator('Workflow !_ with () characters, and spaces', 'job-*id', '{"foo": "bar!@#$%^&*("}') + const id = DependencyGraphConfig.constructJobCorrelator('Workflow !_ with () characters, and spaces', 'job-*id', '{"foo": "bar!@#$%^&*("}') expect(id).toBe('workflow___with_characters_and_spaces-job-id-bar') }) it('without matrix', () => { - const id = dependencyGraph.constructJobCorrelator('workflow', 'jobid', 'null') + const id = DependencyGraphConfig.constructJobCorrelator('workflow', 'jobid', 'null') expect(id).toBe('workflow-jobid') }) it('with dashes in values', () => { - const id = dependencyGraph.constructJobCorrelator('workflow-name', 'job-id', '{"os": "ubuntu-latest"}') + const id = DependencyGraphConfig.constructJobCorrelator('workflow-name', 'job-id', '{"os": "ubuntu-latest"}') expect(id).toBe('workflow-name-job-id-ubuntu-latest') }) it('with single matrix value', () => { - const id = dependencyGraph.constructJobCorrelator('workflow', 'jobid', '{"os": "windows"}') + const id = DependencyGraphConfig.constructJobCorrelator('workflow', 'jobid', '{"os": "windows"}') expect(id).toBe('workflow-jobid-windows') }) it('with composite matrix value', () => { - const id = dependencyGraph.constructJobCorrelator('workflow', 'jobid', '{"os": "windows", "java-version": "21.1", "other": "Value, with COMMA"}') + const id = DependencyGraphConfig.constructJobCorrelator('workflow', 'jobid', '{"os": "windows", "java-version": "21.1", "other": "Value, with COMMA"}') expect(id).toBe('workflow-jobid-windows-211-value_with_comma') }) })