diff --git a/.werft/jobs/build/deploy-to-preview-environment.ts b/.werft/jobs/build/deploy-to-preview-environment.ts index 2ed7b0f482c5b4..06ea27f2c6e389 100644 --- a/.werft/jobs/build/deploy-to-preview-environment.ts +++ b/.werft/jobs/build/deploy-to-preview-environment.ts @@ -153,8 +153,11 @@ export async function deployToPreviewEnvironment(werft: Werft, jobConfig: JobCon // the context namespace is not set at this point const deploymentKubeconfig = withVM ? PREVIEW_K3S_KUBECONFIG_PATH : CORE_DEV_KUBECONFIG_PATH; const hasGitpodHelmInstall = exec(`helm --kubeconfig ${deploymentKubeconfig} status ${helmInstallName} -n ${deploymentConfig.namespace}`, { slice: "check for Helm install", dontCheckRc: true }).code === 0; + werft.done("check for Helm install"); const hasGitpodInstallerInstall = exec(`kubectl --kubeconfig ${deploymentKubeconfig} get configmap gitpod-app -n ${deploymentConfig.namespace}`, { slice: "check for Installer install", dontCheckRc: true }).code === 0; + werft.done("check for Installer install"); werft.log("result of installation checks", `has Helm install: ${hasGitpodHelmInstall}, has Installer install: ${hasGitpodInstallerInstall}`); + werft.done("result of installation checks"); if (withHelm) { werft.log("using Helm", "with-helm was specified."); @@ -339,6 +342,7 @@ async function deployToDevWithInstaller(werft: Werft, jobConfig: JobConfig, depl | kubectl --kubeconfig ${CORE_DEV_KUBECONFIG_PATH} apply -f -`); exec(`/usr/local/bin/helm3 --kubeconfig ${CORE_DEV_KUBECONFIG_PATH} upgrade --install --set image.version=${sweeperVersion} --set command="werft run github -a namespace=${namespace} --remote-job-path .werft/wipe-devstaging.yaml github.com/gitpod-io/gitpod:main" ${allArgsStr} sweeper ./dev/charts/sweeper`); } + werft.done("sweeper"); werft.done(phases.DEPLOY); diff --git a/.werft/jobs/build/job-config.ts b/.werft/jobs/build/job-config.ts index 0752aec26a70fe..763abed93f95c7 100644 --- a/.werft/jobs/build/job-config.ts +++ b/.werft/jobs/build/job-config.ts @@ -148,7 +148,7 @@ export function jobConfig(werft: Werft, context: any): JobConfig { })) globalAttributes['werft.job.config.branch'] = context.Repository.ref werft.addAttributes(globalAttributes) - + werft.done("job config"); werft.done(sliceId) return jobConfig diff --git a/.werft/util/werft.ts b/.werft/util/werft.ts index 5cfca47741d833..1f6c69fca40609 100644 --- a/.werft/util/werft.ts +++ b/.werft/util/werft.ts @@ -20,9 +20,12 @@ export class Werft { private tracer: Tracer; public rootSpan: Span; private sliceSpans: { [slice: string]: Span } = {} + public currentPhase: string; public currentPhaseSpan: Span; private globalSpanAttributes: SpanAttributes = {} + public phases: { [name: string]: { "slices": { [name: string]: { "closed": boolean } } } } = {} + constructor(job: string) { if (werft) { throw new Error("Only one Werft instance should be instantiated per job") @@ -40,6 +43,15 @@ export class Werft { this.endPhase() } + // Check if the phase does already exist + if (this.phases[name]) { + throw new Error(`The phase "${name}" does already exist!`) + } + + // This is a workaround to prevent phases being opened without any slice + this.phases[name] = { "slices": { "default": { "closed": false } } } + this.currentPhase = name; + const rootSpanCtx = trace.setSpan(context.active(), this.rootSpan); this.currentPhaseSpan = this.tracer.startSpan(`phase: ${name}`, { attributes: { @@ -52,13 +64,29 @@ export class Werft { console.log(`[${name}|PHASE] ${desc || name}`) } + private sliceBelongsToCurrentPhase(slice) { + for (const [name, phase] of Object.entries(this.phases)) { + if(phase.slices[slice] && (name != this.currentPhase)) + throw new Error(`The slice ${slice} does not belong to the phase ${name}`); + } + } + public log(slice, msg) { + this.sliceBelongsToCurrentPhase(slice); if (!this.sliceSpans[slice]) { const parentSpanCtx = trace.setSpan(context.active(), this.currentPhaseSpan); const sliceSpan = this.tracer.startSpan(`slice: ${slice}`, undefined, parentSpanCtx) sliceSpan.setAttributes(this.globalSpanAttributes) this.sliceSpans[slice] = sliceSpan } + // Create a new slice in the current phase when it does not already exist + // This is the case if werft.done("PHASE") is directly invoked without any prior log + if (!this.phases[this.currentPhase].slices[slice]) + this.phases[this.currentPhase].slices[slice] = { "closed": false }; + // Check if the slice has already been closed + if (this.phases[this.currentPhase].slices[slice].closed) + throw new Error(`The slice "${slice}" has already been closed!`); + console.log(`[${slice}] ${msg}`) } @@ -86,11 +114,21 @@ export class Werft { } public done(slice: string) { + // This is a workaround to prevent phases being opened without any slice + this.phases[this.currentPhase].slices["default"].closed = true; const span = this.sliceSpans[slice] if (span) { span.end() delete this.sliceSpans[slice] } + // Create a new slice entry that is already closed if no prior entry exists + if (!this.phases[this.currentPhase].slices[slice]) { + this.phases[this.currentPhase].slices[slice] = { "closed": true }; + } else if (this.phases[this.currentPhase].slices[slice].closed) { + throw new Error(`The slice "${slice}" has already been closed!`); + } else { + this.phases[this.currentPhase].slices[slice].closed = true; + } console.log(`[${slice}|DONE]`) } @@ -105,6 +143,17 @@ export class Werft { span.end() delete this.sliceSpans[id] }) + // Check if all slices are closed + let check = true; + for (const [name, slice] of Object.entries(this.phases[this.currentPhase].slices)) { + if(!slice.closed) { + console.log(`The slice "${name}" has not been closed!`); + check = false; + } + } + if (!check) { + throw new Error(`Not all slices inside the phase "${this.currentPhase}" have been closed!`) + } // End the phase this.currentPhaseSpan.end() }