From 24d8d3492a8d1a9e2c8c9f1d4357f171bba7fbcc Mon Sep 17 00:00:00 2001 From: Longwt123 <1075015495@qq.com> Date: Thu, 25 Jun 2026 06:57:43 +0000 Subject: [PATCH 1/5] feat: surface unrecoverable container errors during pod wait MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a CI job references a non-existent image or one it lacks permission to pull, the pod stays in Pending and waitForPodPhases previously timed out with only a generic phase-status message. GitHub Actions users had no indication of the real cause. Detect unrecoverable container waiting reasons (ImagePullBackOff, ErrImagePull, InvalidImageName, CreateContainerConfigError, CreateContainerError) on both init and regular containers, and fail fast with the container name, reason, and Kubernetes message so the error is visible in the Actions log. Refactor getPodPhase into readPod + parsePodPhase so the pod object can be inspected for container errors, and add describePodFailure to aggregate pod phase, conditions, container statuses and Warning events into a single diagnostic string. describePodWarningEvents provides best-effort retrieval of recent Warning events (requires optional events RBAC permission, degrades gracefully when missing). getUnrecoverableWaitingReasons allows operators to extend the built-in fast-fail whitelist via the ACTIONS_RUNNER_K8S_UNRECOVERABLE_WAITING_REASONS env var. All three failure paths in waitForPodPhases now attach full diagnostics: 1. Non-backoff phase (e.g. Failed) — includes pod details + events 2. Unrecoverable container error (e.g. ImagePullBackOff) — fail-fast 3. Timeout — includes pod details so the user can see WHY the pod never became ready README: document the optional events permission and the new env var. Tests: 19 new test cases covering parsePodPhase, getContainerErrors, waitForPodPhases, getUnrecoverableWaitingReasons, describePodFailure, describePodWarningEvents, and edge cases such as forbidden events API and unreadable pods. --- packages/k8s/README.md | 18 + packages/k8s/src/k8s/index.ts | 223 ++++++++++-- .../k8s/tests/wait-for-pod-phases-test.ts | 323 ++++++++++++++++++ 3 files changed, 541 insertions(+), 23 deletions(-) create mode 100644 packages/k8s/tests/wait-for-pod-phases-test.ts diff --git a/packages/k8s/README.md b/packages/k8s/README.md index dc35c347..c2b30487 100644 --- a/packages/k8s/README.md +++ b/packages/k8s/README.md @@ -29,6 +29,16 @@ rules: resources: ["secrets"] verbs: ["get", "list", "create", "delete"] ``` +- (Optional, recommended) Granting `events` read access lets the hooks attach + recent `Warning` events (e.g. `FailedScheduling`, `FailedMount`) to the error + message when a pod fails to come online. This permission is **not required** — + if it is missing the hooks still work, they just omit the event section from + diagnostics. +``` +- apiGroups: [""] + resources: ["events"] + verbs: ["get", "list"] +``` - The `ACTIONS_RUNNER_POD_NAME` env should be set to the name of the pod - The `ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER` env should be set to true to prevent the runner from running any jobs outside of a container - The runner pod should map a persistent volume claim into the `_work` directory @@ -36,6 +46,14 @@ rules: - Some actions runner env's are expected to be set. These are set automatically by the runner. - `RUNNER_WORKSPACE` is expected to be set to the workspace of the runner - `GITHUB_WORKSPACE` is expected to be set to the workspace of the job +- Optional tuning env's + - `ACTIONS_RUNNER_K8S_UNRECOVERABLE_WAITING_REASONS` — comma-separated list of + extra container `waiting` reasons that should be treated as deterministic + terminal failures (fail fast instead of waiting for the timeout). These are + *added* to the built-ins (`ImagePullBackOff`, `ErrImagePull`, + `InvalidImageName`, `CreateContainerConfigError`, `CreateContainerError`); + the built-ins can never be removed. Use with care — only list reasons that + are truly unrecoverable for your workloads (e.g. `CrashLoopBackOff`). ## Limitations diff --git a/packages/k8s/src/k8s/index.ts b/packages/k8s/src/k8s/index.ts index 249a0605..1ee93164 100644 --- a/packages/k8s/src/k8s/index.ts +++ b/packages/k8s/src/k8s/index.ts @@ -368,6 +368,164 @@ export async function pruneSecrets(): Promise { ) } +export const UNRECOVERABLE_WAITING_REASONS = new Set([ + 'ImagePullBackOff', + 'ErrImagePull', + 'InvalidImageName', + 'CreateContainerConfigError', + 'CreateContainerError' +]) + +const MAX_DIAGNOSTIC_EVENTS = 10 + +export function getUnrecoverableWaitingReasons(): Set { + const extra = process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_WAITING_REASONS'] + if (!extra) { + return UNRECOVERABLE_WAITING_REASONS + } + const reasons = new Set(UNRECOVERABLE_WAITING_REASONS) + for (const reason of extra.split(',')) { + const trimmed = reason.trim() + if (trimmed) { + reasons.add(trimmed) + } + } + return reasons +} + +export function getContainerErrors(pod: k8s.V1Pod): string[] { + const errors: string[] = [] + const unrecoverableReasons = getUnrecoverableWaitingReasons() + const allStatuses = [ + ...(pod.status?.initContainerStatuses ?? []), + ...(pod.status?.containerStatuses ?? []) + ] + for (const cs of allStatuses) { + const waiting = cs.state?.waiting + if (waiting?.reason && unrecoverableReasons.has(waiting.reason)) { + errors.push( + `container "${cs.name}": ${waiting.reason}${ + waiting.message ? ` - ${waiting.message}` : '' + }` + ) + } + } + return errors +} + +export async function describePodFailure(podName: string): Promise { + let pod: k8s.V1Pod + try { + pod = await readPod(podName) + } catch (err) { + return `Could not read pod ${podName} for diagnostics: ${ + err instanceof Error ? err.message : String(err) + }` + } + + const lines: string[] = [] + const status = pod.status + + if (status?.phase) { + lines.push( + `Phase: ${status.phase}${ + status.reason ? ` (reason: ${status.reason})` : '' + }` + ) + } + if (status?.message) { + lines.push(`Message: ${status.message}`) + } + + for (const cond of status?.conditions ?? []) { + if (cond.status === 'False') { + lines.push( + `Condition ${cond.type}=False${ + cond.reason ? ` (reason: ${cond.reason})` : '' + }${cond.message ? `: ${cond.message}` : ''}` + ) + } + } + + const allStatuses = [ + ...(status?.initContainerStatuses ?? []), + ...(status?.containerStatuses ?? []) + ] + for (const cs of allStatuses) { + const waiting = cs.state?.waiting + if (waiting?.reason) { + lines.push( + `Container "${cs.name}" waiting: ${waiting.reason}${ + waiting.message ? ` - ${waiting.message}` : '' + }` + ) + } + const terminated = cs.state?.terminated + if (terminated) { + lines.push( + `Container "${cs.name}" terminated: ${ + terminated.reason ?? 'Unknown' + } (exit code ${terminated.exitCode})${ + terminated.message ? ` - ${terminated.message}` : '' + }` + ) + } + } + + lines.push(...(await describePodWarningEvents(podName))) + + if (!lines.length) { + return `No additional diagnostic information available for pod ${podName}` + } + return lines.join('\n') +} + +async function describePodWarningEvents(podName: string): Promise { + let items: k8s.CoreV1Event[] + try { + const { body } = await k8sApi.listNamespacedEvent( + namespace(), + undefined, + undefined, + undefined, + `involvedObject.name=${podName}` + ) + items = body.items + } catch (err) { + core.debug( + `Could not list events for pod ${podName} (the 'events' permission may be missing): ${ + err instanceof Error ? err.message : String(err) + }` + ) + return [] + } + + const warnings = items.filter(e => e.type === 'Warning') + if (!warnings.length) { + return [] + } + + const eventTime = (e: k8s.CoreV1Event): number => { + const t = e.lastTimestamp ?? e.eventTime ?? e.firstTimestamp + return t ? new Date(t).getTime() : 0 + } + warnings.sort((a, b) => eventTime(a) - eventTime(b)) + + const recent = warnings.slice(-MAX_DIAGNOSTIC_EVENTS) + const lines = recent.map(e => { + const count = e.count && e.count > 1 ? ` (x${e.count})` : '' + return `Event [Warning] ${e.reason ?? ''}${count}: ${ + e.message ?? '' + }`.trim() + }) + if (warnings.length > recent.length) { + lines.unshift( + `(showing ${recent.length} of ${warnings.length} warning events)` + ) + } + return lines +} + export async function waitForPodPhases( podName: string, awaitingPhases: Set, @@ -376,22 +534,38 @@ export async function waitForPodPhases( ): Promise { const backOffManager = new BackOffManager(maxTimeSeconds) let phase: PodPhase = PodPhase.UNKNOWN - try { - while (true) { - phase = await getPodPhase(podName) - if (awaitingPhases.has(phase)) { - return - } + while (true) { + const pod = await readPod(podName) + phase = parsePodPhase(pod) + if (awaitingPhases.has(phase)) { + return + } - if (!backOffPhases.has(phase)) { - throw new Error( - `Pod ${podName} is unhealthy with phase status ${phase}` - ) - } + if (!backOffPhases.has(phase)) { + const details = await describePodFailure(podName) + throw new Error( + `Pod ${podName} is unhealthy with phase status ${phase}\n${details}` + ) + } + + const containerErrors = getContainerErrors(pod) + if (containerErrors.length > 0) { + const details = await describePodFailure(podName) + throw new Error( + `Pod ${podName} has unrecoverable container errors: ${containerErrors.join( + '; ' + )}\n${details}` + ) + } + + try { await backOffManager.backOff() + } catch (error) { + const details = await describePodFailure(podName) + throw new Error( + `Pod ${podName} is unhealthy: timed out after ${maxTimeSeconds}s in phase ${phase}\n${details}` + ) } - } catch (error) { - throw new Error(`Pod ${podName} is unhealthy with phase status ${phase}`) } } @@ -414,21 +588,24 @@ export function getPrepareJobTimeoutSeconds(): number { return timeoutSeconds } -async function getPodPhase(podName: string): Promise { - const podPhaseLookup = new Set([ - PodPhase.PENDING, - PodPhase.RUNNING, - PodPhase.SUCCEEDED, - PodPhase.FAILED, - PodPhase.UNKNOWN - ]) +async function readPod(podName: string): Promise { const { body } = await k8sApi.readNamespacedPod(podName, namespace()) - const pod = body + return body +} + +const podPhaseLookup = new Set([ + PodPhase.PENDING, + PodPhase.RUNNING, + PodPhase.SUCCEEDED, + PodPhase.FAILED, + PodPhase.UNKNOWN +]) +export function parsePodPhase(pod: k8s.V1Pod): PodPhase { if (!pod.status?.phase || !podPhaseLookup.has(pod.status.phase)) { return PodPhase.UNKNOWN } - return pod.status?.phase as PodPhase + return pod.status.phase as PodPhase } async function isJobSucceeded(jobName: string): Promise { diff --git a/packages/k8s/tests/wait-for-pod-phases-test.ts b/packages/k8s/tests/wait-for-pod-phases-test.ts new file mode 100644 index 00000000..30e56aa0 --- /dev/null +++ b/packages/k8s/tests/wait-for-pod-phases-test.ts @@ -0,0 +1,323 @@ +import * as k8s from '@kubernetes/client-node' +import { + describePodFailure, + getContainerErrors, + getUnrecoverableWaitingReasons, + parsePodPhase, + UNRECOVERABLE_WAITING_REASONS, + waitForPodPhases +} from '../src/k8s' +import { PodPhase } from '../src/k8s/utils' + +function buildPod( + phase?: string, + opts: { + containerStatuses?: k8s.V1ContainerStatus[] + initContainerStatuses?: k8s.V1ContainerStatus[] + } = {} +): k8s.V1Pod { + return { + status: { + phase, + containerStatuses: opts.containerStatuses, + initContainerStatuses: opts.initContainerStatuses + } + } as k8s.V1Pod +} + +function waitingContainer( + name: string, + reason?: string, + message?: string +): k8s.V1ContainerStatus { + return { + name, + state: { waiting: { reason, message } } + } as k8s.V1ContainerStatus +} + +describe('parsePodPhase', () => { + it('returns the phase when it is a known value', () => { + expect(parsePodPhase(buildPod(PodPhase.RUNNING))).toBe(PodPhase.RUNNING) + expect(parsePodPhase(buildPod(PodPhase.PENDING))).toBe(PodPhase.PENDING) + expect(parsePodPhase(buildPod(PodPhase.SUCCEEDED))).toBe(PodPhase.SUCCEEDED) + expect(parsePodPhase(buildPod(PodPhase.FAILED))).toBe(PodPhase.FAILED) + }) + + it('returns UNKNOWN when phase is missing', () => { + expect(parsePodPhase(buildPod(undefined))).toBe(PodPhase.UNKNOWN) + expect(parsePodPhase({} as k8s.V1Pod)).toBe(PodPhase.UNKNOWN) + }) + + it('returns UNKNOWN when phase is not a recognized value', () => { + expect(parsePodPhase(buildPod('SomethingElse'))).toBe(PodPhase.UNKNOWN) + }) +}) + +describe('getContainerErrors', () => { + it('returns no errors when there are no container statuses', () => { + expect(getContainerErrors(buildPod(PodPhase.PENDING))).toEqual([]) + expect(getContainerErrors({} as k8s.V1Pod)).toEqual([]) + }) + + it('returns no errors when containers are waiting for a recoverable reason', () => { + const pod = buildPod(PodPhase.PENDING, { + containerStatuses: [waitingContainer('job', 'ContainerCreating')] + }) + expect(getContainerErrors(pod)).toEqual([]) + }) + + it('detects every unrecoverable waiting reason', () => { + for (const reason of Array.from(UNRECOVERABLE_WAITING_REASONS)) { + const pod = buildPod(PodPhase.PENDING, { + containerStatuses: [waitingContainer('job', reason)] + }) + expect(getContainerErrors(pod)).toEqual([`container "job": ${reason}`]) + } + }) + + it('includes the waiting message when present', () => { + const pod = buildPod(PodPhase.PENDING, { + containerStatuses: [ + waitingContainer( + 'job', + 'ErrImagePull', + 'Back-off pulling image "does-not-exist:latest"' + ) + ] + }) + expect(getContainerErrors(pod)).toEqual([ + 'container "job": ErrImagePull - Back-off pulling image "does-not-exist:latest"' + ]) + }) + + it('inspects init containers as well as regular containers', () => { + const pod = buildPod(PodPhase.PENDING, { + initContainerStatuses: [waitingContainer('init', 'ImagePullBackOff')], + containerStatuses: [waitingContainer('job', 'CreateContainerError')] + }) + expect(getContainerErrors(pod)).toEqual([ + 'container "init": ImagePullBackOff', + 'container "job": CreateContainerError' + ]) + }) + + it('ignores running/terminated containers and only collects waiting errors', () => { + const pod = buildPod(PodPhase.PENDING, { + containerStatuses: [ + { name: 'running', state: { running: {} } } as k8s.V1ContainerStatus, + waitingContainer('bad', 'InvalidImageName') + ] + }) + expect(getContainerErrors(pod)).toEqual([ + 'container "bad": InvalidImageName' + ]) + }) +}) + +describe('waitForPodPhases', () => { + let readSpy: jest.SpyInstance + let eventSpy: jest.SpyInstance + + beforeEach(() => { + process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] = 'default' + readSpy = jest.spyOn(k8s.CoreV1Api.prototype, 'readNamespacedPod') + eventSpy = jest.spyOn(k8s.CoreV1Api.prototype, 'listNamespacedEvent') + eventSpy.mockResolvedValue({ body: { items: [] } } as never) + }) + + afterEach(() => { + jest.restoreAllMocks() + delete process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] + }) + + it('returns once the pod reaches an awaited phase', async () => { + readSpy.mockResolvedValue({ body: buildPod(PodPhase.RUNNING) } as never) + + await expect( + waitForPodPhases( + 'my-pod', + new Set([PodPhase.RUNNING]), + new Set([PodPhase.PENDING]) + ) + ).resolves.toBeUndefined() + }) + + it('surfaces unrecoverable container errors in the thrown message', async () => { + readSpy.mockResolvedValue({ + body: buildPod(PodPhase.PENDING, { + containerStatuses: [ + waitingContainer( + 'job', + 'ImagePullBackOff', + 'Back-off pulling image "nope:latest"' + ) + ] + }) + } as never) + + await expect( + waitForPodPhases( + 'my-pod', + new Set([PodPhase.RUNNING]), + new Set([PodPhase.PENDING]) + ) + ).rejects.toThrow( + 'container "job": ImagePullBackOff - Back-off pulling image "nope:latest"' + ) + }) + + it('throws with the phase when the pod is in a non-backoff phase', async () => { + readSpy.mockResolvedValue({ + body: buildPod(PodPhase.FAILED) + } as never) + + await expect( + waitForPodPhases( + 'my-pod', + new Set([PodPhase.RUNNING]), + new Set([PodPhase.PENDING]) + ) + ).rejects.toThrow('Pod my-pod is unhealthy with phase status Failed') + }) +}) + +describe('getUnrecoverableWaitingReasons', () => { + afterEach(() => { + delete process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_WAITING_REASONS'] + }) + + it('returns the built-in defaults when the env var is unset', () => { + expect(getUnrecoverableWaitingReasons()).toEqual( + UNRECOVERABLE_WAITING_REASONS + ) + }) + + it('adds extra reasons from the env var without dropping the defaults', () => { + process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_WAITING_REASONS'] = + 'CrashLoopBackOff, RunContainerError' + const reasons = getUnrecoverableWaitingReasons() + for (const builtin of Array.from(UNRECOVERABLE_WAITING_REASONS)) { + expect(reasons.has(builtin)).toBe(true) + } + expect(reasons.has('CrashLoopBackOff')).toBe(true) + expect(reasons.has('RunContainerError')).toBe(true) + }) + + it('makes getContainerErrors honor the extended whitelist', () => { + process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_WAITING_REASONS'] = + 'CrashLoopBackOff' + const pod = buildPod(PodPhase.PENDING, { + containerStatuses: [waitingContainer('job', 'CrashLoopBackOff')] + }) + expect(getContainerErrors(pod)).toEqual([ + 'container "job": CrashLoopBackOff' + ]) + }) +}) + +describe('describePodFailure', () => { + let readSpy: jest.SpyInstance + let eventSpy: jest.SpyInstance + + beforeEach(() => { + process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] = 'default' + readSpy = jest.spyOn(k8s.CoreV1Api.prototype, 'readNamespacedPod') + eventSpy = jest.spyOn(k8s.CoreV1Api.prototype, 'listNamespacedEvent') + eventSpy.mockResolvedValue({ body: { items: [] } } as never) + }) + + afterEach(() => { + jest.restoreAllMocks() + delete process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] + }) + + it('reports phase, failing conditions and terminated containers', async () => { + readSpy.mockResolvedValue({ + body: { + status: { + phase: PodPhase.FAILED, + reason: 'Evicted', + message: 'The node was low on resource: memory', + conditions: [ + { + type: 'PodScheduled', + status: 'False', + reason: 'Unschedulable', + message: 'no nodes available' + } + ], + containerStatuses: [ + { + name: 'job', + state: { + terminated: { exitCode: 137, reason: 'OOMKilled' } + } + } + ] + } + } + } as never) + + const description = await describePodFailure('my-pod') + expect(description).toContain('Phase: Failed (reason: Evicted)') + expect(description).toContain( + 'Message: The node was low on resource: memory' + ) + expect(description).toContain( + 'Condition PodScheduled=False (reason: Unschedulable): no nodes available' + ) + expect(description).toContain( + 'Container "job" terminated: OOMKilled (exit code 137)' + ) + }) + + it('includes recent Warning events and skips Normal ones', async () => { + readSpy.mockResolvedValue({ + body: { status: { phase: PodPhase.PENDING } } + } as never) + eventSpy.mockResolvedValue({ + body: { + items: [ + { + type: 'Normal', + reason: 'Scheduled', + message: 'assigned', + lastTimestamp: new Date('2026-01-01T00:00:00Z') + }, + { + type: 'Warning', + reason: 'FailedScheduling', + message: '0/1 nodes are available', + count: 3, + lastTimestamp: new Date('2026-01-01T00:01:00Z') + } + ] + } + } as never) + + const description = await describePodFailure('my-pod') + expect(description).toContain( + 'Event [Warning] FailedScheduling (x3): 0/1 nodes are available' + ) + expect(description).not.toContain('Scheduled') + }) + + it('degrades gracefully when listing events is forbidden', async () => { + readSpy.mockResolvedValue({ + body: { status: { phase: PodPhase.PENDING } } + } as never) + eventSpy.mockRejectedValue(new Error('events is forbidden') as never) + + const description = await describePodFailure('my-pod') + expect(description).toContain('Phase: Pending') + expect(description).not.toContain('Event [Warning]') + }) + + it('never throws when the pod cannot be read', async () => { + readSpy.mockRejectedValue(new Error('pod not found') as never) + + const description = await describePodFailure('my-pod') + expect(description).toContain('Could not read pod my-pod for diagnostics') + }) +}) From 215e8fd1791ec81215df6a3d0d8f64f4c6569a8d Mon Sep 17 00:00:00 2001 From: xiaoni Date: Wed, 1 Jul 2026 06:47:19 +0000 Subject: [PATCH 2/5] feat(runner-container-hooks): expand k8s error detection from 5 to 11 types --- packages/docker/package-lock.json | 35 +- packages/k8s/package-lock.json | 35 +- packages/k8s/src/hooks/prepare-job.ts | 3 +- packages/k8s/src/hooks/run-container-step.ts | 11 + packages/k8s/src/k8s/index.ts | 149 +++++- packages/k8s/tests/run-container-step-test.ts | 163 +++++++ .../k8s/tests/wait-for-pod-phases-test.ts | 460 +++++++++++++++++- 7 files changed, 784 insertions(+), 72 deletions(-) diff --git a/packages/docker/package-lock.json b/packages/docker/package-lock.json index 5916f71c..f43f482a 100644 --- a/packages/docker/package-lock.json +++ b/packages/docker/package-lock.json @@ -27,22 +27,6 @@ "typescript": "^4.6.3" } }, - "../hooklib": { - "version": "0.1.0", - "license": "MIT", - "dependencies": { - "@actions/core": "^1.9.1" - }, - "devDependencies": { - "@types/node": "^17.0.23", - "@typescript-eslint/parser": "^5.18.0", - "@zeit/ncc": "^0.22.3", - "eslint": "^8.12.0", - "eslint-plugin-github": "^4.3.6", - "prettier": "^2.6.2", - "typescript": "^4.6.3" - } - }, "node_modules/@actions/core": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", @@ -2853,8 +2837,12 @@ } }, "node_modules/hooklib": { - "resolved": "../hooklib", - "link": true + "version": "0.1.0", + "resolved": "file:../hooklib", + "license": "MIT", + "dependencies": { + "@actions/core": "^1.9.1" + } }, "node_modules/html-encoding-sniffer": { "version": "2.0.1", @@ -7581,16 +7569,9 @@ "dev": true }, "hooklib": { - "version": "file:../hooklib", + "version": "0.1.0", "requires": { - "@actions/core": "^1.9.1", - "@types/node": "^17.0.23", - "@typescript-eslint/parser": "^5.18.0", - "@zeit/ncc": "^0.22.3", - "eslint": "^8.12.0", - "eslint-plugin-github": "^4.3.6", - "prettier": "^2.6.2", - "typescript": "^4.6.3" + "@actions/core": "^1.9.1" } }, "html-encoding-sniffer": { diff --git a/packages/k8s/package-lock.json b/packages/k8s/package-lock.json index 079716a8..ba8653dd 100644 --- a/packages/k8s/package-lock.json +++ b/packages/k8s/package-lock.json @@ -26,22 +26,6 @@ "typescript": "^4.6.3" } }, - "../hooklib": { - "version": "0.1.0", - "license": "MIT", - "dependencies": { - "@actions/core": "^1.9.1" - }, - "devDependencies": { - "@types/node": "^17.0.23", - "@typescript-eslint/parser": "^5.18.0", - "@zeit/ncc": "^0.22.3", - "eslint": "^8.12.0", - "eslint-plugin-github": "^4.3.6", - "prettier": "^2.6.2", - "typescript": "^4.6.3" - } - }, "node_modules/@actions/core": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", @@ -2459,8 +2443,12 @@ } }, "node_modules/hooklib": { - "resolved": "../hooklib", - "link": true + "version": "0.1.0", + "resolved": "file:../hooklib", + "license": "MIT", + "dependencies": { + "@actions/core": "^1.9.1" + } }, "node_modules/html-encoding-sniffer": { "version": "2.0.1", @@ -6995,16 +6983,9 @@ "dev": true }, "hooklib": { - "version": "file:../hooklib", + "version": "0.1.0", "requires": { - "@actions/core": "^1.9.1", - "@types/node": "^17.0.23", - "@typescript-eslint/parser": "^5.18.0", - "@zeit/ncc": "^0.22.3", - "eslint": "^8.12.0", - "eslint-plugin-github": "^4.3.6", - "prettier": "^2.6.2", - "typescript": "^4.6.3" + "@actions/core": "^1.9.1" } }, "html-encoding-sniffer": { diff --git a/packages/k8s/src/hooks/prepare-job.ts b/packages/k8s/src/hooks/prepare-job.ts index 1dc7ad3c..7d2001ae 100644 --- a/packages/k8s/src/hooks/prepare-job.ts +++ b/packages/k8s/src/hooks/prepare-job.ts @@ -100,7 +100,8 @@ export async function prepareJob( ) } catch (err) { await prunePods() - throw new Error(`pod failed to come online with error: ${err}`) + const message = err instanceof Error ? err.message : String(err) + throw new Error(`pod failed to come online:\n${message}`) } core.debug('Job pod is ready for traffic') diff --git a/packages/k8s/src/hooks/run-container-step.ts b/packages/k8s/src/hooks/run-container-step.ts index e5261537..92fc962d 100644 --- a/packages/k8s/src/hooks/run-container-step.ts +++ b/packages/k8s/src/hooks/run-container-step.ts @@ -5,6 +5,8 @@ import { createJob, createSecretForEnvs, getContainerJobPodName, + getContainerTerminatedErrors, + getPodByName, getPodLogs, getPodStatus, waitForJobToComplete, @@ -106,6 +108,15 @@ export async function runContainerStep( ) return 1 } + + const pod = await getPodByName(podName) + const terminatedErrors = getContainerTerminatedErrors(pod) + if (terminatedErrors.length > 0) { + core.error( + `Pod ${podName} has unrecoverable container errors:\n${terminatedErrors.join('\n')}` + ) + } + const exitCode = status.containerStatuses[status.containerStatuses.length - 1].state ?.terminated?.exitCode diff --git a/packages/k8s/src/k8s/index.ts b/packages/k8s/src/k8s/index.ts index 1ee93164..e4ee5d94 100644 --- a/packages/k8s/src/k8s/index.ts +++ b/packages/k8s/src/k8s/index.ts @@ -373,7 +373,20 @@ export const UNRECOVERABLE_WAITING_REASONS = new Set([ 'ErrImagePull', 'InvalidImageName', 'CreateContainerConfigError', - 'CreateContainerError' + 'CreateContainerError', + 'FailedMount' +]) + +export const UNRECOVERABLE_EVENT_REASONS = new Set([ + 'FailedScheduling', + 'FailedBinding', + 'FailedMount' +]) + +export const UNRECOVERABLE_TERMINATED_REASONS = new Set([ + 'OOMKilled', + 'Error', + 'FailedPostStartHookError' ]) const MAX_DIAGNOSTIC_EVENTS = 10 @@ -393,6 +406,37 @@ export function getUnrecoverableWaitingReasons(): Set { return reasons } +export function getUnrecoverableEventReasons(): Set { + const extra = process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_EVENT_REASONS'] + if (!extra) { + return UNRECOVERABLE_EVENT_REASONS + } + const reasons = new Set(UNRECOVERABLE_EVENT_REASONS) + for (const reason of extra.split(',')) { + const trimmed = reason.trim() + if (trimmed) { + reasons.add(trimmed) + } + } + return reasons +} + +export function getUnrecoverableTerminatedReasons(): Set { + const extra = + process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_TERMINATED_REASONS'] + if (!extra) { + return UNRECOVERABLE_TERMINATED_REASONS + } + const reasons = new Set(UNRECOVERABLE_TERMINATED_REASONS) + for (const reason of extra.split(',')) { + const trimmed = reason.trim() + if (trimmed) { + reasons.add(trimmed) + } + } + return reasons +} + export function getContainerErrors(pod: k8s.V1Pod): string[] { const errors: string[] = [] const unrecoverableReasons = getUnrecoverableWaitingReasons() @@ -413,6 +457,74 @@ export function getContainerErrors(pod: k8s.V1Pod): string[] { return errors } +export async function getPodEventErrors(podName: string): Promise { + const unrecoverableReasons = getUnrecoverableEventReasons() + let items: k8s.CoreV1Event[] + try { + const { body } = await k8sApi.listNamespacedEvent( + namespace(), + undefined, + undefined, + undefined, + `involvedObject.name=${podName}` + ) + items = body.items + } catch (err) { + core.debug( + `Could not list events for pod ${podName} (the 'events' permission may be missing): ${ + err instanceof Error ? err.message : String(err) + }` + ) + return [] + } + + const errors: string[] = [] + for (const e of items) { + if ( + e.type === 'Warning' && + e.reason && + unrecoverableReasons.has(e.reason) + ) { + errors.push(`Event [Warning] ${e.reason}: ${e.message ?? ''}`) + } + } + return errors +} + +export function getPodConditionErrors(pod: k8s.V1Pod): string[] { + const errors: string[] = [] + for (const cond of pod.status?.conditions ?? []) { + if (cond.status === 'False') { + errors.push( + `Condition ${cond.type}=False (reason: ${cond.reason ?? ''}): ${ + cond.message ?? '' + }` + ) + } + } + return errors +} + +export function getContainerTerminatedErrors(pod: k8s.V1Pod): string[] { + const errors: string[] = [] + const unrecoverableReasons = getUnrecoverableTerminatedReasons() + const allStatuses = [ + ...(pod.status?.initContainerStatuses ?? []), + ...(pod.status?.containerStatuses ?? []) + ] + for (const cs of allStatuses) { + const terminated = cs.state?.terminated + if (terminated?.reason && unrecoverableReasons.has(terminated.reason)) { + errors.push( + `container "${cs.name}": ${terminated.reason} (exit code ${terminated.exitCode}) - ${ + terminated.message ?? '' + }` + ) + } + } + return errors +} + export async function describePodFailure(podName: string): Promise { let pod: k8s.V1Pod try { @@ -437,11 +549,14 @@ export async function describePodFailure(podName: string): Promise { lines.push(`Message: ${status.message}`) } + const separator = '────────────────────────────────────────────────────────────' + lines.push(separator) + for (const cond of status?.conditions ?? []) { if (cond.status === 'False') { lines.push( - `Condition ${cond.type}=False${ - cond.reason ? ` (reason: ${cond.reason})` : '' + ` ✗ ${cond.type}=False${ + cond.reason ? ` (${cond.reason})` : '' }${cond.message ? `: ${cond.message}` : ''}` ) } @@ -455,18 +570,18 @@ export async function describePodFailure(podName: string): Promise { const waiting = cs.state?.waiting if (waiting?.reason) { lines.push( - `Container "${cs.name}" waiting: ${waiting.reason}${ - waiting.message ? ` - ${waiting.message}` : '' + ` ✗ container "${cs.name}": ${waiting.reason}${ + waiting.message ? `\n ${waiting.message}` : '' }` ) } const terminated = cs.state?.terminated if (terminated) { lines.push( - `Container "${cs.name}" terminated: ${ + ` ✗ container "${cs.name}": ${ terminated.reason ?? 'Unknown' } (exit code ${terminated.exitCode})${ - terminated.message ? ` - ${terminated.message}` : '' + terminated.message ? `\n ${terminated.message}` : '' }` ) } @@ -558,6 +673,26 @@ export async function waitForPodPhases( ) } + const conditionErrors = getPodConditionErrors(pod) + if (conditionErrors.length > 0) { + const details = await describePodFailure(podName) + throw new Error( + `Pod ${podName} has unrecoverable condition errors: ${conditionErrors.join( + '; ' + )}\n${details}` + ) + } + + const eventErrors = await getPodEventErrors(podName) + if (eventErrors.length > 0) { + const details = await describePodFailure(podName) + throw new Error( + `Pod ${podName} has unrecoverable event errors: ${eventErrors.join( + '; ' + )}\n${details}` + ) + } + try { await backOffManager.backOff() } catch (error) { diff --git a/packages/k8s/tests/run-container-step-test.ts b/packages/k8s/tests/run-container-step-test.ts index 51a33b76..19c50b5b 100644 --- a/packages/k8s/tests/run-container-step-test.ts +++ b/packages/k8s/tests/run-container-step-test.ts @@ -4,6 +4,14 @@ import { ENV_HOOK_TEMPLATE_PATH } from '../src/k8s/utils' import * as fs from 'fs' import * as yaml from 'js-yaml' import { JOB_CONTAINER_EXTENSION_NAME } from '../src/hooks/constants' +import * as k8s from '@kubernetes/client-node' +import { + getContainerTerminatedErrors, + getUnrecoverableTerminatedReasons, + UNRECOVERABLE_TERMINATED_REASONS +} from '../src/k8s' + +import { PodPhase } from '../src/k8s/utils' jest.useRealTimers() @@ -11,6 +19,34 @@ let testHelper: TestHelper let runContainerStepData: any +function buildPod( + phase?: string, + opts: { + containerStatuses?: k8s.V1ContainerStatus[] + initContainerStatuses?: k8s.V1ContainerStatus[] + } = {} +): k8s.V1Pod { + return { + status: { + phase, + containerStatuses: opts.containerStatuses, + initContainerStatuses: opts.initContainerStatuses + } + } as k8s.V1Pod +} + +function terminatedContainer( + name: string, + reason?: string, + exitCode?: number, + message?: string +): k8s.V1ContainerStatus { + return { + name, + state: { terminated: { reason, exitCode, message } } + } as k8s.V1ContainerStatus +} + describe('Run container step', () => { beforeEach(async () => { testHelper = new TestHelper() @@ -90,3 +126,130 @@ describe('Run container step', () => { ).resolves.not.toThrow() }) }) + +describe('getContainerTerminatedErrors', () => { + it('returns no errors when there are no container statuses', () => { + expect(getContainerTerminatedErrors(buildPod(PodPhase.FAILED))).toEqual( + [] + ) + expect(getContainerTerminatedErrors({} as k8s.V1Pod)).toEqual([]) + }) + + it('returns no errors when containers have running state', () => { + const pod = buildPod(PodPhase.RUNNING, { + containerStatuses: [ + { name: 'job', state: { running: {} } } as k8s.V1ContainerStatus + ] + }) + expect(getContainerTerminatedErrors(pod)).toEqual([]) + }) + + it('returns no errors for Completed terminated reason', () => { + const pod = buildPod(PodPhase.SUCCEEDED, { + containerStatuses: [terminatedContainer('job', 'Completed', 0)] + }) + expect(getContainerTerminatedErrors(pod)).toEqual([]) + }) + + it('detects every unrecoverable terminated reason', () => { + for (const reason of Array.from(UNRECOVERABLE_TERMINATED_REASONS)) { + const pod = buildPod(PodPhase.FAILED, { + containerStatuses: [terminatedContainer('job', reason, 1)] + }) + const errors = getContainerTerminatedErrors(pod) + expect(errors.length).toBe(1) + expect(errors[0]).toContain(reason) + expect(errors[0]).toContain('exit code 1') + } + }) + + it('detects OOMKilled with message', () => { + const pod = buildPod(PodPhase.FAILED, { + containerStatuses: [ + terminatedContainer('job', 'OOMKilled', 137, 'Memory limit exceeded') + ] + }) + const errors = getContainerTerminatedErrors(pod) + expect(errors).toEqual([ + 'container "job": OOMKilled (exit code 137) - Memory limit exceeded' + ]) + }) + + it('detects Error with non-zero exit code', () => { + const pod = buildPod(PodPhase.FAILED, { + containerStatuses: [ + terminatedContainer('job', 'Error', 1, 'container crashed') + ] + }) + const errors = getContainerTerminatedErrors(pod) + expect(errors).toEqual([ + 'container "job": Error (exit code 1) - container crashed' + ]) + }) + + it('detects FailedPostStartHookError', () => { + const pod = buildPod(PodPhase.FAILED, { + containerStatuses: [ + terminatedContainer( + 'job', + 'FailedPostStartHookError', + 137, + 'postStart hook failed' + ) + ] + }) + const errors = getContainerTerminatedErrors(pod) + expect(errors).toEqual([ + 'container "job": FailedPostStartHookError (exit code 137) - postStart hook failed' + ]) + }) + + it('inspects init containers as well as regular containers', () => { + const pod = buildPod(PodPhase.FAILED, { + initContainerStatuses: [terminatedContainer('init', 'OOMKilled', 137)], + containerStatuses: [terminatedContainer('job', 'Error', 1)] + }) + const errors = getContainerTerminatedErrors(pod) + expect(errors.length).toBe(2) + expect(errors[0]).toContain('init') + expect(errors[1]).toContain('job') + }) + + it('returns empty for terminated reason not in the set', () => { + const pod = buildPod(PodPhase.FAILED, { + containerStatuses: [terminatedContainer('job', 'SomeOtherReason', 1)] + }) + expect(getContainerTerminatedErrors(pod)).toEqual([]) + }) +}) + +describe('getUnrecoverableTerminatedReasons', () => { + afterEach(() => { + delete process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_TERMINATED_REASONS'] + }) + + it('returns the built-in defaults when the env var is unset', () => { + expect(getUnrecoverableTerminatedReasons()).toEqual( + UNRECOVERABLE_TERMINATED_REASONS + ) + }) + + it('adds extra reasons from the env var without dropping the defaults', () => { + process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_TERMINATED_REASONS'] = + 'CustomReason, AnotherReason' + const reasons = getUnrecoverableTerminatedReasons() + for (const builtin of Array.from(UNRECOVERABLE_TERMINATED_REASONS)) { + expect(reasons.has(builtin)).toBe(true) + } + expect(reasons.has('CustomReason')).toBe(true) + expect(reasons.has('AnotherReason')).toBe(true) + }) + + it('filters empty strings from env var', () => { + process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_TERMINATED_REASONS'] = + ', CrashLoopBackOff, ' + const reasons = getUnrecoverableTerminatedReasons() + expect(reasons.has('CrashLoopBackOff')).toBe(true) + expect(reasons.has('')).toBe(false) + }) +}) diff --git a/packages/k8s/tests/wait-for-pod-phases-test.ts b/packages/k8s/tests/wait-for-pod-phases-test.ts index 30e56aa0..b08843e6 100644 --- a/packages/k8s/tests/wait-for-pod-phases-test.ts +++ b/packages/k8s/tests/wait-for-pod-phases-test.ts @@ -2,8 +2,15 @@ import * as k8s from '@kubernetes/client-node' import { describePodFailure, getContainerErrors, + getContainerTerminatedErrors, + getPodConditionErrors, + getPodEventErrors, + getUnrecoverableEventReasons, + getUnrecoverableTerminatedReasons, getUnrecoverableWaitingReasons, parsePodPhase, + UNRECOVERABLE_EVENT_REASONS, + UNRECOVERABLE_TERMINATED_REASONS, UNRECOVERABLE_WAITING_REASONS, waitForPodPhases } from '../src/k8s' @@ -14,13 +21,15 @@ function buildPod( opts: { containerStatuses?: k8s.V1ContainerStatus[] initContainerStatuses?: k8s.V1ContainerStatus[] + conditions?: k8s.V1PodCondition[] } = {} ): k8s.V1Pod { return { status: { phase, containerStatuses: opts.containerStatuses, - initContainerStatuses: opts.initContainerStatuses + initContainerStatuses: opts.initContainerStatuses, + conditions: opts.conditions } } as k8s.V1Pod } @@ -36,6 +45,18 @@ function waitingContainer( } as k8s.V1ContainerStatus } +function terminatedContainer( + name: string, + reason?: string, + exitCode?: number, + message?: string +): k8s.V1ContainerStatus { + return { + name, + state: { terminated: { reason, exitCode, message } } + } as k8s.V1ContainerStatus +} + describe('parsePodPhase', () => { it('returns the phase when it is a known value', () => { expect(parsePodPhase(buildPod(PodPhase.RUNNING))).toBe(PodPhase.RUNNING) @@ -67,7 +88,7 @@ describe('getContainerErrors', () => { expect(getContainerErrors(pod)).toEqual([]) }) - it('detects every unrecoverable waiting reason', () => { + it('detects every unrecoverable waiting reason including FailedMount', () => { for (const reason of Array.from(UNRECOVERABLE_WAITING_REASONS)) { const pod = buildPod(PodPhase.PENDING, { containerStatuses: [waitingContainer('job', reason)] @@ -115,6 +136,295 @@ describe('getContainerErrors', () => { }) }) +describe('getPodConditionErrors', () => { + it('returns empty array when no conditions', () => { + expect(getPodConditionErrors(buildPod(PodPhase.PENDING))).toEqual([]) + expect(getPodConditionErrors({} as k8s.V1Pod)).toEqual([]) + }) + + it('returns empty array when all conditions are True', () => { + const pod = buildPod(PodPhase.RUNNING, { + conditions: [ + { type: 'PodScheduled', status: 'True' } as k8s.V1PodCondition, + { type: 'Ready', status: 'True' } as k8s.V1PodCondition + ] + }) + expect(getPodConditionErrors(pod)).toEqual([]) + }) + + it('detects PodScheduled=False with reason and message', () => { + const pod = buildPod(PodPhase.PENDING, { + conditions: [ + { + type: 'PodScheduled', + status: 'False', + reason: 'Unschedulable', + message: '0/1 nodes are available: 1 Insufficient memory.' + } as k8s.V1PodCondition + ] + }) + expect(getPodConditionErrors(pod)).toEqual([ + 'Condition PodScheduled=False (reason: Unschedulable): 0/1 nodes are available: 1 Insufficient memory.' + ]) + }) + + it('detects multiple False conditions', () => { + const pod = buildPod(PodPhase.PENDING, { + conditions: [ + { + type: 'PodScheduled', + status: 'False', + reason: 'Unschedulable', + message: 'no nodes' + } as k8s.V1PodCondition, + { + type: 'Ready', + status: 'False', + reason: 'ContainersNotReady', + message: 'containers unready' + } as k8s.V1PodCondition + ] + }) + const errors = getPodConditionErrors(pod) + expect(errors.length).toBe(2) + expect(errors[0]).toContain('PodScheduled=False') + expect(errors[1]).toContain('Ready=False') + }) + + it('handles conditions without reason or message', () => { + const pod = buildPod(PodPhase.PENDING, { + conditions: [ + { type: 'Ready', status: 'False' } as k8s.V1PodCondition + ] + }) + expect(getPodConditionErrors(pod)).toEqual([ + 'Condition Ready=False (reason: ): ' + ]) + }) +}) + +describe('getPodEventErrors', () => { + let eventSpy: jest.SpyInstance + + beforeEach(() => { + process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] = 'default' + eventSpy = jest.spyOn(k8s.CoreV1Api.prototype, 'listNamespacedEvent') + }) + + afterEach(() => { + jest.restoreAllMocks() + delete process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] + }) + + it('detects FailedScheduling event', async () => { + eventSpy.mockResolvedValue({ + body: { + items: [ + { + type: 'Warning', + reason: 'FailedScheduling', + message: '0/1 nodes are available' + } + ] + } + } as never) + + const errors = await getPodEventErrors('my-pod') + expect(errors).toEqual([ + 'Event [Warning] FailedScheduling: 0/1 nodes are available' + ]) + }) + + it('detects FailedBinding event', async () => { + eventSpy.mockResolvedValue({ + body: { + items: [ + { + type: 'Warning', + reason: 'FailedBinding', + message: 'no persistent volumes available' + } + ] + } + } as never) + + const errors = await getPodEventErrors('my-pod') + expect(errors).toEqual([ + 'Event [Warning] FailedBinding: no persistent volumes available' + ]) + }) + + it('detects FailedMount event', async () => { + eventSpy.mockResolvedValue({ + body: { + items: [ + { + type: 'Warning', + reason: 'FailedMount', + message: 'MountVolume.SetUp failed for volume' + } + ] + } + } as never) + + const errors = await getPodEventErrors('my-pod') + expect(errors).toEqual([ + 'Event [Warning] FailedMount: MountVolume.SetUp failed for volume' + ]) + }) + + it('returns empty when events are Normal type', async () => { + eventSpy.mockResolvedValue({ + body: { + items: [ + { + type: 'Normal', + reason: 'Scheduled', + message: 'assigned' + } + ] + } + } as never) + + const errors = await getPodEventErrors('my-pod') + expect(errors).toEqual([]) + }) + + it('returns empty when event reason is not in unrecoverable set', async () => { + eventSpy.mockResolvedValue({ + body: { + items: [ + { + type: 'Warning', + reason: 'SomeOtherReason', + message: 'something happened' + } + ] + } + } as never) + + const errors = await getPodEventErrors('my-pod') + expect(errors).toEqual([]) + }) + + it('returns empty array when event API is forbidden', async () => { + eventSpy.mockRejectedValue(new Error('events is forbidden') as never) + + const errors = await getPodEventErrors('my-pod') + expect(errors).toEqual([]) + }) + + it('detects multiple unrecoverable events', async () => { + eventSpy.mockResolvedValue({ + body: { + items: [ + { + type: 'Warning', + reason: 'FailedScheduling', + message: '0/1 nodes' + }, + { + type: 'Warning', + reason: 'FailedMount', + message: 'mount failed' + } + ] + } + } as never) + + const errors = await getPodEventErrors('my-pod') + expect(errors.length).toBe(2) + expect(errors[0]).toContain('FailedScheduling') + expect(errors[1]).toContain('FailedMount') + }) +}) + +describe('getContainerTerminatedErrors', () => { + it('returns empty when no container statuses', () => { + expect(getContainerTerminatedErrors(buildPod(PodPhase.FAILED))).toEqual([]) + expect(getContainerTerminatedErrors({} as k8s.V1Pod)).toEqual([]) + }) + + it('returns empty when containers are running or waiting', () => { + const pod = buildPod(PodPhase.RUNNING, { + containerStatuses: [ + { name: 'job', state: { running: {} } } as k8s.V1ContainerStatus, + waitingContainer('init', 'ContainerCreating') + ] + }) + expect(getContainerTerminatedErrors(pod)).toEqual([]) + }) + + it('detects OOMKilled', () => { + const pod = buildPod(PodPhase.FAILED, { + containerStatuses: [ + terminatedContainer('job', 'OOMKilled', 137, 'Memory limit exceeded') + ] + }) + expect(getContainerTerminatedErrors(pod)).toEqual([ + 'container "job": OOMKilled (exit code 137) - Memory limit exceeded' + ]) + }) + + it('detects Error reason with non-zero exit code', () => { + const pod = buildPod(PodPhase.FAILED, { + containerStatuses: [terminatedContainer('job', 'Error', 1)] + }) + expect(getContainerTerminatedErrors(pod)).toEqual([ + 'container "job": Error (exit code 1) - ' + ]) + }) + + it('detects FailedPostStartHookError', () => { + const pod = buildPod(PodPhase.FAILED, { + containerStatuses: [ + terminatedContainer( + 'job', + 'FailedPostStartHookError', + 137, + 'postStart hook failed' + ) + ] + }) + expect(getContainerTerminatedErrors(pod)).toEqual([ + 'container "job": FailedPostStartHookError (exit code 137) - postStart hook failed' + ]) + }) + + it('detects every unrecoverable terminated reason', () => { + for (const reason of Array.from(UNRECOVERABLE_TERMINATED_REASONS)) { + const pod = buildPod(PodPhase.FAILED, { + containerStatuses: [terminatedContainer('job', reason, 1)] + }) + expect(getContainerTerminatedErrors(pod)).toEqual([ + `container "job": ${reason} (exit code 1) - ` + ]) + } + }) + + it('does not detect Completed reason (not in set)', () => { + const pod = buildPod(PodPhase.SUCCEEDED, { + containerStatuses: [ + terminatedContainer('job', 'Completed', 0) + ] + }) + expect(getContainerTerminatedErrors(pod)).toEqual([]) + }) + + it('inspects init containers as well', () => { + const pod = buildPod(PodPhase.FAILED, { + initContainerStatuses: [ + terminatedContainer('init', 'OOMKilled', 137) + ], + containerStatuses: [terminatedContainer('job', 'Error', 1)] + }) + expect(getContainerTerminatedErrors(pod)).toEqual([ + 'container "init": OOMKilled (exit code 137) - ', + 'container "job": Error (exit code 1) - ' + ]) + }) +}) + describe('waitForPodPhases', () => { let readSpy: jest.SpyInstance let eventSpy: jest.SpyInstance @@ -180,6 +490,54 @@ describe('waitForPodPhases', () => { ) ).rejects.toThrow('Pod my-pod is unhealthy with phase status Failed') }) + + it('surfaces condition errors when PodScheduled=False', async () => { + readSpy.mockResolvedValue({ + body: buildPod(PodPhase.PENDING, { + conditions: [ + { + type: 'PodScheduled', + status: 'False', + reason: 'Unschedulable', + message: '0/1 nodes are available' + } as k8s.V1PodCondition + ] + }) + } as never) + + await expect( + waitForPodPhases( + 'my-pod', + new Set([PodPhase.RUNNING]), + new Set([PodPhase.PENDING]) + ) + ).rejects.toThrow('condition errors') + }) + + it('surfaces event errors when FailedScheduling event detected', async () => { + readSpy.mockResolvedValue({ + body: buildPod(PodPhase.PENDING) + } as never) + eventSpy.mockResolvedValue({ + body: { + items: [ + { + type: 'Warning', + reason: 'FailedScheduling', + message: '0/1 nodes are available' + } + ] + } + } as never) + + await expect( + waitForPodPhases( + 'my-pod', + new Set([PodPhase.RUNNING]), + new Set([PodPhase.PENDING]) + ) + ).rejects.toThrow('event errors') + }) }) describe('getUnrecoverableWaitingReasons', () => { @@ -214,6 +572,66 @@ describe('getUnrecoverableWaitingReasons', () => { 'container "job": CrashLoopBackOff' ]) }) + + it('filters empty strings from env var', () => { + process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_WAITING_REASONS'] = ', , ' + const reasons = getUnrecoverableWaitingReasons() + expect(reasons).toEqual(UNRECOVERABLE_WAITING_REASONS) + }) +}) + +describe('getUnrecoverableEventReasons', () => { + afterEach(() => { + delete process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_EVENT_REASONS'] + }) + + it('returns the built-in defaults when the env var is unset', () => { + expect(getUnrecoverableEventReasons()).toEqual(UNRECOVERABLE_EVENT_REASONS) + }) + + it('adds extra reasons from the env var without dropping the defaults', () => { + process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_EVENT_REASONS'] = + 'SomeOtherReason' + const reasons = getUnrecoverableEventReasons() + for (const builtin of Array.from(UNRECOVERABLE_EVENT_REASONS)) { + expect(reasons.has(builtin)).toBe(true) + } + expect(reasons.has('SomeOtherReason')).toBe(true) + }) + + it('filters empty strings from env var', () => { + process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_EVENT_REASONS'] = ', , ' + const reasons = getUnrecoverableEventReasons() + expect(reasons).toEqual(UNRECOVERABLE_EVENT_REASONS) + }) +}) + +describe('getUnrecoverableTerminatedReasons', () => { + afterEach(() => { + delete process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_TERMINATED_REASONS'] + }) + + it('returns the built-in defaults when the env var is unset', () => { + expect(getUnrecoverableTerminatedReasons()).toEqual( + UNRECOVERABLE_TERMINATED_REASONS + ) + }) + + it('adds extra reasons from the env var without dropping the defaults', () => { + process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_TERMINATED_REASONS'] = + 'DeadlineExceeded' + const reasons = getUnrecoverableTerminatedReasons() + for (const builtin of Array.from(UNRECOVERABLE_TERMINATED_REASONS)) { + expect(reasons.has(builtin)).toBe(true) + } + expect(reasons.has('DeadlineExceeded')).toBe(true) + }) + + it('filters empty strings from env var', () => { + process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_TERMINATED_REASONS'] = ', , ' + const reasons = getUnrecoverableTerminatedReasons() + expect(reasons).toEqual(UNRECOVERABLE_TERMINATED_REASONS) + }) }) describe('describePodFailure', () => { @@ -232,7 +650,7 @@ describe('describePodFailure', () => { delete process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] }) - it('reports phase, failing conditions and terminated containers', async () => { + it('reports phase, separator, ✗ conditions and ✗ terminated containers', async () => { readSpy.mockResolvedValue({ body: { status: { @@ -261,14 +679,11 @@ describe('describePodFailure', () => { const description = await describePodFailure('my-pod') expect(description).toContain('Phase: Failed (reason: Evicted)') + expect(description).toContain('Message: The node was low on resource: memory') + expect(description).toContain('────────────────────────────────────────────────────────────') + expect(description).toContain('✗ PodScheduled=False (Unschedulable): no nodes available') expect(description).toContain( - 'Message: The node was low on resource: memory' - ) - expect(description).toContain( - 'Condition PodScheduled=False (reason: Unschedulable): no nodes available' - ) - expect(description).toContain( - 'Container "job" terminated: OOMKilled (exit code 137)' + '✗ container "job": OOMKilled (exit code 137)' ) }) @@ -320,4 +735,29 @@ describe('describePodFailure', () => { const description = await describePodFailure('my-pod') expect(description).toContain('Could not read pod my-pod for diagnostics') }) + + it('formats waiting container with ✗ marker', async () => { + readSpy.mockResolvedValue({ + body: { + status: { + phase: PodPhase.PENDING, + containerStatuses: [ + { + name: 'job', + state: { + waiting: { + reason: 'ErrImagePull', + message: 'image not found' + } + } + } + ] + } + } + } as never) + + const description = await describePodFailure('my-pod') + expect(description).toContain('✗ container "job": ErrImagePull') + expect(description).toContain(' image not found') + }) }) From b03a03850528602c5fd18b1eef7fcde1f6c40e17 Mon Sep 17 00:00:00 2001 From: xiaoni Date: Wed, 1 Jul 2026 07:07:30 +0000 Subject: [PATCH 3/5] fix(runner-container-hooks): add describePodFailure diagnostic output to Running-phase terminated error messages --- packages/k8s/src/hooks/run-container-step.ts | 4 +- packages/k8s/tests/run-container-step-test.ts | 167 ++++++++++++++++++ 2 files changed, 170 insertions(+), 1 deletion(-) diff --git a/packages/k8s/src/hooks/run-container-step.ts b/packages/k8s/src/hooks/run-container-step.ts index 92fc962d..1421c5ab 100644 --- a/packages/k8s/src/hooks/run-container-step.ts +++ b/packages/k8s/src/hooks/run-container-step.ts @@ -4,6 +4,7 @@ import { RunContainerStepArgs } from 'hooklib' import { createJob, createSecretForEnvs, + describePodFailure, getContainerJobPodName, getContainerTerminatedErrors, getPodByName, @@ -112,8 +113,9 @@ export async function runContainerStep( const pod = await getPodByName(podName) const terminatedErrors = getContainerTerminatedErrors(pod) if (terminatedErrors.length > 0) { + const details = await describePodFailure(podName) core.error( - `Pod ${podName} has unrecoverable container errors:\n${terminatedErrors.join('\n')}` + `Pod ${podName} has unrecoverable container errors:\n${terminatedErrors.join('\n')}\n${details}` ) } diff --git a/packages/k8s/tests/run-container-step-test.ts b/packages/k8s/tests/run-container-step-test.ts index 19c50b5b..f2dee50a 100644 --- a/packages/k8s/tests/run-container-step-test.ts +++ b/packages/k8s/tests/run-container-step-test.ts @@ -10,6 +10,9 @@ import { getUnrecoverableTerminatedReasons, UNRECOVERABLE_TERMINATED_REASONS } from '../src/k8s' +import * as k8sModule from '../src/k8s' +import * as coreModule from '@actions/core' +import { RunContainerStepArgs } from 'hooklib' import { PodPhase } from '../src/k8s/utils' @@ -253,3 +256,167 @@ describe('getUnrecoverableTerminatedReasons', () => { expect(reasons.has('')).toBe(false) }) }) + +describe('runContainerStep includes describePodFailure output for terminated errors', () => { + let coreErrorSpy: jest.SpyInstance + let createJobSpy: jest.SpyInstance + let getContainerJobPodNameSpy: jest.SpyInstance + let waitForPodPhasesSpy: jest.SpyInstance + let getPodLogsSpy: jest.SpyInstance + let waitForJobToCompleteSpy: jest.SpyInstance + let getPodStatusSpy: jest.SpyInstance + let getPodByNameSpy: jest.SpyInstance + let describePodFailureSpy: jest.SpyInstance + + const podName = 'test-pod-abc123' + const jobName = 'test-job-xyz789' + + const diagnosticOutput = [ + 'Phase: Failed', + '────────────────────────────────────────────────────────────', + ' ✗ Ready=False (ContainersNotReady): containers with unready status: [job]', + ' ✗ container "job": OOMKilled (exit code 137)', + ' Memory limit exceeded' + ].join('\n') + + function makeMinimalArgs(): RunContainerStepArgs { + return { + image: 'test-image:latest', + workingDirectory: '/__w/repo/repo', + entryPoint: 'bash', + entryPointArgs: ['-c', 'echo test'], + systemMountVolumes: [] + } as RunContainerStepArgs + } + + function podStatusWithTerminated( + reason: string, + exitCode: number, + message?: string + ): k8s.V1PodStatus { + return { + phase: 'Failed', + containerStatuses: [ + { + name: 'job', + image: 'test-image:latest', + imageID: '', + ready: false, + restartCount: 0, + state: { + terminated: { exitCode, reason, message } + } + } as k8s.V1ContainerStatus + ] + } + } + + beforeEach(() => { + process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] = 'default' + delete process.env[ENV_HOOK_TEMPLATE_PATH] + + coreErrorSpy = jest.spyOn(coreModule, 'error').mockImplementation(() => {}) + + createJobSpy = jest.spyOn(k8sModule, 'createJob').mockResolvedValue({ + metadata: { name: jobName } + } as k8s.V1Job) + + getContainerJobPodNameSpy = jest + .spyOn(k8sModule, 'getContainerJobPodName') + .mockResolvedValue(podName) + + waitForPodPhasesSpy = jest + .spyOn(k8sModule, 'waitForPodPhases') + .mockResolvedValue(undefined) + + getPodLogsSpy = jest + .spyOn(k8sModule, 'getPodLogs') + .mockResolvedValue(undefined) + + waitForJobToCompleteSpy = jest + .spyOn(k8sModule, 'waitForJobToComplete') + .mockResolvedValue(undefined) + + describePodFailureSpy = jest + .spyOn(k8sModule, 'describePodFailure') + .mockResolvedValue(diagnosticOutput) + }) + + afterEach(() => { + jest.restoreAllMocks() + delete process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] + }) + + it('includes describePodFailure output in core.error for OOMKilled container', async () => { + const pod: k8s.V1Pod = buildPod(PodPhase.FAILED, { + containerStatuses: [ + terminatedContainer('job', 'OOMKilled', 137, 'Memory limit exceeded') + ] + }) + getPodStatusSpy = jest + .spyOn(k8sModule, 'getPodStatus') + .mockResolvedValue(podStatusWithTerminated('OOMKilled', 137, 'Memory limit exceeded')) + getPodByNameSpy = jest + .spyOn(k8sModule, 'getPodByName') + .mockResolvedValue(pod) + + await runContainerStep(makeMinimalArgs()) + + expect(describePodFailureSpy).toHaveBeenCalledWith(podName) + expect(coreErrorSpy).toHaveBeenCalledTimes(1) + const errorMessage = coreErrorSpy.mock.calls[0][0] + expect(errorMessage).toContain('OOMKilled') + expect(errorMessage).toContain(diagnosticOutput) + }) + + it('includes describePodFailure output in core.error for Error (exit non-zero) container', async () => { + const pod: k8s.V1Pod = buildPod(PodPhase.FAILED, { + containerStatuses: [ + terminatedContainer('job', 'Error', 1, 'container crashed') + ] + }) + getPodStatusSpy = jest + .spyOn(k8sModule, 'getPodStatus') + .mockResolvedValue(podStatusWithTerminated('Error', 1, 'container crashed')) + getPodByNameSpy = jest + .spyOn(k8sModule, 'getPodByName') + .mockResolvedValue(pod) + + await runContainerStep(makeMinimalArgs()) + + expect(describePodFailureSpy).toHaveBeenCalledWith(podName) + expect(coreErrorSpy).toHaveBeenCalledTimes(1) + const errorMessage = coreErrorSpy.mock.calls[0][0] + expect(errorMessage).toContain('Error') + expect(errorMessage).toContain(diagnosticOutput) + }) + + it('includes describePodFailure output in core.error for FailedPostStartHookError container', async () => { + const pod: k8s.V1Pod = buildPod(PodPhase.FAILED, { + containerStatuses: [ + terminatedContainer( + 'job', + 'FailedPostStartHookError', + 137, + 'postStart hook failed' + ) + ] + }) + getPodStatusSpy = jest + .spyOn(k8sModule, 'getPodStatus') + .mockResolvedValue( + podStatusWithTerminated('FailedPostStartHookError', 137, 'postStart hook failed') + ) + getPodByNameSpy = jest + .spyOn(k8sModule, 'getPodByName') + .mockResolvedValue(pod) + + await runContainerStep(makeMinimalArgs()) + + expect(describePodFailureSpy).toHaveBeenCalledWith(podName) + expect(coreErrorSpy).toHaveBeenCalledTimes(1) + const errorMessage = coreErrorSpy.mock.calls[0][0] + expect(errorMessage).toContain('FailedPostStartHookError') + expect(errorMessage).toContain(diagnosticOutput) + }) +}) From 1366e96ed4a93c31af3385d23e1dc9e54b33aa8b Mon Sep 17 00:00:00 2001 From: Longwt123 <1075015495@qq.com> Date: Wed, 1 Jul 2026 08:07:58 +0000 Subject: [PATCH 4/5] fix(runner-container-hooks): address 5 PR review bugs for k8s error detection --- packages/k8s/src/hooks/prepare-job.ts | 6 +- packages/k8s/src/hooks/run-container-step.ts | 1 + packages/k8s/src/k8s/index.ts | 15 +- packages/k8s/tests/prepare-job-test.ts | 91 +++++++++++- packages/k8s/tests/run-container-step-test.ts | 53 +++++++ .../k8s/tests/wait-for-pod-phases-test.ts | 134 ++++++++++++++++-- 6 files changed, 271 insertions(+), 29 deletions(-) diff --git a/packages/k8s/src/hooks/prepare-job.ts b/packages/k8s/src/hooks/prepare-job.ts index 7d2001ae..3072e8dc 100644 --- a/packages/k8s/src/hooks/prepare-job.ts +++ b/packages/k8s/src/hooks/prepare-job.ts @@ -99,7 +99,11 @@ export async function prepareJob( getPrepareJobTimeoutSeconds() ) } catch (err) { - await prunePods() + try { + await prunePods() + } catch (pruneErr) { + core.error(`Failed to prune pods: ${pruneErr instanceof Error ? pruneErr.message : String(pruneErr)}`) + } const message = err instanceof Error ? err.message : String(err) throw new Error(`pod failed to come online:\n${message}`) } diff --git a/packages/k8s/src/hooks/run-container-step.ts b/packages/k8s/src/hooks/run-container-step.ts index 1421c5ab..e544cd63 100644 --- a/packages/k8s/src/hooks/run-container-step.ts +++ b/packages/k8s/src/hooks/run-container-step.ts @@ -117,6 +117,7 @@ export async function runContainerStep( core.error( `Pod ${podName} has unrecoverable container errors:\n${terminatedErrors.join('\n')}\n${details}` ) + return 1 } const exitCode = diff --git a/packages/k8s/src/k8s/index.ts b/packages/k8s/src/k8s/index.ts index e4ee5d94..134e1e01 100644 --- a/packages/k8s/src/k8s/index.ts +++ b/packages/k8s/src/k8s/index.ts @@ -373,8 +373,7 @@ export const UNRECOVERABLE_WAITING_REASONS = new Set([ 'ErrImagePull', 'InvalidImageName', 'CreateContainerConfigError', - 'CreateContainerError', - 'FailedMount' + 'CreateContainerError' ]) export const UNRECOVERABLE_EVENT_REASONS = new Set([ @@ -494,7 +493,7 @@ export async function getPodEventErrors(podName: string): Promise { export function getPodConditionErrors(pod: k8s.V1Pod): string[] { const errors: string[] = [] for (const cond of pod.status?.conditions ?? []) { - if (cond.status === 'False') { + if (cond.type === 'PodScheduled' && cond.status === 'False' && cond.reason === 'Unschedulable') { errors.push( `Condition ${cond.type}=False (reason: ${cond.reason ?? ''}): ${ cond.message ?? '' @@ -683,16 +682,6 @@ export async function waitForPodPhases( ) } - const eventErrors = await getPodEventErrors(podName) - if (eventErrors.length > 0) { - const details = await describePodFailure(podName) - throw new Error( - `Pod ${podName} has unrecoverable event errors: ${eventErrors.join( - '; ' - )}\n${details}` - ) - } - try { await backOffManager.backOff() } catch (error) { diff --git a/packages/k8s/tests/prepare-job-test.ts b/packages/k8s/tests/prepare-job-test.ts index ca94e6c5..8c371536 100644 --- a/packages/k8s/tests/prepare-job-test.ts +++ b/packages/k8s/tests/prepare-job-test.ts @@ -9,10 +9,12 @@ import { generateContainerName, readExtensionFromFile } from '../src/k8s/utils' -import { getPodByName } from '../src/k8s' +import { getPodByName, prunePods, waitForPodPhases } from '../src/k8s' import { V1Container } from '@kubernetes/client-node' import * as yaml from 'js-yaml' import { JOB_CONTAINER_NAME } from '../src/hooks/constants' +import * as k8sModule from '../src/k8s' +import * as coreModule from '@actions/core' jest.useRealTimers() @@ -244,3 +246,90 @@ describe('Prepare job', () => { } ) }) + +describe('prepareJob error handling - prunePods try-catch', () => { + let coreErrorSpy: jest.SpyInstance + let prunePodsSpy: jest.SpyInstance + let waitForPodPhasesSpy: jest.SpyInstance + let createPodSpy: jest.SpyInstance + + beforeEach(() => { + process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] = 'default' + delete process.env[ENV_HOOK_TEMPLATE_PATH] + + coreErrorSpy = jest.spyOn(coreModule, 'error').mockImplementation(() => {}) + prunePodsSpy = jest.spyOn(k8sModule, 'prunePods').mockResolvedValue(undefined) + createPodSpy = jest.spyOn(k8sModule, 'createPod').mockResolvedValue({ + metadata: { name: 'test-pod' } + } as any) + waitForPodPhasesSpy = jest + .spyOn(k8sModule, 'waitForPodPhases') + .mockRejectedValue(new Error('pod failed to come online: unrecoverable condition')) + }) + + afterEach(() => { + jest.restoreAllMocks() + delete process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] + }) + + it('propagates original waitForPodPhases error even when prunePods succeeds', async () => { + const args = { + container: { + image: 'test-image:latest', + environmentVariables: {} + }, + services: [] + } as any + + await expect(prepareJob(args, '/tmp/test-output.json')).rejects.toThrow( + 'pod failed to come online' + ) + expect(prunePodsSpy).toHaveBeenCalledTimes(2) + }) + + it('propagates original waitForPodPhases error even when prunePods throws', async () => { + prunePodsSpy + .mockResolvedValueOnce(undefined) + .mockRejectedValueOnce(new Error('k8s API error: forbidden')) + + const args = { + container: { + image: 'test-image:latest', + environmentVariables: {} + }, + services: [] + } as any + + await expect(prepareJob(args, '/tmp/test-output.json')).rejects.toThrow( + 'pod failed to come online: unrecoverable condition' + ) + expect(coreErrorSpy).toHaveBeenCalledWith( + expect.stringContaining('Failed to prune pods') + ) + }) + + it('logs prunePods error via core.error without masking original error message', async () => { + prunePodsSpy + .mockResolvedValueOnce(undefined) + .mockRejectedValueOnce(new Error('k8s API error: forbidden')) + + const args = { + container: { + image: 'test-image:latest', + environmentVariables: {} + }, + services: [] + } as any + + try { + await prepareJob(args, '/tmp/test-output.json') + } catch (err) { + expect((err as Error).message).toContain('pod failed to come online') + expect((err as Error).message).toContain('unrecoverable condition') + expect((err as Error).message).not.toContain('k8s API error: forbidden') + } + expect(coreErrorSpy).toHaveBeenCalledWith( + expect.stringContaining('k8s API error: forbidden') + ) + }) +}) diff --git a/packages/k8s/tests/run-container-step-test.ts b/packages/k8s/tests/run-container-step-test.ts index f2dee50a..5c3fe669 100644 --- a/packages/k8s/tests/run-container-step-test.ts +++ b/packages/k8s/tests/run-container-step-test.ts @@ -419,4 +419,57 @@ describe('runContainerStep includes describePodFailure output for terminated err expect(errorMessage).toContain('FailedPostStartHookError') expect(errorMessage).toContain(diagnosticOutput) }) + + it('returns 1 when terminatedErrors are detected regardless of exitCode', async () => { + const pod: k8s.V1Pod = buildPod(PodPhase.FAILED, { + containerStatuses: [ + terminatedContainer('job', 'OOMKilled', 137, 'Memory limit exceeded') + ] + }) + getPodStatusSpy = jest + .spyOn(k8sModule, 'getPodStatus') + .mockResolvedValue(podStatusWithTerminated('OOMKilled', 137, 'Memory limit exceeded')) + getPodByNameSpy = jest + .spyOn(k8sModule, 'getPodByName') + .mockResolvedValue(pod) + + const exitCode = await runContainerStep(makeMinimalArgs()) + expect(exitCode).toBe(1) + }) + + it('returns 1 when init container has terminated error and main container exitCode is undefined', async () => { + const pod: k8s.V1Pod = { + status: { + phase: 'Failed', + initContainerStatuses: [ + terminatedContainer('init', 'OOMKilled', 137) + ], + containerStatuses: [ + { name: 'job', state: { running: {} } } as k8s.V1ContainerStatus + ] + } + } as k8s.V1Pod + const podStatus: k8s.V1PodStatus = { + phase: 'Failed', + containerStatuses: [ + { + name: 'job', + image: 'test-image:latest', + imageID: '', + ready: false, + restartCount: 0, + state: { running: {} } + } as k8s.V1ContainerStatus + ] + } + getPodStatusSpy = jest + .spyOn(k8sModule, 'getPodStatus') + .mockResolvedValue(podStatus) + getPodByNameSpy = jest + .spyOn(k8sModule, 'getPodByName') + .mockResolvedValue(pod) + + const exitCode = await runContainerStep(makeMinimalArgs()) + expect(exitCode).toBe(1) + }) }) diff --git a/packages/k8s/tests/wait-for-pod-phases-test.ts b/packages/k8s/tests/wait-for-pod-phases-test.ts index b08843e6..d2c0367f 100644 --- a/packages/k8s/tests/wait-for-pod-phases-test.ts +++ b/packages/k8s/tests/wait-for-pod-phases-test.ts @@ -88,7 +88,14 @@ describe('getContainerErrors', () => { expect(getContainerErrors(pod)).toEqual([]) }) - it('detects every unrecoverable waiting reason including FailedMount', () => { + it('does not detect FailedMount as a waiting reason', () => { + const pod = buildPod(PodPhase.PENDING, { + containerStatuses: [waitingContainer('job', 'FailedMount')] + }) + expect(getContainerErrors(pod)).toEqual([]) + }) + + it('detects every unrecoverable waiting reason', () => { for (const reason of Array.from(UNRECOVERABLE_WAITING_REASONS)) { const pod = buildPod(PodPhase.PENDING, { containerStatuses: [waitingContainer('job', reason)] @@ -152,7 +159,7 @@ describe('getPodConditionErrors', () => { expect(getPodConditionErrors(pod)).toEqual([]) }) - it('detects PodScheduled=False with reason and message', () => { + it('detects PodScheduled=False with Unschedulable reason only', () => { const pod = buildPod(PodPhase.PENDING, { conditions: [ { @@ -168,7 +175,35 @@ describe('getPodConditionErrors', () => { ]) }) - it('detects multiple False conditions', () => { + it('ignores Ready=False which is normal during Pending phase', () => { + const pod = buildPod(PodPhase.PENDING, { + conditions: [ + { + type: 'Ready', + status: 'False', + reason: 'ContainersNotReady', + message: 'containers with unready status: [job]' + } as k8s.V1PodCondition + ] + }) + expect(getPodConditionErrors(pod)).toEqual([]) + }) + + it('ignores PodScheduled=False with non-Unschedulable reason', () => { + const pod = buildPod(PodPhase.PENDING, { + conditions: [ + { + type: 'PodScheduled', + status: 'False', + reason: 'SomeOtherReason', + message: 'some message' + } as k8s.V1PodCondition + ] + }) + expect(getPodConditionErrors(pod)).toEqual([]) + }) + + it('detects PodScheduled=False/Unschedulable alongside other normal False conditions', () => { const pod = buildPod(PodPhase.PENDING, { conditions: [ { @@ -186,19 +221,19 @@ describe('getPodConditionErrors', () => { ] }) const errors = getPodConditionErrors(pod) - expect(errors.length).toBe(2) + expect(errors.length).toBe(1) expect(errors[0]).toContain('PodScheduled=False') - expect(errors[1]).toContain('Ready=False') + expect(errors[0]).toContain('Unschedulable') }) - it('handles conditions without reason or message', () => { + it('handles PodScheduled=False/Unschedulable without message', () => { const pod = buildPod(PodPhase.PENDING, { conditions: [ - { type: 'Ready', status: 'False' } as k8s.V1PodCondition + { type: 'PodScheduled', status: 'False', reason: 'Unschedulable' } as k8s.V1PodCondition ] }) expect(getPodConditionErrors(pod)).toEqual([ - 'Condition Ready=False (reason: ): ' + 'Condition PodScheduled=False (reason: Unschedulable): ' ]) }) }) @@ -491,7 +526,28 @@ describe('waitForPodPhases', () => { ).rejects.toThrow('Pod my-pod is unhealthy with phase status Failed') }) - it('surfaces condition errors when PodScheduled=False', async () => { + it('does NOT fail-fast on Ready=False condition (normal during Pending)', async () => { + readSpy + .mockResolvedValueOnce({ + body: buildPod(PodPhase.PENDING, { + conditions: [ + { type: 'Ready', status: 'False', reason: 'ContainersNotReady', message: 'containers unready' } as k8s.V1PodCondition, + { type: 'ContainersReady', status: 'False', reason: 'ContainersNotReady', message: 'containers unready' } as k8s.V1PodCondition + ] + }) + } as never) + .mockResolvedValueOnce({ body: buildPod(PodPhase.RUNNING) } as never) + + await expect( + waitForPodPhases( + 'my-pod', + new Set([PodPhase.RUNNING]), + new Set([PodPhase.PENDING]) + ) + ).resolves.toBeUndefined() + }) + + it('surfaces condition errors when PodScheduled=False with Unschedulable', async () => { readSpy.mockResolvedValue({ body: buildPod(PodPhase.PENDING, { conditions: [ @@ -514,10 +570,10 @@ describe('waitForPodPhases', () => { ).rejects.toThrow('condition errors') }) - it('surfaces event errors when FailedScheduling event detected', async () => { - readSpy.mockResolvedValue({ - body: buildPod(PodPhase.PENDING) - } as never) + it('does NOT fail-fast on transient event errors like FailedScheduling', async () => { + readSpy + .mockResolvedValueOnce({ body: buildPod(PodPhase.PENDING) } as never) + .mockResolvedValueOnce({ body: buildPod(PodPhase.RUNNING) } as never) eventSpy.mockResolvedValue({ body: { items: [ @@ -536,7 +592,57 @@ describe('waitForPodPhases', () => { new Set([PodPhase.RUNNING]), new Set([PodPhase.PENDING]) ) - ).rejects.toThrow('event errors') + ).resolves.toBeUndefined() + }) + + it('does NOT fail-fast on FailedMount event errors', async () => { + readSpy + .mockResolvedValueOnce({ body: buildPod(PodPhase.PENDING) } as never) + .mockResolvedValueOnce({ body: buildPod(PodPhase.RUNNING) } as never) + eventSpy.mockResolvedValue({ + body: { + items: [ + { + type: 'Warning', + reason: 'FailedMount', + message: 'MountVolume.SetUp failed for volume' + } + ] + } + } as never) + + await expect( + waitForPodPhases( + 'my-pod', + new Set([PodPhase.RUNNING]), + new Set([PodPhase.PENDING]) + ) + ).resolves.toBeUndefined() + }) + + it('does NOT fail-fast on FailedBinding event errors', async () => { + readSpy + .mockResolvedValueOnce({ body: buildPod(PodPhase.PENDING) } as never) + .mockResolvedValueOnce({ body: buildPod(PodPhase.RUNNING) } as never) + eventSpy.mockResolvedValue({ + body: { + items: [ + { + type: 'Warning', + reason: 'FailedBinding', + message: 'no persistent volumes available' + } + ] + } + } as never) + + await expect( + waitForPodPhases( + 'my-pod', + new Set([PodPhase.RUNNING]), + new Set([PodPhase.PENDING]) + ) + ).resolves.toBeUndefined() }) }) From d601f3a85622f864828b5b9bd3596c17dbafe32e Mon Sep 17 00:00:00 2001 From: Longwt123 <1075015495@qq.com> Date: Wed, 1 Jul 2026 08:40:18 +0000 Subject: [PATCH 5/5] fix(runner-container-hooks): fix Bug 3 UTs failing due to missing mock for copyExternalsToRoot --- packages/k8s/coverage/clover.xml | 870 +++++ packages/k8s/coverage/coverage-final.json | 10 + packages/k8s/coverage/lcov-report/base.css | 224 ++ .../coverage/lcov-report/block-navigation.js | 87 + packages/k8s/coverage/lcov-report/favicon.png | Bin 0 -> 540 bytes .../k8s/coverage/lcov-report/hooks/index.html | 131 + .../lcov-report/hooks/prepare-job.ts.html | 886 +++++ .../hooks/run-container-step.ts.html | 592 ++++ packages/k8s/coverage/lcov-report/index.html | 146 + .../k8s/coverage/lcov-report/k8s/index.html | 116 + .../coverage/lcov-report/k8s/index.ts.html | 3028 +++++++++++++++++ .../k8s/coverage/lcov-report/prettify.css | 1 + packages/k8s/coverage/lcov-report/prettify.js | 2 + .../lcov-report/sort-arrow-sprite.png | Bin 0 -> 209 bytes packages/k8s/coverage/lcov-report/sorter.js | 196 ++ .../lcov-report/src/hooks/cleanup-job.ts.html | 100 + .../lcov-report/src/hooks/constants.ts.html | 280 ++ .../coverage/lcov-report/src/hooks/index.html | 191 ++ .../lcov-report/src/hooks/index.ts.html | 97 + .../lcov-report/src/hooks/prepare-job.ts.html | 886 +++++ .../src/hooks/run-container-step.ts.html | 592 ++++ .../src/hooks/run-script-step.ts.html | 199 ++ .../coverage/lcov-report/src/k8s/index.html | 131 + .../lcov-report/src/k8s/index.ts.html | 3028 +++++++++++++++++ .../lcov-report/src/k8s/utils.ts.html | 988 ++++++ .../k8s/coverage/lcov-report/tests/index.html | 116 + .../lcov-report/tests/test-setup.ts.html | 673 ++++ packages/k8s/coverage/lcov.info | 1846 ++++++++++ packages/k8s/tests/prepare-job-test.ts | 4 + 29 files changed, 15420 insertions(+) create mode 100644 packages/k8s/coverage/clover.xml create mode 100644 packages/k8s/coverage/coverage-final.json create mode 100644 packages/k8s/coverage/lcov-report/base.css create mode 100644 packages/k8s/coverage/lcov-report/block-navigation.js create mode 100644 packages/k8s/coverage/lcov-report/favicon.png create mode 100644 packages/k8s/coverage/lcov-report/hooks/index.html create mode 100644 packages/k8s/coverage/lcov-report/hooks/prepare-job.ts.html create mode 100644 packages/k8s/coverage/lcov-report/hooks/run-container-step.ts.html create mode 100644 packages/k8s/coverage/lcov-report/index.html create mode 100644 packages/k8s/coverage/lcov-report/k8s/index.html create mode 100644 packages/k8s/coverage/lcov-report/k8s/index.ts.html create mode 100644 packages/k8s/coverage/lcov-report/prettify.css create mode 100644 packages/k8s/coverage/lcov-report/prettify.js create mode 100644 packages/k8s/coverage/lcov-report/sort-arrow-sprite.png create mode 100644 packages/k8s/coverage/lcov-report/sorter.js create mode 100644 packages/k8s/coverage/lcov-report/src/hooks/cleanup-job.ts.html create mode 100644 packages/k8s/coverage/lcov-report/src/hooks/constants.ts.html create mode 100644 packages/k8s/coverage/lcov-report/src/hooks/index.html create mode 100644 packages/k8s/coverage/lcov-report/src/hooks/index.ts.html create mode 100644 packages/k8s/coverage/lcov-report/src/hooks/prepare-job.ts.html create mode 100644 packages/k8s/coverage/lcov-report/src/hooks/run-container-step.ts.html create mode 100644 packages/k8s/coverage/lcov-report/src/hooks/run-script-step.ts.html create mode 100644 packages/k8s/coverage/lcov-report/src/k8s/index.html create mode 100644 packages/k8s/coverage/lcov-report/src/k8s/index.ts.html create mode 100644 packages/k8s/coverage/lcov-report/src/k8s/utils.ts.html create mode 100644 packages/k8s/coverage/lcov-report/tests/index.html create mode 100644 packages/k8s/coverage/lcov-report/tests/test-setup.ts.html create mode 100644 packages/k8s/coverage/lcov.info diff --git a/packages/k8s/coverage/clover.xml b/packages/k8s/coverage/clover.xml new file mode 100644 index 00000000..87d6efa5 --- /dev/null +++ b/packages/k8s/coverage/clover.xml @@ -0,0 +1,870 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/k8s/coverage/coverage-final.json b/packages/k8s/coverage/coverage-final.json new file mode 100644 index 00000000..bc3332d2 --- /dev/null +++ b/packages/k8s/coverage/coverage-final.json @@ -0,0 +1,10 @@ +{"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/cleanup-job.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/cleanup-job.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":48}},"1":{"start":{"line":4,"column":2},"end":{"line":4,"column":null}},"2":{"start":{"line":3,"column":0},"end":{"line":3,"column":22}}},"fnMap":{"0":{"name":"cleanupJob","decl":{"start":{"line":3,"column":22},"end":{"line":3,"column":32}},"loc":{"start":{"line":3,"column":32},"end":{"line":5,"column":null}}}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":2},"end":{"line":4,"column":null}},"type":"switch","locations":[{"start":{"line":4,"column":2},"end":{"line":4,"column":null}}]}},"s":{"0":1,"1":0,"2":1},"f":{"0":0},"b":{"0":[0]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/constants.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/constants.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}},"1":{"start":{"line":4,"column":15},"end":{"line":4,"column":50}},"2":{"start":{"line":5,"column":2},"end":{"line":9,"column":null}},"3":{"start":{"line":6,"column":4},"end":{"line":8,"column":null}},"4":{"start":{"line":10,"column":2},"end":{"line":10,"column":null}},"5":{"start":{"line":3,"column":0},"end":{"line":3,"column":16}},"6":{"start":{"line":14,"column":2},"end":{"line":17,"column":null}},"7":{"start":{"line":13,"column":0},"end":{"line":13,"column":16}},"8":{"start":{"line":21,"column":2},"end":{"line":24,"column":null}},"9":{"start":{"line":20,"column":0},"end":{"line":20,"column":16}},"10":{"start":{"line":28,"column":15},"end":{"line":28,"column":52}},"11":{"start":{"line":29,"column":2},"end":{"line":31,"column":null}},"12":{"start":{"line":30,"column":4},"end":{"line":30,"column":null}},"13":{"start":{"line":32,"column":2},"end":{"line":32,"column":null}},"14":{"start":{"line":27,"column":0},"end":{"line":27,"column":16}},"15":{"start":{"line":36,"column":2},"end":{"line":39,"column":null}},"16":{"start":{"line":35,"column":0},"end":{"line":35,"column":16}},"17":{"start":{"line":42,"column":13},"end":{"line":42,"column":null}},"18":{"start":{"line":43,"column":13},"end":{"line":43,"column":null}},"19":{"start":{"line":44,"column":13},"end":{"line":44,"column":null}},"20":{"start":{"line":45,"column":13},"end":{"line":45,"column":null}},"21":{"start":{"line":46,"column":13},"end":{"line":46,"column":null}},"22":{"start":{"line":48,"column":0},"end":{"line":48,"column":13}},"23":{"start":{"line":51,"column":4},"end":{"line":51,"column":null}},"24":{"start":{"line":54,"column":2},"end":{"line":56,"column":null}},"25":{"start":{"line":55,"column":4},"end":{"line":55,"column":null}},"26":{"start":{"line":58,"column":2},"end":{"line":60,"column":null}},"27":{"start":{"line":59,"column":4},"end":{"line":59,"column":null}},"28":{"start":{"line":62,"column":2},"end":{"line":64,"column":null}},"29":{"start":{"line":63,"column":4},"end":{"line":63,"column":null}},"30":{"start":{"line":65,"column":0},"end":{"line":65,"column":null}},"31":{"start":{"line":48,"column":13},"end":{"line":48,"column":32}}},"fnMap":{"0":{"name":"getRunnerPodName","decl":{"start":{"line":3,"column":16},"end":{"line":3,"column":32}},"loc":{"start":{"line":3,"column":32},"end":{"line":11,"column":1}}},"1":{"name":"getJobPodName","decl":{"start":{"line":13,"column":16},"end":{"line":13,"column":29}},"loc":{"start":{"line":13,"column":29},"end":{"line":18,"column":1}}},"2":{"name":"getStepPodName","decl":{"start":{"line":20,"column":16},"end":{"line":20,"column":30}},"loc":{"start":{"line":20,"column":30},"end":{"line":25,"column":1}}},"3":{"name":"getVolumeClaimName","decl":{"start":{"line":27,"column":16},"end":{"line":27,"column":34}},"loc":{"start":{"line":27,"column":34},"end":{"line":33,"column":1}}},"4":{"name":"getSecretName","decl":{"start":{"line":35,"column":16},"end":{"line":35,"column":29}},"loc":{"start":{"line":35,"column":29},"end":{"line":40,"column":1}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":48,"column":0},"end":{"line":48,"column":13}},"loc":{"start":{"line":48,"column":0},"end":{"line":65,"column":null}}},"6":{"name":"RunnerInstanceLabel","decl":{"start":{"line":50,"column":2},"end":{"line":50,"column":null}},"loc":{"start":{"line":50,"column":2},"end":{"line":52,"column":3}}},"7":{"name":"(anonymous_7)","decl":{"start":{"line":54,"column":2},"end":{"line":54,"column":6}},"loc":{"start":{"line":54,"column":2},"end":{"line":56,"column":3}}},"8":{"name":"(anonymous_8)","decl":{"start":{"line":58,"column":2},"end":{"line":58,"column":6}},"loc":{"start":{"line":58,"column":2},"end":{"line":60,"column":3}}},"9":{"name":"(anonymous_9)","decl":{"start":{"line":62,"column":2},"end":{"line":62,"column":10}},"loc":{"start":{"line":62,"column":2},"end":{"line":64,"column":3}}}},"branchMap":{"0":{"loc":{"start":{"line":5,"column":2},"end":{"line":9,"column":null}},"type":"if","locations":[{"start":{"line":5,"column":2},"end":{"line":9,"column":null}}]},"1":{"loc":{"start":{"line":29,"column":2},"end":{"line":31,"column":null}},"type":"if","locations":[{"start":{"line":29,"column":2},"end":{"line":31,"column":null}}]}},"s":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":1,"8":0,"9":1,"10":0,"11":0,"12":0,"13":0,"14":1,"15":0,"16":1,"17":1,"18":1,"19":1,"20":1,"21":1,"22":1,"23":0,"24":1,"25":0,"26":1,"27":0,"28":1,"29":0,"30":1,"31":1},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0},"b":{"0":[0],"1":[0]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/index.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/index.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":29}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":29}},"2":{"start":{"line":3,"column":0},"end":{"line":3,"column":33}},"3":{"start":{"line":4,"column":0},"end":{"line":4,"column":36}}},"fnMap":{},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1},"f":{},"b":{}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/prepare-job.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/prepare-job.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":33}},"2":{"start":{"line":4,"column":0},"end":{"line":4,"column":null}},"3":{"start":{"line":10,"column":0},"end":{"line":10,"column":23}},"4":{"start":{"line":11,"column":0},"end":{"line":11,"column":null}},"5":{"start":{"line":19,"column":0},"end":{"line":19,"column":null}},"6":{"start":{"line":29,"column":0},"end":{"line":29,"column":76}},"7":{"start":{"line":35,"column":2},"end":{"line":37,"column":null}},"8":{"start":{"line":36,"column":4},"end":{"line":36,"column":null}},"9":{"start":{"line":39,"column":2},"end":{"line":39,"column":null}},"10":{"start":{"line":41,"column":8},"end":{"line":41,"column":null}},"11":{"start":{"line":42,"column":2},"end":{"line":42,"column":null}},"12":{"start":{"line":44,"column":6},"end":{"line":44,"column":null}},"13":{"start":{"line":45,"column":2},"end":{"line":53,"column":null}},"14":{"start":{"line":46,"column":4},"end":{"line":46,"column":null}},"15":{"start":{"line":47,"column":4},"end":{"line":52,"column":null}},"16":{"start":{"line":55,"column":6},"end":{"line":55,"column":null}},"17":{"start":{"line":56,"column":2},"end":{"line":66,"column":null}},"18":{"start":{"line":57,"column":4},"end":{"line":65,"column":null}},"19":{"start":{"line":58,"column":6},"end":{"line":58,"column":null}},"20":{"start":{"line":59,"column":6},"end":{"line":64,"column":null}},"21":{"start":{"line":68,"column":2},"end":{"line":70,"column":null}},"22":{"start":{"line":69,"column":4},"end":{"line":69,"column":null}},"23":{"start":{"line":72,"column":6},"end":{"line":72,"column":null}},"24":{"start":{"line":74,"column":17},"end":{"line":79,"column":null}},"25":{"start":{"line":74,"column":4},"end":{"line":79,"column":null}},"26":{"start":{"line":81,"column":4},"end":{"line":81,"column":null}},"27":{"start":{"line":82,"column":4},"end":{"line":82,"column":null}},"28":{"start":{"line":83,"column":10},"end":{"line":83,"column":null}},"29":{"start":{"line":84,"column":4},"end":{"line":84,"column":null}},"30":{"start":{"line":87,"column":2},"end":{"line":89,"column":null}},"31":{"start":{"line":88,"column":4},"end":{"line":88,"column":null}},"32":{"start":{"line":90,"column":2},"end":{"line":92,"column":null}},"33":{"start":{"line":95,"column":4},"end":{"line":100,"column":null}},"34":{"start":{"line":103,"column":6},"end":{"line":103,"column":null}},"35":{"start":{"line":105,"column":6},"end":{"line":105,"column":null}},"36":{"start":{"line":107,"column":10},"end":{"line":107,"column":null}},"37":{"start":{"line":108,"column":4},"end":{"line":108,"column":null}},"38":{"start":{"line":111,"column":2},"end":{"line":111,"column":null}},"39":{"start":{"line":113,"column":6},"end":{"line":113,"column":null}},"40":{"start":{"line":115,"column":15},"end":{"line":118,"column":null}},"41":{"start":{"line":115,"column":4},"end":{"line":118,"column":null}},"42":{"start":{"line":120,"column":4},"end":{"line":122,"column":null}},"43":{"start":{"line":123,"column":10},"end":{"line":123,"column":null}},"44":{"start":{"line":124,"column":4},"end":{"line":124,"column":null}},"45":{"start":{"line":126,"column":2},"end":{"line":126,"column":null}},"46":{"start":{"line":127,"column":2},"end":{"line":127,"column":null}},"47":{"start":{"line":31,"column":0},"end":{"line":31,"column":22}},"48":{"start":{"line":136,"column":2},"end":{"line":138,"column":null}},"49":{"start":{"line":137,"column":4},"end":{"line":137,"column":null}},"50":{"start":{"line":139,"column":19},"end":{"line":145,"column":null}},"51":{"start":{"line":147,"column":24},"end":{"line":148,"column":null}},"52":{"start":{"line":148,"column":9},"end":{"line":148,"column":null}},"53":{"start":{"line":150,"column":2},"end":{"line":163,"column":null}},"54":{"start":{"line":151,"column":52},"end":{"line":151,"column":54}},"55":{"start":{"line":152,"column":4},"end":{"line":157,"column":null}},"56":{"start":{"line":153,"column":6},"end":{"line":156,"column":null}},"57":{"start":{"line":153,"column":25},"end":{"line":153,"column":38}},"58":{"start":{"line":153,"column":25},"end":{"line":153,"column":44}},"59":{"start":{"line":153,"column":21},"end":{"line":153,"column":25}},"60":{"start":{"line":154,"column":8},"end":{"line":155,"column":null}},"61":{"start":{"line":159,"column":4},"end":{"line":162,"column":null}},"62":{"start":{"line":165,"column":2},"end":{"line":184,"column":null}},"63":{"start":{"line":167,"column":6},"end":{"line":167,"column":67}},"64":{"start":{"line":167,"column":30},"end":{"line":167,"column":61}},"65":{"start":{"line":169,"column":4},"end":{"line":183,"column":null}},"66":{"start":{"line":170,"column":20},"end":{"line":170,"column":null}},"67":{"start":{"line":172,"column":39},"end":{"line":172,"column":41}},"68":{"start":{"line":173,"column":8},"end":{"line":177,"column":null}},"69":{"start":{"line":174,"column":10},"end":{"line":176,"column":null}},"70":{"start":{"line":174,"column":29},"end":{"line":174,"column":30}},"71":{"start":{"line":174,"column":29},"end":{"line":174,"column":36}},"72":{"start":{"line":174,"column":25},"end":{"line":174,"column":29}},"73":{"start":{"line":175,"column":12},"end":{"line":175,"column":null}},"74":{"start":{"line":179,"column":8},"end":{"line":182,"column":null}},"75":{"start":{"line":186,"column":2},"end":{"line":186,"column":null}},"76":{"start":{"line":190,"column":8},"end":{"line":190,"column":null}},"77":{"start":{"line":191,"column":6},"end":{"line":191,"column":15}},"78":{"start":{"line":192,"column":4},"end":{"line":196,"column":null}},"79":{"start":{"line":203,"column":2},"end":{"line":203,"column":null}},"80":{"start":{"line":206,"column":2},"end":{"line":209,"column":null}},"81":{"start":{"line":207,"column":4},"end":{"line":207,"column":null}},"82":{"start":{"line":208,"column":4},"end":{"line":208,"column":null}},"83":{"start":{"line":211,"column":23},"end":{"line":215,"column":null}},"84":{"start":{"line":216,"column":2},"end":{"line":218,"column":null}},"85":{"start":{"line":217,"column":4},"end":{"line":217,"column":null}},"86":{"start":{"line":220,"column":2},"end":{"line":222,"column":null}},"87":{"start":{"line":221,"column":4},"end":{"line":221,"column":null}},"88":{"start":{"line":224,"column":2},"end":{"line":226,"column":null}},"89":{"start":{"line":225,"column":4},"end":{"line":225,"column":null}},"90":{"start":{"line":228,"column":2},"end":{"line":228,"column":null}},"91":{"start":{"line":229,"column":2},"end":{"line":235,"column":null}},"92":{"start":{"line":229,"column":29},"end":{"line":229,"column":35}},"93":{"start":{"line":229,"column":29},"end":{"line":230,"column":null}},"94":{"start":{"line":229,"column":13},"end":{"line":229,"column":14}},"95":{"start":{"line":229,"column":17},"end":{"line":229,"column":19}},"96":{"start":{"line":229,"column":24},"end":{"line":229,"column":25}},"97":{"start":{"line":232,"column":4},"end":{"line":234,"column":null}},"98":{"start":{"line":233,"column":6},"end":{"line":233,"column":null}},"99":{"start":{"line":237,"column":2},"end":{"line":240,"column":null}},"100":{"start":{"line":242,"column":2},"end":{"line":247,"column":null}},"101":{"start":{"line":243,"column":4},"end":{"line":246,"column":null}},"102":{"start":{"line":249,"column":2},"end":{"line":252,"column":null}},"103":{"start":{"line":254,"column":2},"end":{"line":256,"column":null}},"104":{"start":{"line":255,"column":4},"end":{"line":255,"column":null}},"105":{"start":{"line":258,"column":15},"end":{"line":259,"column":null}},"106":{"start":{"line":259,"column":9},"end":{"line":259,"column":null}},"107":{"start":{"line":262,"column":2},"end":{"line":264,"column":null}},"108":{"start":{"line":263,"column":4},"end":{"line":263,"column":null}},"109":{"start":{"line":266,"column":2},"end":{"line":266,"column":null}},"110":{"start":{"line":200,"column":0},"end":{"line":200,"column":16}}},"fnMap":{"0":{"name":"prepareJob","decl":{"start":{"line":31,"column":22},"end":{"line":31,"column":32}},"loc":{"start":{"line":33,"column":14},"end":{"line":128,"column":null}}},"1":{"name":"(anonymous_23)","decl":{"start":{"line":57,"column":33},"end":{"line":57,"column":40}},"loc":{"start":{"line":57,"column":40},"end":{"line":65,"column":5}}},"2":{"name":"generateResponseFile","decl":{"start":{"line":130,"column":9},"end":{"line":130,"column":29}},"loc":{"start":{"line":134,"column":10},"end":{"line":187,"column":1}}},"3":{"name":"(anonymous_25)","decl":{"start":{"line":148,"column":4},"end":{"line":148,"column":5}},"loc":{"start":{"line":148,"column":5},"end":{"line":148,"column":10}}},"4":{"name":"(anonymous_26)","decl":{"start":{"line":167,"column":25},"end":{"line":167,"column":26}},"loc":{"start":{"line":167,"column":26},"end":{"line":167,"column":51}}},"5":{"name":"(anonymous_27)","decl":{"start":{"line":170,"column":15},"end":{"line":170,"column":16}},"loc":{"start":{"line":170,"column":16},"end":{"line":170,"column":41}}},"6":{"name":"(anonymous_28)","decl":{"start":{"line":171,"column":11},"end":{"line":171,"column":12}},"loc":{"start":{"line":171,"column":12},"end":{"line":183,"column":7}}},"7":{"name":"copyExternalsToRoot","decl":{"start":{"line":189,"column":15},"end":{"line":189,"column":34}},"loc":{"start":{"line":189,"column":34},"end":{"line":198,"column":null}}},"8":{"name":"createContainerSpec","decl":{"start":{"line":200,"column":16},"end":{"line":200,"column":35}},"loc":{"start":{"line":204,"column":35},"end":{"line":267,"column":1}}},"9":{"name":"(anonymous_33)","decl":{"start":{"line":259,"column":4},"end":{"line":259,"column":5}},"loc":{"start":{"line":259,"column":5},"end":{"line":259,"column":10}}}},"branchMap":{"0":{"loc":{"start":{"line":35,"column":2},"end":{"line":37,"column":null}},"type":"if","locations":[{"start":{"line":35,"column":2},"end":{"line":37,"column":null}}]},"1":{"loc":{"start":{"line":45,"column":2},"end":{"line":53,"column":null}},"type":"if","locations":[{"start":{"line":45,"column":2},"end":{"line":53,"column":null}}]},"2":{"loc":{"start":{"line":45,"column":6},"end":{"line":45,"column":27}},"type":"cond-expr","locations":[{"start":{"line":45,"column":20},"end":{"line":45,"column":22}},{"start":{"line":45,"column":20},"end":{"line":45,"column":27}}]},"3":{"loc":{"start":{"line":45,"column":6},"end":{"line":45,"column":22}},"type":"binary-expr","locations":[{"start":{"line":45,"column":6},"end":{"line":45,"column":22}},{"start":{"line":45,"column":20},"end":{"line":45,"column":22}}]},"4":{"loc":{"start":{"line":56,"column":2},"end":{"line":66,"column":null}},"type":"if","locations":[{"start":{"line":56,"column":2},"end":{"line":66,"column":null}}]},"5":{"loc":{"start":{"line":56,"column":6},"end":{"line":56,"column":27}},"type":"cond-expr","locations":[{"start":{"line":56,"column":19},"end":{"line":56,"column":21}},{"start":{"line":56,"column":19},"end":{"line":56,"column":27}}]},"6":{"loc":{"start":{"line":56,"column":6},"end":{"line":56,"column":21}},"type":"binary-expr","locations":[{"start":{"line":56,"column":6},"end":{"line":56,"column":21}},{"start":{"line":56,"column":19},"end":{"line":56,"column":21}}]},"7":{"loc":{"start":{"line":68,"column":2},"end":{"line":70,"column":null}},"type":"if","locations":[{"start":{"line":68,"column":2},"end":{"line":70,"column":null}}]},"8":{"loc":{"start":{"line":68,"column":6},"end":{"line":68,"column":39}},"type":"binary-expr","locations":[{"start":{"line":68,"column":6},"end":{"line":68,"column":16}},{"start":{"line":68,"column":20},"end":{"line":68,"column":39}}]},"9":{"loc":{"start":{"line":68,"column":21},"end":{"line":68,"column":37}},"type":"cond-expr","locations":[{"start":{"line":68,"column":29},"end":{"line":68,"column":31}},{"start":{"line":68,"column":21},"end":{"line":68,"column":37}}]},"10":{"loc":{"start":{"line":68,"column":21},"end":{"line":68,"column":31}},"type":"binary-expr","locations":[{"start":{"line":68,"column":21},"end":{"line":68,"column":31}},{"start":{"line":68,"column":21},"end":{"line":68,"column":31}}]},"11":{"loc":{"start":{"line":83,"column":20},"end":{"line":83,"column":64}},"type":"binary-expr","locations":[{"start":{"line":83,"column":20},"end":{"line":83,"column":57}},{"start":{"line":83,"column":61},"end":{"line":83,"column":64}}]},"12":{"loc":{"start":{"line":83,"column":20},"end":{"line":83,"column":57}},"type":"cond-expr","locations":[{"start":{"line":83,"column":48},"end":{"line":83,"column":50}},{"start":{"line":83,"column":48},"end":{"line":83,"column":57}}]},"13":{"loc":{"start":{"line":83,"column":20},"end":{"line":83,"column":50}},"type":"binary-expr","locations":[{"start":{"line":83,"column":20},"end":{"line":83,"column":50}},{"start":{"line":83,"column":48},"end":{"line":83,"column":50}}]},"14":{"loc":{"start":{"line":83,"column":20},"end":{"line":83,"column":48}},"type":"cond-expr","locations":[{"start":{"line":83,"column":42},"end":{"line":83,"column":44}},{"start":{"line":83,"column":42},"end":{"line":83,"column":48}}]},"15":{"loc":{"start":{"line":83,"column":20},"end":{"line":83,"column":44}},"type":"binary-expr","locations":[{"start":{"line":83,"column":20},"end":{"line":83,"column":44}},{"start":{"line":83,"column":42},"end":{"line":83,"column":44}}]},"16":{"loc":{"start":{"line":83,"column":21},"end":{"line":83,"column":42}},"type":"cond-expr","locations":[{"start":{"line":83,"column":24},"end":{"line":83,"column":32}},{"start":{"line":83,"column":21},"end":{"line":83,"column":42}}]},"17":{"loc":{"start":{"line":83,"column":21},"end":{"line":83,"column":32}},"type":"binary-expr","locations":[{"start":{"line":83,"column":21},"end":{"line":83,"column":34}},{"start":{"line":83,"column":21},"end":{"line":83,"column":32}}]},"18":{"loc":{"start":{"line":87,"column":2},"end":{"line":89,"column":null}},"type":"if","locations":[{"start":{"line":87,"column":2},"end":{"line":89,"column":null}}]},"19":{"loc":{"start":{"line":87,"column":7},"end":{"line":87,"column":33}},"type":"cond-expr","locations":[{"start":{"line":87,"column":27},"end":{"line":87,"column":29}},{"start":{"line":87,"column":27},"end":{"line":87,"column":33}}]},"20":{"loc":{"start":{"line":87,"column":7},"end":{"line":87,"column":29}},"type":"binary-expr","locations":[{"start":{"line":87,"column":7},"end":{"line":87,"column":29}},{"start":{"line":87,"column":27},"end":{"line":87,"column":29}}]},"21":{"loc":{"start":{"line":87,"column":7},"end":{"line":87,"column":27}},"type":"cond-expr","locations":[{"start":{"line":87,"column":17},"end":{"line":87,"column":19}},{"start":{"line":87,"column":7},"end":{"line":87,"column":27}}]},"22":{"loc":{"start":{"line":87,"column":7},"end":{"line":87,"column":19}},"type":"binary-expr","locations":[{"start":{"line":87,"column":7},"end":{"line":87,"column":19}},{"start":{"line":87,"column":7},"end":{"line":87,"column":19}}]},"23":{"loc":{"start":{"line":91,"column":54},"end":{"line":91,"column":80}},"type":"cond-expr","locations":[{"start":{"line":91,"column":74},"end":{"line":91,"column":76}},{"start":{"line":91,"column":74},"end":{"line":91,"column":80}}]},"24":{"loc":{"start":{"line":91,"column":54},"end":{"line":91,"column":76}},"type":"binary-expr","locations":[{"start":{"line":91,"column":54},"end":{"line":91,"column":76}},{"start":{"line":91,"column":74},"end":{"line":91,"column":76}}]},"25":{"loc":{"start":{"line":91,"column":54},"end":{"line":91,"column":74}},"type":"cond-expr","locations":[{"start":{"line":91,"column":64},"end":{"line":91,"column":66}},{"start":{"line":91,"column":54},"end":{"line":91,"column":74}}]},"26":{"loc":{"start":{"line":91,"column":54},"end":{"line":91,"column":66}},"type":"binary-expr","locations":[{"start":{"line":91,"column":54},"end":{"line":91,"column":66}},{"start":{"line":91,"column":54},"end":{"line":91,"column":66}}]},"27":{"loc":{"start":{"line":105,"column":42},"end":{"line":105,"column":105}},"type":"cond-expr","locations":[{"start":{"line":105,"column":70},"end":{"line":105,"column":86}},{"start":{"line":105,"column":89},"end":{"line":105,"column":105}}]},"28":{"loc":{"start":{"line":107,"column":20},"end":{"line":107,"column":68}},"type":"cond-expr","locations":[{"start":{"line":107,"column":43},"end":{"line":107,"column":54}},{"start":{"line":107,"column":57},"end":{"line":107,"column":68}}]},"29":{"loc":{"start":{"line":123,"column":20},"end":{"line":123,"column":64}},"type":"binary-expr","locations":[{"start":{"line":123,"column":20},"end":{"line":123,"column":57}},{"start":{"line":123,"column":61},"end":{"line":123,"column":64}}]},"30":{"loc":{"start":{"line":123,"column":20},"end":{"line":123,"column":57}},"type":"cond-expr","locations":[{"start":{"line":123,"column":48},"end":{"line":123,"column":50}},{"start":{"line":123,"column":48},"end":{"line":123,"column":57}}]},"31":{"loc":{"start":{"line":123,"column":20},"end":{"line":123,"column":50}},"type":"binary-expr","locations":[{"start":{"line":123,"column":20},"end":{"line":123,"column":50}},{"start":{"line":123,"column":48},"end":{"line":123,"column":50}}]},"32":{"loc":{"start":{"line":123,"column":20},"end":{"line":123,"column":48}},"type":"cond-expr","locations":[{"start":{"line":123,"column":42},"end":{"line":123,"column":44}},{"start":{"line":123,"column":42},"end":{"line":123,"column":48}}]},"33":{"loc":{"start":{"line":123,"column":20},"end":{"line":123,"column":44}},"type":"binary-expr","locations":[{"start":{"line":123,"column":20},"end":{"line":123,"column":44}},{"start":{"line":123,"column":42},"end":{"line":123,"column":44}}]},"34":{"loc":{"start":{"line":123,"column":21},"end":{"line":123,"column":42}},"type":"cond-expr","locations":[{"start":{"line":123,"column":24},"end":{"line":123,"column":32}},{"start":{"line":123,"column":21},"end":{"line":123,"column":42}}]},"35":{"loc":{"start":{"line":123,"column":21},"end":{"line":123,"column":32}},"type":"binary-expr","locations":[{"start":{"line":123,"column":21},"end":{"line":123,"column":34}},{"start":{"line":123,"column":21},"end":{"line":123,"column":32}}]},"36":{"loc":{"start":{"line":136,"column":2},"end":{"line":138,"column":null}},"type":"if","locations":[{"start":{"line":136,"column":2},"end":{"line":138,"column":null}}]},"37":{"loc":{"start":{"line":136,"column":7},"end":{"line":136,"column":28}},"type":"cond-expr","locations":[{"start":{"line":136,"column":22},"end":{"line":136,"column":24}},{"start":{"line":136,"column":22},"end":{"line":136,"column":28}}]},"38":{"loc":{"start":{"line":136,"column":7},"end":{"line":136,"column":24}},"type":"binary-expr","locations":[{"start":{"line":136,"column":7},"end":{"line":136,"column":24}},{"start":{"line":136,"column":22},"end":{"line":136,"column":24}}]},"39":{"loc":{"start":{"line":147,"column":24},"end":{"line":148,"column":null}},"type":"cond-expr","locations":[{"start":{"line":147,"column":47},"end":{"line":147,"column":49}},{"start":{"line":147,"column":47},"end":{"line":148,"column":null}}]},"40":{"loc":{"start":{"line":147,"column":24},"end":{"line":147,"column":49}},"type":"binary-expr","locations":[{"start":{"line":147,"column":24},"end":{"line":147,"column":49}},{"start":{"line":147,"column":47},"end":{"line":147,"column":49}}]},"41":{"loc":{"start":{"line":147,"column":24},"end":{"line":147,"column":47}},"type":"cond-expr","locations":[{"start":{"line":147,"column":35},"end":{"line":147,"column":37}},{"start":{"line":147,"column":35},"end":{"line":147,"column":47}}]},"42":{"loc":{"start":{"line":147,"column":24},"end":{"line":147,"column":37}},"type":"binary-expr","locations":[{"start":{"line":147,"column":24},"end":{"line":147,"column":37}},{"start":{"line":147,"column":35},"end":{"line":147,"column":37}}]},"43":{"loc":{"start":{"line":150,"column":2},"end":{"line":163,"column":null}},"type":"if","locations":[{"start":{"line":150,"column":2},"end":{"line":163,"column":null}}]},"44":{"loc":{"start":{"line":152,"column":4},"end":{"line":157,"column":null}},"type":"if","locations":[{"start":{"line":152,"column":4},"end":{"line":157,"column":null}}]},"45":{"loc":{"start":{"line":152,"column":8},"end":{"line":152,"column":28}},"type":"cond-expr","locations":[{"start":{"line":152,"column":21},"end":{"line":152,"column":23}},{"start":{"line":152,"column":8},"end":{"line":152,"column":28}}]},"46":{"loc":{"start":{"line":152,"column":8},"end":{"line":152,"column":23}},"type":"binary-expr","locations":[{"start":{"line":152,"column":8},"end":{"line":152,"column":23}},{"start":{"line":152,"column":8},"end":{"line":152,"column":23}}]},"47":{"loc":{"start":{"line":165,"column":2},"end":{"line":184,"column":null}},"type":"if","locations":[{"start":{"line":165,"column":2},"end":{"line":184,"column":null}}]},"48":{"loc":{"start":{"line":165,"column":6},"end":{"line":165,"column":27}},"type":"cond-expr","locations":[{"start":{"line":165,"column":19},"end":{"line":165,"column":21}},{"start":{"line":165,"column":19},"end":{"line":165,"column":27}}]},"49":{"loc":{"start":{"line":165,"column":6},"end":{"line":165,"column":21}},"type":"binary-expr","locations":[{"start":{"line":165,"column":6},"end":{"line":165,"column":21}},{"start":{"line":165,"column":19},"end":{"line":165,"column":21}}]},"50":{"loc":{"start":{"line":167,"column":6},"end":{"line":167,"column":67}},"type":"binary-expr","locations":[{"start":{"line":167,"column":6},"end":{"line":167,"column":61}},{"start":{"line":167,"column":65},"end":{"line":167,"column":67}}]},"51":{"loc":{"start":{"line":167,"column":6},"end":{"line":167,"column":61}},"type":"cond-expr","locations":[{"start":{"line":167,"column":19},"end":{"line":167,"column":21}},{"start":{"line":167,"column":19},"end":{"line":167,"column":61}}]},"52":{"loc":{"start":{"line":167,"column":6},"end":{"line":167,"column":21}},"type":"binary-expr","locations":[{"start":{"line":167,"column":6},"end":{"line":167,"column":21}},{"start":{"line":167,"column":19},"end":{"line":167,"column":21}}]},"53":{"loc":{"start":{"line":169,"column":35},"end":{"line":183,"column":8}},"type":"cond-expr","locations":[{"start":{"line":169,"column":59},"end":{"line":169,"column":null}},{"start":{"line":169,"column":59},"end":{"line":183,"column":8}}]},"54":{"loc":{"start":{"line":169,"column":35},"end":{"line":169,"column":null}},"type":"binary-expr","locations":[{"start":{"line":169,"column":35},"end":{"line":169,"column":null}},{"start":{"line":169,"column":59},"end":{"line":169,"column":null}}]},"55":{"loc":{"start":{"line":169,"column":35},"end":{"line":169,"column":59}},"type":"cond-expr","locations":[{"start":{"line":169,"column":47},"end":{"line":169,"column":49}},{"start":{"line":169,"column":47},"end":{"line":169,"column":59}}]},"56":{"loc":{"start":{"line":169,"column":35},"end":{"line":169,"column":49}},"type":"binary-expr","locations":[{"start":{"line":169,"column":35},"end":{"line":169,"column":49}},{"start":{"line":169,"column":47},"end":{"line":169,"column":49}}]},"57":{"loc":{"start":{"line":169,"column":35},"end":{"line":169,"column":47}},"type":"cond-expr","locations":[{"start":{"line":169,"column":41},"end":{"line":169,"column":43}},{"start":{"line":169,"column":35},"end":{"line":169,"column":47}}]},"58":{"loc":{"start":{"line":169,"column":35},"end":{"line":169,"column":43}},"type":"binary-expr","locations":[{"start":{"line":169,"column":35},"end":{"line":169,"column":43}},{"start":{"line":169,"column":35},"end":{"line":169,"column":43}}]},"59":{"loc":{"start":{"line":173,"column":8},"end":{"line":177,"column":null}},"type":"if","locations":[{"start":{"line":173,"column":8},"end":{"line":177,"column":null}}]},"60":{"loc":{"start":{"line":173,"column":12},"end":{"line":173,"column":27}},"type":"cond-expr","locations":[{"start":{"line":173,"column":19},"end":{"line":173,"column":21}},{"start":{"line":173,"column":19},"end":{"line":173,"column":27}}]},"61":{"loc":{"start":{"line":173,"column":12},"end":{"line":173,"column":21}},"type":"binary-expr","locations":[{"start":{"line":173,"column":12},"end":{"line":173,"column":21}},{"start":{"line":173,"column":19},"end":{"line":173,"column":21}}]},"62":{"loc":{"start":{"line":191,"column":6},"end":{"line":191,"column":15}},"type":"if","locations":[{"start":{"line":191,"column":6},"end":{"line":191,"column":15}}]},"63":{"loc":{"start":{"line":203,"column":2},"end":{"line":203,"column":null}},"type":"if","locations":[{"start":{"line":203,"column":2},"end":{"line":203,"column":null}}]},"64":{"loc":{"start":{"line":206,"column":2},"end":{"line":209,"column":null}},"type":"if","locations":[{"start":{"line":206,"column":2},"end":{"line":209,"column":null}}]},"65":{"loc":{"start":{"line":206,"column":6},"end":{"line":206,"column":43}},"type":"binary-expr","locations":[{"start":{"line":206,"column":6},"end":{"line":206,"column":27}},{"start":{"line":206,"column":31},"end":{"line":206,"column":43}}]},"66":{"loc":{"start":{"line":216,"column":2},"end":{"line":218,"column":null}},"type":"if","locations":[{"start":{"line":216,"column":2},"end":{"line":218,"column":null}}]},"67":{"loc":{"start":{"line":220,"column":2},"end":{"line":222,"column":null}},"type":"if","locations":[{"start":{"line":220,"column":2},"end":{"line":222,"column":null}}]},"68":{"loc":{"start":{"line":224,"column":2},"end":{"line":226,"column":null}},"type":"if","locations":[{"start":{"line":224,"column":2},"end":{"line":226,"column":null}}]},"69":{"loc":{"start":{"line":224,"column":6},"end":{"line":224,"column":38}},"type":"cond-expr","locations":[{"start":{"line":224,"column":30},"end":{"line":224,"column":32}},{"start":{"line":224,"column":30},"end":{"line":224,"column":38}}]},"70":{"loc":{"start":{"line":224,"column":6},"end":{"line":224,"column":32}},"type":"binary-expr","locations":[{"start":{"line":224,"column":6},"end":{"line":224,"column":32}},{"start":{"line":224,"column":30},"end":{"line":224,"column":32}}]},"71":{"loc":{"start":{"line":232,"column":4},"end":{"line":234,"column":null}},"type":"if","locations":[{"start":{"line":232,"column":4},"end":{"line":234,"column":null}}]},"72":{"loc":{"start":{"line":232,"column":8},"end":{"line":232,"column":31}},"type":"binary-expr","locations":[{"start":{"line":232,"column":8},"end":{"line":232,"column":13}},{"start":{"line":232,"column":17},"end":{"line":232,"column":31}}]},"73":{"loc":{"start":{"line":242,"column":2},"end":{"line":247,"column":null}},"type":"if","locations":[{"start":{"line":242,"column":2},"end":{"line":247,"column":null}}]},"74":{"loc":{"start":{"line":254,"column":2},"end":{"line":256,"column":null}},"type":"if","locations":[{"start":{"line":254,"column":2},"end":{"line":256,"column":null}}]},"75":{"loc":{"start":{"line":258,"column":15},"end":{"line":259,"column":null}},"type":"cond-expr","locations":[{"start":{"line":258,"column":41},"end":{"line":258,"column":43}},{"start":{"line":258,"column":41},"end":{"line":259,"column":null}}]},"76":{"loc":{"start":{"line":258,"column":15},"end":{"line":258,"column":43}},"type":"binary-expr","locations":[{"start":{"line":258,"column":15},"end":{"line":258,"column":43}},{"start":{"line":258,"column":41},"end":{"line":258,"column":43}}]},"77":{"loc":{"start":{"line":258,"column":15},"end":{"line":258,"column":41}},"type":"cond-expr","locations":[{"start":{"line":258,"column":29},"end":{"line":258,"column":31}},{"start":{"line":258,"column":29},"end":{"line":258,"column":41}}]},"78":{"loc":{"start":{"line":258,"column":15},"end":{"line":258,"column":31}},"type":"binary-expr","locations":[{"start":{"line":258,"column":15},"end":{"line":258,"column":31}},{"start":{"line":258,"column":29},"end":{"line":258,"column":31}}]},"79":{"loc":{"start":{"line":262,"column":2},"end":{"line":264,"column":null}},"type":"if","locations":[{"start":{"line":262,"column":2},"end":{"line":264,"column":null}}]}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":3,"8":0,"9":6,"10":3,"11":6,"12":3,"13":3,"14":3,"15":3,"16":3,"17":3,"18":0,"19":0,"20":0,"21":3,"22":0,"23":3,"24":3,"25":3,"26":0,"27":0,"28":0,"29":0,"30":3,"31":0,"32":3,"33":6,"34":6,"35":2,"36":3,"37":3,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":1,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":3,"77":6,"78":0,"79":3,"80":3,"81":3,"82":3,"83":3,"84":3,"85":0,"86":3,"87":3,"88":3,"89":3,"90":3,"91":3,"92":3,"93":3,"94":0,"95":0,"96":0,"97":0,"98":0,"99":3,"100":3,"101":3,"102":3,"103":3,"104":3,"105":0,"106":0,"107":0,"108":0,"109":0,"110":1},"f":{"0":3,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":3,"8":3,"9":0},"b":{"0":[0],"1":[3],"2":[0,3],"3":[3,3],"4":[0],"5":[0,3],"6":[3,3],"7":[0],"8":[3,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0,0],"14":[0,0],"15":[0,0],"16":[0,0],"17":[0,0],"18":[0],"19":[0,3],"20":[3,3],"21":[0,3],"22":[3,3],"23":[0,3],"24":[3,3],"25":[0,3],"26":[3,3],"27":[2,0],"28":[3,0],"29":[0,0],"30":[0,0],"31":[0,0],"32":[0,0],"33":[0,0],"34":[0,0],"35":[0,0],"36":[0],"37":[0,0],"38":[0,0],"39":[0,0],"40":[0,0],"41":[0,0],"42":[0,0],"43":[0],"44":[0],"45":[0,0],"46":[0,0],"47":[0],"48":[0,0],"49":[0,0],"50":[0,0],"51":[0,0],"52":[0,0],"53":[0,0],"54":[0,0],"55":[0,0],"56":[0,0],"57":[0,0],"58":[0,0],"59":[0],"60":[0,0],"61":[0,0],"62":[3],"63":[0],"64":[3],"65":[3,3],"66":[0],"67":[3],"68":[3],"69":[0,3],"70":[3,3],"71":[0],"72":[0,0],"73":[3],"74":[3],"75":[0,0],"76":[0,0],"77":[0,0],"78":[0,0],"79":[0]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/run-container-step.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/run-container-step.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":46}},"2":{"start":{"line":4,"column":0},"end":{"line":4,"column":null}},"3":{"start":{"line":16,"column":0},"end":{"line":16,"column":null}},"4":{"start":{"line":23,"column":0},"end":{"line":23,"column":78}},"5":{"start":{"line":28,"column":2},"end":{"line":30,"column":null}},"6":{"start":{"line":29,"column":4},"end":{"line":29,"column":null}},"7":{"start":{"line":32,"column":6},"end":{"line":32,"column":null}},"8":{"start":{"line":33,"column":6},"end":{"line":33,"column":19}},"9":{"start":{"line":35,"column":12},"end":{"line":37,"column":null}},"10":{"start":{"line":38,"column":6},"end":{"line":38,"column":null}},"11":{"start":{"line":39,"column":6},"end":{"line":41,"column":null}},"12":{"start":{"line":40,"column":8},"end":{"line":40,"column":null}},"13":{"start":{"line":42,"column":19},"end":{"line":42,"column":null}},"14":{"start":{"line":42,"column":6},"end":{"line":42,"column":null}},"15":{"start":{"line":44,"column":6},"end":{"line":44,"column":null}},"16":{"start":{"line":45,"column":12},"end":{"line":45,"column":null}},"17":{"start":{"line":46,"column":6},"end":{"line":46,"column":null}},"18":{"start":{"line":50,"column":8},"end":{"line":50,"column":null}},"19":{"start":{"line":52,"column":2},"end":{"line":52,"column":null}},"20":{"start":{"line":53,"column":8},"end":{"line":53,"column":null}},"21":{"start":{"line":57,"column":10},"end":{"line":57,"column":null}},"22":{"start":{"line":57,"column":4},"end":{"line":57,"column":null}},"23":{"start":{"line":59,"column":4},"end":{"line":59,"column":null}},"24":{"start":{"line":60,"column":10},"end":{"line":60,"column":null}},"25":{"start":{"line":61,"column":4},"end":{"line":61,"column":null}},"26":{"start":{"line":64,"column":2},"end":{"line":70,"column":null}},"27":{"start":{"line":65,"column":4},"end":{"line":69,"column":null}},"28":{"start":{"line":71,"column":2},"end":{"line":71,"column":null}},"29":{"start":{"line":75,"column":14},"end":{"line":75,"column":null}},"30":{"start":{"line":75,"column":4},"end":{"line":75,"column":null}},"31":{"start":{"line":77,"column":4},"end":{"line":77,"column":null}},"32":{"start":{"line":78,"column":10},"end":{"line":78,"column":null}},"33":{"start":{"line":79,"column":4},"end":{"line":79,"column":null}},"34":{"start":{"line":82,"column":2},"end":{"line":91,"column":null}},"35":{"start":{"line":92,"column":2},"end":{"line":92,"column":null}},"36":{"start":{"line":94,"column":2},"end":{"line":94,"column":null}},"37":{"start":{"line":96,"column":2},"end":{"line":96,"column":null}},"38":{"start":{"line":97,"column":2},"end":{"line":97,"column":null}},"39":{"start":{"line":100,"column":17},"end":{"line":100,"column":null}},"40":{"start":{"line":100,"column":8},"end":{"line":100,"column":null}},"41":{"start":{"line":101,"column":2},"end":{"line":103,"column":null}},"42":{"start":{"line":102,"column":4},"end":{"line":102,"column":null}},"43":{"start":{"line":104,"column":2},"end":{"line":111,"column":null}},"44":{"start":{"line":105,"column":4},"end":{"line":109,"column":null}},"45":{"start":{"line":110,"column":4},"end":{"line":110,"column":null}},"46":{"start":{"line":113,"column":14},"end":{"line":113,"column":null}},"47":{"start":{"line":113,"column":8},"end":{"line":113,"column":null}},"48":{"start":{"line":114,"column":8},"end":{"line":114,"column":null}},"49":{"start":{"line":115,"column":6},"end":{"line":115,"column":22}},"50":{"start":{"line":116,"column":20},"end":{"line":116,"column":null}},"51":{"start":{"line":116,"column":10},"end":{"line":116,"column":null}},"52":{"start":{"line":117,"column":4},"end":{"line":119,"column":null}},"53":{"start":{"line":120,"column":4},"end":{"line":120,"column":null}},"54":{"start":{"line":123,"column":8},"end":{"line":125,"column":null}},"55":{"start":{"line":126,"column":2},"end":{"line":126,"column":null}},"56":{"start":{"line":25,"column":0},"end":{"line":25,"column":22}},"57":{"start":{"line":134,"column":23},"end":{"line":134,"column":44}},"58":{"start":{"line":135,"column":2},"end":{"line":135,"column":null}},"59":{"start":{"line":136,"column":2},"end":{"line":136,"column":null}},"60":{"start":{"line":137,"column":2},"end":{"line":137,"column":null}},"61":{"start":{"line":138,"column":2},"end":{"line":140,"column":null}},"62":{"start":{"line":141,"column":2},"end":{"line":143,"column":null}},"63":{"start":{"line":145,"column":2},"end":{"line":154,"column":null}},"64":{"start":{"line":146,"column":4},"end":{"line":153,"column":null}},"65":{"start":{"line":155,"column":2},"end":{"line":155,"column":null}},"66":{"start":{"line":157,"column":2},"end":{"line":159,"column":null}},"67":{"start":{"line":158,"column":4},"end":{"line":158,"column":null}},"68":{"start":{"line":161,"column":15},"end":{"line":162,"column":null}},"69":{"start":{"line":162,"column":9},"end":{"line":162,"column":null}},"70":{"start":{"line":164,"column":2},"end":{"line":166,"column":null}},"71":{"start":{"line":165,"column":4},"end":{"line":165,"column":null}},"72":{"start":{"line":168,"column":2},"end":{"line":168,"column":null}}},"fnMap":{"0":{"name":"runContainerStep","decl":{"start":{"line":25,"column":22},"end":{"line":25,"column":38}},"loc":{"start":{"line":26,"column":37},"end":{"line":127,"column":null}}},"1":{"name":"createContainerSpec","decl":{"start":{"line":129,"column":9},"end":{"line":129,"column":28}},"loc":{"start":{"line":132,"column":35},"end":{"line":169,"column":1}}},"2":{"name":"(anonymous_23)","decl":{"start":{"line":162,"column":4},"end":{"line":162,"column":5}},"loc":{"start":{"line":162,"column":5},"end":{"line":162,"column":10}}}},"branchMap":{"0":{"loc":{"start":{"line":82,"column":2},"end":{"line":91,"column":null}},"type":"switch","locations":[{"start":{"line":82,"column":2},"end":{"line":91,"column":null}}]},"1":{"loc":{"start":{"line":28,"column":2},"end":{"line":30,"column":null}},"type":"if","locations":[{"start":{"line":28,"column":2},"end":{"line":30,"column":null}}]},"2":{"loc":{"start":{"line":33,"column":6},"end":{"line":33,"column":19}},"type":"if","locations":[{"start":{"line":33,"column":6},"end":{"line":33,"column":19}}]},"3":{"loc":{"start":{"line":39,"column":6},"end":{"line":41,"column":null}},"type":"if","locations":[{"start":{"line":39,"column":6},"end":{"line":41,"column":null}}]},"4":{"loc":{"start":{"line":45,"column":22},"end":{"line":45,"column":66}},"type":"binary-expr","locations":[{"start":{"line":45,"column":22},"end":{"line":45,"column":59}},{"start":{"line":45,"column":63},"end":{"line":45,"column":66}}]},"5":{"loc":{"start":{"line":45,"column":22},"end":{"line":45,"column":59}},"type":"cond-expr","locations":[{"start":{"line":45,"column":50},"end":{"line":45,"column":52}},{"start":{"line":45,"column":50},"end":{"line":45,"column":59}}]},"6":{"loc":{"start":{"line":45,"column":22},"end":{"line":45,"column":52}},"type":"binary-expr","locations":[{"start":{"line":45,"column":22},"end":{"line":45,"column":52}},{"start":{"line":45,"column":50},"end":{"line":45,"column":52}}]},"7":{"loc":{"start":{"line":45,"column":22},"end":{"line":45,"column":50}},"type":"cond-expr","locations":[{"start":{"line":45,"column":44},"end":{"line":45,"column":46}},{"start":{"line":45,"column":44},"end":{"line":45,"column":50}}]},"8":{"loc":{"start":{"line":45,"column":22},"end":{"line":45,"column":46}},"type":"binary-expr","locations":[{"start":{"line":45,"column":22},"end":{"line":45,"column":46}},{"start":{"line":45,"column":44},"end":{"line":45,"column":46}}]},"9":{"loc":{"start":{"line":45,"column":23},"end":{"line":45,"column":44}},"type":"cond-expr","locations":[{"start":{"line":45,"column":26},"end":{"line":45,"column":34}},{"start":{"line":45,"column":23},"end":{"line":45,"column":44}}]},"10":{"loc":{"start":{"line":45,"column":23},"end":{"line":45,"column":34}},"type":"binary-expr","locations":[{"start":{"line":45,"column":23},"end":{"line":45,"column":36}},{"start":{"line":45,"column":23},"end":{"line":45,"column":34}}]},"11":{"loc":{"start":{"line":60,"column":20},"end":{"line":60,"column":64}},"type":"binary-expr","locations":[{"start":{"line":60,"column":20},"end":{"line":60,"column":57}},{"start":{"line":60,"column":61},"end":{"line":60,"column":64}}]},"12":{"loc":{"start":{"line":60,"column":20},"end":{"line":60,"column":57}},"type":"cond-expr","locations":[{"start":{"line":60,"column":48},"end":{"line":60,"column":50}},{"start":{"line":60,"column":48},"end":{"line":60,"column":57}}]},"13":{"loc":{"start":{"line":60,"column":20},"end":{"line":60,"column":50}},"type":"binary-expr","locations":[{"start":{"line":60,"column":20},"end":{"line":60,"column":50}},{"start":{"line":60,"column":48},"end":{"line":60,"column":50}}]},"14":{"loc":{"start":{"line":60,"column":20},"end":{"line":60,"column":48}},"type":"cond-expr","locations":[{"start":{"line":60,"column":42},"end":{"line":60,"column":44}},{"start":{"line":60,"column":42},"end":{"line":60,"column":48}}]},"15":{"loc":{"start":{"line":60,"column":20},"end":{"line":60,"column":44}},"type":"binary-expr","locations":[{"start":{"line":60,"column":20},"end":{"line":60,"column":44}},{"start":{"line":60,"column":42},"end":{"line":60,"column":44}}]},"16":{"loc":{"start":{"line":60,"column":21},"end":{"line":60,"column":42}},"type":"cond-expr","locations":[{"start":{"line":60,"column":24},"end":{"line":60,"column":32}},{"start":{"line":60,"column":21},"end":{"line":60,"column":42}}]},"17":{"loc":{"start":{"line":60,"column":21},"end":{"line":60,"column":32}},"type":"binary-expr","locations":[{"start":{"line":60,"column":21},"end":{"line":60,"column":34}},{"start":{"line":60,"column":21},"end":{"line":60,"column":32}}]},"18":{"loc":{"start":{"line":64,"column":2},"end":{"line":70,"column":null}},"type":"if","locations":[{"start":{"line":64,"column":2},"end":{"line":70,"column":null}}]},"19":{"loc":{"start":{"line":64,"column":7},"end":{"line":64,"column":25}},"type":"cond-expr","locations":[{"start":{"line":64,"column":19},"end":{"line":64,"column":21}},{"start":{"line":64,"column":19},"end":{"line":64,"column":25}}]},"20":{"loc":{"start":{"line":64,"column":7},"end":{"line":64,"column":21}},"type":"binary-expr","locations":[{"start":{"line":64,"column":7},"end":{"line":64,"column":21}},{"start":{"line":64,"column":19},"end":{"line":64,"column":21}}]},"21":{"loc":{"start":{"line":71,"column":55},"end":{"line":71,"column":73}},"type":"cond-expr","locations":[{"start":{"line":71,"column":67},"end":{"line":71,"column":69}},{"start":{"line":71,"column":67},"end":{"line":71,"column":73}}]},"22":{"loc":{"start":{"line":71,"column":55},"end":{"line":71,"column":69}},"type":"binary-expr","locations":[{"start":{"line":71,"column":55},"end":{"line":71,"column":69}},{"start":{"line":71,"column":67},"end":{"line":71,"column":69}}]},"23":{"loc":{"start":{"line":78,"column":20},"end":{"line":78,"column":64}},"type":"binary-expr","locations":[{"start":{"line":78,"column":20},"end":{"line":78,"column":57}},{"start":{"line":78,"column":61},"end":{"line":78,"column":64}}]},"24":{"loc":{"start":{"line":78,"column":20},"end":{"line":78,"column":57}},"type":"cond-expr","locations":[{"start":{"line":78,"column":48},"end":{"line":78,"column":50}},{"start":{"line":78,"column":48},"end":{"line":78,"column":57}}]},"25":{"loc":{"start":{"line":78,"column":20},"end":{"line":78,"column":50}},"type":"binary-expr","locations":[{"start":{"line":78,"column":20},"end":{"line":78,"column":50}},{"start":{"line":78,"column":48},"end":{"line":78,"column":50}}]},"26":{"loc":{"start":{"line":78,"column":20},"end":{"line":78,"column":48}},"type":"cond-expr","locations":[{"start":{"line":78,"column":42},"end":{"line":78,"column":44}},{"start":{"line":78,"column":42},"end":{"line":78,"column":48}}]},"27":{"loc":{"start":{"line":78,"column":20},"end":{"line":78,"column":44}},"type":"binary-expr","locations":[{"start":{"line":78,"column":20},"end":{"line":78,"column":44}},{"start":{"line":78,"column":42},"end":{"line":78,"column":44}}]},"28":{"loc":{"start":{"line":78,"column":21},"end":{"line":78,"column":42}},"type":"cond-expr","locations":[{"start":{"line":78,"column":24},"end":{"line":78,"column":32}},{"start":{"line":78,"column":21},"end":{"line":78,"column":42}}]},"29":{"loc":{"start":{"line":78,"column":21},"end":{"line":78,"column":32}},"type":"binary-expr","locations":[{"start":{"line":78,"column":21},"end":{"line":78,"column":34}},{"start":{"line":78,"column":21},"end":{"line":78,"column":32}}]},"30":{"loc":{"start":{"line":101,"column":2},"end":{"line":103,"column":null}},"type":"if","locations":[{"start":{"line":101,"column":2},"end":{"line":103,"column":null}}]},"31":{"loc":{"start":{"line":101,"column":6},"end":{"line":101,"column":19}},"type":"cond-expr","locations":[{"start":{"line":101,"column":12},"end":{"line":101,"column":14}},{"start":{"line":101,"column":6},"end":{"line":101,"column":19}}]},"32":{"loc":{"start":{"line":101,"column":6},"end":{"line":101,"column":14}},"type":"binary-expr","locations":[{"start":{"line":101,"column":6},"end":{"line":101,"column":14}},{"start":{"line":101,"column":6},"end":{"line":101,"column":14}}]},"33":{"loc":{"start":{"line":104,"column":2},"end":{"line":111,"column":null}},"type":"if","locations":[{"start":{"line":104,"column":2},"end":{"line":111,"column":null}}]},"34":{"loc":{"start":{"line":104,"column":7},"end":{"line":104,"column":40}},"type":"cond-expr","locations":[{"start":{"line":104,"column":32},"end":{"line":104,"column":34}},{"start":{"line":104,"column":32},"end":{"line":104,"column":40}}]},"35":{"loc":{"start":{"line":104,"column":7},"end":{"line":104,"column":34}},"type":"binary-expr","locations":[{"start":{"line":104,"column":7},"end":{"line":104,"column":34}},{"start":{"line":104,"column":32},"end":{"line":104,"column":34}}]},"36":{"loc":{"start":{"line":104,"column":7},"end":{"line":104,"column":32}},"type":"cond-expr","locations":[{"start":{"line":104,"column":13},"end":{"line":104,"column":15}},{"start":{"line":104,"column":7},"end":{"line":104,"column":32}}]},"37":{"loc":{"start":{"line":104,"column":7},"end":{"line":104,"column":15}},"type":"binary-expr","locations":[{"start":{"line":104,"column":7},"end":{"line":104,"column":15}},{"start":{"line":104,"column":7},"end":{"line":104,"column":15}}]},"38":{"loc":{"start":{"line":115,"column":6},"end":{"line":115,"column":22}},"type":"if","locations":[{"start":{"line":115,"column":6},"end":{"line":115,"column":22}}]},"39":{"loc":{"start":{"line":124,"column":4},"end":{"line":125,"column":28}},"type":"cond-expr","locations":[{"start":{"line":125,"column":18},"end":{"line":125,"column":20}},{"start":{"line":125,"column":18},"end":{"line":125,"column":28}}]},"40":{"loc":{"start":{"line":124,"column":4},"end":{"line":125,"column":20}},"type":"binary-expr","locations":[{"start":{"line":124,"column":4},"end":{"line":125,"column":20}},{"start":{"line":125,"column":18},"end":{"line":125,"column":20}}]},"41":{"loc":{"start":{"line":124,"column":4},"end":{"line":125,"column":18}},"type":"cond-expr","locations":[{"start":{"line":124,"column":71},"end":{"line":124,"column":null}},{"start":{"line":124,"column":71},"end":{"line":125,"column":18}}]},"42":{"loc":{"start":{"line":124,"column":4},"end":{"line":124,"column":null}},"type":"binary-expr","locations":[{"start":{"line":124,"column":4},"end":{"line":124,"column":null}},{"start":{"line":124,"column":71},"end":{"line":124,"column":null}}]},"43":{"loc":{"start":{"line":126,"column":9},"end":{"line":126,"column":30}},"type":"binary-expr","locations":[{"start":{"line":126,"column":9},"end":{"line":126,"column":25}},{"start":{"line":126,"column":29},"end":{"line":126,"column":30}}]},"44":{"loc":{"start":{"line":138,"column":25},"end":{"line":140,"column":15}},"type":"cond-expr","locations":[{"start":{"line":139,"column":6},"end":{"line":139,"column":28}},{"start":{"line":140,"column":6},"end":{"line":140,"column":15}}]},"45":{"loc":{"start":{"line":141,"column":22},"end":{"line":143,"column":15}},"type":"cond-expr","locations":[{"start":{"line":142,"column":6},"end":{"line":142,"column":39}},{"start":{"line":143,"column":6},"end":{"line":143,"column":15}}]},"46":{"loc":{"start":{"line":141,"column":22},"end":{"line":141,"column":54}},"type":"cond-expr","locations":[{"start":{"line":141,"column":46},"end":{"line":141,"column":48}},{"start":{"line":141,"column":46},"end":{"line":141,"column":54}}]},"47":{"loc":{"start":{"line":141,"column":22},"end":{"line":141,"column":48}},"type":"binary-expr","locations":[{"start":{"line":141,"column":22},"end":{"line":141,"column":48}},{"start":{"line":141,"column":46},"end":{"line":141,"column":48}}]},"48":{"loc":{"start":{"line":145,"column":2},"end":{"line":154,"column":null}},"type":"if","locations":[{"start":{"line":145,"column":2},"end":{"line":154,"column":null}}]},"49":{"loc":{"start":{"line":157,"column":2},"end":{"line":159,"column":null}},"type":"if","locations":[{"start":{"line":157,"column":2},"end":{"line":159,"column":null}}]},"50":{"loc":{"start":{"line":161,"column":15},"end":{"line":162,"column":null}},"type":"cond-expr","locations":[{"start":{"line":161,"column":41},"end":{"line":161,"column":43}},{"start":{"line":161,"column":41},"end":{"line":162,"column":null}}]},"51":{"loc":{"start":{"line":161,"column":15},"end":{"line":161,"column":43}},"type":"binary-expr","locations":[{"start":{"line":161,"column":15},"end":{"line":161,"column":43}},{"start":{"line":161,"column":41},"end":{"line":161,"column":43}}]},"52":{"loc":{"start":{"line":161,"column":15},"end":{"line":161,"column":41}},"type":"cond-expr","locations":[{"start":{"line":161,"column":29},"end":{"line":161,"column":31}},{"start":{"line":161,"column":29},"end":{"line":161,"column":41}}]},"53":{"loc":{"start":{"line":161,"column":15},"end":{"line":161,"column":31}},"type":"binary-expr","locations":[{"start":{"line":161,"column":15},"end":{"line":161,"column":31}},{"start":{"line":161,"column":29},"end":{"line":161,"column":31}}]},"54":{"loc":{"start":{"line":164,"column":2},"end":{"line":166,"column":null}},"type":"if","locations":[{"start":{"line":164,"column":2},"end":{"line":166,"column":null}}]}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":1,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0},"f":{"0":0,"1":0,"2":0},"b":{"0":[0],"1":[0],"2":[0],"3":[0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0,0],"14":[0,0],"15":[0,0],"16":[0,0],"17":[0,0],"18":[0],"19":[0,0],"20":[0,0],"21":[0,0],"22":[0,0],"23":[0,0],"24":[0,0],"25":[0,0],"26":[0,0],"27":[0,0],"28":[0,0],"29":[0,0],"30":[0],"31":[0,0],"32":[0,0],"33":[0],"34":[0,0],"35":[0,0],"36":[0,0],"37":[0,0],"38":[0],"39":[0,0],"40":[0,0],"41":[0,0],"42":[0,0],"43":[0,0],"44":[0,0],"45":[0,0],"46":[0,0],"47":[0,0],"48":[0],"49":[0],"50":[0,0],"51":[0,0],"52":[0,0],"53":[0,0],"54":[0]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/run-script-step.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/hooks/run-script-step.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":24}},"1":{"start":{"line":3,"column":0},"end":{"line":3,"column":37}},"2":{"start":{"line":5,"column":0},"end":{"line":5,"column":36}},"3":{"start":{"line":6,"column":0},"end":{"line":6,"column":52}},"4":{"start":{"line":7,"column":0},"end":{"line":7,"column":48}},"5":{"start":{"line":14,"column":10},"end":{"line":14,"column":63}},"6":{"start":{"line":15,"column":8},"end":{"line":15,"column":40}},"7":{"start":{"line":23,"column":2},"end":{"line":23,"column":null}},"8":{"start":{"line":24,"column":2},"end":{"line":24,"column":null}},"9":{"start":{"line":26,"column":4},"end":{"line":30,"column":null}},"10":{"start":{"line":32,"column":4},"end":{"line":32,"column":null}},"11":{"start":{"line":33,"column":10},"end":{"line":33,"column":null}},"12":{"start":{"line":34,"column":4},"end":{"line":34,"column":null}},"13":{"start":{"line":36,"column":4},"end":{"line":36,"column":null}},"14":{"start":{"line":9,"column":0},"end":{"line":9,"column":22}}},"fnMap":{"0":{"name":"runScriptStep","decl":{"start":{"line":9,"column":22},"end":{"line":9,"column":35}},"loc":{"start":{"line":12,"column":14},"end":{"line":38,"column":null}}}},"branchMap":{"0":{"loc":{"start":{"line":33,"column":20},"end":{"line":33,"column":64}},"type":"binary-expr","locations":[{"start":{"line":33,"column":20},"end":{"line":33,"column":57}},{"start":{"line":33,"column":61},"end":{"line":33,"column":64}}]},"1":{"loc":{"start":{"line":33,"column":20},"end":{"line":33,"column":57}},"type":"cond-expr","locations":[{"start":{"line":33,"column":48},"end":{"line":33,"column":50}},{"start":{"line":33,"column":48},"end":{"line":33,"column":57}}]},"2":{"loc":{"start":{"line":33,"column":20},"end":{"line":33,"column":50}},"type":"binary-expr","locations":[{"start":{"line":33,"column":20},"end":{"line":33,"column":50}},{"start":{"line":33,"column":48},"end":{"line":33,"column":50}}]},"3":{"loc":{"start":{"line":33,"column":20},"end":{"line":33,"column":48}},"type":"cond-expr","locations":[{"start":{"line":33,"column":42},"end":{"line":33,"column":44}},{"start":{"line":33,"column":42},"end":{"line":33,"column":48}}]},"4":{"loc":{"start":{"line":33,"column":20},"end":{"line":33,"column":44}},"type":"binary-expr","locations":[{"start":{"line":33,"column":20},"end":{"line":33,"column":44}},{"start":{"line":33,"column":42},"end":{"line":33,"column":44}}]},"5":{"loc":{"start":{"line":33,"column":21},"end":{"line":33,"column":42}},"type":"cond-expr","locations":[{"start":{"line":33,"column":24},"end":{"line":33,"column":32}},{"start":{"line":33,"column":21},"end":{"line":33,"column":42}}]},"6":{"loc":{"start":{"line":33,"column":21},"end":{"line":33,"column":32}},"type":"binary-expr","locations":[{"start":{"line":33,"column":21},"end":{"line":33,"column":34}},{"start":{"line":33,"column":21},"end":{"line":33,"column":32}}]}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":1},"f":{"0":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/k8s/index.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/k8s/index.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":46}},"2":{"start":{"line":4,"column":0},"end":{"line":4,"column":32}},"3":{"start":{"line":5,"column":0},"end":{"line":5,"column":null}},"4":{"start":{"line":13,"column":0},"end":{"line":13,"column":null}},"5":{"start":{"line":21,"column":11},"end":{"line":21,"column":31}},"6":{"start":{"line":23,"column":0},"end":{"line":23,"column":null}},"7":{"start":{"line":25,"column":15},"end":{"line":25,"column":46}},"8":{"start":{"line":26,"column":22},"end":{"line":26,"column":54}},"9":{"start":{"line":27,"column":30},"end":{"line":27,"column":70}},"10":{"start":{"line":29,"column":42},"end":{"line":29,"column":49}},"11":{"start":{"line":31,"column":13},"end":{"line":31,"column":null}},"12":{"start":{"line":33,"column":13},"end":{"line":64,"column":null}},"13":{"start":{"line":72,"column":8},"end":{"line":72,"column":null}},"14":{"start":{"line":73,"column":2},"end":{"line":75,"column":null}},"15":{"start":{"line":74,"column":4},"end":{"line":74,"column":null}},"16":{"start":{"line":76,"column":2},"end":{"line":78,"column":null}},"17":{"start":{"line":77,"column":4},"end":{"line":77,"column":32}},"18":{"start":{"line":80,"column":8},"end":{"line":80,"column":null}},"19":{"start":{"line":82,"column":2},"end":{"line":82,"column":null}},"20":{"start":{"line":83,"column":2},"end":{"line":83,"column":null}},"21":{"start":{"line":85,"column":2},"end":{"line":85,"column":null}},"22":{"start":{"line":86,"column":2},"end":{"line":86,"column":null}},"23":{"start":{"line":88,"column":8},"end":{"line":88,"column":null}},"24":{"start":{"line":89,"column":2},"end":{"line":91,"column":null}},"25":{"start":{"line":92,"column":2},"end":{"line":92,"column":null}},"26":{"start":{"line":94,"column":2},"end":{"line":94,"column":null}},"27":{"start":{"line":95,"column":2},"end":{"line":95,"column":null}},"28":{"start":{"line":96,"column":2},"end":{"line":96,"column":null}},"29":{"start":{"line":98,"column":19},"end":{"line":98,"column":null}},"30":{"start":{"line":98,"column":8},"end":{"line":98,"column":null}},"31":{"start":{"line":99,"column":6},"end":{"line":99,"column":22}},"32":{"start":{"line":100,"column":4},"end":{"line":100,"column":16}},"33":{"start":{"line":100,"column":27},"end":{"line":100,"column":null}},"34":{"start":{"line":100,"column":4},"end":{"line":100,"column":null}},"35":{"start":{"line":102,"column":4},"end":{"line":102,"column":16}},"36":{"start":{"line":102,"column":27},"end":{"line":102,"column":null}},"37":{"start":{"line":102,"column":4},"end":{"line":102,"column":null}},"38":{"start":{"line":104,"column":8},"end":{"line":104,"column":null}},"39":{"start":{"line":105,"column":2},"end":{"line":110,"column":null}},"40":{"start":{"line":112,"column":6},"end":{"line":112,"column":14}},"41":{"start":{"line":113,"column":19},"end":{"line":113,"column":null}},"42":{"start":{"line":113,"column":10},"end":{"line":113,"column":null}},"43":{"start":{"line":114,"column":4},"end":{"line":116,"column":null}},"44":{"start":{"line":115,"column":6},"end":{"line":115,"column":null}},"45":{"start":{"line":117,"column":10},"end":{"line":117,"column":null}},"46":{"start":{"line":118,"column":4},"end":{"line":118,"column":null}},"47":{"start":{"line":119,"column":4},"end":{"line":119,"column":null}},"48":{"start":{"line":122,"column":2},"end":{"line":124,"column":null}},"49":{"start":{"line":123,"column":4},"end":{"line":123,"column":null}},"50":{"start":{"line":126,"column":2},"end":{"line":128,"column":null}},"51":{"start":{"line":127,"column":4},"end":{"line":127,"column":null}},"52":{"start":{"line":130,"column":19},"end":{"line":130,"column":null}},"53":{"start":{"line":130,"column":10},"end":{"line":130,"column":19}},"54":{"start":{"line":131,"column":2},"end":{"line":131,"column":null}},"55":{"start":{"line":66,"column":0},"end":{"line":66,"column":22}},"56":{"start":{"line":138,"column":8},"end":{"line":138,"column":null}},"57":{"start":{"line":140,"column":8},"end":{"line":140,"column":null}},"58":{"start":{"line":141,"column":2},"end":{"line":141,"column":null}},"59":{"start":{"line":142,"column":2},"end":{"line":142,"column":null}},"60":{"start":{"line":143,"column":2},"end":{"line":143,"column":null}},"61":{"start":{"line":144,"column":2},"end":{"line":144,"column":null}},"62":{"start":{"line":145,"column":2},"end":{"line":145,"column":null}},"63":{"start":{"line":146,"column":2},"end":{"line":146,"column":null}},"64":{"start":{"line":148,"column":2},"end":{"line":148,"column":null}},"65":{"start":{"line":149,"column":2},"end":{"line":149,"column":null}},"66":{"start":{"line":150,"column":2},"end":{"line":150,"column":null}},"67":{"start":{"line":151,"column":2},"end":{"line":151,"column":null}},"68":{"start":{"line":153,"column":2},"end":{"line":153,"column":null}},"69":{"start":{"line":154,"column":2},"end":{"line":154,"column":null}},"70":{"start":{"line":155,"column":2},"end":{"line":155,"column":null}},"71":{"start":{"line":156,"column":2},"end":{"line":156,"column":null}},"72":{"start":{"line":157,"column":2},"end":{"line":157,"column":null}},"73":{"start":{"line":158,"column":2},"end":{"line":158,"column":null}},"74":{"start":{"line":160,"column":19},"end":{"line":160,"column":null}},"75":{"start":{"line":160,"column":8},"end":{"line":160,"column":null}},"76":{"start":{"line":161,"column":6},"end":{"line":161,"column":22}},"77":{"start":{"line":162,"column":4},"end":{"line":162,"column":27}},"78":{"start":{"line":162,"column":38},"end":{"line":162,"column":null}},"79":{"start":{"line":162,"column":4},"end":{"line":162,"column":null}},"80":{"start":{"line":164,"column":4},"end":{"line":164,"column":27}},"81":{"start":{"line":164,"column":38},"end":{"line":164,"column":null}},"82":{"start":{"line":164,"column":4},"end":{"line":164,"column":null}},"83":{"start":{"line":167,"column":8},"end":{"line":167,"column":null}},"84":{"start":{"line":168,"column":2},"end":{"line":173,"column":null}},"85":{"start":{"line":175,"column":2},"end":{"line":184,"column":null}},"86":{"start":{"line":176,"column":4},"end":{"line":180,"column":null}},"87":{"start":{"line":178,"column":6},"end":{"line":178,"column":null}},"88":{"start":{"line":179,"column":6},"end":{"line":179,"column":null}},"89":{"start":{"line":181,"column":4},"end":{"line":183,"column":null}},"90":{"start":{"line":182,"column":6},"end":{"line":182,"column":null}},"91":{"start":{"line":186,"column":19},"end":{"line":186,"column":null}},"92":{"start":{"line":186,"column":10},"end":{"line":186,"column":19}},"93":{"start":{"line":187,"column":2},"end":{"line":187,"column":null}},"94":{"start":{"line":134,"column":0},"end":{"line":134,"column":22}},"95":{"start":{"line":191,"column":8},"end":{"line":191,"column":null}},"96":{"start":{"line":192,"column":8},"end":{"line":192,"column":null}},"97":{"start":{"line":193,"column":9},"end":{"line":193,"column":null}},"98":{"start":{"line":193,"column":13},"end":{"line":193,"column":null}},"99":{"start":{"line":194,"column":20},"end":{"line":202,"column":null}},"100":{"start":{"line":194,"column":10},"end":{"line":202,"column":null}},"101":{"start":{"line":204,"column":8},"end":{"line":204,"column":9}},"102":{"start":{"line":205,"column":6},"end":{"line":205,"column":null}},"103":{"start":{"line":206,"column":6},"end":{"line":206,"column":14}},"104":{"start":{"line":209,"column":4},"end":{"line":213,"column":null}},"105":{"start":{"line":210,"column":6},"end":{"line":212,"column":null}},"106":{"start":{"line":214,"column":4},"end":{"line":214,"column":null}},"107":{"start":{"line":190,"column":0},"end":{"line":190,"column":22}},"108":{"start":{"line":219,"column":2},"end":{"line":225,"column":null}},"109":{"start":{"line":218,"column":0},"end":{"line":218,"column":22}},"110":{"start":{"line":234,"column":8},"end":{"line":234,"column":null}},"111":{"start":{"line":235,"column":2},"end":{"line":235,"column":null}},"112":{"start":{"line":237,"column":2},"end":{"line":266,"column":null}},"113":{"start":{"line":238,"column":4},"end":{"line":265,"column":null}},"114":{"start":{"line":250,"column":10},"end":{"line":260,"column":null}},"115":{"start":{"line":251,"column":12},"end":{"line":251,"column":null}},"116":{"start":{"line":253,"column":12},"end":{"line":258,"column":null}},"117":{"start":{"line":259,"column":12},"end":{"line":259,"column":null}},"118":{"start":{"line":265,"column":18},"end":{"line":265,"column":28}},"119":{"start":{"line":228,"column":0},"end":{"line":228,"column":22}},"120":{"start":{"line":270,"column":8},"end":{"line":270,"column":null}},"121":{"start":{"line":271,"column":9},"end":{"line":271,"column":null}},"122":{"start":{"line":271,"column":13},"end":{"line":271,"column":null}},"123":{"start":{"line":273,"column":10},"end":{"line":273,"column":41}},"124":{"start":{"line":273,"column":6},"end":{"line":275,"column":null}},"125":{"start":{"line":274,"column":8},"end":{"line":274,"column":14}},"126":{"start":{"line":277,"column":6},"end":{"line":277,"column":null}},"127":{"start":{"line":279,"column":4},"end":{"line":279,"column":null}},"128":{"start":{"line":269,"column":0},"end":{"line":269,"column":22}},"129":{"start":{"line":286,"column":8},"end":{"line":296,"column":null}},"130":{"start":{"line":298,"column":8},"end":{"line":298,"column":null}},"131":{"start":{"line":300,"column":8},"end":{"line":300,"column":null}},"132":{"start":{"line":301,"column":8},"end":{"line":301,"column":null}},"133":{"start":{"line":302,"column":2},"end":{"line":302,"column":null}},"134":{"start":{"line":303,"column":2},"end":{"line":303,"column":null}},"135":{"start":{"line":304,"column":2},"end":{"line":304,"column":null}},"136":{"start":{"line":305,"column":2},"end":{"line":305,"column":null}},"137":{"start":{"line":306,"column":2},"end":{"line":306,"column":null}},"138":{"start":{"line":307,"column":2},"end":{"line":309,"column":null}},"139":{"start":{"line":310,"column":2},"end":{"line":310,"column":null}},"140":{"start":{"line":311,"column":2},"end":{"line":311,"column":null}},"141":{"start":{"line":312,"column":2},"end":{"line":316,"column":null}},"142":{"start":{"line":318,"column":19},"end":{"line":318,"column":null}},"143":{"start":{"line":318,"column":10},"end":{"line":318,"column":19}},"144":{"start":{"line":319,"column":2},"end":{"line":319,"column":null}},"145":{"start":{"line":283,"column":0},"end":{"line":283,"column":22}},"146":{"start":{"line":325,"column":8},"end":{"line":325,"column":null}},"147":{"start":{"line":327,"column":8},"end":{"line":327,"column":null}},"148":{"start":{"line":328,"column":8},"end":{"line":328,"column":null}},"149":{"start":{"line":329,"column":2},"end":{"line":329,"column":null}},"150":{"start":{"line":330,"column":2},"end":{"line":330,"column":null}},"151":{"start":{"line":331,"column":2},"end":{"line":331,"column":null}},"152":{"start":{"line":332,"column":2},"end":{"line":332,"column":null}},"153":{"start":{"line":334,"column":2},"end":{"line":336,"column":null}},"154":{"start":{"line":337,"column":2},"end":{"line":337,"column":null}},"155":{"start":{"line":338,"column":2},"end":{"line":338,"column":null}},"156":{"start":{"line":339,"column":2},"end":{"line":341,"column":null}},"157":{"start":{"line":339,"column":13},"end":{"line":339,"column":25}},"158":{"start":{"line":340,"column":4},"end":{"line":340,"column":null}},"159":{"start":{"line":343,"column":2},"end":{"line":343,"column":null}},"160":{"start":{"line":344,"column":2},"end":{"line":344,"column":null}},"161":{"start":{"line":322,"column":0},"end":{"line":322,"column":22}},"162":{"start":{"line":348,"column":2},"end":{"line":348,"column":null}},"163":{"start":{"line":347,"column":0},"end":{"line":347,"column":22}},"164":{"start":{"line":352,"column":21},"end":{"line":359,"column":null}},"165":{"start":{"line":352,"column":8},"end":{"line":359,"column":null}},"166":{"start":{"line":360,"column":2},"end":{"line":362,"column":null}},"167":{"start":{"line":361,"column":4},"end":{"line":361,"column":10}},"168":{"start":{"line":364,"column":2},"end":{"line":368,"column":null}},"169":{"start":{"line":366,"column":16},"end":{"line":366,"column":null}},"170":{"start":{"line":351,"column":0},"end":{"line":351,"column":22}},"171":{"start":{"line":371,"column":13},"end":{"line":377,"column":null}},"172":{"start":{"line":379,"column":13},"end":{"line":383,"column":null}},"173":{"start":{"line":385,"column":13},"end":{"line":389,"column":null}},"174":{"start":{"line":391,"column":30},"end":{"line":391,"column":32}},"175":{"start":{"line":394,"column":16},"end":{"line":394,"column":79}},"176":{"start":{"line":395,"column":2},"end":{"line":397,"column":null}},"177":{"start":{"line":396,"column":4},"end":{"line":396,"column":null}},"178":{"start":{"line":398,"column":18},"end":{"line":398,"column":56}},"179":{"start":{"line":399,"column":2},"end":{"line":404,"column":null}},"180":{"start":{"line":399,"column":23},"end":{"line":399,"column":28}},"181":{"start":{"line":399,"column":23},"end":{"line":399,"column":39}},"182":{"start":{"line":399,"column":19},"end":{"line":399,"column":23}},"183":{"start":{"line":400,"column":20},"end":{"line":400,"column":33}},"184":{"start":{"line":401,"column":4},"end":{"line":403,"column":null}},"185":{"start":{"line":402,"column":6},"end":{"line":402,"column":null}},"186":{"start":{"line":405,"column":2},"end":{"line":405,"column":null}},"187":{"start":{"line":393,"column":0},"end":{"line":393,"column":16}},"188":{"start":{"line":409,"column":16},"end":{"line":409,"column":77}},"189":{"start":{"line":410,"column":2},"end":{"line":412,"column":null}},"190":{"start":{"line":411,"column":4},"end":{"line":411,"column":null}},"191":{"start":{"line":413,"column":18},"end":{"line":413,"column":54}},"192":{"start":{"line":414,"column":2},"end":{"line":419,"column":null}},"193":{"start":{"line":414,"column":23},"end":{"line":414,"column":28}},"194":{"start":{"line":414,"column":23},"end":{"line":414,"column":39}},"195":{"start":{"line":414,"column":19},"end":{"line":414,"column":23}},"196":{"start":{"line":415,"column":20},"end":{"line":415,"column":33}},"197":{"start":{"line":416,"column":4},"end":{"line":418,"column":null}},"198":{"start":{"line":417,"column":6},"end":{"line":417,"column":null}},"199":{"start":{"line":420,"column":2},"end":{"line":420,"column":null}},"200":{"start":{"line":408,"column":0},"end":{"line":408,"column":16}},"201":{"start":{"line":425,"column":4},"end":{"line":425,"column":70}},"202":{"start":{"line":426,"column":2},"end":{"line":428,"column":null}},"203":{"start":{"line":427,"column":4},"end":{"line":427,"column":null}},"204":{"start":{"line":429,"column":18},"end":{"line":429,"column":59}},"205":{"start":{"line":430,"column":2},"end":{"line":435,"column":null}},"206":{"start":{"line":430,"column":23},"end":{"line":430,"column":28}},"207":{"start":{"line":430,"column":23},"end":{"line":430,"column":39}},"208":{"start":{"line":430,"column":19},"end":{"line":430,"column":23}},"209":{"start":{"line":431,"column":20},"end":{"line":431,"column":33}},"210":{"start":{"line":432,"column":4},"end":{"line":434,"column":null}},"211":{"start":{"line":433,"column":6},"end":{"line":433,"column":null}},"212":{"start":{"line":436,"column":2},"end":{"line":436,"column":null}},"213":{"start":{"line":423,"column":0},"end":{"line":423,"column":16}},"214":{"start":{"line":440,"column":27},"end":{"line":440,"column":29}},"215":{"start":{"line":441,"column":31},"end":{"line":441,"column":63}},"216":{"start":{"line":442,"column":19},"end":{"line":444,"column":null}},"217":{"start":{"line":446,"column":2},"end":{"line":455,"column":null}},"218":{"start":{"line":446,"column":19},"end":{"line":446,"column":30}},"219":{"start":{"line":446,"column":15},"end":{"line":446,"column":19}},"220":{"start":{"line":447,"column":20},"end":{"line":447,"column":37}},"221":{"start":{"line":448,"column":4},"end":{"line":454,"column":null}},"222":{"start":{"line":449,"column":6},"end":{"line":453,"column":null}},"223":{"start":{"line":456,"column":2},"end":{"line":456,"column":null}},"224":{"start":{"line":439,"column":0},"end":{"line":439,"column":16}},"225":{"start":{"line":460,"column":8},"end":{"line":460,"column":null}},"226":{"start":{"line":463,"column":21},"end":{"line":469,"column":null}},"227":{"start":{"line":463,"column":12},"end":{"line":463,"column":21}},"228":{"start":{"line":470,"column":4},"end":{"line":470,"column":null}},"229":{"start":{"line":472,"column":4},"end":{"line":476,"column":null}},"230":{"start":{"line":477,"column":4},"end":{"line":477,"column":null}},"231":{"start":{"line":480,"column":8},"end":{"line":480,"column":null}},"232":{"start":{"line":481,"column":2},"end":{"line":489,"column":null}},"233":{"start":{"line":481,"column":13},"end":{"line":481,"column":18}},"234":{"start":{"line":482,"column":4},"end":{"line":488,"column":null}},"235":{"start":{"line":487,"column":6},"end":{"line":487,"column":null}},"236":{"start":{"line":490,"column":2},"end":{"line":490,"column":null}},"237":{"start":{"line":459,"column":0},"end":{"line":459,"column":22}},"238":{"start":{"line":494,"column":27},"end":{"line":494,"column":29}},"239":{"start":{"line":495,"column":2},"end":{"line":503,"column":null}},"240":{"start":{"line":495,"column":21},"end":{"line":495,"column":24}},"241":{"start":{"line":495,"column":21},"end":{"line":495,"column":49}},"242":{"start":{"line":495,"column":17},"end":{"line":495,"column":21}},"243":{"start":{"line":496,"column":4},"end":{"line":502,"column":null}},"244":{"start":{"line":497,"column":6},"end":{"line":501,"column":null}},"245":{"start":{"line":504,"column":2},"end":{"line":504,"column":null}},"246":{"start":{"line":493,"column":0},"end":{"line":493,"column":16}},"247":{"start":{"line":508,"column":27},"end":{"line":508,"column":29}},"248":{"start":{"line":509,"column":31},"end":{"line":509,"column":66}},"249":{"start":{"line":510,"column":19},"end":{"line":512,"column":null}},"250":{"start":{"line":514,"column":2},"end":{"line":523,"column":null}},"251":{"start":{"line":514,"column":19},"end":{"line":514,"column":30}},"252":{"start":{"line":514,"column":15},"end":{"line":514,"column":19}},"253":{"start":{"line":515,"column":23},"end":{"line":515,"column":43}},"254":{"start":{"line":516,"column":4},"end":{"line":522,"column":null}},"255":{"start":{"line":517,"column":6},"end":{"line":521,"column":null}},"256":{"start":{"line":524,"column":2},"end":{"line":524,"column":null}},"257":{"start":{"line":507,"column":0},"end":{"line":507,"column":16}},"258":{"start":{"line":530,"column":10},"end":{"line":530,"column":null}},"259":{"start":{"line":530,"column":4},"end":{"line":530,"column":null}},"260":{"start":{"line":532,"column":4},"end":{"line":534,"column":null}},"261":{"start":{"line":537,"column":8},"end":{"line":537,"column":null}},"262":{"start":{"line":538,"column":8},"end":{"line":538,"column":null}},"263":{"start":{"line":540,"column":2},"end":{"line":546,"column":null}},"264":{"start":{"line":541,"column":4},"end":{"line":545,"column":null}},"265":{"start":{"line":547,"column":2},"end":{"line":549,"column":null}},"266":{"start":{"line":548,"column":4},"end":{"line":548,"column":null}},"267":{"start":{"line":551,"column":8},"end":{"line":551,"column":null}},"268":{"start":{"line":552,"column":2},"end":{"line":552,"column":null}},"269":{"start":{"line":554,"column":2},"end":{"line":562,"column":null}},"270":{"start":{"line":554,"column":13},"end":{"line":554,"column":21}},"271":{"start":{"line":555,"column":4},"end":{"line":561,"column":null}},"272":{"start":{"line":556,"column":6},"end":{"line":560,"column":null}},"273":{"start":{"line":564,"column":8},"end":{"line":567,"column":null}},"274":{"start":{"line":568,"column":2},"end":{"line":587,"column":null}},"275":{"start":{"line":568,"column":13},"end":{"line":568,"column":19}},"276":{"start":{"line":569,"column":10},"end":{"line":569,"column":null}},"277":{"start":{"line":570,"column":4},"end":{"line":576,"column":null}},"278":{"start":{"line":571,"column":6},"end":{"line":575,"column":null}},"279":{"start":{"line":577,"column":10},"end":{"line":577,"column":null}},"280":{"start":{"line":578,"column":4},"end":{"line":586,"column":null}},"281":{"start":{"line":579,"column":6},"end":{"line":585,"column":null}},"282":{"start":{"line":589,"column":2},"end":{"line":589,"column":16}},"283":{"start":{"line":589,"column":2},"end":{"line":589,"column":8}},"284":{"start":{"line":589,"column":17},"end":{"line":589,"column":57}},"285":{"start":{"line":589,"column":2},"end":{"line":589,"column":58}},"286":{"start":{"line":591,"column":2},"end":{"line":593,"column":null}},"287":{"start":{"line":592,"column":4},"end":{"line":592,"column":null}},"288":{"start":{"line":594,"column":2},"end":{"line":594,"column":null}},"289":{"start":{"line":527,"column":0},"end":{"line":527,"column":22}},"290":{"start":{"line":600,"column":21},"end":{"line":606,"column":null}},"291":{"start":{"line":600,"column":12},"end":{"line":600,"column":21}},"292":{"start":{"line":607,"column":4},"end":{"line":607,"column":null}},"293":{"start":{"line":609,"column":4},"end":{"line":613,"column":null}},"294":{"start":{"line":614,"column":4},"end":{"line":614,"column":null}},"295":{"start":{"line":617,"column":8},"end":{"line":617,"column":null}},"296":{"start":{"line":617,"column":37},"end":{"line":617,"column":58}},"297":{"start":{"line":618,"column":2},"end":{"line":620,"column":null}},"298":{"start":{"line":619,"column":4},"end":{"line":619,"column":null}},"299":{"start":{"line":622,"column":8},"end":{"line":625,"column":null}},"300":{"start":{"line":623,"column":14},"end":{"line":623,"column":64}},"301":{"start":{"line":624,"column":4},"end":{"line":624,"column":null}},"302":{"start":{"line":626,"column":2},"end":{"line":626,"column":null}},"303":{"start":{"line":626,"column":26},"end":{"line":626,"column":54}},"304":{"start":{"line":628,"column":8},"end":{"line":628,"column":null}},"305":{"start":{"line":629,"column":8},"end":{"line":634,"column":null}},"306":{"start":{"line":630,"column":18},"end":{"line":630,"column":64}},"307":{"start":{"line":631,"column":4},"end":{"line":633,"column":null}},"308":{"start":{"line":635,"column":2},"end":{"line":639,"column":null}},"309":{"start":{"line":636,"column":4},"end":{"line":638,"column":null}},"310":{"start":{"line":640,"column":2},"end":{"line":640,"column":null}},"311":{"start":{"line":647,"column":2},"end":{"line":647,"column":null}},"312":{"start":{"line":649,"column":8},"end":{"line":649,"column":null}},"313":{"start":{"line":650,"column":6},"end":{"line":650,"column":null}},"314":{"start":{"line":651,"column":9},"end":{"line":651,"column":null}},"315":{"start":{"line":651,"column":13},"end":{"line":651,"column":null}},"316":{"start":{"line":652,"column":16},"end":{"line":652,"column":null}},"317":{"start":{"line":652,"column":10},"end":{"line":652,"column":null}},"318":{"start":{"line":653,"column":4},"end":{"line":653,"column":null}},"319":{"start":{"line":654,"column":4},"end":{"line":656,"column":null}},"320":{"start":{"line":655,"column":6},"end":{"line":655,"column":12}},"321":{"start":{"line":658,"column":8},"end":{"line":658,"column":9}},"322":{"start":{"line":659,"column":22},"end":{"line":659,"column":null}},"323":{"start":{"line":659,"column":12},"end":{"line":659,"column":null}},"324":{"start":{"line":660,"column":6},"end":{"line":662,"column":null}},"325":{"start":{"line":665,"column":10},"end":{"line":665,"column":null}},"326":{"start":{"line":666,"column":8},"end":{"line":666,"column":23}},"327":{"start":{"line":667,"column":22},"end":{"line":667,"column":null}},"328":{"start":{"line":667,"column":12},"end":{"line":667,"column":null}},"329":{"start":{"line":668,"column":6},"end":{"line":672,"column":null}},"330":{"start":{"line":675,"column":10},"end":{"line":675,"column":null}},"331":{"start":{"line":676,"column":8},"end":{"line":676,"column":23}},"332":{"start":{"line":677,"column":22},"end":{"line":677,"column":null}},"333":{"start":{"line":677,"column":12},"end":{"line":677,"column":null}},"334":{"start":{"line":678,"column":6},"end":{"line":682,"column":null}},"335":{"start":{"line":686,"column":6},"end":{"line":686,"column":null}},"336":{"start":{"line":688,"column":22},"end":{"line":688,"column":null}},"337":{"start":{"line":688,"column":12},"end":{"line":688,"column":null}},"338":{"start":{"line":689,"column":6},"end":{"line":691,"column":null}},"339":{"start":{"line":643,"column":0},"end":{"line":643,"column":22}},"340":{"start":{"line":698,"column":4},"end":{"line":698,"column":61}},"341":{"start":{"line":700,"column":2},"end":{"line":702,"column":null}},"342":{"start":{"line":701,"column":4},"end":{"line":701,"column":null}},"343":{"start":{"line":704,"column":25},"end":{"line":704,"column":56}},"344":{"start":{"line":705,"column":2},"end":{"line":710,"column":null}},"345":{"start":{"line":706,"column":4},"end":{"line":708,"column":null}},"346":{"start":{"line":709,"column":4},"end":{"line":709,"column":null}},"347":{"start":{"line":712,"column":2},"end":{"line":712,"column":null}},"348":{"start":{"line":696,"column":0},"end":{"line":696,"column":16}},"349":{"start":{"line":716,"column":19},"end":{"line":716,"column":null}},"350":{"start":{"line":716,"column":10},"end":{"line":716,"column":19}},"351":{"start":{"line":717,"column":2},"end":{"line":717,"column":null}},"352":{"start":{"line":720,"column":23},"end":{"line":726,"column":2}},"353":{"start":{"line":729,"column":2},"end":{"line":731,"column":null}},"354":{"start":{"line":730,"column":4},"end":{"line":730,"column":null}},"355":{"start":{"line":732,"column":2},"end":{"line":732,"column":null}},"356":{"start":{"line":728,"column":0},"end":{"line":728,"column":16}},"357":{"start":{"line":736,"column":19},"end":{"line":736,"column":null}},"358":{"start":{"line":736,"column":10},"end":{"line":736,"column":19}},"359":{"start":{"line":737,"column":8},"end":{"line":737,"column":null}},"360":{"start":{"line":738,"column":2},"end":{"line":740,"column":null}},"361":{"start":{"line":739,"column":4},"end":{"line":739,"column":null}},"362":{"start":{"line":741,"column":2},"end":{"line":741,"column":null}},"363":{"start":{"line":748,"column":8},"end":{"line":748,"column":null}},"364":{"start":{"line":749,"column":8},"end":{"line":749,"column":null}},"365":{"start":{"line":750,"column":2},"end":{"line":753,"column":null}},"366":{"start":{"line":752,"column":4},"end":{"line":752,"column":null}},"367":{"start":{"line":755,"column":2},"end":{"line":757,"column":null}},"368":{"start":{"line":756,"column":4},"end":{"line":756,"column":null}},"369":{"start":{"line":759,"column":12},"end":{"line":763,"column":null}},"370":{"start":{"line":759,"column":8},"end":{"line":763,"column":null}},"371":{"start":{"line":764,"column":2},"end":{"line":764,"column":null}},"372":{"start":{"line":764,"column":31},"end":{"line":764,"column":66}},"373":{"start":{"line":764,"column":51},"end":{"line":764,"column":65}},"374":{"start":{"line":744,"column":0},"end":{"line":744,"column":22}},"375":{"start":{"line":768,"column":18},"end":{"line":775,"column":null}},"376":{"start":{"line":768,"column":8},"end":{"line":775,"column":null}},"377":{"start":{"line":776,"column":2},"end":{"line":778,"column":null}},"378":{"start":{"line":777,"column":4},"end":{"line":777,"column":10}},"379":{"start":{"line":780,"column":2},"end":{"line":784,"column":null}},"380":{"start":{"line":782,"column":13},"end":{"line":782,"column":null}},"381":{"start":{"line":767,"column":0},"end":{"line":767,"column":22}},"382":{"start":{"line":790,"column":19},"end":{"line":790,"column":null}},"383":{"start":{"line":790,"column":10},"end":{"line":790,"column":19}},"384":{"start":{"line":791,"column":2},"end":{"line":791,"column":null}},"385":{"start":{"line":787,"column":0},"end":{"line":787,"column":22}},"386":{"start":{"line":795,"column":8},"end":{"line":795,"column":null}},"387":{"start":{"line":796,"column":8},"end":{"line":799,"column":null}},"388":{"start":{"line":800,"column":2},"end":{"line":811,"column":null}},"389":{"start":{"line":800,"column":13},"end":{"line":800,"column":25}},"390":{"start":{"line":801,"column":4},"end":{"line":810,"column":null}},"391":{"start":{"line":801,"column":15},"end":{"line":801,"column":23}},"392":{"start":{"line":802,"column":6},"end":{"line":802,"column":null}},"393":{"start":{"line":803,"column":6},"end":{"line":803,"column":null}},"394":{"start":{"line":804,"column":6},"end":{"line":804,"column":null}},"395":{"start":{"line":805,"column":6},"end":{"line":805,"column":null}},"396":{"start":{"line":806,"column":6},"end":{"line":806,"column":null}},"397":{"start":{"line":807,"column":6},"end":{"line":807,"column":null}},"398":{"start":{"line":808,"column":6},"end":{"line":808,"column":null}},"399":{"start":{"line":809,"column":6},"end":{"line":809,"column":null}},"400":{"start":{"line":812,"column":20},"end":{"line":812,"column":null}},"401":{"start":{"line":812,"column":8},"end":{"line":812,"column":null}},"402":{"start":{"line":813,"column":2},"end":{"line":813,"column":null}},"403":{"start":{"line":813,"column":33},"end":{"line":813,"column":59}},"404":{"start":{"line":794,"column":0},"end":{"line":794,"column":22}},"405":{"start":{"line":820,"column":6},"end":{"line":820,"column":null}},"406":{"start":{"line":822,"column":4},"end":{"line":830,"column":null}},"407":{"start":{"line":832,"column":4},"end":{"line":832,"column":null}},"408":{"start":{"line":835,"column":2},"end":{"line":835,"column":null}},"409":{"start":{"line":816,"column":0},"end":{"line":816,"column":22}},"410":{"start":{"line":839,"column":15},"end":{"line":839,"column":null}},"411":{"start":{"line":839,"column":8},"end":{"line":839,"column":null}},"412":{"start":{"line":841,"column":8},"end":{"line":841,"column":null}},"413":{"start":{"line":842,"column":2},"end":{"line":844,"column":null}},"414":{"start":{"line":843,"column":4},"end":{"line":843,"column":null}},"415":{"start":{"line":845,"column":2},"end":{"line":845,"column":null}},"416":{"start":{"line":849,"column":8},"end":{"line":849,"column":null}},"417":{"start":{"line":850,"column":2},"end":{"line":850,"column":null}},"418":{"start":{"line":851,"column":2},"end":{"line":852,"column":null}},"419":{"start":{"line":853,"column":2},"end":{"line":864,"column":null}},"420":{"start":{"line":865,"column":2},"end":{"line":865,"column":null}},"421":{"start":{"line":871,"column":8},"end":{"line":871,"column":null}},"422":{"start":{"line":872,"column":2},"end":{"line":872,"column":null}},"423":{"start":{"line":875,"column":8},"end":{"line":875,"column":null}},"424":{"start":{"line":876,"column":2},"end":{"line":876,"column":27}},"425":{"start":{"line":879,"column":2},"end":{"line":879,"column":null}},"426":{"start":{"line":880,"column":2},"end":{"line":886,"column":null}},"427":{"start":{"line":889,"column":2},"end":{"line":891,"column":null}},"428":{"start":{"line":893,"column":2},"end":{"line":893,"column":null}},"429":{"start":{"line":897,"column":2},"end":{"line":899,"column":null}},"430":{"start":{"line":898,"column":4},"end":{"line":898,"column":null}},"431":{"start":{"line":901,"column":18},"end":{"line":901,"column":61}},"432":{"start":{"line":901,"column":47},"end":{"line":901,"column":61}},"433":{"start":{"line":902,"column":2},"end":{"line":906,"column":null}},"434":{"start":{"line":903,"column":4},"end":{"line":905,"column":null}},"435":{"start":{"line":907,"column":2},"end":{"line":907,"column":null}},"436":{"start":{"line":896,"column":0},"end":{"line":896,"column":16}},"437":{"start":{"line":910,"column":0},"end":{"line":910,"column":null}},"438":{"start":{"line":913,"column":22},"end":{"line":913,"column":48}},"439":{"start":{"line":911,"column":10},"end":{"line":911,"column":null}},"440":{"start":{"line":912,"column":2},"end":{"line":912,"column":null}},"441":{"start":{"line":914,"column":4},"end":{"line":916,"column":null}},"442":{"start":{"line":915,"column":6},"end":{"line":915,"column":null}},"443":{"start":{"line":919,"column":8},"end":{"line":933,"column":null}},"444":{"start":{"line":920,"column":4},"end":{"line":922,"column":null}},"445":{"start":{"line":921,"column":6},"end":{"line":921,"column":null}},"446":{"start":{"line":923,"column":4},"end":{"line":923,"column":null}},"447":{"start":{"line":924,"column":4},"end":{"line":926,"column":null}},"448":{"start":{"line":925,"column":6},"end":{"line":925,"column":null}},"449":{"start":{"line":927,"column":4},"end":{"line":929,"column":null}},"450":{"start":{"line":928,"column":6},"end":{"line":928,"column":null}},"451":{"start":{"line":930,"column":4},"end":{"line":932,"column":null}},"452":{"start":{"line":931,"column":6},"end":{"line":931,"column":null}},"453":{"start":{"line":934,"column":0},"end":{"line":934,"column":null}},"454":{"start":{"line":939,"column":39},"end":{"line":939,"column":41}},"455":{"start":{"line":940,"column":2},"end":{"line":942,"column":null}},"456":{"start":{"line":941,"column":4},"end":{"line":941,"column":null}},"457":{"start":{"line":943,"column":2},"end":{"line":974,"column":null}},"458":{"start":{"line":943,"column":31},"end":{"line":943,"column":40}},"459":{"start":{"line":943,"column":31},"end":{"line":943,"column":53}},"460":{"start":{"line":943,"column":27},"end":{"line":943,"column":31}},"461":{"start":{"line":944,"column":27},"end":{"line":944,"column":52}},"462":{"start":{"line":945,"column":4},"end":{"line":947,"column":null}},"463":{"start":{"line":946,"column":6},"end":{"line":946,"column":null}},"464":{"start":{"line":949,"column":17},"end":{"line":949,"column":42}},"465":{"start":{"line":950,"column":4},"end":{"line":951,"column":null}},"466":{"start":{"line":953,"column":22},"end":{"line":953,"column":50}},"467":{"start":{"line":954,"column":4},"end":{"line":956,"column":null}},"468":{"start":{"line":955,"column":6},"end":{"line":955,"column":null}},"469":{"start":{"line":958,"column":22},"end":{"line":964,"column":5}},"470":{"start":{"line":959,"column":18},"end":{"line":959,"column":27}},"471":{"start":{"line":960,"column":6},"end":{"line":962,"column":null}},"472":{"start":{"line":961,"column":8},"end":{"line":961,"column":null}},"473":{"start":{"line":963,"column":6},"end":{"line":963,"column":null}},"474":{"start":{"line":966,"column":4},"end":{"line":971,"column":null}},"475":{"start":{"line":967,"column":6},"end":{"line":967,"column":null}},"476":{"start":{"line":969,"column":6},"end":{"line":969,"column":null}},"477":{"start":{"line":970,"column":6},"end":{"line":970,"column":null}},"478":{"start":{"line":973,"column":4},"end":{"line":973,"column":null}},"479":{"start":{"line":975,"column":2},"end":{"line":975,"column":null}},"480":{"start":{"line":936,"column":0},"end":{"line":936,"column":16}},"481":{"start":{"line":979,"column":19},"end":{"line":979,"column":null}},"482":{"start":{"line":979,"column":10},"end":{"line":979,"column":19}},"483":{"start":{"line":980,"column":2},"end":{"line":980,"column":null}},"484":{"start":{"line":978,"column":0},"end":{"line":978,"column":22}}},"fnMap":{"0":{"name":"createPod","decl":{"start":{"line":66,"column":22},"end":{"line":66,"column":31}},"loc":{"start":{"line":70,"column":35},"end":{"line":132,"column":null}}},"1":{"name":"createJob","decl":{"start":{"line":134,"column":22},"end":{"line":134,"column":31}},"loc":{"start":{"line":136,"column":35},"end":{"line":188,"column":null}}},"2":{"name":"getContainerJobPodName","decl":{"start":{"line":190,"column":22},"end":{"line":190,"column":44}},"loc":{"start":{"line":190,"column":60},"end":{"line":216,"column":null}}},"3":{"name":"deletePod","decl":{"start":{"line":218,"column":22},"end":{"line":218,"column":31}},"loc":{"start":{"line":218,"column":47},"end":{"line":226,"column":null}}},"4":{"name":"execPodStep","decl":{"start":{"line":228,"column":22},"end":{"line":228,"column":33}},"loc":{"start":{"line":232,"column":25},"end":{"line":267,"column":null}}},"5":{"name":"(anonymous_35)","decl":{"start":{"line":237,"column":20},"end":{"line":237,"column":30}},"loc":{"start":{"line":237,"column":45},"end":{"line":266,"column":3}}},"6":{"name":"(anonymous_36)","decl":{"start":{"line":248,"column":8},"end":{"line":248,"column":12}},"loc":{"start":{"line":248,"column":12},"end":{"line":261,"column":9}}},"7":{"name":"(anonymous_37)","decl":{"start":{"line":265,"column":13},"end":{"line":265,"column":14}},"loc":{"start":{"line":265,"column":14},"end":{"line":265,"column":24}}},"8":{"name":"waitForJobToComplete","decl":{"start":{"line":269,"column":22},"end":{"line":269,"column":42}},"loc":{"start":{"line":269,"column":58},"end":{"line":281,"column":null}}},"9":{"name":"createDockerSecret","decl":{"start":{"line":283,"column":22},"end":{"line":283,"column":40}},"loc":{"start":{"line":284,"column":20},"end":{"line":320,"column":null}}},"10":{"name":"createSecretForEnvs","decl":{"start":{"line":322,"column":22},"end":{"line":322,"column":41}},"loc":{"start":{"line":324,"column":1},"end":{"line":345,"column":null}}},"11":{"name":"deleteSecret","decl":{"start":{"line":347,"column":22},"end":{"line":347,"column":34}},"loc":{"start":{"line":347,"column":53},"end":{"line":349,"column":null}}},"12":{"name":"pruneSecrets","decl":{"start":{"line":351,"column":22},"end":{"line":351,"column":34}},"loc":{"start":{"line":351,"column":34},"end":{"line":369,"column":null}}},"13":{"name":"(anonymous_53)","decl":{"start":{"line":366,"column":6},"end":{"line":366,"column":12}},"loc":{"start":{"line":366,"column":12},"end":{"line":366,"column":null}}},"14":{"name":"getUnrecoverableWaitingReasons","decl":{"start":{"line":393,"column":16},"end":{"line":393,"column":46}},"loc":{"start":{"line":393,"column":46},"end":{"line":406,"column":1}}},"15":{"name":"getUnrecoverableEventReasons","decl":{"start":{"line":408,"column":16},"end":{"line":408,"column":44}},"loc":{"start":{"line":408,"column":44},"end":{"line":421,"column":1}}},"16":{"name":"getUnrecoverableTerminatedReasons","decl":{"start":{"line":423,"column":16},"end":{"line":423,"column":49}},"loc":{"start":{"line":423,"column":49},"end":{"line":437,"column":1}}},"17":{"name":"getContainerErrors","decl":{"start":{"line":439,"column":16},"end":{"line":439,"column":34}},"loc":{"start":{"line":439,"column":49},"end":{"line":457,"column":1}}},"18":{"name":"getPodEventErrors","decl":{"start":{"line":459,"column":22},"end":{"line":459,"column":39}},"loc":{"start":{"line":459,"column":55},"end":{"line":491,"column":null}}},"19":{"name":"getPodConditionErrors","decl":{"start":{"line":493,"column":16},"end":{"line":493,"column":37}},"loc":{"start":{"line":493,"column":52},"end":{"line":505,"column":1}}},"20":{"name":"getContainerTerminatedErrors","decl":{"start":{"line":507,"column":16},"end":{"line":507,"column":44}},"loc":{"start":{"line":507,"column":59},"end":{"line":525,"column":1}}},"21":{"name":"describePodFailure","decl":{"start":{"line":527,"column":22},"end":{"line":527,"column":40}},"loc":{"start":{"line":527,"column":56},"end":{"line":595,"column":null}}},"22":{"name":"describePodWarningEvents","decl":{"start":{"line":597,"column":15},"end":{"line":597,"column":39}},"loc":{"start":{"line":597,"column":55},"end":{"line":641,"column":null}}},"23":{"name":"(anonymous_69)","decl":{"start":{"line":617,"column":32},"end":{"line":617,"column":33}},"loc":{"start":{"line":617,"column":33},"end":{"line":617,"column":38}}},"24":{"name":"(anonymous_70)","decl":{"start":{"line":622,"column":20},"end":{"line":622,"column":21}},"loc":{"start":{"line":622,"column":39},"end":{"line":625,"column":3}}},"25":{"name":"(anonymous_71)","decl":{"start":{"line":626,"column":16},"end":{"line":626,"column":17}},"loc":{"start":{"line":626,"column":21},"end":{"line":626,"column":35}}},"26":{"name":"(anonymous_72)","decl":{"start":{"line":629,"column":27},"end":{"line":629,"column":28}},"loc":{"start":{"line":629,"column":28},"end":{"line":634,"column":3}}},"27":{"name":"waitForPodPhases","decl":{"start":{"line":643,"column":22},"end":{"line":643,"column":38}},"loc":{"start":{"line":647,"column":52},"end":{"line":694,"column":null}}},"28":{"name":"getPrepareJobTimeoutSeconds","decl":{"start":{"line":696,"column":16},"end":{"line":696,"column":43}},"loc":{"start":{"line":696,"column":43},"end":{"line":713,"column":1}}},"29":{"name":"readPod","decl":{"start":{"line":715,"column":15},"end":{"line":715,"column":22}},"loc":{"start":{"line":715,"column":38},"end":{"line":718,"column":null}}},"30":{"name":"parsePodPhase","decl":{"start":{"line":728,"column":16},"end":{"line":728,"column":29}},"loc":{"start":{"line":728,"column":44},"end":{"line":733,"column":1}}},"31":{"name":"isJobSucceeded","decl":{"start":{"line":735,"column":15},"end":{"line":735,"column":29}},"loc":{"start":{"line":735,"column":45},"end":{"line":742,"column":null}}},"32":{"name":"getPodLogs","decl":{"start":{"line":744,"column":22},"end":{"line":744,"column":32}},"loc":{"start":{"line":746,"column":23},"end":{"line":765,"column":null}}},"33":{"name":"(anonymous_87)","decl":{"start":{"line":750,"column":23},"end":{"line":750,"column":28}},"loc":{"start":{"line":750,"column":28},"end":{"line":753,"column":3}}},"34":{"name":"(anonymous_88)","decl":{"start":{"line":755,"column":24},"end":{"line":755,"column":27}},"loc":{"start":{"line":755,"column":27},"end":{"line":757,"column":3}}},"35":{"name":"(anonymous_89)","decl":{"start":{"line":764,"column":20},"end":{"line":764,"column":27}},"loc":{"start":{"line":764,"column":27},"end":{"line":764,"column":32}}},"36":{"name":"(anonymous_90)","decl":{"start":{"line":764,"column":45},"end":{"line":764,"column":51}},"loc":{"start":{"line":764,"column":45},"end":{"line":764,"column":58}}},"37":{"name":"prunePods","decl":{"start":{"line":767,"column":22},"end":{"line":767,"column":31}},"loc":{"start":{"line":767,"column":31},"end":{"line":785,"column":null}}},"38":{"name":"(anonymous_94)","decl":{"start":{"line":782,"column":6},"end":{"line":782,"column":9}},"loc":{"start":{"line":782,"column":9},"end":{"line":782,"column":null}}},"39":{"name":"getPodStatus","decl":{"start":{"line":787,"column":22},"end":{"line":787,"column":34}},"loc":{"start":{"line":788,"column":14},"end":{"line":792,"column":null}}},"40":{"name":"isAuthPermissionsOK","decl":{"start":{"line":794,"column":22},"end":{"line":794,"column":41}},"loc":{"start":{"line":794,"column":41},"end":{"line":814,"column":null}}},"41":{"name":"(anonymous_101)","decl":{"start":{"line":813,"column":25},"end":{"line":813,"column":29}},"loc":{"start":{"line":813,"column":29},"end":{"line":813,"column":59}}},"42":{"name":"isPodContainerAlpine","decl":{"start":{"line":816,"column":22},"end":{"line":816,"column":42}},"loc":{"start":{"line":818,"column":23},"end":{"line":836,"column":null}}},"43":{"name":"getCurrentNodeName","decl":{"start":{"line":838,"column":15},"end":{"line":838,"column":33}},"loc":{"start":{"line":838,"column":33},"end":{"line":846,"column":null}}},"44":{"name":"getPodAffinity","decl":{"start":{"line":848,"column":15},"end":{"line":848,"column":29}},"loc":{"start":{"line":848,"column":46},"end":{"line":866,"column":null}}},"45":{"name":"getPreferredPodAffinity","decl":{"start":{"line":868,"column":15},"end":{"line":868,"column":38}},"loc":{"start":{"line":869,"column":18},"end":{"line":894,"column":null}}},"46":{"name":"namespace","decl":{"start":{"line":896,"column":16},"end":{"line":896,"column":25}},"loc":{"start":{"line":896,"column":25},"end":{"line":908,"column":1}}},"47":{"name":"(anonymous_115)","decl":{"start":{"line":901,"column":40},"end":{"line":901,"column":43}},"loc":{"start":{"line":901,"column":43},"end":{"line":901,"column":50}}},"48":{"name":"(anonymous_116)","decl":{"start":{"line":910,"column":0},"end":{"line":910,"column":null}},"loc":{"start":{"line":910,"column":0},"end":{"line":934,"column":null}}},"49":{"name":"BackOffManager","decl":{"start":{"line":913,"column":2},"end":{"line":913,"column":22}},"loc":{"start":{"line":913,"column":48},"end":{"line":917,"column":3}}},"50":{"name":"(anonymous_118)","decl":{"start":{"line":919,"column":2},"end":{"line":919,"column":8}},"loc":{"start":{"line":919,"column":2},"end":{"line":933,"column":null}}},"51":{"name":"(anonymous_121)","decl":{"start":{"line":920,"column":22},"end":{"line":920,"column":29}},"loc":{"start":{"line":920,"column":29},"end":{"line":921,"column":16}}},"52":{"name":"containerPorts","decl":{"start":{"line":936,"column":16},"end":{"line":936,"column":30}},"loc":{"start":{"line":937,"column":26},"end":{"line":976,"column":1}}},"53":{"name":"(anonymous_123)","decl":{"start":{"line":958,"column":22},"end":{"line":958,"column":23}},"loc":{"start":{"line":958,"column":32},"end":{"line":964,"column":5}}},"54":{"name":"getPodByName","decl":{"start":{"line":978,"column":22},"end":{"line":978,"column":34}},"loc":{"start":{"line":978,"column":39},"end":{"line":981,"column":null}}}},"branchMap":{"0":{"loc":{"start":{"line":73,"column":2},"end":{"line":75,"column":null}},"type":"if","locations":[{"start":{"line":73,"column":2},"end":{"line":75,"column":null}}]},"1":{"loc":{"start":{"line":76,"column":2},"end":{"line":78,"column":null}},"type":"if","locations":[{"start":{"line":76,"column":2},"end":{"line":78,"column":null}}]},"2":{"loc":{"start":{"line":76,"column":6},"end":{"line":76,"column":22}},"type":"cond-expr","locations":[{"start":{"line":76,"column":14},"end":{"line":76,"column":16}},{"start":{"line":76,"column":6},"end":{"line":76,"column":22}}]},"3":{"loc":{"start":{"line":76,"column":6},"end":{"line":76,"column":16}},"type":"binary-expr","locations":[{"start":{"line":76,"column":6},"end":{"line":76,"column":16}},{"start":{"line":76,"column":6},"end":{"line":76,"column":16}}]},"4":{"loc":{"start":{"line":99,"column":6},"end":{"line":99,"column":22}},"type":"if","locations":[{"start":{"line":99,"column":6},"end":{"line":99,"column":22}}]},"5":{"loc":{"start":{"line":112,"column":6},"end":{"line":112,"column":14}},"type":"if","locations":[{"start":{"line":112,"column":6},"end":{"line":112,"column":14}}]},"6":{"loc":{"start":{"line":114,"column":4},"end":{"line":116,"column":null}},"type":"if","locations":[{"start":{"line":114,"column":4},"end":{"line":116,"column":null}}]},"7":{"loc":{"start":{"line":114,"column":9},"end":{"line":114,"column":31}},"type":"cond-expr","locations":[{"start":{"line":114,"column":25},"end":{"line":114,"column":27}},{"start":{"line":114,"column":25},"end":{"line":114,"column":31}}]},"8":{"loc":{"start":{"line":114,"column":9},"end":{"line":114,"column":27}},"type":"binary-expr","locations":[{"start":{"line":114,"column":9},"end":{"line":114,"column":27}},{"start":{"line":114,"column":25},"end":{"line":114,"column":27}}]},"9":{"loc":{"start":{"line":114,"column":9},"end":{"line":114,"column":25}},"type":"cond-expr","locations":[{"start":{"line":114,"column":15},"end":{"line":114,"column":17}},{"start":{"line":114,"column":9},"end":{"line":114,"column":25}}]},"10":{"loc":{"start":{"line":114,"column":9},"end":{"line":114,"column":17}},"type":"binary-expr","locations":[{"start":{"line":114,"column":9},"end":{"line":114,"column":17}},{"start":{"line":114,"column":9},"end":{"line":114,"column":17}}]},"11":{"loc":{"start":{"line":122,"column":2},"end":{"line":124,"column":null}},"type":"if","locations":[{"start":{"line":122,"column":2},"end":{"line":124,"column":null}}]},"12":{"loc":{"start":{"line":122,"column":6},"end":{"line":122,"column":25}},"type":"cond-expr","locations":[{"start":{"line":122,"column":15},"end":{"line":122,"column":17}},{"start":{"line":122,"column":6},"end":{"line":122,"column":25}}]},"13":{"loc":{"start":{"line":122,"column":6},"end":{"line":122,"column":17}},"type":"binary-expr","locations":[{"start":{"line":122,"column":6},"end":{"line":122,"column":17}},{"start":{"line":122,"column":6},"end":{"line":122,"column":17}}]},"14":{"loc":{"start":{"line":126,"column":2},"end":{"line":128,"column":null}},"type":"if","locations":[{"start":{"line":126,"column":2},"end":{"line":128,"column":null}}]},"15":{"loc":{"start":{"line":126,"column":6},"end":{"line":126,"column":21}},"type":"cond-expr","locations":[{"start":{"line":126,"column":15},"end":{"line":126,"column":17}},{"start":{"line":126,"column":6},"end":{"line":126,"column":21}}]},"16":{"loc":{"start":{"line":126,"column":6},"end":{"line":126,"column":17}},"type":"binary-expr","locations":[{"start":{"line":126,"column":6},"end":{"line":126,"column":17}},{"start":{"line":126,"column":6},"end":{"line":126,"column":17}}]},"17":{"loc":{"start":{"line":161,"column":6},"end":{"line":161,"column":22}},"type":"if","locations":[{"start":{"line":161,"column":6},"end":{"line":161,"column":22}}]},"18":{"loc":{"start":{"line":175,"column":2},"end":{"line":184,"column":null}},"type":"if","locations":[{"start":{"line":175,"column":2},"end":{"line":184,"column":null}}]},"19":{"loc":{"start":{"line":176,"column":4},"end":{"line":180,"column":null}},"type":"if","locations":[{"start":{"line":176,"column":4},"end":{"line":180,"column":null}}]},"20":{"loc":{"start":{"line":181,"column":4},"end":{"line":183,"column":null}},"type":"if","locations":[{"start":{"line":181,"column":4},"end":{"line":183,"column":null}}]},"21":{"loc":{"start":{"line":193,"column":9},"end":{"line":193,"column":null}},"type":"if","locations":[{"start":{"line":193,"column":9},"end":{"line":193,"column":null}}]},"22":{"loc":{"start":{"line":204,"column":8},"end":{"line":204,"column":9}},"type":"if","locations":[{"start":{"line":204,"column":8},"end":{"line":204,"column":9}}]},"23":{"loc":{"start":{"line":204,"column":9},"end":{"line":204,"column":35}},"type":"cond-expr","locations":[{"start":{"line":204,"column":27},"end":{"line":204,"column":29}},{"start":{"line":204,"column":27},"end":{"line":204,"column":35}}]},"24":{"loc":{"start":{"line":204,"column":9},"end":{"line":204,"column":29}},"type":"binary-expr","locations":[{"start":{"line":204,"column":9},"end":{"line":204,"column":29}},{"start":{"line":204,"column":27},"end":{"line":204,"column":29}}]},"25":{"loc":{"start":{"line":209,"column":4},"end":{"line":213,"column":null}},"type":"if","locations":[{"start":{"line":209,"column":4},"end":{"line":213,"column":null}}]},"26":{"loc":{"start":{"line":209,"column":9},"end":{"line":209,"column":45}},"type":"cond-expr","locations":[{"start":{"line":209,"column":39},"end":{"line":209,"column":41}},{"start":{"line":209,"column":39},"end":{"line":209,"column":45}}]},"27":{"loc":{"start":{"line":209,"column":9},"end":{"line":209,"column":41}},"type":"binary-expr","locations":[{"start":{"line":209,"column":9},"end":{"line":209,"column":41}},{"start":{"line":209,"column":39},"end":{"line":209,"column":41}}]},"28":{"loc":{"start":{"line":219,"column":2},"end":{"line":225,"column":null}},"type":"switch","locations":[{"start":{"line":219,"column":2},"end":{"line":225,"column":null}}]},"29":{"loc":{"start":{"line":246,"column":8},"end":{"line":246,"column":21}},"type":"cond-expr","locations":[{"start":{"line":246,"column":8},"end":{"line":246,"column":13}},{"start":{"line":246,"column":17},"end":{"line":246,"column":21}}]},"30":{"loc":{"start":{"line":246,"column":8},"end":{"line":246,"column":17}},"type":"binary-expr","locations":[{"start":{"line":246,"column":8},"end":{"line":246,"column":17}},{"start":{"line":246,"column":8},"end":{"line":246,"column":17}}]},"31":{"loc":{"start":{"line":250,"column":10},"end":{"line":260,"column":null}},"type":"if","locations":[{"start":{"line":250,"column":10},"end":{"line":260,"column":null}},{"start":{"line":252,"column":17},"end":{"line":260,"column":null}}]},"32":{"loc":{"start":{"line":255,"column":25},"end":{"line":255,"column":38}},"type":"cond-expr","locations":[{"start":{"line":255,"column":29},"end":{"line":255,"column":31}},{"start":{"line":255,"column":25},"end":{"line":255,"column":38}}]},"33":{"loc":{"start":{"line":255,"column":25},"end":{"line":255,"column":31}},"type":"binary-expr","locations":[{"start":{"line":255,"column":25},"end":{"line":255,"column":31}},{"start":{"line":255,"column":25},"end":{"line":255,"column":31}}]},"34":{"loc":{"start":{"line":256,"column":25},"end":{"line":256,"column":38}},"type":"cond-expr","locations":[{"start":{"line":256,"column":29},"end":{"line":256,"column":31}},{"start":{"line":256,"column":25},"end":{"line":256,"column":38}}]},"35":{"loc":{"start":{"line":256,"column":25},"end":{"line":256,"column":31}},"type":"binary-expr","locations":[{"start":{"line":256,"column":25},"end":{"line":256,"column":31}},{"start":{"line":256,"column":25},"end":{"line":256,"column":31}}]},"36":{"loc":{"start":{"line":259,"column":19},"end":{"line":259,"column":32}},"type":"cond-expr","locations":[{"start":{"line":259,"column":23},"end":{"line":259,"column":25}},{"start":{"line":259,"column":19},"end":{"line":259,"column":32}}]},"37":{"loc":{"start":{"line":259,"column":19},"end":{"line":259,"column":25}},"type":"binary-expr","locations":[{"start":{"line":259,"column":19},"end":{"line":259,"column":25}},{"start":{"line":259,"column":19},"end":{"line":259,"column":25}}]},"38":{"loc":{"start":{"line":279,"column":4},"end":{"line":279,"column":null}},"type":"switch","locations":[{"start":{"line":279,"column":4},"end":{"line":279,"column":null}}]},"39":{"loc":{"start":{"line":271,"column":9},"end":{"line":271,"column":null}},"type":"if","locations":[{"start":{"line":271,"column":9},"end":{"line":271,"column":null}}]},"40":{"loc":{"start":{"line":273,"column":6},"end":{"line":275,"column":null}},"type":"if","locations":[{"start":{"line":273,"column":6},"end":{"line":275,"column":null}}]},"41":{"loc":{"start":{"line":288,"column":7},"end":{"line":288,"column":58}},"type":"binary-expr","locations":[{"start":{"line":288,"column":7},"end":{"line":288,"column":25}},{"start":{"line":288,"column":29},"end":{"line":288,"column":58}}]},"42":{"loc":{"start":{"line":348,"column":2},"end":{"line":348,"column":null}},"type":"switch","locations":[{"start":{"line":348,"column":2},"end":{"line":348,"column":null}}]},"43":{"loc":{"start":{"line":352,"column":21},"end":{"line":359,"column":null}},"type":"switch","locations":[{"start":{"line":352,"column":21},"end":{"line":359,"column":null}}]},"44":{"loc":{"start":{"line":360,"column":2},"end":{"line":362,"column":null}},"type":"if","locations":[{"start":{"line":360,"column":2},"end":{"line":362,"column":null}}]},"45":{"loc":{"start":{"line":366,"column":16},"end":{"line":366,"column":75}},"type":"binary-expr","locations":[{"start":{"line":366,"column":16},"end":{"line":366,"column":37}},{"start":{"line":366,"column":41},"end":{"line":366,"column":75}}]},"46":{"loc":{"start":{"line":366,"column":16},"end":{"line":366,"column":37}},"type":"cond-expr","locations":[{"start":{"line":366,"column":31},"end":{"line":366,"column":33}},{"start":{"line":366,"column":31},"end":{"line":366,"column":37}}]},"47":{"loc":{"start":{"line":366,"column":16},"end":{"line":366,"column":33}},"type":"binary-expr","locations":[{"start":{"line":366,"column":16},"end":{"line":366,"column":33}},{"start":{"line":366,"column":31},"end":{"line":366,"column":33}}]},"48":{"loc":{"start":{"line":395,"column":2},"end":{"line":397,"column":null}},"type":"if","locations":[{"start":{"line":395,"column":2},"end":{"line":397,"column":null}}]},"49":{"loc":{"start":{"line":401,"column":4},"end":{"line":403,"column":null}},"type":"if","locations":[{"start":{"line":401,"column":4},"end":{"line":403,"column":null}}]},"50":{"loc":{"start":{"line":410,"column":2},"end":{"line":412,"column":null}},"type":"if","locations":[{"start":{"line":410,"column":2},"end":{"line":412,"column":null}}]},"51":{"loc":{"start":{"line":416,"column":4},"end":{"line":418,"column":null}},"type":"if","locations":[{"start":{"line":416,"column":4},"end":{"line":418,"column":null}}]},"52":{"loc":{"start":{"line":426,"column":2},"end":{"line":428,"column":null}},"type":"if","locations":[{"start":{"line":426,"column":2},"end":{"line":428,"column":null}}]},"53":{"loc":{"start":{"line":432,"column":4},"end":{"line":434,"column":null}},"type":"if","locations":[{"start":{"line":432,"column":4},"end":{"line":434,"column":null}}]},"54":{"loc":{"start":{"line":443,"column":8},"end":{"line":443,"column":47}},"type":"cond-expr","locations":[{"start":{"line":443,"column":41},"end":{"line":443,"column":45}},{"start":{"line":443,"column":45},"end":{"line":443,"column":47}}]},"55":{"loc":{"start":{"line":443,"column":8},"end":{"line":443,"column":45}},"type":"binary-expr","locations":[{"start":{"line":443,"column":8},"end":{"line":443,"column":45}},{"start":{"line":443,"column":41},"end":{"line":443,"column":45}}]},"56":{"loc":{"start":{"line":443,"column":8},"end":{"line":443,"column":41}},"type":"cond-expr","locations":[{"start":{"line":443,"column":18},"end":{"line":443,"column":20}},{"start":{"line":443,"column":18},"end":{"line":443,"column":41}}]},"57":{"loc":{"start":{"line":443,"column":8},"end":{"line":443,"column":20}},"type":"binary-expr","locations":[{"start":{"line":443,"column":8},"end":{"line":443,"column":20}},{"start":{"line":443,"column":18},"end":{"line":443,"column":20}}]},"58":{"loc":{"start":{"line":444,"column":8},"end":{"line":444,"column":43}},"type":"cond-expr","locations":[{"start":{"line":444,"column":37},"end":{"line":444,"column":41}},{"start":{"line":444,"column":41},"end":{"line":444,"column":43}}]},"59":{"loc":{"start":{"line":444,"column":8},"end":{"line":444,"column":41}},"type":"binary-expr","locations":[{"start":{"line":444,"column":8},"end":{"line":444,"column":41}},{"start":{"line":444,"column":37},"end":{"line":444,"column":41}}]},"60":{"loc":{"start":{"line":444,"column":8},"end":{"line":444,"column":37}},"type":"cond-expr","locations":[{"start":{"line":444,"column":18},"end":{"line":444,"column":20}},{"start":{"line":444,"column":18},"end":{"line":444,"column":37}}]},"61":{"loc":{"start":{"line":444,"column":8},"end":{"line":444,"column":20}},"type":"binary-expr","locations":[{"start":{"line":444,"column":8},"end":{"line":444,"column":20}},{"start":{"line":444,"column":18},"end":{"line":444,"column":20}}]},"62":{"loc":{"start":{"line":447,"column":20},"end":{"line":447,"column":37}},"type":"cond-expr","locations":[{"start":{"line":447,"column":28},"end":{"line":447,"column":30}},{"start":{"line":447,"column":28},"end":{"line":447,"column":37}}]},"63":{"loc":{"start":{"line":447,"column":20},"end":{"line":447,"column":30}},"type":"binary-expr","locations":[{"start":{"line":447,"column":20},"end":{"line":447,"column":30}},{"start":{"line":447,"column":28},"end":{"line":447,"column":30}}]},"64":{"loc":{"start":{"line":448,"column":4},"end":{"line":454,"column":null}},"type":"if","locations":[{"start":{"line":448,"column":4},"end":{"line":454,"column":null}}]},"65":{"loc":{"start":{"line":448,"column":8},"end":{"line":448,"column":67}},"type":"binary-expr","locations":[{"start":{"line":448,"column":8},"end":{"line":448,"column":23}},{"start":{"line":448,"column":27},"end":{"line":448,"column":67}}]},"66":{"loc":{"start":{"line":448,"column":8},"end":{"line":448,"column":23}},"type":"cond-expr","locations":[{"start":{"line":448,"column":15},"end":{"line":448,"column":17}},{"start":{"line":448,"column":8},"end":{"line":448,"column":23}}]},"67":{"loc":{"start":{"line":448,"column":8},"end":{"line":448,"column":17}},"type":"binary-expr","locations":[{"start":{"line":448,"column":8},"end":{"line":448,"column":17}},{"start":{"line":448,"column":8},"end":{"line":448,"column":17}}]},"68":{"loc":{"start":{"line":451,"column":10},"end":{"line":451,"column":56}},"type":"cond-expr","locations":[{"start":{"line":451,"column":28},"end":{"line":451,"column":51}},{"start":{"line":451,"column":54},"end":{"line":451,"column":56}}]},"69":{"loc":{"start":{"line":474,"column":8},"end":{"line":474,"column":56}},"type":"cond-expr","locations":[{"start":{"line":474,"column":31},"end":{"line":474,"column":42}},{"start":{"line":474,"column":45},"end":{"line":474,"column":56}}]},"70":{"loc":{"start":{"line":482,"column":4},"end":{"line":488,"column":null}},"type":"if","locations":[{"start":{"line":482,"column":4},"end":{"line":488,"column":null}}]},"71":{"loc":{"start":{"line":483,"column":6},"end":{"line":485,"column":40}},"type":"binary-expr","locations":[{"start":{"line":483,"column":6},"end":{"line":483,"column":26}},{"start":{"line":484,"column":6},"end":{"line":484,"column":14}},{"start":{"line":485,"column":6},"end":{"line":485,"column":40}}]},"72":{"loc":{"start":{"line":487,"column":50},"end":{"line":487,"column":65}},"type":"cond-expr","locations":[{"start":{"line":487,"column":59},"end":{"line":487,"column":63}},{"start":{"line":487,"column":63},"end":{"line":487,"column":65}}]},"73":{"loc":{"start":{"line":487,"column":50},"end":{"line":487,"column":63}},"type":"binary-expr","locations":[{"start":{"line":487,"column":50},"end":{"line":487,"column":63}},{"start":{"line":487,"column":59},"end":{"line":487,"column":63}}]},"74":{"loc":{"start":{"line":495,"column":21},"end":{"line":495,"column":49}},"type":"cond-expr","locations":[{"start":{"line":495,"column":43},"end":{"line":495,"column":47}},{"start":{"line":495,"column":47},"end":{"line":495,"column":49}}]},"75":{"loc":{"start":{"line":495,"column":21},"end":{"line":495,"column":47}},"type":"binary-expr","locations":[{"start":{"line":495,"column":21},"end":{"line":495,"column":47}},{"start":{"line":495,"column":43},"end":{"line":495,"column":47}}]},"76":{"loc":{"start":{"line":495,"column":21},"end":{"line":495,"column":43}},"type":"cond-expr","locations":[{"start":{"line":495,"column":31},"end":{"line":495,"column":33}},{"start":{"line":495,"column":31},"end":{"line":495,"column":43}}]},"77":{"loc":{"start":{"line":495,"column":21},"end":{"line":495,"column":33}},"type":"binary-expr","locations":[{"start":{"line":495,"column":21},"end":{"line":495,"column":33}},{"start":{"line":495,"column":31},"end":{"line":495,"column":33}}]},"78":{"loc":{"start":{"line":496,"column":4},"end":{"line":502,"column":null}},"type":"if","locations":[{"start":{"line":496,"column":4},"end":{"line":502,"column":null}}]},"79":{"loc":{"start":{"line":496,"column":8},"end":{"line":496,"column":98}},"type":"binary-expr","locations":[{"start":{"line":496,"column":8},"end":{"line":496,"column":36}},{"start":{"line":496,"column":40},"end":{"line":496,"column":63}},{"start":{"line":496,"column":67},"end":{"line":496,"column":98}}]},"80":{"loc":{"start":{"line":498,"column":49},"end":{"line":498,"column":66}},"type":"cond-expr","locations":[{"start":{"line":498,"column":60},"end":{"line":498,"column":64}},{"start":{"line":498,"column":64},"end":{"line":498,"column":66}}]},"81":{"loc":{"start":{"line":498,"column":49},"end":{"line":498,"column":64}},"type":"binary-expr","locations":[{"start":{"line":498,"column":49},"end":{"line":498,"column":64}},{"start":{"line":498,"column":60},"end":{"line":498,"column":64}}]},"82":{"loc":{"start":{"line":499,"column":10},"end":{"line":499,"column":28}},"type":"cond-expr","locations":[{"start":{"line":499,"column":22},"end":{"line":499,"column":26}},{"start":{"line":499,"column":26},"end":{"line":499,"column":28}}]},"83":{"loc":{"start":{"line":499,"column":10},"end":{"line":499,"column":26}},"type":"binary-expr","locations":[{"start":{"line":499,"column":10},"end":{"line":499,"column":26}},{"start":{"line":499,"column":22},"end":{"line":499,"column":26}}]},"84":{"loc":{"start":{"line":511,"column":8},"end":{"line":511,"column":47}},"type":"cond-expr","locations":[{"start":{"line":511,"column":41},"end":{"line":511,"column":45}},{"start":{"line":511,"column":45},"end":{"line":511,"column":47}}]},"85":{"loc":{"start":{"line":511,"column":8},"end":{"line":511,"column":45}},"type":"binary-expr","locations":[{"start":{"line":511,"column":8},"end":{"line":511,"column":45}},{"start":{"line":511,"column":41},"end":{"line":511,"column":45}}]},"86":{"loc":{"start":{"line":511,"column":8},"end":{"line":511,"column":41}},"type":"cond-expr","locations":[{"start":{"line":511,"column":18},"end":{"line":511,"column":20}},{"start":{"line":511,"column":18},"end":{"line":511,"column":41}}]},"87":{"loc":{"start":{"line":511,"column":8},"end":{"line":511,"column":20}},"type":"binary-expr","locations":[{"start":{"line":511,"column":8},"end":{"line":511,"column":20}},{"start":{"line":511,"column":18},"end":{"line":511,"column":20}}]},"88":{"loc":{"start":{"line":512,"column":8},"end":{"line":512,"column":43}},"type":"cond-expr","locations":[{"start":{"line":512,"column":37},"end":{"line":512,"column":41}},{"start":{"line":512,"column":41},"end":{"line":512,"column":43}}]},"89":{"loc":{"start":{"line":512,"column":8},"end":{"line":512,"column":41}},"type":"binary-expr","locations":[{"start":{"line":512,"column":8},"end":{"line":512,"column":41}},{"start":{"line":512,"column":37},"end":{"line":512,"column":41}}]},"90":{"loc":{"start":{"line":512,"column":8},"end":{"line":512,"column":37}},"type":"cond-expr","locations":[{"start":{"line":512,"column":18},"end":{"line":512,"column":20}},{"start":{"line":512,"column":18},"end":{"line":512,"column":37}}]},"91":{"loc":{"start":{"line":512,"column":8},"end":{"line":512,"column":20}},"type":"binary-expr","locations":[{"start":{"line":512,"column":8},"end":{"line":512,"column":20}},{"start":{"line":512,"column":18},"end":{"line":512,"column":20}}]},"92":{"loc":{"start":{"line":515,"column":23},"end":{"line":515,"column":43}},"type":"cond-expr","locations":[{"start":{"line":515,"column":31},"end":{"line":515,"column":33}},{"start":{"line":515,"column":31},"end":{"line":515,"column":43}}]},"93":{"loc":{"start":{"line":515,"column":23},"end":{"line":515,"column":33}},"type":"binary-expr","locations":[{"start":{"line":515,"column":23},"end":{"line":515,"column":33}},{"start":{"line":515,"column":31},"end":{"line":515,"column":33}}]},"94":{"loc":{"start":{"line":516,"column":4},"end":{"line":522,"column":null}},"type":"if","locations":[{"start":{"line":516,"column":4},"end":{"line":522,"column":null}}]},"95":{"loc":{"start":{"line":516,"column":8},"end":{"line":516,"column":73}},"type":"binary-expr","locations":[{"start":{"line":516,"column":8},"end":{"line":516,"column":26}},{"start":{"line":516,"column":30},"end":{"line":516,"column":73}}]},"96":{"loc":{"start":{"line":516,"column":8},"end":{"line":516,"column":26}},"type":"cond-expr","locations":[{"start":{"line":516,"column":18},"end":{"line":516,"column":20}},{"start":{"line":516,"column":8},"end":{"line":516,"column":26}}]},"97":{"loc":{"start":{"line":516,"column":8},"end":{"line":516,"column":20}},"type":"binary-expr","locations":[{"start":{"line":516,"column":8},"end":{"line":516,"column":20}},{"start":{"line":516,"column":8},"end":{"line":516,"column":20}}]},"98":{"loc":{"start":{"line":519,"column":10},"end":{"line":519,"column":34}},"type":"cond-expr","locations":[{"start":{"line":519,"column":28},"end":{"line":519,"column":32}},{"start":{"line":519,"column":32},"end":{"line":519,"column":34}}]},"99":{"loc":{"start":{"line":519,"column":10},"end":{"line":519,"column":32}},"type":"binary-expr","locations":[{"start":{"line":519,"column":10},"end":{"line":519,"column":32}},{"start":{"line":519,"column":28},"end":{"line":519,"column":32}}]},"100":{"loc":{"start":{"line":533,"column":6},"end":{"line":533,"column":54}},"type":"cond-expr","locations":[{"start":{"line":533,"column":29},"end":{"line":533,"column":40}},{"start":{"line":533,"column":43},"end":{"line":533,"column":54}}]},"101":{"loc":{"start":{"line":540,"column":2},"end":{"line":546,"column":null}},"type":"if","locations":[{"start":{"line":540,"column":2},"end":{"line":546,"column":null}}]},"102":{"loc":{"start":{"line":540,"column":6},"end":{"line":540,"column":19}},"type":"cond-expr","locations":[{"start":{"line":540,"column":12},"end":{"line":540,"column":14}},{"start":{"line":540,"column":6},"end":{"line":540,"column":19}}]},"103":{"loc":{"start":{"line":540,"column":6},"end":{"line":540,"column":14}},"type":"binary-expr","locations":[{"start":{"line":540,"column":6},"end":{"line":540,"column":14}},{"start":{"line":540,"column":6},"end":{"line":540,"column":14}}]},"104":{"loc":{"start":{"line":543,"column":8},"end":{"line":543,"column":58}},"type":"cond-expr","locations":[{"start":{"line":543,"column":24},"end":{"line":543,"column":53}},{"start":{"line":543,"column":56},"end":{"line":543,"column":58}}]},"105":{"loc":{"start":{"line":547,"column":2},"end":{"line":549,"column":null}},"type":"if","locations":[{"start":{"line":547,"column":2},"end":{"line":549,"column":null}}]},"106":{"loc":{"start":{"line":547,"column":6},"end":{"line":547,"column":21}},"type":"cond-expr","locations":[{"start":{"line":547,"column":12},"end":{"line":547,"column":14}},{"start":{"line":547,"column":6},"end":{"line":547,"column":21}}]},"107":{"loc":{"start":{"line":547,"column":6},"end":{"line":547,"column":14}},"type":"binary-expr","locations":[{"start":{"line":547,"column":6},"end":{"line":547,"column":14}},{"start":{"line":547,"column":6},"end":{"line":547,"column":14}}]},"108":{"loc":{"start":{"line":554,"column":21},"end":{"line":554,"column":45}},"type":"cond-expr","locations":[{"start":{"line":554,"column":39},"end":{"line":554,"column":43}},{"start":{"line":554,"column":43},"end":{"line":554,"column":45}}]},"109":{"loc":{"start":{"line":554,"column":21},"end":{"line":554,"column":43}},"type":"binary-expr","locations":[{"start":{"line":554,"column":21},"end":{"line":554,"column":43}},{"start":{"line":554,"column":39},"end":{"line":554,"column":43}}]},"110":{"loc":{"start":{"line":554,"column":21},"end":{"line":554,"column":39}},"type":"cond-expr","locations":[{"start":{"line":554,"column":27},"end":{"line":554,"column":29}},{"start":{"line":554,"column":21},"end":{"line":554,"column":39}}]},"111":{"loc":{"start":{"line":554,"column":21},"end":{"line":554,"column":29}},"type":"binary-expr","locations":[{"start":{"line":554,"column":21},"end":{"line":554,"column":29}},{"start":{"line":554,"column":21},"end":{"line":554,"column":29}}]},"112":{"loc":{"start":{"line":555,"column":4},"end":{"line":561,"column":null}},"type":"if","locations":[{"start":{"line":555,"column":4},"end":{"line":561,"column":null}}]},"113":{"loc":{"start":{"line":558,"column":10},"end":{"line":558,"column":48}},"type":"cond-expr","locations":[{"start":{"line":558,"column":24},"end":{"line":558,"column":43}},{"start":{"line":558,"column":46},"end":{"line":558,"column":48}}]},"114":{"loc":{"start":{"line":559,"column":11},"end":{"line":559,"column":50}},"type":"cond-expr","locations":[{"start":{"line":559,"column":26},"end":{"line":559,"column":45}},{"start":{"line":559,"column":48},"end":{"line":559,"column":50}}]},"115":{"loc":{"start":{"line":565,"column":8},"end":{"line":565,"column":43}},"type":"cond-expr","locations":[{"start":{"line":565,"column":37},"end":{"line":565,"column":41}},{"start":{"line":565,"column":41},"end":{"line":565,"column":43}}]},"116":{"loc":{"start":{"line":565,"column":8},"end":{"line":565,"column":41}},"type":"binary-expr","locations":[{"start":{"line":565,"column":8},"end":{"line":565,"column":41}},{"start":{"line":565,"column":37},"end":{"line":565,"column":41}}]},"117":{"loc":{"start":{"line":565,"column":8},"end":{"line":565,"column":37}},"type":"cond-expr","locations":[{"start":{"line":565,"column":14},"end":{"line":565,"column":16}},{"start":{"line":565,"column":8},"end":{"line":565,"column":37}}]},"118":{"loc":{"start":{"line":565,"column":8},"end":{"line":565,"column":16}},"type":"binary-expr","locations":[{"start":{"line":565,"column":8},"end":{"line":565,"column":16}},{"start":{"line":565,"column":8},"end":{"line":565,"column":16}}]},"119":{"loc":{"start":{"line":566,"column":8},"end":{"line":566,"column":39}},"type":"cond-expr","locations":[{"start":{"line":566,"column":33},"end":{"line":566,"column":37}},{"start":{"line":566,"column":37},"end":{"line":566,"column":39}}]},"120":{"loc":{"start":{"line":566,"column":8},"end":{"line":566,"column":37}},"type":"binary-expr","locations":[{"start":{"line":566,"column":8},"end":{"line":566,"column":37}},{"start":{"line":566,"column":33},"end":{"line":566,"column":37}}]},"121":{"loc":{"start":{"line":566,"column":8},"end":{"line":566,"column":33}},"type":"cond-expr","locations":[{"start":{"line":566,"column":14},"end":{"line":566,"column":16}},{"start":{"line":566,"column":8},"end":{"line":566,"column":33}}]},"122":{"loc":{"start":{"line":566,"column":8},"end":{"line":566,"column":16}},"type":"binary-expr","locations":[{"start":{"line":566,"column":8},"end":{"line":566,"column":16}},{"start":{"line":566,"column":8},"end":{"line":566,"column":16}}]},"123":{"loc":{"start":{"line":569,"column":20},"end":{"line":569,"column":37}},"type":"cond-expr","locations":[{"start":{"line":569,"column":28},"end":{"line":569,"column":30}},{"start":{"line":569,"column":28},"end":{"line":569,"column":37}}]},"124":{"loc":{"start":{"line":569,"column":20},"end":{"line":569,"column":30}},"type":"binary-expr","locations":[{"start":{"line":569,"column":20},"end":{"line":569,"column":30}},{"start":{"line":569,"column":28},"end":{"line":569,"column":30}}]},"125":{"loc":{"start":{"line":570,"column":4},"end":{"line":576,"column":null}},"type":"if","locations":[{"start":{"line":570,"column":4},"end":{"line":576,"column":null}}]},"126":{"loc":{"start":{"line":570,"column":8},"end":{"line":570,"column":23}},"type":"cond-expr","locations":[{"start":{"line":570,"column":15},"end":{"line":570,"column":17}},{"start":{"line":570,"column":8},"end":{"line":570,"column":23}}]},"127":{"loc":{"start":{"line":570,"column":8},"end":{"line":570,"column":17}},"type":"binary-expr","locations":[{"start":{"line":570,"column":8},"end":{"line":570,"column":17}},{"start":{"line":570,"column":8},"end":{"line":570,"column":17}}]},"128":{"loc":{"start":{"line":573,"column":10},"end":{"line":573,"column":59}},"type":"cond-expr","locations":[{"start":{"line":573,"column":28},"end":{"line":573,"column":54}},{"start":{"line":573,"column":57},"end":{"line":573,"column":59}}]},"129":{"loc":{"start":{"line":577,"column":23},"end":{"line":577,"column":43}},"type":"cond-expr","locations":[{"start":{"line":577,"column":31},"end":{"line":577,"column":33}},{"start":{"line":577,"column":31},"end":{"line":577,"column":43}}]},"130":{"loc":{"start":{"line":577,"column":23},"end":{"line":577,"column":33}},"type":"binary-expr","locations":[{"start":{"line":577,"column":23},"end":{"line":577,"column":33}},{"start":{"line":577,"column":31},"end":{"line":577,"column":33}}]},"131":{"loc":{"start":{"line":578,"column":4},"end":{"line":586,"column":null}},"type":"if","locations":[{"start":{"line":578,"column":4},"end":{"line":586,"column":null}}]},"132":{"loc":{"start":{"line":581,"column":10},"end":{"line":581,"column":40}},"type":"cond-expr","locations":[{"start":{"line":581,"column":27},"end":{"line":581,"column":31}},{"start":{"line":581,"column":31},"end":{"line":581,"column":40}}]},"133":{"loc":{"start":{"line":581,"column":10},"end":{"line":581,"column":31}},"type":"binary-expr","locations":[{"start":{"line":581,"column":10},"end":{"line":581,"column":31}},{"start":{"line":581,"column":27},"end":{"line":581,"column":31}}]},"134":{"loc":{"start":{"line":583,"column":10},"end":{"line":583,"column":65}},"type":"cond-expr","locations":[{"start":{"line":583,"column":31},"end":{"line":583,"column":60}},{"start":{"line":583,"column":63},"end":{"line":583,"column":65}}]},"135":{"loc":{"start":{"line":591,"column":2},"end":{"line":593,"column":null}},"type":"if","locations":[{"start":{"line":591,"column":2},"end":{"line":593,"column":null}}]},"136":{"loc":{"start":{"line":611,"column":8},"end":{"line":611,"column":56}},"type":"cond-expr","locations":[{"start":{"line":611,"column":31},"end":{"line":611,"column":42}},{"start":{"line":611,"column":45},"end":{"line":611,"column":56}}]},"137":{"loc":{"start":{"line":618,"column":2},"end":{"line":620,"column":null}},"type":"if","locations":[{"start":{"line":618,"column":2},"end":{"line":620,"column":null}}]},"138":{"loc":{"start":{"line":623,"column":14},"end":{"line":623,"column":64}},"type":"cond-expr","locations":[{"start":{"line":623,"column":44},"end":{"line":623,"column":48}},{"start":{"line":623,"column":48},"end":{"line":623,"column":64}}]},"139":{"loc":{"start":{"line":623,"column":14},"end":{"line":623,"column":48}},"type":"binary-expr","locations":[{"start":{"line":623,"column":14},"end":{"line":623,"column":48}},{"start":{"line":623,"column":44},"end":{"line":623,"column":48}}]},"140":{"loc":{"start":{"line":623,"column":14},"end":{"line":623,"column":44}},"type":"cond-expr","locations":[{"start":{"line":623,"column":29},"end":{"line":623,"column":33}},{"start":{"line":623,"column":33},"end":{"line":623,"column":44}}]},"141":{"loc":{"start":{"line":623,"column":14},"end":{"line":623,"column":33}},"type":"binary-expr","locations":[{"start":{"line":623,"column":14},"end":{"line":623,"column":33}},{"start":{"line":623,"column":29},"end":{"line":623,"column":33}}]},"142":{"loc":{"start":{"line":624,"column":11},"end":{"line":624,"column":40}},"type":"cond-expr","locations":[{"start":{"line":624,"column":15},"end":{"line":624,"column":36}},{"start":{"line":624,"column":39},"end":{"line":624,"column":40}}]},"143":{"loc":{"start":{"line":630,"column":18},"end":{"line":630,"column":64}},"type":"cond-expr","locations":[{"start":{"line":630,"column":43},"end":{"line":630,"column":59}},{"start":{"line":630,"column":62},"end":{"line":630,"column":64}}]},"144":{"loc":{"start":{"line":630,"column":18},"end":{"line":630,"column":40}},"type":"binary-expr","locations":[{"start":{"line":630,"column":18},"end":{"line":630,"column":25}},{"start":{"line":630,"column":29},"end":{"line":630,"column":40}}]},"145":{"loc":{"start":{"line":631,"column":30},"end":{"line":631,"column":44}},"type":"cond-expr","locations":[{"start":{"line":631,"column":38},"end":{"line":631,"column":42}},{"start":{"line":631,"column":42},"end":{"line":631,"column":44}}]},"146":{"loc":{"start":{"line":631,"column":30},"end":{"line":631,"column":42}},"type":"binary-expr","locations":[{"start":{"line":631,"column":30},"end":{"line":631,"column":42}},{"start":{"line":631,"column":38},"end":{"line":631,"column":42}}]},"147":{"loc":{"start":{"line":632,"column":6},"end":{"line":632,"column":21}},"type":"cond-expr","locations":[{"start":{"line":632,"column":15},"end":{"line":632,"column":19}},{"start":{"line":632,"column":19},"end":{"line":632,"column":21}}]},"148":{"loc":{"start":{"line":632,"column":6},"end":{"line":632,"column":19}},"type":"binary-expr","locations":[{"start":{"line":632,"column":6},"end":{"line":632,"column":19}},{"start":{"line":632,"column":15},"end":{"line":632,"column":19}}]},"149":{"loc":{"start":{"line":635,"column":2},"end":{"line":639,"column":null}},"type":"if","locations":[{"start":{"line":635,"column":2},"end":{"line":639,"column":null}}]},"150":{"loc":{"start":{"line":647,"column":2},"end":{"line":647,"column":null}},"type":"if","locations":[{"start":{"line":647,"column":2},"end":{"line":647,"column":null}}]},"151":{"loc":{"start":{"line":651,"column":9},"end":{"line":651,"column":null}},"type":"if","locations":[{"start":{"line":651,"column":9},"end":{"line":651,"column":null}}]},"152":{"loc":{"start":{"line":654,"column":4},"end":{"line":656,"column":null}},"type":"if","locations":[{"start":{"line":654,"column":4},"end":{"line":656,"column":null}}]},"153":{"loc":{"start":{"line":658,"column":8},"end":{"line":658,"column":9}},"type":"if","locations":[{"start":{"line":658,"column":8},"end":{"line":658,"column":9}}]},"154":{"loc":{"start":{"line":666,"column":8},"end":{"line":666,"column":23}},"type":"if","locations":[{"start":{"line":666,"column":8},"end":{"line":666,"column":23}}]},"155":{"loc":{"start":{"line":676,"column":8},"end":{"line":676,"column":23}},"type":"if","locations":[{"start":{"line":676,"column":8},"end":{"line":676,"column":23}}]},"156":{"loc":{"start":{"line":700,"column":2},"end":{"line":702,"column":null}},"type":"if","locations":[{"start":{"line":700,"column":2},"end":{"line":702,"column":null}}]},"157":{"loc":{"start":{"line":705,"column":2},"end":{"line":710,"column":null}},"type":"if","locations":[{"start":{"line":705,"column":2},"end":{"line":710,"column":null}}]},"158":{"loc":{"start":{"line":705,"column":6},"end":{"line":705,"column":44}},"type":"binary-expr","locations":[{"start":{"line":705,"column":6},"end":{"line":705,"column":21}},{"start":{"line":705,"column":25},"end":{"line":705,"column":44}}]},"159":{"loc":{"start":{"line":716,"column":19},"end":{"line":716,"column":null}},"type":"switch","locations":[{"start":{"line":716,"column":19},"end":{"line":716,"column":null}}]},"160":{"loc":{"start":{"line":729,"column":2},"end":{"line":731,"column":null}},"type":"if","locations":[{"start":{"line":729,"column":2},"end":{"line":731,"column":null}}]},"161":{"loc":{"start":{"line":729,"column":6},"end":{"line":729,"column":65}},"type":"binary-expr","locations":[{"start":{"line":729,"column":6},"end":{"line":729,"column":28}},{"start":{"line":729,"column":28},"end":{"line":729,"column":65}}]},"162":{"loc":{"start":{"line":729,"column":7},"end":{"line":729,"column":24}},"type":"cond-expr","locations":[{"start":{"line":729,"column":17},"end":{"line":729,"column":19}},{"start":{"line":729,"column":17},"end":{"line":729,"column":24}}]},"163":{"loc":{"start":{"line":729,"column":7},"end":{"line":729,"column":19}},"type":"binary-expr","locations":[{"start":{"line":729,"column":7},"end":{"line":729,"column":19}},{"start":{"line":729,"column":17},"end":{"line":729,"column":19}}]},"164":{"loc":{"start":{"line":736,"column":19},"end":{"line":736,"column":null}},"type":"switch","locations":[{"start":{"line":736,"column":19},"end":{"line":736,"column":null}}]},"165":{"loc":{"start":{"line":738,"column":2},"end":{"line":740,"column":null}},"type":"if","locations":[{"start":{"line":738,"column":2},"end":{"line":740,"column":null}}]},"166":{"loc":{"start":{"line":738,"column":6},"end":{"line":738,"column":24}},"type":"cond-expr","locations":[{"start":{"line":738,"column":16},"end":{"line":738,"column":18}},{"start":{"line":738,"column":16},"end":{"line":738,"column":24}}]},"167":{"loc":{"start":{"line":738,"column":6},"end":{"line":738,"column":18}},"type":"binary-expr","locations":[{"start":{"line":738,"column":6},"end":{"line":738,"column":18}},{"start":{"line":738,"column":16},"end":{"line":738,"column":18}}]},"168":{"loc":{"start":{"line":741,"column":11},"end":{"line":741,"column":32}},"type":"cond-expr","locations":[{"start":{"line":741,"column":21},"end":{"line":741,"column":23}},{"start":{"line":741,"column":21},"end":{"line":741,"column":32}}]},"169":{"loc":{"start":{"line":741,"column":11},"end":{"line":741,"column":23}},"type":"binary-expr","locations":[{"start":{"line":741,"column":11},"end":{"line":741,"column":23}},{"start":{"line":741,"column":21},"end":{"line":741,"column":23}}]},"170":{"loc":{"start":{"line":768,"column":18},"end":{"line":775,"column":null}},"type":"switch","locations":[{"start":{"line":768,"column":18},"end":{"line":775,"column":null}}]},"171":{"loc":{"start":{"line":776,"column":2},"end":{"line":778,"column":null}},"type":"if","locations":[{"start":{"line":776,"column":2},"end":{"line":778,"column":null}}]},"172":{"loc":{"start":{"line":782,"column":13},"end":{"line":782,"column":63}},"type":"binary-expr","locations":[{"start":{"line":782,"column":13},"end":{"line":782,"column":31}},{"start":{"line":782,"column":35},"end":{"line":782,"column":63}}]},"173":{"loc":{"start":{"line":782,"column":13},"end":{"line":782,"column":31}},"type":"cond-expr","locations":[{"start":{"line":782,"column":25},"end":{"line":782,"column":27}},{"start":{"line":782,"column":25},"end":{"line":782,"column":31}}]},"174":{"loc":{"start":{"line":782,"column":13},"end":{"line":782,"column":27}},"type":"binary-expr","locations":[{"start":{"line":782,"column":13},"end":{"line":782,"column":27}},{"start":{"line":782,"column":25},"end":{"line":782,"column":27}}]},"175":{"loc":{"start":{"line":790,"column":19},"end":{"line":790,"column":null}},"type":"switch","locations":[{"start":{"line":790,"column":19},"end":{"line":790,"column":null}}]},"176":{"loc":{"start":{"line":813,"column":33},"end":{"line":813,"column":58}},"type":"cond-expr","locations":[{"start":{"line":813,"column":49},"end":{"line":813,"column":51}},{"start":{"line":813,"column":49},"end":{"line":813,"column":58}}]},"177":{"loc":{"start":{"line":813,"column":33},"end":{"line":813,"column":51}},"type":"binary-expr","locations":[{"start":{"line":813,"column":33},"end":{"line":813,"column":51}},{"start":{"line":813,"column":49},"end":{"line":813,"column":51}}]},"178":{"loc":{"start":{"line":835,"column":2},"end":{"line":835,"column":null}},"type":"switch","locations":[{"start":{"line":835,"column":2},"end":{"line":835,"column":null}}]},"179":{"loc":{"start":{"line":839,"column":15},"end":{"line":839,"column":null}},"type":"switch","locations":[{"start":{"line":839,"column":15},"end":{"line":839,"column":null}}]},"180":{"loc":{"start":{"line":841,"column":19},"end":{"line":841,"column":43}},"type":"cond-expr","locations":[{"start":{"line":841,"column":33},"end":{"line":841,"column":35}},{"start":{"line":841,"column":33},"end":{"line":841,"column":43}}]},"181":{"loc":{"start":{"line":841,"column":19},"end":{"line":841,"column":35}},"type":"binary-expr","locations":[{"start":{"line":841,"column":19},"end":{"line":841,"column":35}},{"start":{"line":841,"column":33},"end":{"line":841,"column":35}}]},"182":{"loc":{"start":{"line":842,"column":2},"end":{"line":844,"column":null}},"type":"if","locations":[{"start":{"line":842,"column":2},"end":{"line":844,"column":null}}]},"183":{"loc":{"start":{"line":897,"column":2},"end":{"line":899,"column":null}},"type":"if","locations":[{"start":{"line":897,"column":2},"end":{"line":899,"column":null}}]},"184":{"loc":{"start":{"line":902,"column":2},"end":{"line":906,"column":null}},"type":"if","locations":[{"start":{"line":902,"column":2},"end":{"line":906,"column":null}}]},"185":{"loc":{"start":{"line":902,"column":7},"end":{"line":902,"column":25}},"type":"cond-expr","locations":[{"start":{"line":902,"column":14},"end":{"line":902,"column":16}},{"start":{"line":902,"column":7},"end":{"line":902,"column":25}}]},"186":{"loc":{"start":{"line":902,"column":7},"end":{"line":902,"column":16}},"type":"binary-expr","locations":[{"start":{"line":902,"column":7},"end":{"line":902,"column":16}},{"start":{"line":902,"column":7},"end":{"line":902,"column":16}}]},"187":{"loc":{"start":{"line":914,"column":4},"end":{"line":916,"column":null}},"type":"if","locations":[{"start":{"line":914,"column":4},"end":{"line":916,"column":null}}]},"188":{"loc":{"start":{"line":914,"column":8},"end":{"line":914,"column":51}},"type":"binary-expr","locations":[{"start":{"line":914,"column":8},"end":{"line":914,"column":26}},{"start":{"line":914,"column":30},"end":{"line":914,"column":51}}]},"189":{"loc":{"start":{"line":920,"column":4},"end":{"line":922,"column":null}},"type":"switch","locations":[{"start":{"line":920,"column":4},"end":{"line":922,"column":null}}]},"190":{"loc":{"start":{"line":924,"column":4},"end":{"line":926,"column":null}},"type":"if","locations":[{"start":{"line":924,"column":4},"end":{"line":926,"column":null}}]},"191":{"loc":{"start":{"line":924,"column":8},"end":{"line":924,"column":73}},"type":"binary-expr","locations":[{"start":{"line":924,"column":8},"end":{"line":924,"column":30}},{"start":{"line":924,"column":34},"end":{"line":924,"column":73}}]},"192":{"loc":{"start":{"line":927,"column":4},"end":{"line":929,"column":null}},"type":"if","locations":[{"start":{"line":927,"column":4},"end":{"line":929,"column":null}}]},"193":{"loc":{"start":{"line":930,"column":4},"end":{"line":932,"column":null}},"type":"if","locations":[{"start":{"line":930,"column":4},"end":{"line":932,"column":null}}]},"194":{"loc":{"start":{"line":940,"column":2},"end":{"line":942,"column":null}},"type":"if","locations":[{"start":{"line":940,"column":2},"end":{"line":942,"column":null}}]},"195":{"loc":{"start":{"line":940,"column":7},"end":{"line":940,"column":37}},"type":"cond-expr","locations":[{"start":{"line":940,"column":29},"end":{"line":940,"column":31}},{"start":{"line":940,"column":29},"end":{"line":940,"column":37}}]},"196":{"loc":{"start":{"line":940,"column":7},"end":{"line":940,"column":31}},"type":"binary-expr","locations":[{"start":{"line":940,"column":7},"end":{"line":940,"column":31}},{"start":{"line":940,"column":29},"end":{"line":940,"column":31}}]},"197":{"loc":{"start":{"line":945,"column":4},"end":{"line":947,"column":null}},"type":"if","locations":[{"start":{"line":945,"column":4},"end":{"line":947,"column":null}}]},"198":{"loc":{"start":{"line":951,"column":6},"end":{"line":951,"column":75}},"type":"cond-expr","locations":[{"start":{"line":951,"column":36},"end":{"line":951,"column":67}},{"start":{"line":951,"column":70},"end":{"line":951,"column":75}}]},"199":{"loc":{"start":{"line":954,"column":4},"end":{"line":956,"column":null}},"type":"if","locations":[{"start":{"line":954,"column":4},"end":{"line":956,"column":null}}]},"200":{"loc":{"start":{"line":960,"column":6},"end":{"line":962,"column":null}},"type":"if","locations":[{"start":{"line":960,"column":6},"end":{"line":962,"column":null}}]},"201":{"loc":{"start":{"line":960,"column":10},"end":{"line":960,"column":58}},"type":"binary-expr","locations":[{"start":{"line":960,"column":10},"end":{"line":960,"column":32}},{"start":{"line":960,"column":36},"end":{"line":960,"column":43}},{"start":{"line":960,"column":47},"end":{"line":960,"column":58}}]},"202":{"loc":{"start":{"line":966,"column":4},"end":{"line":971,"column":null}},"type":"if","locations":[{"start":{"line":966,"column":4},"end":{"line":971,"column":null}},{"start":{"line":968,"column":11},"end":{"line":971,"column":null}}]},"203":{"loc":{"start":{"line":979,"column":19},"end":{"line":979,"column":null}},"type":"switch","locations":[{"start":{"line":979,"column":19},"end":{"line":979,"column":null}}]}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":1,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":0,"78":0,"79":0,"80":0,"81":0,"82":0,"83":0,"84":0,"85":0,"86":0,"87":0,"88":0,"89":0,"90":0,"91":0,"92":0,"93":0,"94":1,"95":0,"96":0,"97":0,"98":0,"99":0,"100":0,"101":0,"102":0,"103":0,"104":0,"105":0,"106":0,"107":1,"108":0,"109":1,"110":0,"111":0,"112":0,"113":0,"114":0,"115":0,"116":0,"117":0,"118":0,"119":1,"120":0,"121":0,"122":0,"123":0,"124":0,"125":0,"126":0,"127":0,"128":1,"129":0,"130":0,"131":0,"132":0,"133":0,"134":0,"135":0,"136":0,"137":0,"138":0,"139":0,"140":0,"141":0,"142":0,"143":0,"144":0,"145":1,"146":0,"147":0,"148":0,"149":0,"150":0,"151":0,"152":0,"153":0,"154":0,"155":0,"156":0,"157":0,"158":0,"159":0,"160":0,"161":1,"162":0,"163":1,"164":0,"165":0,"166":0,"167":0,"168":0,"169":0,"170":1,"171":1,"172":1,"173":1,"174":1,"175":0,"176":0,"177":0,"178":0,"179":0,"180":0,"181":0,"182":0,"183":0,"184":0,"185":0,"186":0,"187":1,"188":0,"189":0,"190":0,"191":0,"192":0,"193":0,"194":0,"195":0,"196":0,"197":0,"198":0,"199":0,"200":1,"201":0,"202":0,"203":0,"204":0,"205":0,"206":0,"207":0,"208":0,"209":0,"210":0,"211":0,"212":0,"213":1,"214":0,"215":0,"216":0,"217":0,"218":0,"219":0,"220":0,"221":0,"222":0,"223":0,"224":1,"225":0,"226":0,"227":0,"228":0,"229":0,"230":0,"231":0,"232":0,"233":0,"234":0,"235":0,"236":0,"237":1,"238":0,"239":0,"240":0,"241":0,"242":0,"243":0,"244":0,"245":0,"246":1,"247":0,"248":0,"249":0,"250":0,"251":0,"252":0,"253":0,"254":0,"255":0,"256":0,"257":1,"258":0,"259":0,"260":0,"261":0,"262":0,"263":0,"264":0,"265":0,"266":0,"267":0,"268":0,"269":0,"270":0,"271":0,"272":0,"273":0,"274":0,"275":0,"276":0,"277":0,"278":0,"279":0,"280":0,"281":0,"282":0,"283":0,"284":0,"285":0,"286":0,"287":0,"288":0,"289":1,"290":0,"291":0,"292":0,"293":0,"294":0,"295":0,"296":0,"297":0,"298":0,"299":0,"300":0,"301":0,"302":0,"303":0,"304":0,"305":0,"306":0,"307":0,"308":0,"309":0,"310":0,"311":0,"312":0,"313":0,"314":0,"315":0,"316":0,"317":0,"318":0,"319":0,"320":0,"321":0,"322":0,"323":0,"324":0,"325":0,"326":0,"327":0,"328":0,"329":0,"330":0,"331":0,"332":0,"333":0,"334":0,"335":0,"336":0,"337":0,"338":0,"339":1,"340":3,"341":3,"342":3,"343":0,"344":0,"345":0,"346":0,"347":0,"348":1,"349":0,"350":0,"351":0,"352":1,"353":0,"354":0,"355":0,"356":1,"357":0,"358":0,"359":0,"360":0,"361":0,"362":0,"363":0,"364":0,"365":0,"366":0,"367":0,"368":0,"369":0,"370":0,"371":0,"372":0,"373":0,"374":1,"375":0,"376":0,"377":0,"378":0,"379":0,"380":0,"381":1,"382":0,"383":0,"384":0,"385":1,"386":0,"387":0,"388":0,"389":0,"390":0,"391":0,"392":0,"393":0,"394":0,"395":0,"396":0,"397":0,"398":0,"399":0,"400":0,"401":0,"402":0,"403":0,"404":1,"405":0,"406":0,"407":0,"408":0,"409":1,"410":0,"411":0,"412":0,"413":0,"414":0,"415":0,"416":0,"417":0,"418":0,"419":0,"420":0,"421":0,"422":0,"423":0,"424":0,"425":0,"426":0,"427":0,"428":0,"429":0,"430":0,"431":0,"432":0,"433":0,"434":0,"435":0,"436":1,"437":1,"438":0,"439":0,"440":0,"441":0,"442":0,"443":1,"444":0,"445":0,"446":0,"447":0,"448":0,"449":0,"450":0,"451":0,"452":0,"453":1,"454":3,"455":3,"456":3,"457":0,"458":0,"459":0,"460":0,"461":0,"462":0,"463":0,"464":0,"465":0,"466":0,"467":0,"468":0,"469":0,"470":0,"471":0,"472":0,"473":0,"474":0,"475":0,"476":0,"477":0,"478":0,"479":0,"480":1,"481":0,"482":0,"483":0,"484":1},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":3,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":1,"49":0,"50":0,"51":0,"52":3,"53":0,"54":0},"b":{"0":[0],"1":[0],"2":[0,0],"3":[0,0],"4":[0],"5":[0],"6":[0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0],"12":[0,0],"13":[0,0],"14":[0],"15":[0,0],"16":[0,0],"17":[0],"18":[0],"19":[0],"20":[0],"21":[0],"22":[0],"23":[0,0],"24":[0,0],"25":[0],"26":[0,0],"27":[0,0],"28":[0],"29":[0,0],"30":[0,0],"31":[0,0],"32":[0,0],"33":[0,0],"34":[0,0],"35":[0,0],"36":[0,0],"37":[0,0],"38":[0],"39":[0],"40":[0],"41":[0,0],"42":[0],"43":[0],"44":[0],"45":[0,0],"46":[0,0],"47":[0,0],"48":[0],"49":[0],"50":[0],"51":[0],"52":[0],"53":[0],"54":[0,0],"55":[0,0],"56":[0,0],"57":[0,0],"58":[0,0],"59":[0,0],"60":[0,0],"61":[0,0],"62":[0,0],"63":[0,0],"64":[0],"65":[0,0],"66":[0,0],"67":[0,0],"68":[0,0],"69":[0,0],"70":[0],"71":[0,0,0],"72":[0,0],"73":[0,0],"74":[0,0],"75":[0,0],"76":[0,0],"77":[0,0],"78":[0],"79":[0,0,0],"80":[0,0],"81":[0,0],"82":[0,0],"83":[0,0],"84":[0,0],"85":[0,0],"86":[0,0],"87":[0,0],"88":[0,0],"89":[0,0],"90":[0,0],"91":[0,0],"92":[0,0],"93":[0,0],"94":[0],"95":[0,0],"96":[0,0],"97":[0,0],"98":[0,0],"99":[0,0],"100":[0,0],"101":[0],"102":[0,0],"103":[0,0],"104":[0,0],"105":[0],"106":[0,0],"107":[0,0],"108":[0,0],"109":[0,0],"110":[0,0],"111":[0,0],"112":[0],"113":[0,0],"114":[0,0],"115":[0,0],"116":[0,0],"117":[0,0],"118":[0,0],"119":[0,0],"120":[0,0],"121":[0,0],"122":[0,0],"123":[0,0],"124":[0,0],"125":[0],"126":[0,0],"127":[0,0],"128":[0,0],"129":[0,0],"130":[0,0],"131":[0],"132":[0,0],"133":[0,0],"134":[0,0],"135":[0],"136":[0,0],"137":[0],"138":[0,0],"139":[0,0],"140":[0,0],"141":[0,0],"142":[0,0],"143":[0,0],"144":[0,0],"145":[0,0],"146":[0,0],"147":[0,0],"148":[0,0],"149":[0],"150":[0],"151":[0],"152":[0],"153":[0],"154":[0],"155":[0],"156":[3],"157":[0],"158":[0,0],"159":[0],"160":[0],"161":[0,0],"162":[0,0],"163":[0,0],"164":[0],"165":[0],"166":[0,0],"167":[0,0],"168":[0,0],"169":[0,0],"170":[0],"171":[0],"172":[0,0],"173":[0,0],"174":[0,0],"175":[0],"176":[0,0],"177":[0,0],"178":[0],"179":[0],"180":[0,0],"181":[0,0],"182":[0],"183":[0],"184":[0],"185":[0,0],"186":[0,0],"187":[0],"188":[0,0],"189":[0],"190":[0],"191":[0,0],"192":[0],"193":[0],"194":[3],"195":[3,0],"196":[3,3],"197":[0],"198":[0,0],"199":[0],"200":[0],"201":[0,0,0],"202":[0,0],"203":[0]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/k8s/utils.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/src/k8s/utils.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":24}},"1":{"start":{"line":3,"column":0},"end":{"line":3,"column":31}},"2":{"start":{"line":4,"column":0},"end":{"line":4,"column":37}},"3":{"start":{"line":6,"column":0},"end":{"line":6,"column":28}},"4":{"start":{"line":7,"column":0},"end":{"line":7,"column":35}},"5":{"start":{"line":8,"column":0},"end":{"line":8,"column":41}},"6":{"start":{"line":9,"column":0},"end":{"line":9,"column":63}},"7":{"start":{"line":10,"column":0},"end":{"line":10,"column":30}},"8":{"start":{"line":12,"column":13},"end":{"line":12,"column":null}},"9":{"start":{"line":13,"column":13},"end":{"line":13,"column":null}},"10":{"start":{"line":15,"column":13},"end":{"line":15,"column":null}},"11":{"start":{"line":16,"column":13},"end":{"line":16,"column":null}},"12":{"start":{"line":19,"column":2},"end":{"line":19,"column":null}},"13":{"start":{"line":20,"column":2},"end":{"line":20,"column":null}},"14":{"start":{"line":21,"column":2},"end":{"line":21,"column":null}},"15":{"start":{"line":23,"column":38},"end":{"line":28,"column":null}},"16":{"start":{"line":30,"column":24},"end":{"line":30,"column":62}},"17":{"start":{"line":31,"column":2},"end":{"line":57,"column":null}},"18":{"start":{"line":32,"column":14},"end":{"line":32,"column":49}},"19":{"start":{"line":33,"column":34},"end":{"line":33,"column":74}},"20":{"start":{"line":34,"column":4},"end":{"line":55,"column":null}},"21":{"start":{"line":56,"column":4},"end":{"line":56,"column":null}},"22":{"start":{"line":59,"column":2},"end":{"line":61,"column":null}},"23":{"start":{"line":60,"column":4},"end":{"line":60,"column":null}},"24":{"start":{"line":63,"column":2},"end":{"line":79,"column":null}},"25":{"start":{"line":81,"column":2},"end":{"line":83,"column":null}},"26":{"start":{"line":82,"column":4},"end":{"line":82,"column":null}},"27":{"start":{"line":85,"column":2},"end":{"line":107,"column":null}},"28":{"start":{"line":85,"column":27},"end":{"line":85,"column":43}},"29":{"start":{"line":85,"column":23},"end":{"line":85,"column":27}},"30":{"start":{"line":86,"column":27},"end":{"line":86,"column":29}},"31":{"start":{"line":87,"column":4},"end":{"line":99,"column":null}},"32":{"start":{"line":88,"column":6},"end":{"line":92,"column":null}},"33":{"start":{"line":89,"column":8},"end":{"line":91,"column":null}},"34":{"start":{"line":94,"column":6},"end":{"line":96,"column":null}},"35":{"start":{"line":98,"column":6},"end":{"line":98,"column":null}},"36":{"start":{"line":101,"column":4},"end":{"line":106,"column":null}},"37":{"start":{"line":109,"column":2},"end":{"line":109,"column":null}},"38":{"start":{"line":18,"column":0},"end":{"line":18,"column":16}},"39":{"start":{"line":119,"column":19},"end":{"line":119,"column":21}},"40":{"start":{"line":120,"column":2},"end":{"line":125,"column":null}},"41":{"start":{"line":123,"column":6},"end":{"line":123,"column":75}},"42":{"start":{"line":124,"column":4},"end":{"line":124,"column":null}},"43":{"start":{"line":126,"column":26},"end":{"line":126,"column":28}},"44":{"start":{"line":128,"column":2},"end":{"line":150,"column":null}},"45":{"start":{"line":129,"column":32},"end":{"line":129,"column":34}},"46":{"start":{"line":130,"column":4},"end":{"line":148,"column":null}},"47":{"start":{"line":130,"column":31},"end":{"line":130,"column":37}},"48":{"start":{"line":130,"column":31},"end":{"line":130,"column":67}},"49":{"start":{"line":130,"column":15},"end":{"line":130,"column":16}},"50":{"start":{"line":130,"column":19},"end":{"line":130,"column":21}},"51":{"start":{"line":130,"column":26},"end":{"line":130,"column":27}},"52":{"start":{"line":131,"column":6},"end":{"line":140,"column":null}},"53":{"start":{"line":137,"column":8},"end":{"line":139,"column":null}},"54":{"start":{"line":141,"column":6},"end":{"line":147,"column":null}},"55":{"start":{"line":149,"column":4},"end":{"line":149,"column":null}},"56":{"start":{"line":152,"column":18},"end":{"line":156,"column":null}},"57":{"start":{"line":159,"column":19},"end":{"line":159,"column":35}},"58":{"start":{"line":160,"column":25},"end":{"line":160,"column":65}},"59":{"start":{"line":161,"column":2},"end":{"line":161,"column":null}},"60":{"start":{"line":162,"column":2},"end":{"line":165,"column":null}},"61":{"start":{"line":112,"column":0},"end":{"line":112,"column":16}},"62":{"start":{"line":169,"column":22},"end":{"line":169,"column":44}},"63":{"start":{"line":170,"column":15},"end":{"line":170,"column":44}},"64":{"start":{"line":172,"column":2},"end":{"line":174,"column":null}},"65":{"start":{"line":173,"column":4},"end":{"line":173,"column":null}},"66":{"start":{"line":176,"column":2},"end":{"line":176,"column":null}},"67":{"start":{"line":168,"column":0},"end":{"line":168,"column":16}},"68":{"start":{"line":191,"column":2},"end":{"line":212,"column":null}},"69":{"start":{"line":191,"column":29},"end":{"line":191,"column":35}},"70":{"start":{"line":191,"column":29},"end":{"line":191,"column":49}},"71":{"start":{"line":191,"column":13},"end":{"line":191,"column":14}},"72":{"start":{"line":191,"column":17},"end":{"line":191,"column":19}},"73":{"start":{"line":191,"column":24},"end":{"line":191,"column":25}},"74":{"start":{"line":192,"column":4},"end":{"line":211,"column":null}},"75":{"start":{"line":193,"column":6},"end":{"line":195,"column":null}},"76":{"start":{"line":194,"column":8},"end":{"line":194,"column":null}},"77":{"start":{"line":196,"column":6},"end":{"line":196,"column":14}},"78":{"start":{"line":197,"column":11},"end":{"line":211,"column":null}},"79":{"start":{"line":198,"column":6},"end":{"line":198,"column":null}},"80":{"start":{"line":199,"column":6},"end":{"line":199,"column":14}},"81":{"start":{"line":200,"column":11},"end":{"line":211,"column":null}},"82":{"start":{"line":201,"column":19},"end":{"line":201,"column":42}},"83":{"start":{"line":202,"column":6},"end":{"line":202,"column":null}},"84":{"start":{"line":203,"column":11},"end":{"line":211,"column":null}},"85":{"start":{"line":204,"column":27},"end":{"line":204,"column":55}},"86":{"start":{"line":205,"column":6},"end":{"line":205,"column":null}},"87":{"start":{"line":206,"column":11},"end":{"line":211,"column":null}},"88":{"start":{"line":207,"column":20},"end":{"line":207,"column":50}},"89":{"start":{"line":208,"column":6},"end":{"line":208,"column":null}},"90":{"start":{"line":210,"column":6},"end":{"line":210,"column":null}},"91":{"start":{"line":187,"column":0},"end":{"line":187,"column":16}},"92":{"start":{"line":219,"column":2},"end":{"line":232,"column":null}},"93":{"start":{"line":219,"column":29},"end":{"line":219,"column":35}},"94":{"start":{"line":219,"column":29},"end":{"line":219,"column":49}},"95":{"start":{"line":219,"column":13},"end":{"line":219,"column":14}},"96":{"start":{"line":219,"column":17},"end":{"line":219,"column":19}},"97":{"start":{"line":219,"column":24},"end":{"line":219,"column":25}},"98":{"start":{"line":220,"column":4},"end":{"line":231,"column":null}},"99":{"start":{"line":221,"column":6},"end":{"line":224,"column":null}},"100":{"start":{"line":223,"column":15},"end":{"line":223,"column":null}},"101":{"start":{"line":226,"column":11},"end":{"line":231,"column":null}},"102":{"start":{"line":227,"column":22},"end":{"line":227,"column":45}},"103":{"start":{"line":228,"column":6},"end":{"line":228,"column":null}},"104":{"start":{"line":230,"column":6},"end":{"line":230,"column":null}},"105":{"start":{"line":215,"column":0},"end":{"line":215,"column":16}},"106":{"start":{"line":239,"column":2},"end":{"line":243,"column":null}},"107":{"start":{"line":240,"column":4},"end":{"line":242,"column":null}},"108":{"start":{"line":244,"column":2},"end":{"line":251,"column":null}},"109":{"start":{"line":245,"column":4},"end":{"line":250,"column":null}},"110":{"start":{"line":245,"column":31},"end":{"line":245,"column":37}},"111":{"start":{"line":245,"column":31},"end":{"line":245,"column":58}},"112":{"start":{"line":245,"column":15},"end":{"line":245,"column":16}},"113":{"start":{"line":245,"column":19},"end":{"line":245,"column":21}},"114":{"start":{"line":245,"column":26},"end":{"line":245,"column":27}},"115":{"start":{"line":246,"column":6},"end":{"line":248,"column":null}},"116":{"start":{"line":247,"column":8},"end":{"line":247,"column":null}},"117":{"start":{"line":249,"column":6},"end":{"line":249,"column":null}},"118":{"start":{"line":253,"column":2},"end":{"line":262,"column":null}},"119":{"start":{"line":254,"column":4},"end":{"line":261,"column":null}},"120":{"start":{"line":254,"column":31},"end":{"line":254,"column":37}},"121":{"start":{"line":254,"column":31},"end":{"line":254,"column":63}},"122":{"start":{"line":254,"column":15},"end":{"line":254,"column":16}},"123":{"start":{"line":254,"column":19},"end":{"line":254,"column":21}},"124":{"start":{"line":254,"column":26},"end":{"line":254,"column":27}},"125":{"start":{"line":255,"column":6},"end":{"line":259,"column":null}},"126":{"start":{"line":256,"column":8},"end":{"line":258,"column":null}},"127":{"start":{"line":260,"column":6},"end":{"line":260,"column":null}},"128":{"start":{"line":235,"column":0},"end":{"line":235,"column":16}},"129":{"start":{"line":266,"column":19},"end":{"line":266,"column":54}},"130":{"start":{"line":267,"column":2},"end":{"line":269,"column":null}},"131":{"start":{"line":268,"column":4},"end":{"line":268,"column":null}},"132":{"start":{"line":270,"column":14},"end":{"line":270,"column":58}},"133":{"start":{"line":271,"column":2},"end":{"line":273,"column":null}},"134":{"start":{"line":272,"column":4},"end":{"line":272,"column":null}},"135":{"start":{"line":274,"column":2},"end":{"line":274,"column":null}},"136":{"start":{"line":265,"column":0},"end":{"line":265,"column":16}},"137":{"start":{"line":278,"column":2},"end":{"line":278,"column":null}},"138":{"start":{"line":277,"column":0},"end":{"line":277,"column":16}},"139":{"start":{"line":281,"column":0},"end":{"line":281,"column":null}},"140":{"start":{"line":282,"column":2},"end":{"line":282,"column":null}},"141":{"start":{"line":283,"column":2},"end":{"line":283,"column":null}},"142":{"start":{"line":284,"column":2},"end":{"line":284,"column":null}},"143":{"start":{"line":285,"column":2},"end":{"line":285,"column":null}},"144":{"start":{"line":286,"column":2},"end":{"line":286,"column":null}},"145":{"start":{"line":287,"column":2},"end":{"line":287,"column":null}},"146":{"start":{"line":291,"column":17},"end":{"line":291,"column":27}},"147":{"start":{"line":292,"column":2},"end":{"line":294,"column":null}},"148":{"start":{"line":293,"column":4},"end":{"line":293,"column":null}},"149":{"start":{"line":295,"column":2},"end":{"line":295,"column":17}},"150":{"start":{"line":296,"column":2},"end":{"line":296,"column":null}},"151":{"start":{"line":300,"column":2},"end":{"line":300,"column":null}},"152":{"start":{"line":299,"column":0},"end":{"line":299,"column":16}}},"fnMap":{"0":{"name":"containerVolumes","decl":{"start":{"line":18,"column":16},"end":{"line":18,"column":32}},"loc":{"start":{"line":21,"column":25},"end":{"line":110,"column":1}}},"1":{"name":"writeEntryPointScript","decl":{"start":{"line":112,"column":16},"end":{"line":112,"column":37}},"loc":{"start":{"line":117,"column":50},"end":{"line":166,"column":1}}},"2":{"name":"generateContainerName","decl":{"start":{"line":168,"column":16},"end":{"line":168,"column":37}},"loc":{"start":{"line":168,"column":51},"end":{"line":177,"column":1}}},"3":{"name":"mergeContainerWithOptions","decl":{"start":{"line":187,"column":16},"end":{"line":187,"column":41}},"loc":{"start":{"line":189,"column":23},"end":{"line":213,"column":1}}},"4":{"name":"mergePodSpecWithOptions","decl":{"start":{"line":215,"column":16},"end":{"line":215,"column":39}},"loc":{"start":{"line":217,"column":21},"end":{"line":233,"column":1}}},"5":{"name":"(anonymous_11)","decl":{"start":{"line":223,"column":10},"end":{"line":223,"column":11}},"loc":{"start":{"line":223,"column":11},"end":{"line":223,"column":null}}},"6":{"name":"mergeObjectMeta","decl":{"start":{"line":235,"column":16},"end":{"line":235,"column":31}},"loc":{"start":{"line":237,"column":24},"end":{"line":263,"column":1}}},"7":{"name":"readExtensionFromFile","decl":{"start":{"line":265,"column":16},"end":{"line":265,"column":37}},"loc":{"start":{"line":265,"column":37},"end":{"line":275,"column":1}}},"8":{"name":"useKubeScheduler","decl":{"start":{"line":277,"column":16},"end":{"line":277,"column":32}},"loc":{"start":{"line":277,"column":32},"end":{"line":279,"column":1}}},"9":{"name":"(anonymous_15)","decl":{"start":{"line":281,"column":0},"end":{"line":281,"column":12}},"loc":{"start":{"line":281,"column":20},"end":{"line":288,"column":1}}},"10":{"name":"mergeLists","decl":{"start":{"line":290,"column":9},"end":{"line":290,"column":19}},"loc":{"start":{"line":290,"column":45},"end":{"line":297,"column":1}}},"11":{"name":"fixArgs","decl":{"start":{"line":299,"column":16},"end":{"line":299,"column":23}},"loc":{"start":{"line":299,"column":38},"end":{"line":301,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":19,"column":2},"end":{"line":19,"column":null}},"type":"if","locations":[{"start":{"line":19,"column":2},"end":{"line":19,"column":null}}]},"1":{"loc":{"start":{"line":20,"column":2},"end":{"line":20,"column":null}},"type":"if","locations":[{"start":{"line":20,"column":2},"end":{"line":20,"column":null}}]},"2":{"loc":{"start":{"line":21,"column":2},"end":{"line":21,"column":null}},"type":"if","locations":[{"start":{"line":21,"column":2},"end":{"line":21,"column":null}}]},"3":{"loc":{"start":{"line":31,"column":2},"end":{"line":57,"column":null}},"type":"if","locations":[{"start":{"line":31,"column":2},"end":{"line":57,"column":null}}]},"4":{"loc":{"start":{"line":59,"column":2},"end":{"line":61,"column":null}},"type":"if","locations":[{"start":{"line":59,"column":2},"end":{"line":61,"column":null}}]},"5":{"loc":{"start":{"line":81,"column":2},"end":{"line":83,"column":null}},"type":"if","locations":[{"start":{"line":81,"column":2},"end":{"line":83,"column":null}}]},"6":{"loc":{"start":{"line":81,"column":7},"end":{"line":81,"column":31}},"type":"cond-expr","locations":[{"start":{"line":81,"column":23},"end":{"line":81,"column":25}},{"start":{"line":81,"column":7},"end":{"line":81,"column":31}}]},"7":{"loc":{"start":{"line":81,"column":7},"end":{"line":81,"column":25}},"type":"binary-expr","locations":[{"start":{"line":81,"column":7},"end":{"line":81,"column":25}},{"start":{"line":81,"column":7},"end":{"line":81,"column":25}}]},"8":{"loc":{"start":{"line":87,"column":4},"end":{"line":99,"column":null}},"type":"if","locations":[{"start":{"line":87,"column":4},"end":{"line":99,"column":null}},{"start":{"line":97,"column":11},"end":{"line":99,"column":null}}]},"9":{"loc":{"start":{"line":88,"column":6},"end":{"line":92,"column":null}},"type":"if","locations":[{"start":{"line":88,"column":6},"end":{"line":92,"column":null}}]},"10":{"loc":{"start":{"line":120,"column":2},"end":{"line":125,"column":null}},"type":"if","locations":[{"start":{"line":120,"column":2},"end":{"line":125,"column":null}}]},"11":{"loc":{"start":{"line":120,"column":6},"end":{"line":120,"column":25}},"type":"cond-expr","locations":[{"start":{"line":120,"column":17},"end":{"line":120,"column":19}},{"start":{"line":120,"column":6},"end":{"line":120,"column":25}}]},"12":{"loc":{"start":{"line":120,"column":6},"end":{"line":120,"column":19}},"type":"binary-expr","locations":[{"start":{"line":120,"column":6},"end":{"line":120,"column":19}},{"start":{"line":120,"column":6},"end":{"line":120,"column":19}}]},"13":{"loc":{"start":{"line":123,"column":6},"end":{"line":123,"column":75}},"type":"cond-expr","locations":[{"start":{"line":123,"column":40},"end":{"line":123,"column":51}},{"start":{"line":123,"column":54},"end":{"line":123,"column":75}}]},"14":{"loc":{"start":{"line":128,"column":2},"end":{"line":150,"column":null}},"type":"if","locations":[{"start":{"line":128,"column":2},"end":{"line":150,"column":null}}]},"15":{"loc":{"start":{"line":128,"column":6},"end":{"line":128,"column":73}},"type":"binary-expr","locations":[{"start":{"line":128,"column":6},"end":{"line":128,"column":26}},{"start":{"line":128,"column":30},"end":{"line":128,"column":73}}]},"16":{"loc":{"start":{"line":131,"column":6},"end":{"line":140,"column":null}},"type":"if","locations":[{"start":{"line":131,"column":6},"end":{"line":140,"column":null}}]},"17":{"loc":{"start":{"line":132,"column":8},"end":{"line":135,"column":25}},"type":"binary-expr","locations":[{"start":{"line":132,"column":8},"end":{"line":132,"column":25}},{"start":{"line":133,"column":8},"end":{"line":133,"column":25}},{"start":{"line":134,"column":8},"end":{"line":134,"column":25}},{"start":{"line":135,"column":8},"end":{"line":135,"column":25}}]},"18":{"loc":{"start":{"line":156,"column":4},"end":{"line":156,"column":58}},"type":"cond-expr","locations":[{"start":{"line":156,"column":29},"end":{"line":156,"column":53}},{"start":{"line":156,"column":56},"end":{"line":156,"column":58}}]},"19":{"loc":{"start":{"line":156,"column":4},"end":{"line":156,"column":26}},"type":"cond-expr","locations":[{"start":{"line":156,"column":18},"end":{"line":156,"column":20}},{"start":{"line":156,"column":4},"end":{"line":156,"column":26}}]},"20":{"loc":{"start":{"line":156,"column":4},"end":{"line":156,"column":20}},"type":"binary-expr","locations":[{"start":{"line":156,"column":4},"end":{"line":156,"column":20}},{"start":{"line":156,"column":4},"end":{"line":156,"column":20}}]},"21":{"loc":{"start":{"line":170,"column":15},"end":{"line":170,"column":44}},"type":"cond-expr","locations":[{"start":{"line":170,"column":26},"end":{"line":170,"column":28}},{"start":{"line":170,"column":15},"end":{"line":170,"column":44}}]},"22":{"loc":{"start":{"line":170,"column":15},"end":{"line":170,"column":28}},"type":"binary-expr","locations":[{"start":{"line":170,"column":15},"end":{"line":170,"column":28}},{"start":{"line":170,"column":15},"end":{"line":170,"column":28}}]},"23":{"loc":{"start":{"line":172,"column":2},"end":{"line":174,"column":null}},"type":"if","locations":[{"start":{"line":172,"column":2},"end":{"line":174,"column":null}}]},"24":{"loc":{"start":{"line":192,"column":4},"end":{"line":211,"column":null}},"type":"if","locations":[{"start":{"line":192,"column":4},"end":{"line":211,"column":null}},{"start":{"line":197,"column":11},"end":{"line":211,"column":null}}]},"25":{"loc":{"start":{"line":193,"column":6},"end":{"line":195,"column":null}},"type":"if","locations":[{"start":{"line":193,"column":6},"end":{"line":195,"column":null}}]},"26":{"loc":{"start":{"line":197,"column":11},"end":{"line":211,"column":null}},"type":"if","locations":[{"start":{"line":197,"column":11},"end":{"line":211,"column":null}},{"start":{"line":200,"column":11},"end":{"line":211,"column":null}}]},"27":{"loc":{"start":{"line":200,"column":11},"end":{"line":211,"column":null}},"type":"if","locations":[{"start":{"line":200,"column":11},"end":{"line":211,"column":null}},{"start":{"line":203,"column":11},"end":{"line":211,"column":null}}]},"28":{"loc":{"start":{"line":203,"column":11},"end":{"line":211,"column":null}},"type":"if","locations":[{"start":{"line":203,"column":11},"end":{"line":211,"column":null}},{"start":{"line":206,"column":11},"end":{"line":211,"column":null}}]},"29":{"loc":{"start":{"line":203,"column":15},"end":{"line":203,"column":46}},"type":"binary-expr","locations":[{"start":{"line":203,"column":15},"end":{"line":203,"column":37}},{"start":{"line":203,"column":41},"end":{"line":203,"column":46}}]},"30":{"loc":{"start":{"line":206,"column":11},"end":{"line":211,"column":null}},"type":"if","locations":[{"start":{"line":206,"column":11},"end":{"line":211,"column":null}},{"start":{"line":209,"column":11},"end":{"line":211,"column":null}}]},"31":{"loc":{"start":{"line":206,"column":15},"end":{"line":206,"column":39}},"type":"binary-expr","locations":[{"start":{"line":206,"column":15},"end":{"line":206,"column":30}},{"start":{"line":206,"column":34},"end":{"line":206,"column":39}}]},"32":{"loc":{"start":{"line":220,"column":4},"end":{"line":231,"column":null}},"type":"if","locations":[{"start":{"line":220,"column":4},"end":{"line":231,"column":null}},{"start":{"line":226,"column":11},"end":{"line":231,"column":null}}]},"33":{"loc":{"start":{"line":223,"column":16},"end":{"line":223,"column":62}},"type":"cond-expr","locations":[{"start":{"line":223,"column":22},"end":{"line":223,"column":24}},{"start":{"line":223,"column":22},"end":{"line":223,"column":62}}]},"34":{"loc":{"start":{"line":223,"column":16},"end":{"line":223,"column":24}},"type":"binary-expr","locations":[{"start":{"line":223,"column":16},"end":{"line":223,"column":24}},{"start":{"line":223,"column":22},"end":{"line":223,"column":24}}]},"35":{"loc":{"start":{"line":226,"column":11},"end":{"line":231,"column":null}},"type":"if","locations":[{"start":{"line":226,"column":11},"end":{"line":231,"column":null}},{"start":{"line":229,"column":11},"end":{"line":231,"column":null}}]},"36":{"loc":{"start":{"line":226,"column":15},"end":{"line":226,"column":41}},"type":"binary-expr","locations":[{"start":{"line":226,"column":15},"end":{"line":226,"column":32}},{"start":{"line":226,"column":36},"end":{"line":226,"column":41}}]},"37":{"loc":{"start":{"line":239,"column":2},"end":{"line":243,"column":null}},"type":"if","locations":[{"start":{"line":239,"column":2},"end":{"line":243,"column":null}}]},"38":{"loc":{"start":{"line":239,"column":6},"end":{"line":239,"column":61}},"type":"binary-expr","locations":[{"start":{"line":239,"column":6},"end":{"line":239,"column":32}},{"start":{"line":239,"column":32},"end":{"line":239,"column":61}}]},"39":{"loc":{"start":{"line":239,"column":7},"end":{"line":239,"column":28}},"type":"cond-expr","locations":[{"start":{"line":239,"column":20},"end":{"line":239,"column":22}},{"start":{"line":239,"column":20},"end":{"line":239,"column":28}}]},"40":{"loc":{"start":{"line":239,"column":7},"end":{"line":239,"column":22}},"type":"binary-expr","locations":[{"start":{"line":239,"column":7},"end":{"line":239,"column":22}},{"start":{"line":239,"column":20},"end":{"line":239,"column":22}}]},"41":{"loc":{"start":{"line":239,"column":33},"end":{"line":239,"column":59}},"type":"cond-expr","locations":[{"start":{"line":239,"column":46},"end":{"line":239,"column":48}},{"start":{"line":239,"column":46},"end":{"line":239,"column":59}}]},"42":{"loc":{"start":{"line":239,"column":33},"end":{"line":239,"column":48}},"type":"binary-expr","locations":[{"start":{"line":239,"column":33},"end":{"line":239,"column":48}},{"start":{"line":239,"column":46},"end":{"line":239,"column":48}}]},"43":{"loc":{"start":{"line":244,"column":2},"end":{"line":251,"column":null}},"type":"if","locations":[{"start":{"line":244,"column":2},"end":{"line":251,"column":null}}]},"44":{"loc":{"start":{"line":244,"column":6},"end":{"line":244,"column":18}},"type":"cond-expr","locations":[{"start":{"line":244,"column":10},"end":{"line":244,"column":12}},{"start":{"line":244,"column":6},"end":{"line":244,"column":18}}]},"45":{"loc":{"start":{"line":244,"column":6},"end":{"line":244,"column":12}},"type":"binary-expr","locations":[{"start":{"line":244,"column":6},"end":{"line":244,"column":12}},{"start":{"line":244,"column":6},"end":{"line":244,"column":12}}]},"46":{"loc":{"start":{"line":246,"column":6},"end":{"line":248,"column":null}},"type":"if","locations":[{"start":{"line":246,"column":6},"end":{"line":248,"column":null}}]},"47":{"loc":{"start":{"line":246,"column":10},"end":{"line":246,"column":38}},"type":"cond-expr","locations":[{"start":{"line":246,"column":31},"end":{"line":246,"column":34}},{"start":{"line":246,"column":31},"end":{"line":246,"column":38}}]},"48":{"loc":{"start":{"line":246,"column":10},"end":{"line":246,"column":34}},"type":"binary-expr","locations":[{"start":{"line":246,"column":10},"end":{"line":246,"column":34}},{"start":{"line":246,"column":31},"end":{"line":246,"column":34}}]},"49":{"loc":{"start":{"line":246,"column":10},"end":{"line":246,"column":31}},"type":"cond-expr","locations":[{"start":{"line":246,"column":23},"end":{"line":246,"column":25}},{"start":{"line":246,"column":23},"end":{"line":246,"column":31}}]},"50":{"loc":{"start":{"line":246,"column":10},"end":{"line":246,"column":25}},"type":"binary-expr","locations":[{"start":{"line":246,"column":10},"end":{"line":246,"column":25}},{"start":{"line":246,"column":23},"end":{"line":246,"column":25}}]},"51":{"loc":{"start":{"line":253,"column":2},"end":{"line":262,"column":null}},"type":"if","locations":[{"start":{"line":253,"column":2},"end":{"line":262,"column":null}}]},"52":{"loc":{"start":{"line":253,"column":6},"end":{"line":253,"column":23}},"type":"cond-expr","locations":[{"start":{"line":253,"column":10},"end":{"line":253,"column":12}},{"start":{"line":253,"column":6},"end":{"line":253,"column":23}}]},"53":{"loc":{"start":{"line":253,"column":6},"end":{"line":253,"column":12}},"type":"binary-expr","locations":[{"start":{"line":253,"column":6},"end":{"line":253,"column":12}},{"start":{"line":253,"column":6},"end":{"line":253,"column":12}}]},"54":{"loc":{"start":{"line":255,"column":6},"end":{"line":259,"column":null}},"type":"if","locations":[{"start":{"line":255,"column":6},"end":{"line":259,"column":null}}]},"55":{"loc":{"start":{"line":255,"column":10},"end":{"line":255,"column":43}},"type":"cond-expr","locations":[{"start":{"line":255,"column":36},"end":{"line":255,"column":39}},{"start":{"line":255,"column":36},"end":{"line":255,"column":43}}]},"56":{"loc":{"start":{"line":255,"column":10},"end":{"line":255,"column":39}},"type":"binary-expr","locations":[{"start":{"line":255,"column":10},"end":{"line":255,"column":39}},{"start":{"line":255,"column":36},"end":{"line":255,"column":39}}]},"57":{"loc":{"start":{"line":255,"column":10},"end":{"line":255,"column":36}},"type":"cond-expr","locations":[{"start":{"line":255,"column":23},"end":{"line":255,"column":25}},{"start":{"line":255,"column":23},"end":{"line":255,"column":36}}]},"58":{"loc":{"start":{"line":255,"column":10},"end":{"line":255,"column":25}},"type":"binary-expr","locations":[{"start":{"line":255,"column":10},"end":{"line":255,"column":25}},{"start":{"line":255,"column":23},"end":{"line":255,"column":25}}]},"59":{"loc":{"start":{"line":267,"column":2},"end":{"line":269,"column":null}},"type":"if","locations":[{"start":{"line":267,"column":2},"end":{"line":269,"column":null}}]},"60":{"loc":{"start":{"line":271,"column":2},"end":{"line":273,"column":null}},"type":"if","locations":[{"start":{"line":271,"column":2},"end":{"line":273,"column":null}}]},"61":{"loc":{"start":{"line":271,"column":6},"end":{"line":271,"column":37}},"type":"binary-expr","locations":[{"start":{"line":271,"column":6},"end":{"line":271,"column":10}},{"start":{"line":271,"column":14},"end":{"line":271,"column":37}}]},"62":{"loc":{"start":{"line":281,"column":12},"end":{"line":281,"column":null}},"type":"binary-expr","locations":[{"start":{"line":281,"column":12},"end":{"line":281,"column":20}},{"start":{"line":281,"column":12},"end":{"line":281,"column":null}}]},"63":{"loc":{"start":{"line":291,"column":17},"end":{"line":291,"column":27}},"type":"binary-expr","locations":[{"start":{"line":291,"column":17},"end":{"line":291,"column":21}},{"start":{"line":291,"column":25},"end":{"line":291,"column":27}}]},"64":{"loc":{"start":{"line":292,"column":2},"end":{"line":294,"column":null}},"type":"if","locations":[{"start":{"line":292,"column":2},"end":{"line":294,"column":null}}]},"65":{"loc":{"start":{"line":292,"column":7},"end":{"line":292,"column":19}},"type":"cond-expr","locations":[{"start":{"line":292,"column":11},"end":{"line":292,"column":13}},{"start":{"line":292,"column":7},"end":{"line":292,"column":19}}]},"66":{"loc":{"start":{"line":292,"column":7},"end":{"line":292,"column":13}},"type":"binary-expr","locations":[{"start":{"line":292,"column":7},"end":{"line":292,"column":13}},{"start":{"line":292,"column":7},"end":{"line":292,"column":13}}]}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":6,"13":3,"14":6,"15":3,"16":3,"17":3,"18":0,"19":0,"20":0,"21":0,"22":3,"23":0,"24":3,"25":3,"26":3,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":1,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":1,"62":0,"63":0,"64":0,"65":0,"66":0,"67":1,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":0,"78":0,"79":0,"80":0,"81":0,"82":0,"83":0,"84":0,"85":0,"86":0,"87":0,"88":0,"89":0,"90":0,"91":1,"92":0,"93":0,"94":0,"95":0,"96":0,"97":0,"98":0,"99":0,"100":0,"101":0,"102":0,"103":0,"104":0,"105":1,"106":0,"107":0,"108":0,"109":0,"110":0,"111":0,"112":0,"113":0,"114":0,"115":0,"116":0,"117":0,"118":0,"119":0,"120":0,"121":0,"122":0,"123":0,"124":0,"125":0,"126":0,"127":0,"128":1,"129":3,"130":3,"131":3,"132":0,"133":0,"134":0,"135":0,"136":1,"137":0,"138":1,"139":1,"140":1,"141":1,"142":1,"143":1,"144":1,"145":1,"146":0,"147":0,"148":0,"149":0,"150":0,"151":3,"152":1},"f":{"0":3,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":3,"8":0,"9":1,"10":0,"11":3},"b":{"0":[3],"1":[0],"2":[3],"3":[0],"4":[0],"5":[3],"6":[0,3],"7":[3,3],"8":[0,0],"9":[0],"10":[0],"11":[0,0],"12":[0,0],"13":[0,0],"14":[0],"15":[0,0],"16":[0],"17":[0,0,0,0],"18":[0,0],"19":[0,0],"20":[0,0],"21":[0,0],"22":[0,0],"23":[0],"24":[0,0],"25":[0],"26":[0,0],"27":[0,0],"28":[0,0],"29":[0,0],"30":[0,0],"31":[0,0],"32":[0,0],"33":[0,0],"34":[0,0],"35":[0,0],"36":[0,0],"37":[0],"38":[0,0],"39":[0,0],"40":[0,0],"41":[0,0],"42":[0,0],"43":[0],"44":[0,0],"45":[0,0],"46":[0],"47":[0,0],"48":[0,0],"49":[0,0],"50":[0,0],"51":[0],"52":[0,0],"53":[0,0],"54":[0],"55":[0,0],"56":[0,0],"57":[0,0],"58":[0,0],"59":[3],"60":[0],"61":[0,0],"62":[1,1],"63":[0,0],"64":[0],"65":[0,0],"66":[0,0]}} +,"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/tests/test-setup.ts": {"path":"/__w/backlog/backlog/work/runner-container-hooks/packages/k8s/tests/test-setup.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":46}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":24}},"2":{"start":{"line":4,"column":0},"end":{"line":4,"column":28}},"3":{"start":{"line":5,"column":0},"end":{"line":5,"column":35}},"4":{"start":{"line":7,"column":11},"end":{"line":7,"column":31}},"5":{"start":{"line":9,"column":0},"end":{"line":9,"column":null}},"6":{"start":{"line":11,"column":15},"end":{"line":11,"column":46}},"7":{"start":{"line":12,"column":22},"end":{"line":12,"column":56}},"8":{"start":{"line":14,"column":0},"end":{"line":14,"column":13}},"9":{"start":{"line":18,"column":4},"end":{"line":18,"column":null}},"10":{"start":{"line":19,"column":4},"end":{"line":19,"column":null}},"11":{"start":{"line":22,"column":15},"end":{"line":45,"column":null}},"12":{"start":{"line":23,"column":4},"end":{"line":23,"column":null}},"13":{"start":{"line":24,"column":4},"end":{"line":24,"column":null}},"14":{"start":{"line":25,"column":4},"end":{"line":25,"column":null}},"15":{"start":{"line":26,"column":4},"end":{"line":26,"column":null}},"16":{"start":{"line":27,"column":4},"end":{"line":27,"column":null}},"17":{"start":{"line":29,"column":4},"end":{"line":29,"column":null}},"18":{"start":{"line":30,"column":4},"end":{"line":30,"column":null}},"19":{"start":{"line":31,"column":4},"end":{"line":31,"column":null}},"20":{"start":{"line":33,"column":4},"end":{"line":36,"column":null}},"21":{"start":{"line":38,"column":4},"end":{"line":38,"column":null}},"22":{"start":{"line":40,"column":6},"end":{"line":40,"column":null}},"23":{"start":{"line":41,"column":6},"end":{"line":41,"column":null}},"24":{"start":{"line":43,"column":6},"end":{"line":43,"column":null}},"25":{"start":{"line":47,"column":15},"end":{"line":52,"column":null}},"26":{"start":{"line":49,"column":6},"end":{"line":49,"column":null}},"27":{"start":{"line":50,"column":6},"end":{"line":50,"column":null}},"28":{"start":{"line":53,"column":15},"end":{"line":77,"column":null}},"29":{"start":{"line":54,"column":4},"end":{"line":62,"column":null}},"30":{"start":{"line":63,"column":4},"end":{"line":63,"column":null}},"31":{"start":{"line":64,"column":4},"end":{"line":64,"column":null}},"32":{"start":{"line":65,"column":4},"end":{"line":67,"column":null}},"33":{"start":{"line":68,"column":4},"end":{"line":76,"column":null}},"34":{"start":{"line":78,"column":9},"end":{"line":82,"column":null}},"35":{"start":{"line":79,"column":21},"end":{"line":79,"column":66}},"36":{"start":{"line":80,"column":4},"end":{"line":80,"column":null}},"37":{"start":{"line":81,"column":4},"end":{"line":81,"column":null}},"38":{"start":{"line":84,"column":9},"end":{"line":87,"column":null}},"39":{"start":{"line":85,"column":21},"end":{"line":85,"column":54}},"40":{"start":{"line":86,"column":4},"end":{"line":86,"column":null}},"41":{"start":{"line":89,"column":15},"end":{"line":106,"column":null}},"42":{"start":{"line":90,"column":10},"end":{"line":94,"column":null}},"43":{"start":{"line":96,"column":10},"end":{"line":104,"column":null}},"44":{"start":{"line":105,"column":4},"end":{"line":105,"column":null}},"45":{"start":{"line":108,"column":15},"end":{"line":152,"column":null}},"46":{"start":{"line":109,"column":8},"end":{"line":115,"column":null}},"47":{"start":{"line":116,"column":4},"end":{"line":116,"column":null}},"48":{"start":{"line":118,"column":8},"end":{"line":133,"column":null}},"49":{"start":{"line":134,"column":4},"end":{"line":134,"column":null}},"50":{"start":{"line":135,"column":8},"end":{"line":150,"column":null}},"51":{"start":{"line":151,"column":4},"end":{"line":151,"column":null}},"52":{"start":{"line":154,"column":9},"end":{"line":169,"column":null}},"53":{"start":{"line":155,"column":23},"end":{"line":159,"column":null}},"54":{"start":{"line":162,"column":4},"end":{"line":162,"column":null}},"55":{"start":{"line":163,"column":4},"end":{"line":163,"column":null}},"56":{"start":{"line":164,"column":4},"end":{"line":166,"column":null}},"57":{"start":{"line":165,"column":6},"end":{"line":165,"column":null}},"58":{"start":{"line":168,"column":4},"end":{"line":168,"column":null}},"59":{"start":{"line":171,"column":9},"end":{"line":181,"column":null}},"60":{"start":{"line":172,"column":26},"end":{"line":176,"column":null}},"61":{"start":{"line":179,"column":4},"end":{"line":179,"column":null}},"62":{"start":{"line":180,"column":4},"end":{"line":180,"column":null}},"63":{"start":{"line":183,"column":9},"end":{"line":195,"column":null}},"64":{"start":{"line":184,"column":29},"end":{"line":188,"column":null}},"65":{"start":{"line":191,"column":4},"end":{"line":191,"column":null}},"66":{"start":{"line":192,"column":4},"end":{"line":192,"column":null}},"67":{"start":{"line":193,"column":4},"end":{"line":193,"column":null}},"68":{"start":{"line":194,"column":4},"end":{"line":194,"column":null}},"69":{"start":{"line":196,"column":0},"end":{"line":196,"column":null}},"70":{"start":{"line":14,"column":13},"end":{"line":14,"column":23}}},"fnMap":{"0":{"name":"(anonymous_19)","decl":{"start":{"line":14,"column":0},"end":{"line":14,"column":13}},"loc":{"start":{"line":14,"column":0},"end":{"line":196,"column":null}}},"1":{"name":"TestHelper","decl":{"start":{"line":17,"column":2},"end":{"line":17,"column":null}},"loc":{"start":{"line":17,"column":2},"end":{"line":20,"column":3}}},"2":{"name":"(anonymous_21)","decl":{"start":{"line":22,"column":2},"end":{"line":22,"column":15}},"loc":{"start":{"line":22,"column":2},"end":{"line":45,"column":null}}},"3":{"name":"(anonymous_24)","decl":{"start":{"line":47,"column":2},"end":{"line":47,"column":15}},"loc":{"start":{"line":47,"column":2},"end":{"line":52,"column":null}}},"4":{"name":"(anonymous_27)","decl":{"start":{"line":53,"column":2},"end":{"line":53,"column":15}},"loc":{"start":{"line":53,"column":2},"end":{"line":77,"column":null}}},"5":{"name":"(anonymous_30)","decl":{"start":{"line":62,"column":13},"end":{"line":62,"column":14}},"loc":{"start":{"line":62,"column":14},"end":{"line":62,"column":20}}},"6":{"name":"(anonymous_31)","decl":{"start":{"line":63,"column":68},"end":{"line":63,"column":69}},"loc":{"start":{"line":63,"column":69},"end":{"line":63,"column":75}}},"7":{"name":"(anonymous_32)","decl":{"start":{"line":64,"column":66},"end":{"line":64,"column":67}},"loc":{"start":{"line":64,"column":67},"end":{"line":64,"column":73}}},"8":{"name":"(anonymous_33)","decl":{"start":{"line":67,"column":13},"end":{"line":67,"column":14}},"loc":{"start":{"line":67,"column":14},"end":{"line":67,"column":20}}},"9":{"name":"(anonymous_34)","decl":{"start":{"line":76,"column":13},"end":{"line":76,"column":14}},"loc":{"start":{"line":76,"column":14},"end":{"line":76,"column":20}}},"10":{"name":"(anonymous_35)","decl":{"start":{"line":78,"column":2},"end":{"line":78,"column":9}},"loc":{"start":{"line":78,"column":37},"end":{"line":82,"column":3}}},"11":{"name":"(anonymous_36)","decl":{"start":{"line":84,"column":2},"end":{"line":84,"column":9}},"loc":{"start":{"line":84,"column":36},"end":{"line":87,"column":3}}},"12":{"name":"(anonymous_37)","decl":{"start":{"line":89,"column":2},"end":{"line":89,"column":15}},"loc":{"start":{"line":89,"column":2},"end":{"line":106,"column":null}}},"13":{"name":"(anonymous_40)","decl":{"start":{"line":108,"column":2},"end":{"line":108,"column":15}},"loc":{"start":{"line":108,"column":2},"end":{"line":152,"column":null}}},"14":{"name":"(anonymous_43)","decl":{"start":{"line":154,"column":2},"end":{"line":154,"column":9}},"loc":{"start":{"line":154,"column":2},"end":{"line":169,"column":3}}},"15":{"name":"(anonymous_44)","decl":{"start":{"line":164,"column":37},"end":{"line":164,"column":38}},"loc":{"start":{"line":164,"column":38},"end":{"line":166,"column":5}}},"16":{"name":"(anonymous_45)","decl":{"start":{"line":171,"column":2},"end":{"line":171,"column":9}},"loc":{"start":{"line":171,"column":2},"end":{"line":181,"column":3}}},"17":{"name":"(anonymous_46)","decl":{"start":{"line":183,"column":2},"end":{"line":183,"column":9}},"loc":{"start":{"line":183,"column":2},"end":{"line":195,"column":3}}}},"branchMap":{"0":{"loc":{"start":{"line":54,"column":4},"end":{"line":62,"column":null}},"type":"switch","locations":[{"start":{"line":54,"column":4},"end":{"line":62,"column":null}}]},"1":{"loc":{"start":{"line":79,"column":44},"end":{"line":79,"column":64}},"type":"binary-expr","locations":[{"start":{"line":79,"column":44},"end":{"line":79,"column":52}},{"start":{"line":79,"column":56},"end":{"line":79,"column":64}}]}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":0,"10":0,"11":1,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":1,"26":0,"27":0,"28":1,"29":0,"30":0,"31":0,"32":0,"33":0,"34":1,"35":0,"36":0,"37":0,"38":1,"39":0,"40":0,"41":1,"42":0,"43":0,"44":0,"45":1,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":1,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":1,"60":0,"61":0,"62":0,"63":1,"64":0,"65":0,"66":0,"67":0,"68":0,"69":1,"70":1},"f":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0},"b":{"0":[0],"1":[0,0]}} +} diff --git a/packages/k8s/coverage/lcov-report/base.css b/packages/k8s/coverage/lcov-report/base.css new file mode 100644 index 00000000..f418035b --- /dev/null +++ b/packages/k8s/coverage/lcov-report/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/packages/k8s/coverage/lcov-report/block-navigation.js b/packages/k8s/coverage/lcov-report/block-navigation.js new file mode 100644 index 00000000..cc121302 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selecter that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/packages/k8s/coverage/lcov-report/favicon.png b/packages/k8s/coverage/lcov-report/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..6691817834a957c938e7f09640a37a645fb31457 GIT binary patch literal 540 zcmV+%0^|LOP)wSzy{h>9elhJ=8GnBQmf?)AI(^#wDA_`!QTxaXXE&bjxo zTGCc%V|W`}Lwz0rDO*qBbGY-M@aNENIZ1rK?nOAibaC*vb%CF;I_~lkJawax%_+1J zLn(#pv_v{f0`v`Cfp6()7MB(>IoTAiQdKxgxX?VyV&KVZ7b$vn<8|Z<9$35C+G_8SH0x6Y(xB&~bmn%r}ceRwbc0000 + + + + Code coverage report for hooks + + + + + + + + + +
+
+

All files hooks

+
+ +
+ 34.23% + Statements + 63/184 +
+ + +
+ 14.22% + Branches + 34/239 +
+ + +
+ 15.38% + Functions + 2/13 +
+ + +
+ 34.75% + Lines + 57/164 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
prepare-job.ts +
+
8.1%9/1110%0/1400%0/109.27%9/97
run-container-step.ts +
+
73.97%54/7334.34%34/9966.66%2/371.64%48/67
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/hooks/prepare-job.ts.html b/packages/k8s/coverage/lcov-report/hooks/prepare-job.ts.html new file mode 100644 index 00000000..713c0a8f --- /dev/null +++ b/packages/k8s/coverage/lcov-report/hooks/prepare-job.ts.html @@ -0,0 +1,886 @@ + + + + + + Code coverage report for hooks/prepare-job.ts + + + + + + + + + +
+
+

All files / hooks prepare-job.ts

+
+ +
+ 8.1% + Statements + 9/111 +
+ + +
+ 0% + Branches + 0/140 +
+ + +
+ 0% + Functions + 0/10 +
+ + +
+ 9.27% + Lines + 9/97 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +2681x +1x +  +1x +  +  +  +  +  +1x +1x +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as core from '@actions/core'
+import * as io from '@actions/io'
+import * as k8s from '@kubernetes/client-node'
+import {
+  JobContainerInfo,
+  ContextPorts,
+  PrepareJobArgs,
+  writeToResponseFile
+} from 'hooklib'
+import path from 'path'
+import {
+  containerPorts,
+  createPod,
+  isPodContainerAlpine,
+  prunePods,
+  waitForPodPhases,
+  getPrepareJobTimeoutSeconds
+} from '../k8s'
+import {
+  containerVolumes,
+  DEFAULT_CONTAINER_ENTRY_POINT,
+  DEFAULT_CONTAINER_ENTRY_POINT_ARGS,
+  generateContainerName,
+  mergeContainerWithOptions,
+  readExtensionFromFile,
+  PodPhase,
+  fixArgs
+} from '../k8s/utils'
+import { CONTAINER_EXTENSION_PREFIX, JOB_CONTAINER_NAME } from './constants'
+ 
+export async function prepareJob(
+  args: PrepareJobArgs,
+  responseFile
+): Promise<void> {
+  Iif (!args.container) {
+    throw new Error('Job Container is required.')
+  }
+ 
+  await prunePods()
+ 
+  const extension = readExtensionFromFile()
+  await copyExternalsToRoot()
+ 
+  let container: k8s.V1Container | undefined = undefined
+  Iif (args.container?.image) {
+    core.debug(`Using image '${args.container.image}' for job image`)
+    container = createContainerSpec(
+      args.container,
+      JOB_CONTAINER_NAME,
+      true,
+      extension
+    )
+  }
+ 
+  let services: k8s.V1Container[] = []
+  Iif (args.services?.length) {
+    services = args.services.map(service => {
+      core.debug(`Adding service '${service.image}' to pod definition`)
+      return createContainerSpec(
+        service,
+        generateContainerName(service.image),
+        false,
+        extension
+      )
+    })
+  }
+ 
+  Iif (!container && !services?.length) {
+    throw new Error('No containers exist, skipping hook invocation')
+  }
+ 
+  let createdPod: k8s.V1Pod | undefined = undefined
+  try {
+    createdPod = await createPod(
+      container,
+      services,
+      args.container.registry,
+      extension
+    )
+  } catch (err) {
+    await prunePods()
+    core.debug(`createPod failed: ${JSON.stringify(err)}`)
+    const message = (err as any)?.response?.body?.message || err
+    throw new Error(`failed to create job pod: ${message}`)
+  }
+ 
+  Iif (!createdPod?.metadata?.name) {
+    throw new Error('created pod should have metadata.name')
+  }
+  core.debug(
+    `Job pod created, waiting for it to come online ${createdPod?.metadata?.name}`
+  )
+ 
+  try {
+    await waitForPodPhases(
+      createdPod.metadata.name,
+      new Set([PodPhase.RUNNING]),
+      new Set([PodPhase.PENDING]),
+      getPrepareJobTimeoutSeconds()
+    )
+  } catch (err) {
+    try {
+      await prunePods()
+    } catch (pruneErr) {
+      core.error(`Failed to prune pods: ${pruneErr instanceof Error ? pruneErr.message : String(pruneErr)}`)
+    }
+    const message = err instanceof Error ? err.message : String(err)
+    throw new Error(`pod failed to come online:\n${message}`)
+  }
+ 
+  core.debug('Job pod is ready for traffic')
+ 
+  let isAlpine = false
+  try {
+    isAlpine = await isPodContainerAlpine(
+      createdPod.metadata.name,
+      JOB_CONTAINER_NAME
+    )
+  } catch (err) {
+    core.debug(
+      `Failed to determine if the pod is alpine: ${JSON.stringify(err)}`
+    )
+    const message = (err as any)?.response?.body?.message || err
+    throw new Error(`failed to determine if the pod is alpine: ${message}`)
+  }
+  core.debug(`Setting isAlpine to ${isAlpine}`)
+  generateResponseFile(responseFile, args, createdPod, isAlpine)
+}
+ 
+function generateResponseFile(
+  responseFile: string,
+  args: PrepareJobArgs,
+  appPod: k8s.V1Pod,
+  isAlpine
+): void {
+  Iif (!appPod.metadata?.name) {
+    throw new Error('app pod must have metadata.name specified')
+  }
+  const response = {
+    state: {
+      jobPod: appPod.metadata.name
+    },
+    context: {},
+    isAlpine
+  }
+ 
+  const mainContainer = appPod.spec?.containers?.find(
+    c => c.name === JOB_CONTAINER_NAME
+  )
+  Iif (mainContainer) {
+    const mainContainerContextPorts: ContextPorts = {}
+    Iif (mainContainer?.ports) {
+      for (const port of mainContainer.ports) {
+        mainContainerContextPorts[port.containerPort] =
+          mainContainerContextPorts.hostPort
+      }
+    }
+ 
+    response.context['container'] = {
+      image: mainContainer.image,
+      ports: mainContainerContextPorts
+    }
+  }
+ 
+  Iif (args.services?.length) {
+    const serviceContainerNames =
+      args.services?.map(s => generateContainerName(s.image)) || []
+ 
+    response.context['services'] = appPod?.spec?.containers
+      ?.filter(c => serviceContainerNames.includes(c.name))
+      .map(c => {
+        const ctxPorts: ContextPorts = {}
+        Iif (c.ports?.length) {
+          for (const port of c.ports) {
+            ctxPorts[port.containerPort] = port.hostPort
+          }
+        }
+ 
+        return {
+          image: c.image,
+          ports: ctxPorts
+        }
+      })
+  }
+ 
+  writeToResponseFile(responseFile, JSON.stringify(response))
+}
+ 
+async function copyExternalsToRoot(): Promise<void> {
+  const workspace = process.env['RUNNER_WORKSPACE']
+  if (Iworkspace) {
+    await io.cp(
+      path.join(workspace, '../../externals'),
+      path.join(workspace, '../externals'),
+      { force: true, recursive: true, copySourceDirectory: false }
+    )
+  }
+}
+ 
+export function createContainerSpec(
+  container: JobContainerInfo,
+  name: string,
+  IjobContainer = false,
+  extension?: k8s.V1PodTemplateSpec
+): k8s.V1Container {
+  Iif (!container.entryPoint && jobContainer) {
+    container.entryPoint = DEFAULT_CONTAINER_ENTRY_POINT
+    container.entryPointArgs = DEFAULT_CONTAINER_ENTRY_POINT_ARGS
+  }
+ 
+  const podContainer = {
+    name,
+    image: container.image,
+    ports: containerPorts(container)
+  } as k8s.V1Container
+  Iif (container.workingDirectory) {
+    podContainer.workingDir = container.workingDirectory
+  }
+ 
+  Iif (container.entryPoint) {
+    podContainer.command = [container.entryPoint]
+  }
+ 
+  Iif (container.entryPointArgs?.length > 0) {
+    podContainer.args = fixArgs(container.entryPointArgs)
+  }
+ 
+  podContainer.env = []
+  for (const [key, value] of Object.entries(
+    container['environmentVariables']
+  )) {
+    Iif (value && key !== 'HOME') {
+      podContainer.env.push({ name: key, value: value as string })
+    }
+  }
+ 
+  podContainer.env.push({
+    name: 'GITHUB_ACTIONS',
+    value: 'true'
+  })
+ 
+  Iif (!('CI' in container['environmentVariables'])) {
+    podContainer.env.push({
+      name: 'CI',
+      value: 'true'
+    })
+  }
+ 
+  podContainer.volumeMounts = containerVolumes(
+    container.userMountVolumes,
+    jobContainer
+  )
+ 
+  Iif (!extension) {
+    return podContainer
+  }
+ 
+  const from = extension.spec?.containers?.find(
+    c => c.name === CONTAINER_EXTENSION_PREFIX + name
+  )
+ 
+  Iif (from) {
+    mergeContainerWithOptions(podContainer, from)
+  }
+ 
+  return podContainer
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/hooks/run-container-step.ts.html b/packages/k8s/coverage/lcov-report/hooks/run-container-step.ts.html new file mode 100644 index 00000000..66134a10 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/hooks/run-container-step.ts.html @@ -0,0 +1,592 @@ + + + + + + Code coverage report for hooks/run-container-step.ts + + + + + + + + + +
+
+

All files / hooks run-container-step.ts

+
+ +
+ 73.97% + Statements + 54/73 +
+ + +
+ 34.34% + Branches + 34/99 +
+ + +
+ 66.66% + Functions + 2/3 +
+ + +
+ 71.64% + Lines + 48/67 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +1701x +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +1x +  +1x +  +  +9x +  +  +  +9x +14x +  +4x +  +  +4x +4x +4x +  +4x +  +4x +4x +4x +  +  +  +5x +  +5x +5x +  +  +  +5x +  +  +  +  +  +  +5x +  +  +  +  +  +  +5x +  +  +  +5x +  +  +  +  +  +  +10x +  +  +  +  +  +  +  +  +  +5x +  +10x +  +5x +10x +  +  +5x +5x +  +  +5x +  +  +  +  +  +  +  +  +5x +5x +5x +5x +5x +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +5x +5x +5x +5x +  +  +5x +  +  +  +5x +  +  +  +  +  +  +  +  +  +5x +  +5x +5x +  +  +  +  +  +  +  +  +  +  +  + 
import * as core from '@actions/core'
+import * as k8s from '@kubernetes/client-node'
+import { RunContainerStepArgs } from 'hooklib'
+import {
+  createJob,
+  createSecretForEnvs,
+  describePodFailure,
+  getContainerJobPodName,
+  getContainerTerminatedErrors,
+  getPodByName,
+  getPodLogs,
+  getPodStatus,
+  waitForJobToComplete,
+  waitForPodPhases
+} from '../k8s'
+import {
+  containerVolumes,
+  fixArgs,
+  mergeContainerWithOptions,
+  PodPhase,
+  readExtensionFromFile
+} from '../k8s/utils'
+import { JOB_CONTAINER_EXTENSION_NAME, JOB_CONTAINER_NAME } from './constants'
+ 
+export async function runContainerStep(
+  stepContainer: RunContainerStepArgs
+): Promise<number> {
+  Iif (stepContainer.dockerfile) {
+    throw new Error('Building container actions is not currently supported')
+  }
+ 
+  let secretName: string | undefined = undefined
+  if (stepContainer.environmentVariables) {
+    try {
+      const envs = JSON.parse(
+        JSON.stringify(stepContainer.environmentVariables)
+      )
+      envs['GITHUB_ACTIONS'] = 'true'
+      if (!('CI' in envs)) {
+        envs.CI = 'true'
+      }
+      secretName = await createSecretForEnvs(envs)
+    } catch (err) {
+      core.debug(`createSecretForEnvs failed: ${JSON.stringify(err)}`)
+      const message = (err as any)?.response?.body?.message || err
+      throw new Error(`failed to create script environment: ${message}`)
+    }
+  }
+ 
+  const extension = readExtensionFromFile()
+ 
+  core.debug(`Created secret ${secretName} for container job envs`)
+  const container = createContainerSpec(stepContainer, secretName, extension)
+ 
+  let job: k8s.V1Job
+  try {
+    job = await createJob(container, extension)
+  } catch (err) {
+    core.debug(`createJob failed: ${JSON.stringify(err)}`)
+    const message = (err as any)?.response?.body?.message || err
+    throw new Error(`failed to run script step: ${message}`)
+  }
+ 
+  Iif (!job.metadata?.name) {
+    throw new Error(
+      `Expected job ${JSON.stringify(
+        job
+      )} to have correctly set the metadata.name`
+    )
+  }
+  core.debug(`Job created, waiting for pod to start: ${job.metadata?.name}`)
+ 
+  let podName: string
+  try {
+    podName = await getContainerJobPodName(job.metadata.name)
+  } catch (err) {
+    core.debug(`getContainerJobPodName failed: ${JSON.stringify(err)}`)
+    const message = (err as any)?.response?.body?.message || err
+    throw new Error(`failed to get container job pod name: ${message}`)
+  }
+ 
+  await waitForPodPhases(
+    podName,
+    new Set([
+      PodPhase.COMPLETED,
+      PodPhase.RUNNING,
+      PodPhase.SUCCEEDED,
+      PodPhase.FAILED
+    ]),
+    new Set([PodPhase.PENDING, PodPhase.UNKNOWN])
+  )
+  core.debug('Container step is running or complete, pulling logs')
+ 
+  await getPodLogs(podName, JOB_CONTAINER_NAME)
+ 
+  core.debug('Waiting for container job to complete')
+  await waitForJobToComplete(job.metadata.name)
+ 
+  // pod has failed so pull the status code from the container
+  const status = await getPodStatus(podName)
+  Iif (status?.phase === 'Succeeded') {
+    return 0
+  }
+  Iif (!status?.containerStatuses?.length) {
+    core.error(
+      `Can't determine container status from response:  ${JSON.stringify(
+        status
+      )}`
+    )
+    return 1
+  }
+ 
+  const pod = await getPodByName(podName)
+  const terminatedErrors = getContainerTerminatedErrors(pod)
+  if (IterminatedErrors.length > 0) {
+    const details = await describePodFailure(podName)
+    core.error(
+      `Pod ${podName} has unrecoverable container errors:\n${terminatedErrors.join('\n')}\n${details}`
+    )
+    return 1
+  }
+ 
+  const exitCode =
+    status.containerStatuses[status.containerStatuses.length - 1].state
+      ?.terminated?.exitCode
+  return Number(exitCode) || 1
+}
+ 
+function createContainerSpec(
+  container: RunContainerStepArgs,
+  secretName?: string,
+  extension?: k8s.V1PodTemplateSpec
+): k8s.V1Container {
+  const podContainer = new k8s.V1Container()
+  podContainer.name = JOB_CONTAINER_NAME
+  podContainer.image = container.image
+  podContainer.workingDir = container.workingDirectory
+  podContainer.command = container.entryPoint
+    ? [container.entryPoint]
+    : undefined
+  podContainer.args = container.entryPointArgs?.length
+    ? fixArgs(container.entryPointArgs)
+    : undefined
+ 
+  Iif (secretName) {
+    podContainer.envFrom = [
+      {
+        secretRef: {
+          name: secretName,
+          optional: false
+        }
+      }
+    ]
+  }
+  podContainer.volumeMounts = containerVolumes(undefined, false, true)
+ 
+  if (!extension) {
+    return podContainer
+  }
+ 
+  const from = extension.spec?.containers?.find(
+    c => c.name === JOB_CONTAINER_EXTENSION_NAME
+  )
+  Iif (from) {
+    mergeContainerWithOptions(podContainer, from)
+  }
+ 
+  return podContainer
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/index.html b/packages/k8s/coverage/lcov-report/index.html new file mode 100644 index 00000000..ea929c54 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/index.html @@ -0,0 +1,146 @@ + + + + + + Code coverage report for All files + + + + + + + + + +
+
+

All files

+
+ +
+ 21.75% + Statements + 206/947 +
+ + +
+ 6.55% + Branches + 47/717 +
+ + +
+ 10.9% + Functions + 12/110 +
+ + +
+ 24.27% + Lines + 201/828 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
src/hooks +
+
36.55%87/23812.89%33/25616%4/2538.24%83/217
src/k8s +
+
15.36%98/6383.05%14/45810.44%7/6718.11%98/541
tests +
+
29.57%21/710%0/35.55%1/1828.57%20/70
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/k8s/index.html b/packages/k8s/coverage/lcov-report/k8s/index.html new file mode 100644 index 00000000..790df482 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/k8s/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for k8s + + + + + + + + + +
+
+

All files k8s

+
+ +
+ 47.42% + Statements + 230/485 +
+ + +
+ 50.58% + Branches + 173/342 +
+ + +
+ 36.36% + Functions + 20/55 +
+ + +
+ 47.71% + Lines + 198/415 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
index.ts +
+
47.42%230/48550.58%173/34236.36%20/5547.71%198/415
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/k8s/index.ts.html b/packages/k8s/coverage/lcov-report/k8s/index.ts.html new file mode 100644 index 00000000..9250f7cf --- /dev/null +++ b/packages/k8s/coverage/lcov-report/k8s/index.ts.html @@ -0,0 +1,3028 @@ + + + + + + Code coverage report for k8s/index.ts + + + + + + + + + +
+
+

All files / k8s index.ts

+
+ +
+ 47.42% + Statements + 230/485 +
+ + +
+ 50.58% + Branches + 173/342 +
+ + +
+ 36.36% + Functions + 20/55 +
+ + +
+ 47.71% + Lines + 198/415 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +9822x +2x +  +2x +2x +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +2x +  +2x +  +2x +2x +2x +  +2x +  +2x +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +4x +  +4x +4x +4x +4x +4x +4x +  +4x +  +  +4x +4x +12x +12x +  +  +8x +  +  +  +2x +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +2x +  +  +  +  +  +2x +  +  +  +  +  +2x +  +2x +22x +22x +19x +  +3x +6x +6x +6x +3x +  +  +3x +  +  +2x +10x +10x +8x +  +2x +4x +4x +4x +1x +  +  +2x +  +  +2x +  +34x +34x +30x +  +4x +9x +9x +9x +4x +  +  +4x +  +  +2x +19x +19x +19x +  +  +  +38x +14x +14x +11x +  +  +  +  +  +  +19x +  +  +2x +7x +  +  +7x +  +  +  +  +  +  +6x +  +1x +  +  +  +  +1x +  +  +6x +7x +7x +  +  +  +  +5x +  +  +6x +  +  +2x +13x +13x +11x +4x +  +  +  +  +  +  +13x +  +  +2x +28x +28x +28x +  +  +  +56x +28x +28x +21x +  +  +  +  +  +  +28x +  +  +2x +  +  +8x +  +1x +  +  +  +  +7x +7x +  +7x +7x +  +  +  +  +  +7x +1x +  +  +7x +7x +  +7x +2x +2x +  +  +  +  +  +  +  +7x +  +  +  +7x +3x +3x +2x +  +  +  +  +  +3x +3x +1x +  +  +  +  +  +  +  +  +  +7x +  +7x +  +  +7x +  +  +  +  +  +7x +  +  +  +  +  +  +6x +  +1x +  +  +  +  +1x +  +  +6x +6x +5x +  +  +1x +  +  +  +1x +  +1x +1x +1x +1x +  +  +  +1x +  +  +  +  +1x +  +  +2x +  +  +  +16x +  +8x +8x +12x +12x +12x +12x +5x +  +  +13x +1x +1x +  +  +  +  +6x +11x +1x +1x +  +  +  +  +  +  +5x +9x +1x +1x +  +  +  +  +  +  +  +8x +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +20x +19x +  +  +2x +  +  +  +  +  +  +  +2x +19x +3x +  +16x +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +38x +38x +  +  +  +  +  +  +  +  +  +  +  +2x +8x +8x +8x +8x +  +  +  +  +2x +8x +4x +  +4x +4x +  +  +4x +4x +  +4x +  +  +  +2x +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  + 
import * as core from '@actions/core'
+import * as k8s from '@kubernetes/client-node'
+import { ContainerInfo, Registry } from 'hooklib'
+import * as stream from 'stream'
+import {
+  getJobPodName,
+  getRunnerPodName,
+  getSecretName,
+  getStepPodName,
+  getVolumeClaimName,
+  RunnerInstanceLabel
+} from '../hooks/constants'
+import {
+  PodPhase,
+  mergePodSpecWithOptions,
+  mergeObjectMeta,
+  useKubeScheduler,
+  fixArgs
+} from './utils'
+ 
+const kc = new k8s.KubeConfig()
+ 
+kc.loadFromDefault()
+ 
+const k8sApi = kc.makeApiClient(k8s.CoreV1Api)
+const k8sBatchV1Api = kc.makeApiClient(k8s.BatchV1Api)
+const k8sAuthorizationV1Api = kc.makeApiClient(k8s.AuthorizationV1Api)
+ 
+const DEFAULT_WAIT_FOR_POD_TIME_SECONDS = 10 * 60 // 10 min
+ 
+export const POD_VOLUME_NAME = 'work'
+ 
+export const requiredPermissions = [
+  {
+    group: '',
+    verbs: ['get', 'list', 'create', 'delete'],
+    resource: 'pods',
+    subresource: ''
+  },
+  {
+    group: '',
+    verbs: ['get', 'create'],
+    resource: 'pods',
+    subresource: 'exec'
+  },
+  {
+    group: '',
+    verbs: ['get', 'list', 'watch'],
+    resource: 'pods',
+    subresource: 'log'
+  },
+  {
+    group: 'batch',
+    verbs: ['get', 'list', 'create', 'delete'],
+    resource: 'jobs',
+    subresource: ''
+  },
+  {
+    group: '',
+    verbs: ['create', 'delete', 'get', 'list'],
+    resource: 'secrets',
+    subresource: ''
+  }
+]
+ 
+export async function createPod(
+  jobContainer?: k8s.V1Container,
+  services?: k8s.V1Container[],
+  registry?: Registry,
+  extension?: k8s.V1PodTemplateSpec
+): Promise<k8s.V1Pod> {
+  const containers: k8s.V1Container[] = []
+  Iif (jobContainer) {
+    containers.push(jobContainer)
+  }
+  Iif (services?.length) {
+    containers.push(...services)
+  }
+ 
+  const appPod = new k8s.V1Pod()
+ 
+  appPod.apiVersion = 'v1'
+  appPod.kind = 'Pod'
+ 
+  appPod.metadata = new k8s.V1ObjectMeta()
+  appPod.metadata.name = getJobPodName()
+ 
+  const instanceLabel = new RunnerInstanceLabel()
+  appPod.metadata.labels = {
+    [instanceLabel.key]: instanceLabel.value
+  }
+  appPod.metadata.annotations = {}
+ 
+  appPod.spec = new k8s.V1PodSpec()
+  appPod.spec.containers = containers
+  appPod.spec.restartPolicy = 'Never'
+ 
+  const nodeName = await getCurrentNodeName()
+  if (IuseKubeScheduler()) {
+    appPod.spec.affinity = await getPodAffinity(nodeName)
+  } else {
+    appPod.spec.affinity = await getPreferredPodAffinity(nodeName)
+  }
+  const claimName = getVolumeClaimName()
+  appPod.spec.volumes = [
+    {
+      name: 'work',
+      persistentVolumeClaim: { claimName }
+    }
+  ]
+ 
+  if (Iregistry) {
+    const secret = await createDockerSecret(registry)
+    Iif (!secret?.metadata?.name) {
+      throw new Error(`created secret does not have secret.metadata.name`)
+    }
+    const secretReference = new k8s.V1LocalObjectReference()
+    secretReference.name = secret.metadata.name
+    appPod.spec.imagePullSecrets = [secretReference]
+  }
+ 
+  Iif (extension?.metadata) {
+    mergeObjectMeta(appPod, extension.metadata)
+  }
+ 
+  Iif (extension?.spec) {
+    mergePodSpecWithOptions(appPod.spec, extension.spec)
+  }
+ 
+  const { body } = await k8sApi.createNamespacedPod(namespace(), appPod)
+  return body
+}
+ 
+export async function createJob(
+  container: k8s.V1Container,
+  extension?: k8s.V1PodTemplateSpec
+): Promise<k8s.V1Job> {
+  const runnerInstanceLabel = new RunnerInstanceLabel()
+ 
+  const job = new k8s.V1Job()
+  job.apiVersion = 'batch/v1'
+  job.kind = 'Job'
+  job.metadata = new k8s.V1ObjectMeta()
+  job.metadata.name = getStepPodName()
+  job.metadata.labels = { [runnerInstanceLabel.key]: runnerInstanceLabel.value }
+  job.metadata.annotations = {}
+ 
+  job.spec = new k8s.V1JobSpec()
+  job.spec.ttlSecondsAfterFinished = 300
+  job.spec.backoffLimit = 0
+  job.spec.template = new k8s.V1PodTemplateSpec()
+ 
+  job.spec.template.spec = new k8s.V1PodSpec()
+  job.spec.template.metadata = new k8s.V1ObjectMeta()
+  job.spec.template.metadata.labels = {}
+  job.spec.template.metadata.annotations = {}
+  job.spec.template.spec.containers = [container]
+  job.spec.template.spec.restartPolicy = 'Never'
+ 
+  const nodeName = await getCurrentNodeName()
+  if (IuseKubeScheduler()) {
+    job.spec.template.spec.affinity = await getPodAffinity(nodeName)
+  } else {
+    job.spec.template.spec.affinity = await getPreferredPodAffinity(nodeName)
+  }
+ 
+  const claimName = getVolumeClaimName()
+  job.spec.template.spec.volumes = [
+    {
+      name: 'work',
+      persistentVolumeClaim: { claimName }
+    }
+  ]
+ 
+  Iif (extension) {
+    Iif (extension.metadata) {
+      // apply metadata both to the job and the pod created by the job
+      mergeObjectMeta(job, extension.metadata)
+      mergeObjectMeta(job.spec.template, extension.metadata)
+    }
+    Iif (extension.spec) {
+      mergePodSpecWithOptions(job.spec.template.spec, extension.spec)
+    }
+  }
+ 
+  const { body } = await k8sBatchV1Api.createNamespacedJob(namespace(), job)
+  return body
+}
+ 
+export async function getContainerJobPodName(jobName: string): Promise<string> {
+  const selector = `job-name=${jobName}`
+  const backOffManager = new BackOffManager(60)
+  while (Itrue) {
+    const podList = await k8sApi.listNamespacedPod(
+      namespace(),
+      undefined,
+      undefined,
+      undefined,
+      undefined,
+      selector,
+      1
+    )
+ 
+    if (I!podList.body.items?.length) {
+      await backOffManager.backOff()
+      continue
+    }
+ 
+    Iif (!podList.body.items[0].metadata?.name) {
+      throw new Error(
+        `Failed to determine the name of the pod for job ${jobName}`
+      )
+    }
+    return podList.body.items[0].metadata.name
+  }
+}
+ 
+export async function deletePod(podName: string): Promise<void> {
+  await k8sApi.deleteNamespacedPod(
+    podName,
+    namespace(),
+    undefined,
+    undefined,
+    0
+  )
+}
+ 
+export async function execPodStep(
+  command: string[],
+  podName: string,
+  containerName: string,
+  stdin?: stream.Readable
+): Promise<void> {
+  const exec = new k8s.Exec(kc)
+  command = fixArgs(command)
+  // Exec returns a websocket. If websocket fails, we should reject the promise. Otherwise, websocket will call a callback. Since at that point, websocket is not failing, we can safely resolve or reject the promise.
+  await new Promise(function (resolve, reject) {
+    exec
+      .exec(
+        namespace(),
+        podName,
+        containerName,
+        command,
+        process.stdout,
+        process.stderr,
+        stdin ?? null,
+        false /* tty */,
+        resp => {
+          // kube.exec returns an error if exit code is not 0, but we can't actually get the exit code
+          if (resp.status === 'Success') {
+            resolve(resp.code)
+          } else {
+            core.debug(
+              JSON.stringify({
+                message: resp?.message,
+                details: resp?.details
+              })
+            )
+            reject(resp?.message)
+          }
+        }
+      )
+      // If exec.exec fails, explicitly reject the outer promise
+      // eslint-disable-next-line github/no-then
+      .catch(e => reject(e))
+  })
+}
+ 
+export async function waitForJobToComplete(jobName: string): Promise<void> {
+  const backOffManager = new BackOffManager()
+  while (Itrue) {
+    try {
+      Iif (await isJobSucceeded(jobName)) {
+        return
+      }
+    } catch (error) {
+      throw new Error(`job ${jobName} has failed`)
+    }
+    await backOffManager.backOff()
+  }
+}
+ 
+export async function createDockerSecret(
+  registry: Registry
+): Promise<k8s.V1Secret> {
+  const authContent = {
+    auths: {
+      [registry.serverUrl || 'https://index.docker.io/v1/']: {
+        username: registry.username,
+        password: registry.password,
+        auth: Buffer.from(`${registry.username}:${registry.password}`).toString(
+          'base64'
+        )
+      }
+    }
+  }
+ 
+  const runnerInstanceLabel = new RunnerInstanceLabel()
+ 
+  const secretName = getSecretName()
+  const secret = new k8s.V1Secret()
+  secret.immutable = true
+  secret.apiVersion = 'v1'
+  secret.metadata = new k8s.V1ObjectMeta()
+  secret.metadata.name = secretName
+  secret.metadata.namespace = namespace()
+  secret.metadata.labels = {
+    [runnerInstanceLabel.key]: runnerInstanceLabel.value
+  }
+  secret.type = 'kubernetes.io/dockerconfigjson'
+  secret.kind = 'Secret'
+  secret.data = {
+    '.dockerconfigjson': Buffer.from(JSON.stringify(authContent)).toString(
+      'base64'
+    )
+  }
+ 
+  const { body } = await k8sApi.createNamespacedSecret(namespace(), secret)
+  return body
+}
+ 
+export async function createSecretForEnvs(envs: {
+  [key: string]: string
+}): Promise<string> {
+  const runnerInstanceLabel = new RunnerInstanceLabel()
+ 
+  const secret = new k8s.V1Secret()
+  const secretName = getSecretName()
+  secret.immutable = true
+  secret.apiVersion = 'v1'
+  secret.metadata = new k8s.V1ObjectMeta()
+  secret.metadata.name = secretName
+ 
+  secret.metadata.labels = {
+    [runnerInstanceLabel.key]: runnerInstanceLabel.value
+  }
+  secret.kind = 'Secret'
+  secret.data = {}
+  for (const [key, value] of Object.entries(envs)) {
+    secret.data[key] = Buffer.from(value).toString('base64')
+  }
+ 
+  await k8sApi.createNamespacedSecret(namespace(), secret)
+  return secretName
+}
+ 
+export async function deleteSecret(secretName: string): Promise<void> {
+  await k8sApi.deleteNamespacedSecret(secretName, namespace())
+}
+ 
+export async function pruneSecrets(): Promise<void> {
+  const secretList = await k8sApi.listNamespacedSecret(
+    namespace(),
+    undefined,
+    undefined,
+    undefined,
+    undefined,
+    new RunnerInstanceLabel().toString()
+  )
+  Iif (!secretList.body.items.length) {
+    return
+  }
+ 
+  await Promise.all(
+    secretList.body.items.map(
+      secret => secret.metadata?.name && deleteSecret(secret.metadata.name)
+    )
+  )
+}
+ 
+export const UNRECOVERABLE_WAITING_REASONS = new Set([
+  'ImagePullBackOff',
+  'ErrImagePull',
+  'InvalidImageName',
+  'CreateContainerConfigError',
+  'CreateContainerError'
+])
+ 
+export const UNRECOVERABLE_EVENT_REASONS = new Set([
+  'FailedScheduling',
+  'FailedBinding',
+  'FailedMount'
+])
+ 
+export const UNRECOVERABLE_TERMINATED_REASONS = new Set([
+  'OOMKilled',
+  'Error',
+  'FailedPostStartHookError'
+])
+ 
+const MAX_DIAGNOSTIC_EVENTS = 10
+ 
+export function getUnrecoverableWaitingReasons(): Set<string> {
+  const extra = process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_WAITING_REASONS']
+  if (!extra) {
+    return UNRECOVERABLE_WAITING_REASONS
+  }
+  const reasons = new Set(UNRECOVERABLE_WAITING_REASONS)
+  for (const reason of extra.split(',')) {
+    const trimmed = reason.trim()
+    if (trimmed) {
+      reasons.add(trimmed)
+    }
+  }
+  return reasons
+}
+ 
+export function getUnrecoverableEventReasons(): Set<string> {
+  const extra = process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_EVENT_REASONS']
+  if (!extra) {
+    return UNRECOVERABLE_EVENT_REASONS
+  }
+  const reasons = new Set(UNRECOVERABLE_EVENT_REASONS)
+  for (const reason of extra.split(',')) {
+    const trimmed = reason.trim()
+    if (trimmed) {
+      reasons.add(trimmed)
+    }
+  }
+  return reasons
+}
+ 
+export function getUnrecoverableTerminatedReasons(): Set<string> {
+  const extra =
+    process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_TERMINATED_REASONS']
+  if (!extra) {
+    return UNRECOVERABLE_TERMINATED_REASONS
+  }
+  const reasons = new Set(UNRECOVERABLE_TERMINATED_REASONS)
+  for (const reason of extra.split(',')) {
+    const trimmed = reason.trim()
+    if (trimmed) {
+      reasons.add(trimmed)
+    }
+  }
+  return reasons
+}
+ 
+export function getContainerErrors(pod: k8s.V1Pod): string[] {
+  const errors: string[] = []
+  const unrecoverableReasons = getUnrecoverableWaitingReasons()
+  const allStatuses = [
+    ...(pod.status?.initContainerStatuses ?? []),
+    ...(pod.status?.containerStatuses ?? [])
+  ]
+  for (const cs of allStatuses) {
+    const waiting = cs.state?.waiting
+    if (waiting?.reason && unrecoverableReasons.has(waiting.reason)) {
+      errors.push(
+        `container "${cs.name}": ${waiting.reason}${
+          waiting.message ? ` - ${waiting.message}` : ''
+        }`
+      )
+    }
+  }
+  return errors
+}
+ 
+export async function getPodEventErrors(podName: string): Promise<string[]> {
+  const unrecoverableReasons = getUnrecoverableEventReasons()
+  let items: k8s.CoreV1Event[]
+  try {
+    const { body } = await k8sApi.listNamespacedEvent(
+      namespace(),
+      undefined,
+      undefined,
+      undefined,
+      `involvedObject.name=${podName}`
+    )
+    items = body.items
+  } catch (err) {
+    core.debug(
+      `Could not list events for pod ${podName} (the 'events' permission may be missing): ${
+        err instanceof Error ? err.message : String(err)
+      }`
+    )
+    return []
+  }
+ 
+  const errors: string[] = []
+  for (const e of items) {
+    if (
+      e.type === 'Warning' &&
+      e.reason &&
+      unrecoverableReasons.has(e.reason)
+    ) {
+      errors.push(`Event [Warning] ${e.reason}: ${e.message ?? ''}`)
+    }
+  }
+  return errors
+}
+ 
+export function getPodConditionErrors(pod: k8s.V1Pod): string[] {
+  const errors: string[] = []
+  for (const cond of pod.status?.conditions ?? []) {
+    if (cond.type === 'PodScheduled' && cond.status === 'False' && cond.reason === 'Unschedulable') {
+      errors.push(
+        `Condition ${cond.type}=False (reason: ${cond.reason ?? ''}): ${
+          cond.message ?? ''
+        }`
+      )
+    }
+  }
+  return errors
+}
+ 
+export function getContainerTerminatedErrors(pod: k8s.V1Pod): string[] {
+  const errors: string[] = []
+  const unrecoverableReasons = getUnrecoverableTerminatedReasons()
+  const allStatuses = [
+    ...(pod.status?.initContainerStatuses ?? []),
+    ...(pod.status?.containerStatuses ?? [])
+  ]
+  for (const cs of allStatuses) {
+    const terminated = cs.state?.terminated
+    if (terminated?.reason && unrecoverableReasons.has(terminated.reason)) {
+      errors.push(
+        `container "${cs.name}": ${terminated.reason} (exit code ${terminated.exitCode}) - ${
+          terminated.message ?? ''
+        }`
+      )
+    }
+  }
+  return errors
+}
+ 
+export async function describePodFailure(podName: string): Promise<string> {
+  let pod: k8s.V1Pod
+  try {
+    pod = await readPod(podName)
+  } catch (err) {
+    return `Could not read pod ${podName} for diagnostics: ${
+      err instanceof Error ? err.message : String(err)
+    }`
+  }
+ 
+  const lines: string[] = []
+  const status = pod.status
+ 
+  if (status?.phase) {
+    lines.push(
+      `Phase: ${status.phase}${
+        status.reason ? ` (reason: ${status.reason})` : ''
+      }`
+    )
+  }
+  if (status?.message) {
+    lines.push(`Message: ${status.message}`)
+  }
+ 
+  const separator = '────────────────────────────────────────────────────────────'
+  lines.push(separator)
+ 
+  for (const cond of status?.conditions ?? []) {
+    if (cond.status === 'False') {
+      lines.push(
+        `  ✗ ${cond.type}=False${
+          cond.reason ? ` (${cond.reason})` : ''
+        }${cond.message ? `: ${cond.message}` : ''}`
+      )
+    }
+  }
+ 
+  const allStatuses = [
+    ...(status?.initContainerStatuses ?? []),
+    ...(status?.containerStatuses ?? [])
+  ]
+  for (const cs of allStatuses) {
+    const waiting = cs.state?.waiting
+    if (waiting?.reason) {
+      lines.push(
+        `  ✗ container "${cs.name}": ${waiting.reason}${
+          waiting.message ? `\n    ${waiting.message}` : ''
+        }`
+      )
+    }
+    const terminated = cs.state?.terminated
+    if (terminated) {
+      lines.push(
+        `  ✗ container "${cs.name}": ${
+          terminated.reason ?? 'Unknown'
+        } (exit code ${terminated.exitCode})${
+          terminated.message ? `\n    ${terminated.message}` : ''
+        }`
+      )
+    }
+  }
+ 
+  lines.push(...(await describePodWarningEvents(podName)))
+ 
+  Iif (!lines.length) {
+    return `No additional diagnostic information available for pod ${podName}`
+  }
+  return lines.join('\n')
+}
+ 
+async function describePodWarningEvents(podName: string): Promise<string[]> {
+  let items: k8s.CoreV1Event[]
+  try {
+    const { body } = await k8sApi.listNamespacedEvent(
+      namespace(),
+      undefined,
+      undefined,
+      undefined,
+      `involvedObject.name=${podName}`
+    )
+    items = body.items
+  } catch (err) {
+    core.debug(
+      `Could not list events for pod ${podName} (the 'events' permission may be missing): ${
+        err instanceof Error ? err.message : String(err)
+      }`
+    )
+    return []
+  }
+ 
+  const warnings = items.filter(e => e.type === 'Warning')
+  if (!warnings.length) {
+    return []
+  }
+ 
+  const eventTime = (e: k8s.CoreV1Event): number => {
+    const t = e.lastTimestamp ?? e.eventTime ?? e.firstTimestamp
+    return t ? new Date(t).getTime() : 0
+  }
+  warnings.sort((a, b) => eventTime(a) - eventTime(b))
+ 
+  const recent = warnings.slice(-MAX_DIAGNOSTIC_EVENTS)
+  const lines = recent.map(e => {
+    const count = e.count && e.count > 1 ? ` (x${e.count})` : ''
+    return `Event [Warning] ${e.reason ?? ''}${count}: ${
+      e.message ?? ''
+    }`.trim()
+  })
+  Iif (warnings.length > recent.length) {
+    lines.unshift(
+      `(showing ${recent.length} of ${warnings.length} warning events)`
+    )
+  }
+  return lines
+}
+ 
+export async function waitForPodPhases(
+  podName: string,
+  awaitingPhases: Set<PodPhase>,
+  backOffPhases: Set<PodPhase>,
+  maxTimeSeconds = DEFAULT_WAIT_FOR_POD_TIME_SECONDS
+): Promise<void> {
+  const backOffManager = new BackOffManager(maxTimeSeconds)
+  let phase: PodPhase = PodPhase.UNKNOWN
+  while (Itrue) {
+    const pod = await readPod(podName)
+    phase = parsePodPhase(pod)
+    if (awaitingPhases.has(phase)) {
+      return
+    }
+ 
+    if (!backOffPhases.has(phase)) {
+      const details = await describePodFailure(podName)
+      throw new Error(
+        `Pod ${podName} is unhealthy with phase status ${phase}\n${details}`
+      )
+    }
+ 
+    const containerErrors = getContainerErrors(pod)
+    if (containerErrors.length > 0) {
+      const details = await describePodFailure(podName)
+      throw new Error(
+        `Pod ${podName} has unrecoverable container errors: ${containerErrors.join(
+          '; '
+        )}\n${details}`
+      )
+    }
+ 
+    const conditionErrors = getPodConditionErrors(pod)
+    if (conditionErrors.length > 0) {
+      const details = await describePodFailure(podName)
+      throw new Error(
+        `Pod ${podName} has unrecoverable condition errors: ${conditionErrors.join(
+          '; '
+        )}\n${details}`
+      )
+    }
+ 
+    try {
+      await backOffManager.backOff()
+    } catch (error) {
+      const details = await describePodFailure(podName)
+      throw new Error(
+        `Pod ${podName} is unhealthy: timed out after ${maxTimeSeconds}s in phase ${phase}\n${details}`
+      )
+    }
+  }
+}
+ 
+export function getPrepareJobTimeoutSeconds(): number {
+  const envTimeoutSeconds =
+    process.env['ACTIONS_RUNNER_PREPARE_JOB_TIMEOUT_SECONDS']
+ 
+  Iif (!envTimeoutSeconds) {
+    return DEFAULT_WAIT_FOR_POD_TIME_SECONDS
+  }
+ 
+  const timeoutSeconds = parseInt(envTimeoutSeconds, 10)
+  Iif (!timeoutSeconds || timeoutSeconds <= 0) {
+    core.warning(
+      `Prepare job timeout is invalid ("${timeoutSeconds}"): use an int > 0`
+    )
+    return DEFAULT_WAIT_FOR_POD_TIME_SECONDS
+  }
+ 
+  return timeoutSeconds
+}
+ 
+async function readPod(podName: string): Promise<k8s.V1Pod> {
+  const { body } = await k8sApi.readNamespacedPod(podName, namespace())
+  return body
+}
+ 
+const podPhaseLookup = new Set<string>([
+  PodPhase.PENDING,
+  PodPhase.RUNNING,
+  PodPhase.SUCCEEDED,
+  PodPhase.FAILED,
+  PodPhase.UNKNOWN
+])
+ 
+export function parsePodPhase(pod: k8s.V1Pod): PodPhase {
+  if (!pod.status?.phase || !podPhaseLookup.has(pod.status.phase)) {
+    return PodPhase.UNKNOWN
+  }
+  return pod.status.phase as PodPhase
+}
+ 
+async function isJobSucceeded(jobName: string): Promise<boolean> {
+  const { body } = await k8sBatchV1Api.readNamespacedJob(jobName, namespace())
+  const job = body
+  Iif (job.status?.failed) {
+    throw new Error(`job ${jobName} has failed`)
+  }
+  return !!job.status?.succeeded
+}
+ 
+export async function getPodLogs(
+  podName: string,
+  containerName: string
+): Promise<void> {
+  const log = new k8s.Log(kc)
+  const logStream = new stream.PassThrough()
+  logStream.on('data', chunk => {
+    // use write rather than console.log to prevent double line feed
+    process.stdout.write(chunk)
+  })
+ 
+  logStream.on('error', err => {
+    process.stderr.write(err.message)
+  })
+ 
+  const r = await log.log(namespace(), podName, containerName, logStream, {
+    follow: true,
+    pretty: false,
+    timestamps: false
+  })
+  await new Promise(resolve => r.on('close', () => resolve(null)))
+}
+ 
+export async function prunePods(): Promise<void> {
+  const podList = await k8sApi.listNamespacedPod(
+    namespace(),
+    undefined,
+    undefined,
+    undefined,
+    undefined,
+    new RunnerInstanceLabel().toString()
+  )
+  Iif (!podList.body.items.length) {
+    return
+  }
+ 
+  await Promise.all(
+    podList.body.items.map(
+      pod => pod.metadata?.name && deletePod(pod.metadata.name)
+    )
+  )
+}
+ 
+export async function getPodStatus(
+  name: string
+): Promise<k8s.V1PodStatus | undefined> {
+  const { body } = await k8sApi.readNamespacedPod(name, namespace())
+  return body.status
+}
+ 
+export async function isAuthPermissionsOK(): Promise<boolean> {
+  const sar = new k8s.V1SelfSubjectAccessReview()
+  const asyncs: Promise<{
+    response: unknown
+    body: k8s.V1SelfSubjectAccessReview
+  }>[] = []
+  for (const resource of requiredPermissions) {
+    for (const verb of resource.verbs) {
+      sar.spec = new k8s.V1SelfSubjectAccessReviewSpec()
+      sar.spec.resourceAttributes = new k8s.V1ResourceAttributes()
+      sar.spec.resourceAttributes.verb = verb
+      sar.spec.resourceAttributes.namespace = namespace()
+      sar.spec.resourceAttributes.group = resource.group
+      sar.spec.resourceAttributes.resource = resource.resource
+      sar.spec.resourceAttributes.subresource = resource.subresource
+      asyncs.push(k8sAuthorizationV1Api.createSelfSubjectAccessReview(sar))
+    }
+  }
+  const responses = await Promise.all(asyncs)
+  return responses.every(resp => resp.body.status?.allowed)
+}
+ 
+export async function isPodContainerAlpine(
+  podName: string,
+  containerName: string
+): Promise<boolean> {
+  let isAlpine = true
+  try {
+    await execPodStep(
+      [
+        'sh',
+        '-c',
+        `'[ $(cat /etc/*release* | grep -i -e "^ID=*alpine*" -c) != 0 ] || exit 1'`
+      ],
+      podName,
+      containerName
+    )
+  } catch (err) {
+    isAlpine = false
+  }
+ 
+  return isAlpine
+}
+ 
+async function getCurrentNodeName(): Promise<string> {
+  const resp = await k8sApi.readNamespacedPod(getRunnerPodName(), namespace())
+ 
+  const nodeName = resp.body.spec?.nodeName
+  Iif (!nodeName) {
+    throw new Error('Failed to determine node name')
+  }
+  return nodeName
+}
+ 
+async function getPodAffinity(nodeName: string): Promise<k8s.V1Affinity> {
+  const affinity = new k8s.V1Affinity()
+  affinity.nodeAffinity = new k8s.V1NodeAffinity()
+  affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution =
+    new k8s.V1NodeSelector()
+  affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms =
+    [
+      {
+        matchExpressions: [
+          {
+            key: 'kubernetes.io/hostname',
+            operator: 'In',
+            values: [nodeName]
+          }
+        ]
+      }
+    ]
+  return affinity
+}
+ 
+async function getPreferredPodAffinity(
+  nodeName: string
+): Promise<k8s.V1Affinity> {
+  const affinity = new k8s.V1Affinity()
+  affinity.nodeAffinity = new k8s.V1NodeAffinity()
+ 
+  // 创建 PreferredSchedulingTerm 对象
+  const preferredTerm = new k8s.V1PreferredSchedulingTerm()
+  preferredTerm.weight = 1 // 设置权重(1-100)
+ 
+  // 创建 NodeSelectorTerm
+  preferredTerm.preference = new k8s.V1NodeSelectorTerm()
+  preferredTerm.preference.matchExpressions = [
+    {
+      key: 'kubernetes.io/hostname',
+      operator: 'In',
+      values: [nodeName]
+    }
+  ]
+ 
+  // 将 PreferredSchedulingTerm 添加到数组中
+  affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution = [
+    preferredTerm
+  ]
+ 
+  return affinity
+}
+ 
+export function namespace(): string {
+  if (process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE']) {
+    return process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE']
+  }
+ 
+  const context = kc.getContexts().find(ctx => ctx.namespace)
+  Iif (!context?.namespace) {
+    throw new Error(
+      'Failed to determine namespace, falling back to `default`. Namespace should be set in context, or in env variable "ACTIONS_RUNNER_KUBERNETES_NAMESPACE"'
+    )
+  }
+  return context.namespace
+}
+ 
+class BackOffManager {
+  private backOffSeconds = 1
+  totalTime = 0
+  constructor(private throwAfterSeconds?: number) {
+    Iif (!throwAfterSeconds || throwAfterSeconds < 0) {
+      this.throwAfterSeconds = undefined
+    }
+  }
+ 
+  async backOff(): Promise<void> {
+    await new Promise(resolve =>
+      setTimeout(resolve, this.backOffSeconds * 1000)
+    )
+    this.totalTime += this.backOffSeconds
+    Iif (this.throwAfterSeconds && this.throwAfterSeconds < this.totalTime) {
+      throw new Error('backoff timeout')
+    }
+    if (this.backOffSeconds < 20) {
+      this.backOffSeconds *= 2
+    }
+    Iif (this.backOffSeconds > 20) {
+      this.backOffSeconds = 20
+    }
+  }
+}
+ 
+export function containerPorts(
+  container: ContainerInfo
+): k8s.V1ContainerPort[] {
+  const ports: k8s.V1ContainerPort[] = []
+  Iif (!container.portMappings?.length) {
+    return ports
+  }
+  for (const portDefinition of container.portMappings) {
+    const portProtoSplit = portDefinition.split('/')
+    Iif (portProtoSplit.length > 2) {
+      throw new Error(`Unexpected port format: ${portDefinition}`)
+    }
+ 
+    const port = new k8s.V1ContainerPort()
+    port.protocol =
+      portProtoSplit.length === 2 ? portProtoSplit[1].toUpperCase() : 'TCP'
+ 
+    const portSplit = portProtoSplit[0].split(':')
+    Iif (portSplit.length > 2) {
+      throw new Error('ports should have at most one ":" separator')
+    }
+ 
+    const parsePort = (p: string): number => {
+      const num = Number(p)
+      Iif (!Number.isInteger(num) || num < 1 || num > 65535) {
+        throw new Error(`invalid container port: ${p}`)
+      }
+      return num
+    }
+ 
+    if (portSplit.length === 1) {
+      port.containerPort = parsePort(portSplit[0])
+    } else {
+      port.hostPort = parsePort(portSplit[0])
+      port.containerPort = parsePort(portSplit[1])
+    }
+ 
+    ports.push(port)
+  }
+  return ports
+}
+ 
+export async function getPodByName(name): Promise<k8s.V1Pod> {
+  const { body } = await k8sApi.readNamespacedPod(name, namespace())
+  return body
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/prettify.css b/packages/k8s/coverage/lcov-report/prettify.css new file mode 100644 index 00000000..b317a7cd --- /dev/null +++ b/packages/k8s/coverage/lcov-report/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/packages/k8s/coverage/lcov-report/prettify.js b/packages/k8s/coverage/lcov-report/prettify.js new file mode 100644 index 00000000..b3225238 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/packages/k8s/coverage/lcov-report/sort-arrow-sprite.png b/packages/k8s/coverage/lcov-report/sort-arrow-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..03f704a609c6fd0dbfdac63466a7d7c958b5cbf3 GIT binary patch literal 209 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>Jii$m5978H@?Fn+^JD|Y9yzj{W`447Gxa{7*dM7nnnD-Lb z6^}Hx2)'; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSearchBox(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/packages/k8s/coverage/lcov-report/src/hooks/cleanup-job.ts.html b/packages/k8s/coverage/lcov-report/src/hooks/cleanup-job.ts.html new file mode 100644 index 00000000..584c5eb1 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/hooks/cleanup-job.ts.html @@ -0,0 +1,100 @@ + + + + + + Code coverage report for src/hooks/cleanup-job.ts + + + + + + + + + +
+
+

All files / src/hooks cleanup-job.ts

+
+ +
+ 66.66% + Statements + 2/3 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 66.66% + Lines + 2/3 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +61x +  +1x +  +  + 
import { prunePods, pruneSecrets } from '../k8s'
+ 
+export async function cleanupJob(): Promise<void> {
+  await Promise.all([prunePods(), pruneSecrets()])
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/hooks/constants.ts.html b/packages/k8s/coverage/lcov-report/src/hooks/constants.ts.html new file mode 100644 index 00000000..76ab4987 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/hooks/constants.ts.html @@ -0,0 +1,280 @@ + + + + + + Code coverage report for src/hooks/constants.ts + + + + + + + + + +
+
+

All files / src/hooks constants.ts

+
+ +
+ 53.12% + Statements + 17/32 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 10% + Functions + 1/10 +
+ + +
+ 51.61% + Lines + 16/31 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +661x +  +1x +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +1x +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +1x +1x +1x +1x +1x +  +1x +  +  +  +  +  +1x +  +  +  +1x +  +  +  +1x +  +  +1x + 
import { v4 as uuidv4 } from 'uuid'
+ 
+export function getRunnerPodName(): string {
+  const name = process.env.ACTIONS_RUNNER_POD_NAME
+  Iif (!name) {
+    throw new Error(
+      "'ACTIONS_RUNNER_POD_NAME' env is required, please contact your self hosted runner administrator"
+    )
+  }
+  return name
+}
+ 
+export function getJobPodName(): string {
+  return `${getRunnerPodName().substring(
+    0,
+    MAX_POD_NAME_LENGTH - '-workflow'.length
+  )}-workflow`
+}
+ 
+export function getStepPodName(): string {
+  return `${getRunnerPodName().substring(
+    0,
+    MAX_POD_NAME_LENGTH - ('-step-'.length + STEP_POD_NAME_SUFFIX_LENGTH)
+  )}-step-${uuidv4().substring(0, STEP_POD_NAME_SUFFIX_LENGTH)}`
+}
+ 
+export function getVolumeClaimName(): string {
+  const name = process.env.ACTIONS_RUNNER_CLAIM_NAME
+  Iif (!name) {
+    return `${getRunnerPodName()}-work`
+  }
+  return name
+}
+ 
+export function getSecretName(): string {
+  return `${getRunnerPodName().substring(
+    0,
+    MAX_POD_NAME_LENGTH - ('-secret-'.length + STEP_POD_NAME_SUFFIX_LENGTH)
+  )}-secret-${uuidv4().substring(0, STEP_POD_NAME_SUFFIX_LENGTH)}`
+}
+ 
+export const MAX_POD_NAME_LENGTH = 63
+export const STEP_POD_NAME_SUFFIX_LENGTH = 8
+export const CONTAINER_EXTENSION_PREFIX = '$'
+export const JOB_CONTAINER_NAME = 'job'
+export const JOB_CONTAINER_EXTENSION_NAME = '$job'
+ 
+export class RunnerInstanceLabel {
+  private podName: string
+  constructor() {
+    this.podName = getRunnerPodName()
+  }
+ 
+  get key(): string {
+    return 'runner-pod'
+  }
+ 
+  get value(): string {
+    return this.podName
+  }
+ 
+  toString(): string {
+    return `runner-pod=${this.podName}`
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/hooks/index.html b/packages/k8s/coverage/lcov-report/src/hooks/index.html new file mode 100644 index 00000000..e597c42c --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/hooks/index.html @@ -0,0 +1,191 @@ + + + + + + Code coverage report for src/hooks + + + + + + + + + +
+
+

All files src/hooks

+
+ +
+ 36.55% + Statements + 87/238 +
+ + +
+ 12.89% + Branches + 33/256 +
+ + +
+ 16% + Functions + 4/25 +
+ + +
+ 38.24% + Lines + 83/217 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
cleanup-job.ts +
+
66.66%2/30%0/10%0/166.66%2/3
constants.ts +
+
53.12%17/320%0/210%1/1051.61%16/31
index.ts +
+
100%4/4100%0/0100%0/0100%4/4
prepare-job.ts +
+
46.84%52/11123.57%33/14030%3/1050.51%49/97
run-container-step.ts +
+
8.21%6/730%0/990%0/38.95%6/67
run-script-step.ts +
+
40%6/150%0/140%0/140%6/15
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/hooks/index.ts.html b/packages/k8s/coverage/lcov-report/src/hooks/index.ts.html new file mode 100644 index 00000000..5df4c176 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/hooks/index.ts.html @@ -0,0 +1,97 @@ + + + + + + Code coverage report for src/hooks/index.ts + + + + + + + + + +
+
+

All files / src/hooks index.ts

+
+ +
+ 100% + Statements + 4/4 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 4/4 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +51x +1x +1x +1x + 
export * from './cleanup-job'
+export * from './prepare-job'
+export * from './run-script-step'
+export * from './run-container-step'
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/hooks/prepare-job.ts.html b/packages/k8s/coverage/lcov-report/src/hooks/prepare-job.ts.html new file mode 100644 index 00000000..695c5ea5 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/hooks/prepare-job.ts.html @@ -0,0 +1,886 @@ + + + + + + Code coverage report for src/hooks/prepare-job.ts + + + + + + + + + +
+
+

All files / src/hooks prepare-job.ts

+
+ +
+ 46.84% + Statements + 52/111 +
+ + +
+ 23.57% + Branches + 33/140 +
+ + +
+ 30% + Functions + 3/10 +
+ + +
+ 50.51% + Lines + 49/97 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +2681x +1x +  +1x +  +  +  +  +  +1x +1x +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +1x +  +1x +  +  +  +3x +  +  +  +6x +  +3x +6x +  +3x +3x +3x +3x +  +  +  +  +  +  +  +3x +3x +  +  +  +  +  +  +  +  +  +  +  +3x +  +  +  +3x +  +3x +  +  +  +  +  +  +  +  +  +  +  +  +3x +  +  +3x +  +  +  +  +6x +  +  +  +  +  +  +  +6x +  +2x +  +3x +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +3x +6x +  +  +  +  +  +  +  +  +1x +  +  +3x +  +  +3x +3x +3x +  +  +3x +  +  +  +  +3x +  +  +  +3x +3x +  +  +3x +3x +  +  +3x +3x +  +  +  +  +  +  +  +3x +  +  +  +  +3x +3x +  +  +  +  +  +3x +  +  +  +  +3x +3x +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as core from '@actions/core'
+import * as io from '@actions/io'
+import * as k8s from '@kubernetes/client-node'
+import {
+  JobContainerInfo,
+  ContextPorts,
+  PrepareJobArgs,
+  writeToResponseFile
+} from 'hooklib'
+import path from 'path'
+import {
+  containerPorts,
+  createPod,
+  isPodContainerAlpine,
+  prunePods,
+  waitForPodPhases,
+  getPrepareJobTimeoutSeconds
+} from '../k8s'
+import {
+  containerVolumes,
+  DEFAULT_CONTAINER_ENTRY_POINT,
+  DEFAULT_CONTAINER_ENTRY_POINT_ARGS,
+  generateContainerName,
+  mergeContainerWithOptions,
+  readExtensionFromFile,
+  PodPhase,
+  fixArgs
+} from '../k8s/utils'
+import { CONTAINER_EXTENSION_PREFIX, JOB_CONTAINER_NAME } from './constants'
+ 
+export async function prepareJob(
+  args: PrepareJobArgs,
+  responseFile
+): Promise<void> {
+  Iif (!args.container) {
+    throw new Error('Job Container is required.')
+  }
+ 
+  await prunePods()
+ 
+  const extension = readExtensionFromFile()
+  await copyExternalsToRoot()
+ 
+  let container: k8s.V1Container | undefined = undefined
+  if (args.container?.image) {
+    core.debug(`Using image '${args.container.image}' for job image`)
+    container = createContainerSpec(
+      args.container,
+      JOB_CONTAINER_NAME,
+      true,
+      extension
+    )
+  }
+ 
+  let services: k8s.V1Container[] = []
+  Iif (args.services?.length) {
+    services = args.services.map(service => {
+      core.debug(`Adding service '${service.image}' to pod definition`)
+      return createContainerSpec(
+        service,
+        generateContainerName(service.image),
+        false,
+        extension
+      )
+    })
+  }
+ 
+  Iif (!container && !services?.length) {
+    throw new Error('No containers exist, skipping hook invocation')
+  }
+ 
+  let createdPod: k8s.V1Pod | undefined = undefined
+  try {
+    createdPod = await createPod(
+      container,
+      services,
+      args.container.registry,
+      extension
+    )
+  } catch (err) {
+    await prunePods()
+    core.debug(`createPod failed: ${JSON.stringify(err)}`)
+    const message = (err as any)?.response?.body?.message || err
+    throw new Error(`failed to create job pod: ${message}`)
+  }
+ 
+  Iif (!createdPod?.metadata?.name) {
+    throw new Error('created pod should have metadata.name')
+  }
+  core.debug(
+    `Job pod created, waiting for it to come online ${createdPod?.metadata?.name}`
+  )
+ 
+  try {
+    await waitForPodPhases(
+      createdPod.metadata.name,
+      new Set([PodPhase.RUNNING]),
+      new Set([PodPhase.PENDING]),
+      getPrepareJobTimeoutSeconds()
+    )
+  } catch (err) {
+    try {
+      await prunePods()
+    } catch (pruneErr) {
+      core.error(`Failed to prune pods: ${pruneErr instanceof Error ? pruneErr.message : String(pruneErr)}`)
+    }
+    const message = err instanceof Error ? err.message : String(err)
+    throw new Error(`pod failed to come online:\n${message}`)
+  }
+ 
+  core.debug('Job pod is ready for traffic')
+ 
+  let isAlpine = false
+  try {
+    isAlpine = await isPodContainerAlpine(
+      createdPod.metadata.name,
+      JOB_CONTAINER_NAME
+    )
+  } catch (err) {
+    core.debug(
+      `Failed to determine if the pod is alpine: ${JSON.stringify(err)}`
+    )
+    const message = (err as any)?.response?.body?.message || err
+    throw new Error(`failed to determine if the pod is alpine: ${message}`)
+  }
+  core.debug(`Setting isAlpine to ${isAlpine}`)
+  generateResponseFile(responseFile, args, createdPod, isAlpine)
+}
+ 
+function generateResponseFile(
+  responseFile: string,
+  args: PrepareJobArgs,
+  appPod: k8s.V1Pod,
+  isAlpine
+): void {
+  Iif (!appPod.metadata?.name) {
+    throw new Error('app pod must have metadata.name specified')
+  }
+  const response = {
+    state: {
+      jobPod: appPod.metadata.name
+    },
+    context: {},
+    isAlpine
+  }
+ 
+  const mainContainer = appPod.spec?.containers?.find(
+    c => c.name === JOB_CONTAINER_NAME
+  )
+  Iif (mainContainer) {
+    const mainContainerContextPorts: ContextPorts = {}
+    Iif (mainContainer?.ports) {
+      for (const port of mainContainer.ports) {
+        mainContainerContextPorts[port.containerPort] =
+          mainContainerContextPorts.hostPort
+      }
+    }
+ 
+    response.context['container'] = {
+      image: mainContainer.image,
+      ports: mainContainerContextPorts
+    }
+  }
+ 
+  Iif (args.services?.length) {
+    const serviceContainerNames =
+      args.services?.map(s => generateContainerName(s.image)) || []
+ 
+    response.context['services'] = appPod?.spec?.containers
+      ?.filter(c => serviceContainerNames.includes(c.name))
+      .map(c => {
+        const ctxPorts: ContextPorts = {}
+        Iif (c.ports?.length) {
+          for (const port of c.ports) {
+            ctxPorts[port.containerPort] = port.hostPort
+          }
+        }
+ 
+        return {
+          image: c.image,
+          ports: ctxPorts
+        }
+      })
+  }
+ 
+  writeToResponseFile(responseFile, JSON.stringify(response))
+}
+ 
+async function copyExternalsToRoot(): Promise<void> {
+  const workspace = process.env['RUNNER_WORKSPACE']
+  if (workspace) {
+    await io.cp(
+      path.join(workspace, '../../externals'),
+      path.join(workspace, '../externals'),
+      { force: true, recursive: true, copySourceDirectory: false }
+    )
+  }
+}
+ 
+export function createContainerSpec(
+  container: JobContainerInfo,
+  name: string,
+  IjobContainer = false,
+  extension?: k8s.V1PodTemplateSpec
+): k8s.V1Container {
+  if (!container.entryPoint && jobContainer) {
+    container.entryPoint = DEFAULT_CONTAINER_ENTRY_POINT
+    container.entryPointArgs = DEFAULT_CONTAINER_ENTRY_POINT_ARGS
+  }
+ 
+  const podContainer = {
+    name,
+    image: container.image,
+    ports: containerPorts(container)
+  } as k8s.V1Container
+  Iif (container.workingDirectory) {
+    podContainer.workingDir = container.workingDirectory
+  }
+ 
+  if (container.entryPoint) {
+    podContainer.command = [container.entryPoint]
+  }
+ 
+  if (container.entryPointArgs?.length > 0) {
+    podContainer.args = fixArgs(container.entryPointArgs)
+  }
+ 
+  podContainer.env = []
+  for (const [key, value] of Object.entries(
+    container['environmentVariables']
+  )) {
+    Iif (value && key !== 'HOME') {
+      podContainer.env.push({ name: key, value: value as string })
+    }
+  }
+ 
+  podContainer.env.push({
+    name: 'GITHUB_ACTIONS',
+    value: 'true'
+  })
+ 
+  if (!('CI' in container['environmentVariables'])) {
+    podContainer.env.push({
+      name: 'CI',
+      value: 'true'
+    })
+  }
+ 
+  podContainer.volumeMounts = containerVolumes(
+    container.userMountVolumes,
+    jobContainer
+  )
+ 
+  if (!extension) {
+    return podContainer
+  }
+ 
+  const from = extension.spec?.containers?.find(
+    c => c.name === CONTAINER_EXTENSION_PREFIX + name
+  )
+ 
+  Iif (from) {
+    mergeContainerWithOptions(podContainer, from)
+  }
+ 
+  return podContainer
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/hooks/run-container-step.ts.html b/packages/k8s/coverage/lcov-report/src/hooks/run-container-step.ts.html new file mode 100644 index 00000000..597716b9 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/hooks/run-container-step.ts.html @@ -0,0 +1,592 @@ + + + + + + Code coverage report for src/hooks/run-container-step.ts + + + + + + + + + +
+
+

All files / src/hooks run-container-step.ts

+
+ +
+ 8.21% + Statements + 6/73 +
+ + +
+ 0% + Branches + 0/99 +
+ + +
+ 0% + Functions + 0/3 +
+ + +
+ 8.95% + Lines + 6/67 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +1701x +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as core from '@actions/core'
+import * as k8s from '@kubernetes/client-node'
+import { RunContainerStepArgs } from 'hooklib'
+import {
+  createJob,
+  createSecretForEnvs,
+  describePodFailure,
+  getContainerJobPodName,
+  getContainerTerminatedErrors,
+  getPodByName,
+  getPodLogs,
+  getPodStatus,
+  waitForJobToComplete,
+  waitForPodPhases
+} from '../k8s'
+import {
+  containerVolumes,
+  fixArgs,
+  mergeContainerWithOptions,
+  PodPhase,
+  readExtensionFromFile
+} from '../k8s/utils'
+import { JOB_CONTAINER_EXTENSION_NAME, JOB_CONTAINER_NAME } from './constants'
+ 
+export async function runContainerStep(
+  stepContainer: RunContainerStepArgs
+): Promise<number> {
+  Iif (stepContainer.dockerfile) {
+    throw new Error('Building container actions is not currently supported')
+  }
+ 
+  let secretName: string | undefined = undefined
+  if (IstepContainer.environmentVariables) {
+    try {
+      const envs = JSON.parse(
+        JSON.stringify(stepContainer.environmentVariables)
+      )
+      envs['GITHUB_ACTIONS'] = 'true'
+      Iif (!('CI' in envs)) {
+        envs.CI = 'true'
+      }
+      secretName = await createSecretForEnvs(envs)
+    } catch (err) {
+      core.debug(`createSecretForEnvs failed: ${JSON.stringify(err)}`)
+      const message = (err as any)?.response?.body?.message || err
+      throw new Error(`failed to create script environment: ${message}`)
+    }
+  }
+ 
+  const extension = readExtensionFromFile()
+ 
+  core.debug(`Created secret ${secretName} for container job envs`)
+  const container = createContainerSpec(stepContainer, secretName, extension)
+ 
+  let job: k8s.V1Job
+  try {
+    job = await createJob(container, extension)
+  } catch (err) {
+    core.debug(`createJob failed: ${JSON.stringify(err)}`)
+    const message = (err as any)?.response?.body?.message || err
+    throw new Error(`failed to run script step: ${message}`)
+  }
+ 
+  Iif (!job.metadata?.name) {
+    throw new Error(
+      `Expected job ${JSON.stringify(
+        job
+      )} to have correctly set the metadata.name`
+    )
+  }
+  core.debug(`Job created, waiting for pod to start: ${job.metadata?.name}`)
+ 
+  let podName: string
+  try {
+    podName = await getContainerJobPodName(job.metadata.name)
+  } catch (err) {
+    core.debug(`getContainerJobPodName failed: ${JSON.stringify(err)}`)
+    const message = (err as any)?.response?.body?.message || err
+    throw new Error(`failed to get container job pod name: ${message}`)
+  }
+ 
+  await waitForPodPhases(
+    podName,
+    new Set([
+      PodPhase.COMPLETED,
+      PodPhase.RUNNING,
+      PodPhase.SUCCEEDED,
+      PodPhase.FAILED
+    ]),
+    new Set([PodPhase.PENDING, PodPhase.UNKNOWN])
+  )
+  core.debug('Container step is running or complete, pulling logs')
+ 
+  await getPodLogs(podName, JOB_CONTAINER_NAME)
+ 
+  core.debug('Waiting for container job to complete')
+  await waitForJobToComplete(job.metadata.name)
+ 
+  // pod has failed so pull the status code from the container
+  const status = await getPodStatus(podName)
+  Iif (status?.phase === 'Succeeded') {
+    return 0
+  }
+  Iif (!status?.containerStatuses?.length) {
+    core.error(
+      `Can't determine container status from response:  ${JSON.stringify(
+        status
+      )}`
+    )
+    return 1
+  }
+ 
+  const pod = await getPodByName(podName)
+  const terminatedErrors = getContainerTerminatedErrors(pod)
+  if (IterminatedErrors.length > 0) {
+    const details = await describePodFailure(podName)
+    core.error(
+      `Pod ${podName} has unrecoverable container errors:\n${terminatedErrors.join('\n')}\n${details}`
+    )
+    return 1
+  }
+ 
+  const exitCode =
+    status.containerStatuses[status.containerStatuses.length - 1].state
+      ?.terminated?.exitCode
+  return Number(exitCode) || 1
+}
+ 
+function createContainerSpec(
+  container: RunContainerStepArgs,
+  secretName?: string,
+  extension?: k8s.V1PodTemplateSpec
+): k8s.V1Container {
+  const podContainer = new k8s.V1Container()
+  podContainer.name = JOB_CONTAINER_NAME
+  podContainer.image = container.image
+  podContainer.workingDir = container.workingDirectory
+  podContainer.command = container.entryPoint
+    ? [container.entryPoint]
+    : undefined
+  podContainer.args = container.entryPointArgs?.length
+    ? fixArgs(container.entryPointArgs)
+    : undefined
+ 
+  Iif (secretName) {
+    podContainer.envFrom = [
+      {
+        secretRef: {
+          name: secretName,
+          optional: false
+        }
+      }
+    ]
+  }
+  podContainer.volumeMounts = containerVolumes(undefined, false, true)
+ 
+  Iif (!extension) {
+    return podContainer
+  }
+ 
+  const from = extension.spec?.containers?.find(
+    c => c.name === JOB_CONTAINER_EXTENSION_NAME
+  )
+  Iif (from) {
+    mergeContainerWithOptions(podContainer, from)
+  }
+ 
+  return podContainer
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/hooks/run-script-step.ts.html b/packages/k8s/coverage/lcov-report/src/hooks/run-script-step.ts.html new file mode 100644 index 00000000..1bcbb0f0 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/hooks/run-script-step.ts.html @@ -0,0 +1,199 @@ + + + + + + Code coverage report for src/hooks/run-script-step.ts + + + + + + + + + +
+
+

All files / src/hooks run-script-step.ts

+
+ +
+ 40% + Statements + 6/15 +
+ + +
+ 0% + Branches + 0/14 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 40% + Lines + 6/15 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39  +1x +1x +  +1x +1x +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
/* eslint-disable @typescript-eslint/no-unused-vars */
+import * as fs from 'fs'
+import * as core from '@actions/core'
+import { RunScriptStepArgs } from 'hooklib'
+import { execPodStep } from '../k8s'
+import { writeEntryPointScript } from '../k8s/utils'
+import { JOB_CONTAINER_NAME } from './constants'
+ 
+export async function runScriptStep(
+  args: RunScriptStepArgs,
+  state,
+  responseFile
+): Promise<void> {
+  const { entryPoint, entryPointArgs, environmentVariables } = args
+  const { containerPath, runnerPath } = writeEntryPointScript(
+    args.workingDirectory,
+    entryPoint,
+    entryPointArgs,
+    args.prependPath,
+    environmentVariables
+  )
+ 
+  args.entryPoint = 'sh'
+  args.entryPointArgs = ['-e', containerPath]
+  try {
+    await execPodStep(
+      [args.entryPoint, ...args.entryPointArgs],
+      state.jobPod,
+      JOB_CONTAINER_NAME
+    )
+  } catch (err) {
+    core.debug(`execPodStep failed: ${JSON.stringify(err)}`)
+    const message = (err as any)?.response?.body?.message || err
+    throw new Error(`failed to run script step: ${message}`)
+  } finally {
+    fs.rmSync(runnerPath)
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/k8s/index.html b/packages/k8s/coverage/lcov-report/src/k8s/index.html new file mode 100644 index 00000000..fe188308 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/k8s/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for src/k8s + + + + + + + + + +
+
+

All files src/k8s

+
+ +
+ 15.36% + Statements + 98/638 +
+ + +
+ 3.05% + Branches + 14/458 +
+ + +
+ 10.44% + Functions + 7/67 +
+ + +
+ 18.11% + Lines + 98/541 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
index.ts +
+
11.54%56/4851.46%5/3425.45%3/5513.49%56/415
utils.ts +
+
27.45%42/1537.75%9/11633.33%4/1233.33%42/126
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/k8s/index.ts.html b/packages/k8s/coverage/lcov-report/src/k8s/index.ts.html new file mode 100644 index 00000000..88919100 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/k8s/index.ts.html @@ -0,0 +1,3028 @@ + + + + + + Code coverage report for src/k8s/index.ts + + + + + + + + + +
+
+

All files / src/k8s index.ts

+
+ +
+ 11.54% + Statements + 56/485 +
+ + +
+ 1.46% + Branches + 5/342 +
+ + +
+ 5.45% + Functions + 3/55 +
+ + +
+ 13.49% + Lines + 56/415 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +9821x +1x +  +1x +1x +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +1x +  +1x +  +1x +1x +1x +  +1x +  +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +1x +  +  +  +  +  +1x +  +  +  +  +  +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +3x +  +3x +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +1x +  +  +3x +3x +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  + 
import * as core from '@actions/core'
+import * as k8s from '@kubernetes/client-node'
+import { ContainerInfo, Registry } from 'hooklib'
+import * as stream from 'stream'
+import {
+  getJobPodName,
+  getRunnerPodName,
+  getSecretName,
+  getStepPodName,
+  getVolumeClaimName,
+  RunnerInstanceLabel
+} from '../hooks/constants'
+import {
+  PodPhase,
+  mergePodSpecWithOptions,
+  mergeObjectMeta,
+  useKubeScheduler,
+  fixArgs
+} from './utils'
+ 
+const kc = new k8s.KubeConfig()
+ 
+kc.loadFromDefault()
+ 
+const k8sApi = kc.makeApiClient(k8s.CoreV1Api)
+const k8sBatchV1Api = kc.makeApiClient(k8s.BatchV1Api)
+const k8sAuthorizationV1Api = kc.makeApiClient(k8s.AuthorizationV1Api)
+ 
+const DEFAULT_WAIT_FOR_POD_TIME_SECONDS = 10 * 60 // 10 min
+ 
+export const POD_VOLUME_NAME = 'work'
+ 
+export const requiredPermissions = [
+  {
+    group: '',
+    verbs: ['get', 'list', 'create', 'delete'],
+    resource: 'pods',
+    subresource: ''
+  },
+  {
+    group: '',
+    verbs: ['get', 'create'],
+    resource: 'pods',
+    subresource: 'exec'
+  },
+  {
+    group: '',
+    verbs: ['get', 'list', 'watch'],
+    resource: 'pods',
+    subresource: 'log'
+  },
+  {
+    group: 'batch',
+    verbs: ['get', 'list', 'create', 'delete'],
+    resource: 'jobs',
+    subresource: ''
+  },
+  {
+    group: '',
+    verbs: ['create', 'delete', 'get', 'list'],
+    resource: 'secrets',
+    subresource: ''
+  }
+]
+ 
+export async function createPod(
+  jobContainer?: k8s.V1Container,
+  services?: k8s.V1Container[],
+  registry?: Registry,
+  extension?: k8s.V1PodTemplateSpec
+): Promise<k8s.V1Pod> {
+  const containers: k8s.V1Container[] = []
+  Iif (jobContainer) {
+    containers.push(jobContainer)
+  }
+  Iif (services?.length) {
+    containers.push(...services)
+  }
+ 
+  const appPod = new k8s.V1Pod()
+ 
+  appPod.apiVersion = 'v1'
+  appPod.kind = 'Pod'
+ 
+  appPod.metadata = new k8s.V1ObjectMeta()
+  appPod.metadata.name = getJobPodName()
+ 
+  const instanceLabel = new RunnerInstanceLabel()
+  appPod.metadata.labels = {
+    [instanceLabel.key]: instanceLabel.value
+  }
+  appPod.metadata.annotations = {}
+ 
+  appPod.spec = new k8s.V1PodSpec()
+  appPod.spec.containers = containers
+  appPod.spec.restartPolicy = 'Never'
+ 
+  const nodeName = await getCurrentNodeName()
+  if (IuseKubeScheduler()) {
+    appPod.spec.affinity = await getPodAffinity(nodeName)
+  } else {
+    appPod.spec.affinity = await getPreferredPodAffinity(nodeName)
+  }
+  const claimName = getVolumeClaimName()
+  appPod.spec.volumes = [
+    {
+      name: 'work',
+      persistentVolumeClaim: { claimName }
+    }
+  ]
+ 
+  if (Iregistry) {
+    const secret = await createDockerSecret(registry)
+    Iif (!secret?.metadata?.name) {
+      throw new Error(`created secret does not have secret.metadata.name`)
+    }
+    const secretReference = new k8s.V1LocalObjectReference()
+    secretReference.name = secret.metadata.name
+    appPod.spec.imagePullSecrets = [secretReference]
+  }
+ 
+  Iif (extension?.metadata) {
+    mergeObjectMeta(appPod, extension.metadata)
+  }
+ 
+  Iif (extension?.spec) {
+    mergePodSpecWithOptions(appPod.spec, extension.spec)
+  }
+ 
+  const { body } = await k8sApi.createNamespacedPod(namespace(), appPod)
+  return body
+}
+ 
+export async function createJob(
+  container: k8s.V1Container,
+  extension?: k8s.V1PodTemplateSpec
+): Promise<k8s.V1Job> {
+  const runnerInstanceLabel = new RunnerInstanceLabel()
+ 
+  const job = new k8s.V1Job()
+  job.apiVersion = 'batch/v1'
+  job.kind = 'Job'
+  job.metadata = new k8s.V1ObjectMeta()
+  job.metadata.name = getStepPodName()
+  job.metadata.labels = { [runnerInstanceLabel.key]: runnerInstanceLabel.value }
+  job.metadata.annotations = {}
+ 
+  job.spec = new k8s.V1JobSpec()
+  job.spec.ttlSecondsAfterFinished = 300
+  job.spec.backoffLimit = 0
+  job.spec.template = new k8s.V1PodTemplateSpec()
+ 
+  job.spec.template.spec = new k8s.V1PodSpec()
+  job.spec.template.metadata = new k8s.V1ObjectMeta()
+  job.spec.template.metadata.labels = {}
+  job.spec.template.metadata.annotations = {}
+  job.spec.template.spec.containers = [container]
+  job.spec.template.spec.restartPolicy = 'Never'
+ 
+  const nodeName = await getCurrentNodeName()
+  if (IuseKubeScheduler()) {
+    job.spec.template.spec.affinity = await getPodAffinity(nodeName)
+  } else {
+    job.spec.template.spec.affinity = await getPreferredPodAffinity(nodeName)
+  }
+ 
+  const claimName = getVolumeClaimName()
+  job.spec.template.spec.volumes = [
+    {
+      name: 'work',
+      persistentVolumeClaim: { claimName }
+    }
+  ]
+ 
+  Iif (extension) {
+    Iif (extension.metadata) {
+      // apply metadata both to the job and the pod created by the job
+      mergeObjectMeta(job, extension.metadata)
+      mergeObjectMeta(job.spec.template, extension.metadata)
+    }
+    Iif (extension.spec) {
+      mergePodSpecWithOptions(job.spec.template.spec, extension.spec)
+    }
+  }
+ 
+  const { body } = await k8sBatchV1Api.createNamespacedJob(namespace(), job)
+  return body
+}
+ 
+export async function getContainerJobPodName(jobName: string): Promise<string> {
+  const selector = `job-name=${jobName}`
+  const backOffManager = new BackOffManager(60)
+  while (Itrue) {
+    const podList = await k8sApi.listNamespacedPod(
+      namespace(),
+      undefined,
+      undefined,
+      undefined,
+      undefined,
+      selector,
+      1
+    )
+ 
+    if (I!podList.body.items?.length) {
+      await backOffManager.backOff()
+      continue
+    }
+ 
+    Iif (!podList.body.items[0].metadata?.name) {
+      throw new Error(
+        `Failed to determine the name of the pod for job ${jobName}`
+      )
+    }
+    return podList.body.items[0].metadata.name
+  }
+}
+ 
+export async function deletePod(podName: string): Promise<void> {
+  await k8sApi.deleteNamespacedPod(
+    podName,
+    namespace(),
+    undefined,
+    undefined,
+    0
+  )
+}
+ 
+export async function execPodStep(
+  command: string[],
+  podName: string,
+  containerName: string,
+  stdin?: stream.Readable
+): Promise<void> {
+  const exec = new k8s.Exec(kc)
+  command = fixArgs(command)
+  // Exec returns a websocket. If websocket fails, we should reject the promise. Otherwise, websocket will call a callback. Since at that point, websocket is not failing, we can safely resolve or reject the promise.
+  await new Promise(function (resolve, reject) {
+    exec
+      .exec(
+        namespace(),
+        podName,
+        containerName,
+        command,
+        process.stdout,
+        process.stderr,
+        stdin ?? null,
+        false /* tty */,
+        resp => {
+          // kube.exec returns an error if exit code is not 0, but we can't actually get the exit code
+          if (resp.status === 'Success') {
+            resolve(resp.code)
+          } else {
+            core.debug(
+              JSON.stringify({
+                message: resp?.message,
+                details: resp?.details
+              })
+            )
+            reject(resp?.message)
+          }
+        }
+      )
+      // If exec.exec fails, explicitly reject the outer promise
+      // eslint-disable-next-line github/no-then
+      .catch(e => reject(e))
+  })
+}
+ 
+export async function waitForJobToComplete(jobName: string): Promise<void> {
+  const backOffManager = new BackOffManager()
+  while (Itrue) {
+    try {
+      Iif (await isJobSucceeded(jobName)) {
+        return
+      }
+    } catch (error) {
+      throw new Error(`job ${jobName} has failed`)
+    }
+    await backOffManager.backOff()
+  }
+}
+ 
+export async function createDockerSecret(
+  registry: Registry
+): Promise<k8s.V1Secret> {
+  const authContent = {
+    auths: {
+      [registry.serverUrl || 'https://index.docker.io/v1/']: {
+        username: registry.username,
+        password: registry.password,
+        auth: Buffer.from(`${registry.username}:${registry.password}`).toString(
+          'base64'
+        )
+      }
+    }
+  }
+ 
+  const runnerInstanceLabel = new RunnerInstanceLabel()
+ 
+  const secretName = getSecretName()
+  const secret = new k8s.V1Secret()
+  secret.immutable = true
+  secret.apiVersion = 'v1'
+  secret.metadata = new k8s.V1ObjectMeta()
+  secret.metadata.name = secretName
+  secret.metadata.namespace = namespace()
+  secret.metadata.labels = {
+    [runnerInstanceLabel.key]: runnerInstanceLabel.value
+  }
+  secret.type = 'kubernetes.io/dockerconfigjson'
+  secret.kind = 'Secret'
+  secret.data = {
+    '.dockerconfigjson': Buffer.from(JSON.stringify(authContent)).toString(
+      'base64'
+    )
+  }
+ 
+  const { body } = await k8sApi.createNamespacedSecret(namespace(), secret)
+  return body
+}
+ 
+export async function createSecretForEnvs(envs: {
+  [key: string]: string
+}): Promise<string> {
+  const runnerInstanceLabel = new RunnerInstanceLabel()
+ 
+  const secret = new k8s.V1Secret()
+  const secretName = getSecretName()
+  secret.immutable = true
+  secret.apiVersion = 'v1'
+  secret.metadata = new k8s.V1ObjectMeta()
+  secret.metadata.name = secretName
+ 
+  secret.metadata.labels = {
+    [runnerInstanceLabel.key]: runnerInstanceLabel.value
+  }
+  secret.kind = 'Secret'
+  secret.data = {}
+  for (const [key, value] of Object.entries(envs)) {
+    secret.data[key] = Buffer.from(value).toString('base64')
+  }
+ 
+  await k8sApi.createNamespacedSecret(namespace(), secret)
+  return secretName
+}
+ 
+export async function deleteSecret(secretName: string): Promise<void> {
+  await k8sApi.deleteNamespacedSecret(secretName, namespace())
+}
+ 
+export async function pruneSecrets(): Promise<void> {
+  const secretList = await k8sApi.listNamespacedSecret(
+    namespace(),
+    undefined,
+    undefined,
+    undefined,
+    undefined,
+    new RunnerInstanceLabel().toString()
+  )
+  Iif (!secretList.body.items.length) {
+    return
+  }
+ 
+  await Promise.all(
+    secretList.body.items.map(
+      secret => secret.metadata?.name && deleteSecret(secret.metadata.name)
+    )
+  )
+}
+ 
+export const UNRECOVERABLE_WAITING_REASONS = new Set([
+  'ImagePullBackOff',
+  'ErrImagePull',
+  'InvalidImageName',
+  'CreateContainerConfigError',
+  'CreateContainerError'
+])
+ 
+export const UNRECOVERABLE_EVENT_REASONS = new Set([
+  'FailedScheduling',
+  'FailedBinding',
+  'FailedMount'
+])
+ 
+export const UNRECOVERABLE_TERMINATED_REASONS = new Set([
+  'OOMKilled',
+  'Error',
+  'FailedPostStartHookError'
+])
+ 
+const MAX_DIAGNOSTIC_EVENTS = 10
+ 
+export function getUnrecoverableWaitingReasons(): Set<string> {
+  const extra = process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_WAITING_REASONS']
+  Iif (!extra) {
+    return UNRECOVERABLE_WAITING_REASONS
+  }
+  const reasons = new Set(UNRECOVERABLE_WAITING_REASONS)
+  for (const reason of extra.split(',')) {
+    const trimmed = reason.trim()
+    Iif (trimmed) {
+      reasons.add(trimmed)
+    }
+  }
+  return reasons
+}
+ 
+export function getUnrecoverableEventReasons(): Set<string> {
+  const extra = process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_EVENT_REASONS']
+  Iif (!extra) {
+    return UNRECOVERABLE_EVENT_REASONS
+  }
+  const reasons = new Set(UNRECOVERABLE_EVENT_REASONS)
+  for (const reason of extra.split(',')) {
+    const trimmed = reason.trim()
+    Iif (trimmed) {
+      reasons.add(trimmed)
+    }
+  }
+  return reasons
+}
+ 
+export function getUnrecoverableTerminatedReasons(): Set<string> {
+  const extra =
+    process.env['ACTIONS_RUNNER_K8S_UNRECOVERABLE_TERMINATED_REASONS']
+  Iif (!extra) {
+    return UNRECOVERABLE_TERMINATED_REASONS
+  }
+  const reasons = new Set(UNRECOVERABLE_TERMINATED_REASONS)
+  for (const reason of extra.split(',')) {
+    const trimmed = reason.trim()
+    Iif (trimmed) {
+      reasons.add(trimmed)
+    }
+  }
+  return reasons
+}
+ 
+export function getContainerErrors(pod: k8s.V1Pod): string[] {
+  const errors: string[] = []
+  const unrecoverableReasons = getUnrecoverableWaitingReasons()
+  const allStatuses = [
+    ...(pod.status?.initContainerStatuses ?? []),
+    ...(pod.status?.containerStatuses ?? [])
+  ]
+  for (const cs of allStatuses) {
+    const waiting = cs.state?.waiting
+    Iif (waiting?.reason && unrecoverableReasons.has(waiting.reason)) {
+      errors.push(
+        `container "${cs.name}": ${waiting.reason}${
+          waiting.message ? ` - ${waiting.message}` : ''
+        }`
+      )
+    }
+  }
+  return errors
+}
+ 
+export async function getPodEventErrors(podName: string): Promise<string[]> {
+  const unrecoverableReasons = getUnrecoverableEventReasons()
+  let items: k8s.CoreV1Event[]
+  try {
+    const { body } = await k8sApi.listNamespacedEvent(
+      namespace(),
+      undefined,
+      undefined,
+      undefined,
+      `involvedObject.name=${podName}`
+    )
+    items = body.items
+  } catch (err) {
+    core.debug(
+      `Could not list events for pod ${podName} (the 'events' permission may be missing): ${
+        err instanceof Error ? err.message : String(err)
+      }`
+    )
+    return []
+  }
+ 
+  const errors: string[] = []
+  for (const e of items) {
+    Iif (
+      e.type === 'Warning' &&
+      e.reason &&
+      unrecoverableReasons.has(e.reason)
+    ) {
+      errors.push(`Event [Warning] ${e.reason}: ${e.message ?? ''}`)
+    }
+  }
+  return errors
+}
+ 
+export function getPodConditionErrors(pod: k8s.V1Pod): string[] {
+  const errors: string[] = []
+  for (const cond of pod.status?.conditions ?? []) {
+    Iif (cond.type === 'PodScheduled' && cond.status === 'False' && cond.reason === 'Unschedulable') {
+      errors.push(
+        `Condition ${cond.type}=False (reason: ${cond.reason ?? ''}): ${
+          cond.message ?? ''
+        }`
+      )
+    }
+  }
+  return errors
+}
+ 
+export function getContainerTerminatedErrors(pod: k8s.V1Pod): string[] {
+  const errors: string[] = []
+  const unrecoverableReasons = getUnrecoverableTerminatedReasons()
+  const allStatuses = [
+    ...(pod.status?.initContainerStatuses ?? []),
+    ...(pod.status?.containerStatuses ?? [])
+  ]
+  for (const cs of allStatuses) {
+    const terminated = cs.state?.terminated
+    Iif (terminated?.reason && unrecoverableReasons.has(terminated.reason)) {
+      errors.push(
+        `container "${cs.name}": ${terminated.reason} (exit code ${terminated.exitCode}) - ${
+          terminated.message ?? ''
+        }`
+      )
+    }
+  }
+  return errors
+}
+ 
+export async function describePodFailure(podName: string): Promise<string> {
+  let pod: k8s.V1Pod
+  try {
+    pod = await readPod(podName)
+  } catch (err) {
+    return `Could not read pod ${podName} for diagnostics: ${
+      err instanceof Error ? err.message : String(err)
+    }`
+  }
+ 
+  const lines: string[] = []
+  const status = pod.status
+ 
+  Iif (status?.phase) {
+    lines.push(
+      `Phase: ${status.phase}${
+        status.reason ? ` (reason: ${status.reason})` : ''
+      }`
+    )
+  }
+  Iif (status?.message) {
+    lines.push(`Message: ${status.message}`)
+  }
+ 
+  const separator = '────────────────────────────────────────────────────────────'
+  lines.push(separator)
+ 
+  for (const cond of status?.conditions ?? []) {
+    Iif (cond.status === 'False') {
+      lines.push(
+        `  ✗ ${cond.type}=False${
+          cond.reason ? ` (${cond.reason})` : ''
+        }${cond.message ? `: ${cond.message}` : ''}`
+      )
+    }
+  }
+ 
+  const allStatuses = [
+    ...(status?.initContainerStatuses ?? []),
+    ...(status?.containerStatuses ?? [])
+  ]
+  for (const cs of allStatuses) {
+    const waiting = cs.state?.waiting
+    Iif (waiting?.reason) {
+      lines.push(
+        `  ✗ container "${cs.name}": ${waiting.reason}${
+          waiting.message ? `\n    ${waiting.message}` : ''
+        }`
+      )
+    }
+    const terminated = cs.state?.terminated
+    Iif (terminated) {
+      lines.push(
+        `  ✗ container "${cs.name}": ${
+          terminated.reason ?? 'Unknown'
+        } (exit code ${terminated.exitCode})${
+          terminated.message ? `\n    ${terminated.message}` : ''
+        }`
+      )
+    }
+  }
+ 
+  lines.push(...(await describePodWarningEvents(podName)))
+ 
+  Iif (!lines.length) {
+    return `No additional diagnostic information available for pod ${podName}`
+  }
+  return lines.join('\n')
+}
+ 
+async function describePodWarningEvents(podName: string): Promise<string[]> {
+  let items: k8s.CoreV1Event[]
+  try {
+    const { body } = await k8sApi.listNamespacedEvent(
+      namespace(),
+      undefined,
+      undefined,
+      undefined,
+      `involvedObject.name=${podName}`
+    )
+    items = body.items
+  } catch (err) {
+    core.debug(
+      `Could not list events for pod ${podName} (the 'events' permission may be missing): ${
+        err instanceof Error ? err.message : String(err)
+      }`
+    )
+    return []
+  }
+ 
+  const warnings = items.filter(e => e.type === 'Warning')
+  Iif (!warnings.length) {
+    return []
+  }
+ 
+  const eventTime = (e: k8s.CoreV1Event): number => {
+    const t = e.lastTimestamp ?? e.eventTime ?? e.firstTimestamp
+    return t ? new Date(t).getTime() : 0
+  }
+  warnings.sort((a, b) => eventTime(a) - eventTime(b))
+ 
+  const recent = warnings.slice(-MAX_DIAGNOSTIC_EVENTS)
+  const lines = recent.map(e => {
+    const count = e.count && e.count > 1 ? ` (x${e.count})` : ''
+    return `Event [Warning] ${e.reason ?? ''}${count}: ${
+      e.message ?? ''
+    }`.trim()
+  })
+  Iif (warnings.length > recent.length) {
+    lines.unshift(
+      `(showing ${recent.length} of ${warnings.length} warning events)`
+    )
+  }
+  return lines
+}
+ 
+export async function waitForPodPhases(
+  podName: string,
+  awaitingPhases: Set<PodPhase>,
+  backOffPhases: Set<PodPhase>,
+  ImaxTimeSeconds = DEFAULT_WAIT_FOR_POD_TIME_SECONDS
+): Promise<void> {
+  const backOffManager = new BackOffManager(maxTimeSeconds)
+  let phase: PodPhase = PodPhase.UNKNOWN
+  while (Itrue) {
+    const pod = await readPod(podName)
+    phase = parsePodPhase(pod)
+    Iif (awaitingPhases.has(phase)) {
+      return
+    }
+ 
+    if (I!backOffPhases.has(phase)) {
+      const details = await describePodFailure(podName)
+      throw new Error(
+        `Pod ${podName} is unhealthy with phase status ${phase}\n${details}`
+      )
+    }
+ 
+    const containerErrors = getContainerErrors(pod)
+    if (IcontainerErrors.length > 0) {
+      const details = await describePodFailure(podName)
+      throw new Error(
+        `Pod ${podName} has unrecoverable container errors: ${containerErrors.join(
+          '; '
+        )}\n${details}`
+      )
+    }
+ 
+    const conditionErrors = getPodConditionErrors(pod)
+    if (IconditionErrors.length > 0) {
+      const details = await describePodFailure(podName)
+      throw new Error(
+        `Pod ${podName} has unrecoverable condition errors: ${conditionErrors.join(
+          '; '
+        )}\n${details}`
+      )
+    }
+ 
+    try {
+      await backOffManager.backOff()
+    } catch (error) {
+      const details = await describePodFailure(podName)
+      throw new Error(
+        `Pod ${podName} is unhealthy: timed out after ${maxTimeSeconds}s in phase ${phase}\n${details}`
+      )
+    }
+  }
+}
+ 
+export function getPrepareJobTimeoutSeconds(): number {
+  const envTimeoutSeconds =
+    process.env['ACTIONS_RUNNER_PREPARE_JOB_TIMEOUT_SECONDS']
+ 
+  if (!envTimeoutSeconds) {
+    return DEFAULT_WAIT_FOR_POD_TIME_SECONDS
+  }
+ 
+  const timeoutSeconds = parseInt(envTimeoutSeconds, 10)
+  Iif (!timeoutSeconds || timeoutSeconds <= 0) {
+    core.warning(
+      `Prepare job timeout is invalid ("${timeoutSeconds}"): use an int > 0`
+    )
+    return DEFAULT_WAIT_FOR_POD_TIME_SECONDS
+  }
+ 
+  return timeoutSeconds
+}
+ 
+async function readPod(podName: string): Promise<k8s.V1Pod> {
+  const { body } = await k8sApi.readNamespacedPod(podName, namespace())
+  return body
+}
+ 
+const podPhaseLookup = new Set<string>([
+  PodPhase.PENDING,
+  PodPhase.RUNNING,
+  PodPhase.SUCCEEDED,
+  PodPhase.FAILED,
+  PodPhase.UNKNOWN
+])
+ 
+export function parsePodPhase(pod: k8s.V1Pod): PodPhase {
+  Iif (!pod.status?.phase || !podPhaseLookup.has(pod.status.phase)) {
+    return PodPhase.UNKNOWN
+  }
+  return pod.status.phase as PodPhase
+}
+ 
+async function isJobSucceeded(jobName: string): Promise<boolean> {
+  const { body } = await k8sBatchV1Api.readNamespacedJob(jobName, namespace())
+  const job = body
+  Iif (job.status?.failed) {
+    throw new Error(`job ${jobName} has failed`)
+  }
+  return !!job.status?.succeeded
+}
+ 
+export async function getPodLogs(
+  podName: string,
+  containerName: string
+): Promise<void> {
+  const log = new k8s.Log(kc)
+  const logStream = new stream.PassThrough()
+  logStream.on('data', chunk => {
+    // use write rather than console.log to prevent double line feed
+    process.stdout.write(chunk)
+  })
+ 
+  logStream.on('error', err => {
+    process.stderr.write(err.message)
+  })
+ 
+  const r = await log.log(namespace(), podName, containerName, logStream, {
+    follow: true,
+    pretty: false,
+    timestamps: false
+  })
+  await new Promise(resolve => r.on('close', () => resolve(null)))
+}
+ 
+export async function prunePods(): Promise<void> {
+  const podList = await k8sApi.listNamespacedPod(
+    namespace(),
+    undefined,
+    undefined,
+    undefined,
+    undefined,
+    new RunnerInstanceLabel().toString()
+  )
+  Iif (!podList.body.items.length) {
+    return
+  }
+ 
+  await Promise.all(
+    podList.body.items.map(
+      pod => pod.metadata?.name && deletePod(pod.metadata.name)
+    )
+  )
+}
+ 
+export async function getPodStatus(
+  name: string
+): Promise<k8s.V1PodStatus | undefined> {
+  const { body } = await k8sApi.readNamespacedPod(name, namespace())
+  return body.status
+}
+ 
+export async function isAuthPermissionsOK(): Promise<boolean> {
+  const sar = new k8s.V1SelfSubjectAccessReview()
+  const asyncs: Promise<{
+    response: unknown
+    body: k8s.V1SelfSubjectAccessReview
+  }>[] = []
+  for (const resource of requiredPermissions) {
+    for (const verb of resource.verbs) {
+      sar.spec = new k8s.V1SelfSubjectAccessReviewSpec()
+      sar.spec.resourceAttributes = new k8s.V1ResourceAttributes()
+      sar.spec.resourceAttributes.verb = verb
+      sar.spec.resourceAttributes.namespace = namespace()
+      sar.spec.resourceAttributes.group = resource.group
+      sar.spec.resourceAttributes.resource = resource.resource
+      sar.spec.resourceAttributes.subresource = resource.subresource
+      asyncs.push(k8sAuthorizationV1Api.createSelfSubjectAccessReview(sar))
+    }
+  }
+  const responses = await Promise.all(asyncs)
+  return responses.every(resp => resp.body.status?.allowed)
+}
+ 
+export async function isPodContainerAlpine(
+  podName: string,
+  containerName: string
+): Promise<boolean> {
+  let isAlpine = true
+  try {
+    await execPodStep(
+      [
+        'sh',
+        '-c',
+        `'[ $(cat /etc/*release* | grep -i -e "^ID=*alpine*" -c) != 0 ] || exit 1'`
+      ],
+      podName,
+      containerName
+    )
+  } catch (err) {
+    isAlpine = false
+  }
+ 
+  return isAlpine
+}
+ 
+async function getCurrentNodeName(): Promise<string> {
+  const resp = await k8sApi.readNamespacedPod(getRunnerPodName(), namespace())
+ 
+  const nodeName = resp.body.spec?.nodeName
+  Iif (!nodeName) {
+    throw new Error('Failed to determine node name')
+  }
+  return nodeName
+}
+ 
+async function getPodAffinity(nodeName: string): Promise<k8s.V1Affinity> {
+  const affinity = new k8s.V1Affinity()
+  affinity.nodeAffinity = new k8s.V1NodeAffinity()
+  affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution =
+    new k8s.V1NodeSelector()
+  affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms =
+    [
+      {
+        matchExpressions: [
+          {
+            key: 'kubernetes.io/hostname',
+            operator: 'In',
+            values: [nodeName]
+          }
+        ]
+      }
+    ]
+  return affinity
+}
+ 
+async function getPreferredPodAffinity(
+  nodeName: string
+): Promise<k8s.V1Affinity> {
+  const affinity = new k8s.V1Affinity()
+  affinity.nodeAffinity = new k8s.V1NodeAffinity()
+ 
+  // 创建 PreferredSchedulingTerm 对象
+  const preferredTerm = new k8s.V1PreferredSchedulingTerm()
+  preferredTerm.weight = 1 // 设置权重(1-100)
+ 
+  // 创建 NodeSelectorTerm
+  preferredTerm.preference = new k8s.V1NodeSelectorTerm()
+  preferredTerm.preference.matchExpressions = [
+    {
+      key: 'kubernetes.io/hostname',
+      operator: 'In',
+      values: [nodeName]
+    }
+  ]
+ 
+  // 将 PreferredSchedulingTerm 添加到数组中
+  affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution = [
+    preferredTerm
+  ]
+ 
+  return affinity
+}
+ 
+export function namespace(): string {
+  Iif (process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE']) {
+    return process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE']
+  }
+ 
+  const context = kc.getContexts().find(ctx => ctx.namespace)
+  Iif (!context?.namespace) {
+    throw new Error(
+      'Failed to determine namespace, falling back to `default`. Namespace should be set in context, or in env variable "ACTIONS_RUNNER_KUBERNETES_NAMESPACE"'
+    )
+  }
+  return context.namespace
+}
+ 
+class BackOffManager {
+  private backOffSeconds = 1
+  totalTime = 0
+  constructor(private throwAfterSeconds?: number) {
+    Iif (!throwAfterSeconds || throwAfterSeconds < 0) {
+      this.throwAfterSeconds = undefined
+    }
+  }
+ 
+  async backOff(): Promise<void> {
+    await new Promise(resolve =>
+      setTimeout(resolve, this.backOffSeconds * 1000)
+    )
+    this.totalTime += this.backOffSeconds
+    Iif (this.throwAfterSeconds && this.throwAfterSeconds < this.totalTime) {
+      throw new Error('backoff timeout')
+    }
+    Iif (this.backOffSeconds < 20) {
+      this.backOffSeconds *= 2
+    }
+    Iif (this.backOffSeconds > 20) {
+      this.backOffSeconds = 20
+    }
+  }
+}
+ 
+export function containerPorts(
+  container: ContainerInfo
+): k8s.V1ContainerPort[] {
+  const ports: k8s.V1ContainerPort[] = []
+  if (!container.portMappings?.length) {
+    return ports
+  }
+  for (const portDefinition of container.portMappings) {
+    const portProtoSplit = portDefinition.split('/')
+    Iif (portProtoSplit.length > 2) {
+      throw new Error(`Unexpected port format: ${portDefinition}`)
+    }
+ 
+    const port = new k8s.V1ContainerPort()
+    port.protocol =
+      portProtoSplit.length === 2 ? portProtoSplit[1].toUpperCase() : 'TCP'
+ 
+    const portSplit = portProtoSplit[0].split(':')
+    Iif (portSplit.length > 2) {
+      throw new Error('ports should have at most one ":" separator')
+    }
+ 
+    const parsePort = (p: string): number => {
+      const num = Number(p)
+      Iif (!Number.isInteger(num) || num < 1 || num > 65535) {
+        throw new Error(`invalid container port: ${p}`)
+      }
+      return num
+    }
+ 
+    if (portSplit.length === 1) {
+      port.containerPort = parsePort(portSplit[0])
+    } else {
+      port.hostPort = parsePort(portSplit[0])
+      port.containerPort = parsePort(portSplit[1])
+    }
+ 
+    ports.push(port)
+  }
+  return ports
+}
+ 
+export async function getPodByName(name): Promise<k8s.V1Pod> {
+  const { body } = await k8sApi.readNamespacedPod(name, namespace())
+  return body
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/src/k8s/utils.ts.html b/packages/k8s/coverage/lcov-report/src/k8s/utils.ts.html new file mode 100644 index 00000000..0e436fd0 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/src/k8s/utils.ts.html @@ -0,0 +1,988 @@ + + + + + + Code coverage report for src/k8s/utils.ts + + + + + + + + + +
+
+

All files / src/k8s utils.ts

+
+ +
+ 27.45% + Statements + 42/153 +
+ + +
+ 7.75% + Branches + 9/116 +
+ + +
+ 33.33% + Functions + 4/12 +
+ + +
+ 33.33% + Lines + 42/126 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302  +1x +1x +1x +  +1x +1x +1x +1x +1x +  +1x +1x +  +1x +1x +  +1x +6x +3x +6x +  +3x +  +  +  +  +  +  +3x +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +3x +  +  +  +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +3x +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +3x +3x +3x +  +  +  +  +  +  +  +  +1x +  +  +  +1x +1x +1x +1x +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +1x +3x +  + 
import * as k8s from '@kubernetes/client-node'
+import * as fs from 'fs'
+import * as yaml from 'js-yaml'
+import * as core from '@actions/core'
+import { Mount } from 'hooklib'
+import * as path from 'path'
+import { v1 as uuidv4 } from 'uuid'
+import { POD_VOLUME_NAME } from './index'
+import { CONTAINER_EXTENSION_PREFIX } from '../hooks/constants'
+import * as shlex from 'shlex'
+ 
+export const DEFAULT_CONTAINER_ENTRY_POINT_ARGS = [`-f`, `/dev/null`]
+export const DEFAULT_CONTAINER_ENTRY_POINT = 'tail'
+ 
+export const ENV_HOOK_TEMPLATE_PATH = 'ACTIONS_RUNNER_CONTAINER_HOOK_TEMPLATE'
+export const ENV_USE_KUBE_SCHEDULER = 'ACTIONS_RUNNER_USE_KUBE_SCHEDULER'
+ 
+export function containerVolumes(
+  userMountVolumes: Mount[] = [],
+  IjobContainer = true,
+  containerAction = false
+): k8s.V1VolumeMount[] {
+  const mounts: k8s.V1VolumeMount[] = [
+    {
+      name: POD_VOLUME_NAME,
+      mountPath: '/__w'
+    }
+  ]
+ 
+  const workspacePath = process.env.GITHUB_WORKSPACE as string
+  Iif (containerAction) {
+    const i = workspacePath.lastIndexOf('_work/')
+    const workspaceRelativePath = workspacePath.slice(i + '_work/'.length)
+    mounts.push(
+      {
+        name: POD_VOLUME_NAME,
+        mountPath: '/github/workspace',
+        subPath: workspaceRelativePath
+      },
+      {
+        name: POD_VOLUME_NAME,
+        mountPath: '/github/file_commands',
+        subPath: '_temp/_runner_file_commands'
+      },
+      {
+        name: POD_VOLUME_NAME,
+        mountPath: '/github/home',
+        subPath: '_temp/_github_home'
+      },
+      {
+        name: POD_VOLUME_NAME,
+        mountPath: '/github/workflow',
+        subPath: '_temp/_github_workflow'
+      }
+    )
+    return mounts
+  }
+ 
+  Iif (!jobContainer) {
+    return mounts
+  }
+ 
+  mounts.push(
+    {
+      name: POD_VOLUME_NAME,
+      mountPath: '/__e',
+      subPath: 'externals'
+    },
+    {
+      name: POD_VOLUME_NAME,
+      mountPath: '/github/home',
+      subPath: '_temp/_github_home'
+    },
+    {
+      name: POD_VOLUME_NAME,
+      mountPath: '/github/workflow',
+      subPath: '_temp/_github_workflow'
+    }
+  )
+ 
+  if (!userMountVolumes?.length) {
+    return mounts
+  }
+ 
+  for (const userVolume of userMountVolumes) {
+    let sourceVolumePath = ''
+    if (path.isAbsolute(userVolume.sourceVolumePath)) {
+      Iif (!userVolume.sourceVolumePath.startsWith(workspacePath)) {
+        throw new Error(
+          'Volume mounts outside of the work folder are not supported'
+        )
+      }
+      // source volume path should be relative path
+      sourceVolumePath = userVolume.sourceVolumePath.slice(
+        workspacePath.length + 1
+      )
+    } else {
+      sourceVolumePath = userVolume.sourceVolumePath
+    }
+ 
+    mounts.push({
+      name: POD_VOLUME_NAME,
+      mountPath: userVolume.targetVolumePath,
+      subPath: sourceVolumePath,
+      readOnly: userVolume.readOnly
+    })
+  }
+ 
+  return mounts
+}
+ 
+export function writeEntryPointScript(
+  workingDirectory: string,
+  entryPoint: string,
+  entryPointArgs?: string[],
+  prependPath?: string[],
+  environmentVariables?: { [key: string]: string }
+): { containerPath: string; runnerPath: string } {
+  let exportPath = ''
+  Iif (prependPath?.length) {
+    // TODO: remove compatibility with typeof prependPath === 'string' as we bump to next major version, the hooks will lose PrependPath compat with runners 2.293.0 and older
+    const prepend =
+      typeof prependPath === 'string' ? prependPath : prependPath.join(':')
+    exportPath = `export PATH=${prepend}:$PATH`
+  }
+  let environmentPrefix = ''
+ 
+  Iif (environmentVariables && Object.entries(environmentVariables).length) {
+    const envBuffer: string[] = []
+    for (const [key, value] of Object.entries(environmentVariables)) {
+      Iif (
+        key.includes(`=`) ||
+        key.includes(`'`) ||
+        key.includes(`"`) ||
+        key.includes(`$`)
+      ) {
+        throw new Error(
+          `environment key ${key} is invalid - the key must not contain =, $, ', or "`
+        )
+      }
+      envBuffer.push(
+        `"${key}=${value
+          .replace(/\\/g, '\\\\')
+          .replace(/"/g, '\\"')
+          .replace(/\$/g, '\\$')
+          .replace(/`/g, '\\`')}"`
+      )
+    }
+    environmentPrefix = `env ${envBuffer.join(' ')} `
+  }
+ 
+  const content = `#!/bin/sh -l
+${exportPath}
+cd ${workingDirectory} && \
+exec ${environmentPrefix} ${entryPoint} ${
+    entryPointArgs?.length ? entryPointArgs.join(' ') : ''
+  }
+`
+  const filename = `${uuidv4()}.sh`
+  const entryPointPath = `${process.env.RUNNER_TEMP}/${filename}`
+  fs.writeFileSync(entryPointPath, content)
+  return {
+    containerPath: `/__w/_temp/${filename}`,
+    runnerPath: entryPointPath
+  }
+}
+ 
+export function generateContainerName(image: string): string {
+  const nameWithTag = image.split('/').pop()
+  const name = nameWithTag?.split(':').at(0)
+ 
+  Iif (!name) {
+    throw new Error(`Image definition '${image}' is invalid`)
+  }
+ 
+  return name
+}
+ 
+// Overwrite or append based on container options
+//
+// Keep in mind, envs and volumes could be passed as fields in container definition
+// so default volume mounts and envs are appended first, and then create options are used
+// to append more values
+//
+// Rest of the fields are just applied
+// For example, container.createOptions.container.image is going to overwrite container.image field
+export function mergeContainerWithOptions(
+  base: k8s.V1Container,
+  from: k8s.V1Container
+): void {
+  for (const [key, value] of Object.entries(from)) {
+    if (key === 'name') {
+      Iif (value !== CONTAINER_EXTENSION_PREFIX + base.name) {
+        core.warning("Skipping name override: name can't be overwritten")
+      }
+      continue
+    } else if (key === 'image') {
+      core.warning("Skipping image override: image can't be overwritten")
+      continue
+    } else if (key === 'env') {
+      const envs = value as k8s.V1EnvVar[]
+      base.env = mergeLists(base.env, envs)
+    } else if (key === 'volumeMounts' && value) {
+      const volumeMounts = value as k8s.V1VolumeMount[]
+      base.volumeMounts = mergeLists(base.volumeMounts, volumeMounts)
+    } else if (key === 'ports' && value) {
+      const ports = value as k8s.V1ContainerPort[]
+      base.ports = mergeLists(base.ports, ports)
+    } else {
+      base[key] = value
+    }
+  }
+}
+ 
+export function mergePodSpecWithOptions(
+  base: k8s.V1PodSpec,
+  from: k8s.V1PodSpec
+): void {
+  for (const [key, value] of Object.entries(from)) {
+    if (key === 'containers') {
+      base.containers.push(
+        ...from.containers.filter(
+          e => !e.name?.startsWith(CONTAINER_EXTENSION_PREFIX)
+        )
+      )
+    } else if (key === 'volumes' && value) {
+      const volumes = value as k8s.V1Volume[]
+      base.volumes = mergeLists(base.volumes, volumes)
+    } else {
+      base[key] = value
+    }
+  }
+}
+ 
+export function mergeObjectMeta(
+  base: { metadata?: k8s.V1ObjectMeta },
+  from: k8s.V1ObjectMeta
+): void {
+  Iif (!base.metadata?.labels || !base.metadata?.annotations) {
+    throw new Error(
+      "Can't merge metadata: base.metadata or base.annotations field is undefined"
+    )
+  }
+  Iif (from?.labels) {
+    for (const [key, value] of Object.entries(from.labels)) {
+      Iif (base.metadata?.labels?.[key]) {
+        core.warning(`Label ${key} is already defined and will be overwritten`)
+      }
+      base.metadata.labels[key] = value
+    }
+  }
+ 
+  Iif (from?.annotations) {
+    for (const [key, value] of Object.entries(from.annotations)) {
+      Iif (base.metadata?.annotations?.[key]) {
+        core.warning(
+          `Annotation ${key} is already defined and will be overwritten`
+        )
+      }
+      base.metadata.annotations[key] = value
+    }
+  }
+}
+ 
+export function readExtensionFromFile(): k8s.V1PodTemplateSpec | undefined {
+  const filePath = process.env[ENV_HOOK_TEMPLATE_PATH]
+  if (!filePath) {
+    return undefined
+  }
+  const doc = yaml.load(fs.readFileSync(filePath, 'utf8'))
+  Iif (!doc || typeof doc !== 'object') {
+    throw new Error(`Failed to parse ${filePath}`)
+  }
+  return doc as k8s.V1PodTemplateSpec
+}
+ 
+export function useKubeScheduler(): boolean {
+  return process.env[ENV_USE_KUBE_SCHEDULER] === 'true'
+}
+ 
+export enum PodPhase {
+  PENDING = 'Pending',
+  RUNNING = 'Running',
+  SUCCEEDED = 'Succeeded',
+  FAILED = 'Failed',
+  UNKNOWN = 'Unknown',
+  COMPLETED = 'Completed'
+}
+ 
+function mergeLists<T>(base?: T[], from?: T[]): T[] {
+  const b: T[] = base || []
+  Iif (!from?.length) {
+    return b
+  }
+  b.push(...from)
+  return b
+}
+ 
+export function fixArgs(args: string[]): string[] {
+  return shlex.split(args.join(' '))
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/tests/index.html b/packages/k8s/coverage/lcov-report/tests/index.html new file mode 100644 index 00000000..fa0dbbaf --- /dev/null +++ b/packages/k8s/coverage/lcov-report/tests/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for tests + + + + + + + + + +
+
+

All files tests

+
+ +
+ 29.57% + Statements + 21/71 +
+ + +
+ 0% + Branches + 0/3 +
+ + +
+ 5.55% + Functions + 1/18 +
+ + +
+ 28.57% + Lines + 20/70 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
test-setup.ts +
+
29.57%21/710%0/35.55%1/1828.57%20/70
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov-report/tests/test-setup.ts.html b/packages/k8s/coverage/lcov-report/tests/test-setup.ts.html new file mode 100644 index 00000000..4a47cad7 --- /dev/null +++ b/packages/k8s/coverage/lcov-report/tests/test-setup.ts.html @@ -0,0 +1,673 @@ + + + + + + Code coverage report for tests/test-setup.ts + + + + + + + + + +
+
+

All files / tests test-setup.ts

+
+ +
+ 29.57% + Statements + 21/71 +
+ + +
+ 0% + Branches + 0/3 +
+ + +
+ 5.55% + Functions + 1/18 +
+ + +
+ 28.57% + Lines + 20/70 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +1971x +1x +  +1x +1x +  +1x +  +1x +  +1x +1x +  +1x +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +1x +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +1x + 
import * as k8s from '@kubernetes/client-node'
+import * as fs from 'fs'
+import { HookData } from 'hooklib/lib'
+import * as path from 'path'
+import { v4 as uuidv4 } from 'uuid'
+ 
+const kc = new k8s.KubeConfig()
+ 
+kc.loadFromDefault()
+ 
+const k8sApi = kc.makeApiClient(k8s.CoreV1Api)
+const k8sStorageApi = kc.makeApiClient(k8s.StorageV1Api)
+ 
+export class TestHelper {
+  private tempDirPath: string
+  private podName: string
+  constructor() {
+    this.tempDirPath = `${__dirname}/_temp/runner`
+    this.podName = uuidv4().replace(/-/g, '')
+  }
+ 
+  public async initialize(): Promise<void> {
+    process.env['ACTIONS_RUNNER_POD_NAME'] = `${this.podName}`
+    process.env['RUNNER_WORKSPACE'] = `${this.tempDirPath}/_work/repo`
+    process.env['RUNNER_TEMP'] = `${this.tempDirPath}/_work/_temp`
+    process.env['GITHUB_WORKSPACE'] = `${this.tempDirPath}/_work/repo/repo`
+    process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] = 'default'
+ 
+    fs.mkdirSync(`${this.tempDirPath}/_work/repo/repo`, { recursive: true })
+    fs.mkdirSync(`${this.tempDirPath}/externals`, { recursive: true })
+    fs.mkdirSync(process.env.RUNNER_TEMP, { recursive: true })
+ 
+    fs.copyFileSync(
+      path.resolve(`${__dirname}/../../../examples/example-script.sh`),
+      `${process.env.RUNNER_TEMP}/example-script.sh`
+    )
+ 
+    await this.cleanupK8sResources()
+    try {
+      await this.createTestVolume()
+      await this.createTestJobPod()
+    } catch (e) {
+      console.log(e)
+    }
+  }
+ 
+  public async cleanup(): Promise<void> {
+    try {
+      await this.cleanupK8sResources()
+      fs.rmSync(this.tempDirPath, { recursive: true })
+    } catch {}
+  }
+  public async cleanupK8sResources() {
+    await k8sApi
+      .deleteNamespacedPersistentVolumeClaim(
+        `${this.podName}-work`,
+        'default',
+        undefined,
+        undefined,
+        0
+      )
+      .catch(e => {})
+    await k8sApi.deletePersistentVolume(`${this.podName}-pv`).catch(e => {})
+    await k8sStorageApi.deleteStorageClass('local-storage').catch(e => {})
+    await k8sApi
+      .deleteNamespacedPod(this.podName, 'default', undefined, undefined, 0)
+      .catch(e => {})
+    await k8sApi
+      .deleteNamespacedPod(
+        `${this.podName}-workflow`,
+        'default',
+        undefined,
+        undefined,
+        0
+      )
+      .catch(e => {})
+  }
+  public createFile(fileName?: string): string {
+    const filePath = `${this.tempDirPath}/${fileName || uuidv4()}`
+    fs.writeFileSync(filePath, '')
+    return filePath
+  }
+ 
+  public removeFile(fileName: string): void {
+    const filePath = `${this.tempDirPath}/${fileName}`
+    fs.rmSync(filePath)
+  }
+ 
+  public async createTestJobPod() {
+    const container = {
+      name: 'nginx',
+      image: 'nginx:latest',
+      imagePullPolicy: 'IfNotPresent'
+    } as k8s.V1Container
+ 
+    const pod: k8s.V1Pod = {
+      metadata: {
+        name: this.podName
+      },
+      spec: {
+        restartPolicy: 'Never',
+        containers: [container]
+      }
+    } as k8s.V1Pod
+    await k8sApi.createNamespacedPod('default', pod)
+  }
+ 
+  public async createTestVolume() {
+    var sc: k8s.V1StorageClass = {
+      metadata: {
+        name: 'local-storage'
+      },
+      provisioner: 'kubernetes.io/no-provisioner',
+      volumeBindingMode: 'Immediate'
+    }
+    await k8sStorageApi.createStorageClass(sc)
+ 
+    var volume: k8s.V1PersistentVolume = {
+      metadata: {
+        name: `${this.podName}-pv`
+      },
+      spec: {
+        storageClassName: 'local-storage',
+        capacity: {
+          storage: '2Gi'
+        },
+        volumeMode: 'Filesystem',
+        accessModes: ['ReadWriteOnce'],
+        hostPath: {
+          path: `${this.tempDirPath}/_work`
+        }
+      }
+    }
+    await k8sApi.createPersistentVolume(volume)
+    var volumeClaim: k8s.V1PersistentVolumeClaim = {
+      metadata: {
+        name: `${this.podName}-work`
+      },
+      spec: {
+        accessModes: ['ReadWriteOnce'],
+        volumeMode: 'Filesystem',
+        storageClassName: 'local-storage',
+        volumeName: `${this.podName}-pv`,
+        resources: {
+          requests: {
+            storage: '1Gi'
+          }
+        }
+      }
+    }
+    await k8sApi.createNamespacedPersistentVolumeClaim('default', volumeClaim)
+  }
+ 
+  public getPrepareJobDefinition(): HookData {
+    const prepareJob = JSON.parse(
+      fs.readFileSync(
+        path.resolve(__dirname + '/../../../examples/prepare-job.json'),
+        'utf8'
+      )
+    )
+ 
+    prepareJob.args.container.userMountVolumes = undefined
+    prepareJob.args.container.registry = null
+    prepareJob.args.services.forEach(s => {
+      s.registry = null
+    })
+ 
+    return prepareJob
+  }
+ 
+  public getRunScriptStepDefinition(): HookData {
+    const runScriptStep = JSON.parse(
+      fs.readFileSync(
+        path.resolve(__dirname + '/../../../examples/run-script-step.json'),
+        'utf8'
+      )
+    )
+ 
+    runScriptStep.args.entryPointArgs[1] = `/__w/_temp/example-script.sh`
+    return runScriptStep
+  }
+ 
+  public getRunContainerStepDefinition(): HookData {
+    const runContainerStep = JSON.parse(
+      fs.readFileSync(
+        path.resolve(__dirname + '/../../../examples/run-container-step.json'),
+        'utf8'
+      )
+    )
+ 
+    runContainerStep.args.entryPointArgs[1] = `/__w/_temp/example-script.sh`
+    runContainerStep.args.userMountVolumes = undefined
+    runContainerStep.args.registry = null
+    return runContainerStep
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/packages/k8s/coverage/lcov.info b/packages/k8s/coverage/lcov.info new file mode 100644 index 00000000..ccee93e4 --- /dev/null +++ b/packages/k8s/coverage/lcov.info @@ -0,0 +1,1846 @@ +TN: +SF:src/hooks/cleanup-job.ts +FN:3,cleanupJob +FNF:1 +FNH:0 +FNDA:0,cleanupJob +DA:1,1 +DA:3,1 +DA:4,0 +LF:3 +LH:2 +BRDA:4,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:src/hooks/constants.ts +FN:3,getRunnerPodName +FN:13,getJobPodName +FN:20,getStepPodName +FN:27,getVolumeClaimName +FN:35,getSecretName +FN:48,(anonymous_5) +FN:50,RunnerInstanceLabel +FN:54,(anonymous_7) +FN:58,(anonymous_8) +FN:62,(anonymous_9) +FNF:10 +FNH:1 +FNDA:0,getRunnerPodName +FNDA:0,getJobPodName +FNDA:0,getStepPodName +FNDA:0,getVolumeClaimName +FNDA:0,getSecretName +FNDA:1,(anonymous_5) +FNDA:0,RunnerInstanceLabel +FNDA:0,(anonymous_7) +FNDA:0,(anonymous_8) +FNDA:0,(anonymous_9) +DA:1,1 +DA:3,1 +DA:4,0 +DA:5,0 +DA:6,0 +DA:10,0 +DA:13,1 +DA:14,0 +DA:20,1 +DA:21,0 +DA:27,1 +DA:28,0 +DA:29,0 +DA:30,0 +DA:32,0 +DA:35,1 +DA:36,0 +DA:42,1 +DA:43,1 +DA:44,1 +DA:45,1 +DA:46,1 +DA:48,1 +DA:51,0 +DA:54,1 +DA:55,0 +DA:58,1 +DA:59,0 +DA:62,1 +DA:63,0 +DA:65,1 +LF:31 +LH:16 +BRDA:5,0,0,0 +BRDA:29,1,0,0 +BRF:2 +BRH:0 +end_of_record +TN: +SF:src/hooks/index.ts +FNF:0 +FNH:0 +DA:1,1 +DA:2,1 +DA:3,1 +DA:4,1 +LF:4 +LH:4 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/hooks/prepare-job.ts +FN:31,prepareJob +FN:57,(anonymous_23) +FN:130,generateResponseFile +FN:148,(anonymous_25) +FN:167,(anonymous_26) +FN:170,(anonymous_27) +FN:171,(anonymous_28) +FN:189,copyExternalsToRoot +FN:200,createContainerSpec +FN:259,(anonymous_33) +FNF:10 +FNH:3 +FNDA:3,prepareJob +FNDA:0,(anonymous_23) +FNDA:0,generateResponseFile +FNDA:0,(anonymous_25) +FNDA:0,(anonymous_26) +FNDA:0,(anonymous_27) +FNDA:0,(anonymous_28) +FNDA:3,copyExternalsToRoot +FNDA:3,createContainerSpec +FNDA:0,(anonymous_33) +DA:1,1 +DA:2,1 +DA:4,1 +DA:10,1 +DA:11,1 +DA:19,1 +DA:29,1 +DA:31,1 +DA:35,3 +DA:36,0 +DA:39,6 +DA:41,3 +DA:42,6 +DA:44,3 +DA:45,3 +DA:46,3 +DA:47,3 +DA:55,3 +DA:56,3 +DA:57,0 +DA:58,0 +DA:59,0 +DA:68,3 +DA:69,0 +DA:72,3 +DA:74,3 +DA:81,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:87,3 +DA:88,0 +DA:90,3 +DA:95,6 +DA:103,6 +DA:105,2 +DA:107,3 +DA:108,3 +DA:111,0 +DA:113,0 +DA:115,0 +DA:120,0 +DA:123,0 +DA:124,0 +DA:126,0 +DA:127,0 +DA:136,0 +DA:137,0 +DA:139,0 +DA:147,0 +DA:148,0 +DA:150,0 +DA:151,0 +DA:152,0 +DA:153,0 +DA:154,0 +DA:159,0 +DA:165,0 +DA:167,0 +DA:169,0 +DA:170,0 +DA:172,0 +DA:173,0 +DA:174,0 +DA:175,0 +DA:179,0 +DA:186,0 +DA:190,3 +DA:191,6 +DA:192,0 +DA:200,1 +DA:203,3 +DA:206,3 +DA:207,3 +DA:208,3 +DA:211,3 +DA:216,3 +DA:217,0 +DA:220,3 +DA:221,3 +DA:224,3 +DA:225,3 +DA:228,3 +DA:229,3 +DA:232,0 +DA:233,0 +DA:237,3 +DA:242,3 +DA:243,3 +DA:249,3 +DA:254,3 +DA:255,3 +DA:258,0 +DA:259,0 +DA:262,0 +DA:263,0 +DA:266,0 +LF:97 +LH:49 +BRDA:35,0,0,0 +BRDA:45,1,0,3 +BRDA:45,2,0,0 +BRDA:45,2,1,3 +BRDA:45,3,0,3 +BRDA:45,3,1,3 +BRDA:56,4,0,0 +BRDA:56,5,0,0 +BRDA:56,5,1,3 +BRDA:56,6,0,3 +BRDA:56,6,1,3 +BRDA:68,7,0,0 +BRDA:68,8,0,3 +BRDA:68,8,1,0 +BRDA:68,9,0,0 +BRDA:68,9,1,0 +BRDA:68,10,0,0 +BRDA:68,10,1,0 +BRDA:83,11,0,0 +BRDA:83,11,1,0 +BRDA:83,12,0,0 +BRDA:83,12,1,0 +BRDA:83,13,0,0 +BRDA:83,13,1,0 +BRDA:83,14,0,0 +BRDA:83,14,1,0 +BRDA:83,15,0,0 +BRDA:83,15,1,0 +BRDA:83,16,0,0 +BRDA:83,16,1,0 +BRDA:83,17,0,0 +BRDA:83,17,1,0 +BRDA:87,18,0,0 +BRDA:87,19,0,0 +BRDA:87,19,1,3 +BRDA:87,20,0,3 +BRDA:87,20,1,3 +BRDA:87,21,0,0 +BRDA:87,21,1,3 +BRDA:87,22,0,3 +BRDA:87,22,1,3 +BRDA:91,23,0,0 +BRDA:91,23,1,3 +BRDA:91,24,0,3 +BRDA:91,24,1,3 +BRDA:91,25,0,0 +BRDA:91,25,1,3 +BRDA:91,26,0,3 +BRDA:91,26,1,3 +BRDA:105,27,0,2 +BRDA:105,27,1,0 +BRDA:107,28,0,3 +BRDA:107,28,1,0 +BRDA:123,29,0,0 +BRDA:123,29,1,0 +BRDA:123,30,0,0 +BRDA:123,30,1,0 +BRDA:123,31,0,0 +BRDA:123,31,1,0 +BRDA:123,32,0,0 +BRDA:123,32,1,0 +BRDA:123,33,0,0 +BRDA:123,33,1,0 +BRDA:123,34,0,0 +BRDA:123,34,1,0 +BRDA:123,35,0,0 +BRDA:123,35,1,0 +BRDA:136,36,0,0 +BRDA:136,37,0,0 +BRDA:136,37,1,0 +BRDA:136,38,0,0 +BRDA:136,38,1,0 +BRDA:147,39,0,0 +BRDA:147,39,1,0 +BRDA:147,40,0,0 +BRDA:147,40,1,0 +BRDA:147,41,0,0 +BRDA:147,41,1,0 +BRDA:147,42,0,0 +BRDA:147,42,1,0 +BRDA:150,43,0,0 +BRDA:152,44,0,0 +BRDA:152,45,0,0 +BRDA:152,45,1,0 +BRDA:152,46,0,0 +BRDA:152,46,1,0 +BRDA:165,47,0,0 +BRDA:165,48,0,0 +BRDA:165,48,1,0 +BRDA:165,49,0,0 +BRDA:165,49,1,0 +BRDA:167,50,0,0 +BRDA:167,50,1,0 +BRDA:167,51,0,0 +BRDA:167,51,1,0 +BRDA:167,52,0,0 +BRDA:167,52,1,0 +BRDA:169,53,0,0 +BRDA:169,53,1,0 +BRDA:169,54,0,0 +BRDA:169,54,1,0 +BRDA:169,55,0,0 +BRDA:169,55,1,0 +BRDA:169,56,0,0 +BRDA:169,56,1,0 +BRDA:169,57,0,0 +BRDA:169,57,1,0 +BRDA:169,58,0,0 +BRDA:169,58,1,0 +BRDA:173,59,0,0 +BRDA:173,60,0,0 +BRDA:173,60,1,0 +BRDA:173,61,0,0 +BRDA:173,61,1,0 +BRDA:191,62,0,3 +BRDA:203,63,0,0 +BRDA:206,64,0,3 +BRDA:206,65,0,3 +BRDA:206,65,1,3 +BRDA:216,66,0,0 +BRDA:220,67,0,3 +BRDA:224,68,0,3 +BRDA:224,69,0,0 +BRDA:224,69,1,3 +BRDA:224,70,0,3 +BRDA:224,70,1,3 +BRDA:232,71,0,0 +BRDA:232,72,0,0 +BRDA:232,72,1,0 +BRDA:242,73,0,3 +BRDA:254,74,0,3 +BRDA:258,75,0,0 +BRDA:258,75,1,0 +BRDA:258,76,0,0 +BRDA:258,76,1,0 +BRDA:258,77,0,0 +BRDA:258,77,1,0 +BRDA:258,78,0,0 +BRDA:258,78,1,0 +BRDA:262,79,0,0 +BRF:140 +BRH:33 +end_of_record +TN: +SF:src/hooks/run-container-step.ts +FN:25,runContainerStep +FN:129,createContainerSpec +FN:162,(anonymous_23) +FNF:3 +FNH:0 +FNDA:0,runContainerStep +FNDA:0,createContainerSpec +FNDA:0,(anonymous_23) +DA:1,1 +DA:2,1 +DA:4,1 +DA:16,1 +DA:23,1 +DA:25,1 +DA:28,0 +DA:29,0 +DA:32,0 +DA:33,0 +DA:35,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:42,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:50,0 +DA:52,0 +DA:53,0 +DA:57,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:64,0 +DA:65,0 +DA:71,0 +DA:75,0 +DA:77,0 +DA:78,0 +DA:79,0 +DA:82,0 +DA:92,0 +DA:94,0 +DA:96,0 +DA:97,0 +DA:100,0 +DA:101,0 +DA:102,0 +DA:104,0 +DA:105,0 +DA:110,0 +DA:113,0 +DA:114,0 +DA:115,0 +DA:116,0 +DA:117,0 +DA:120,0 +DA:123,0 +DA:126,0 +DA:134,0 +DA:135,0 +DA:136,0 +DA:137,0 +DA:138,0 +DA:141,0 +DA:145,0 +DA:146,0 +DA:155,0 +DA:157,0 +DA:158,0 +DA:161,0 +DA:162,0 +DA:164,0 +DA:165,0 +DA:168,0 +LF:67 +LH:6 +BRDA:82,0,0,0 +BRDA:28,1,0,0 +BRDA:33,2,0,0 +BRDA:39,3,0,0 +BRDA:45,4,0,0 +BRDA:45,4,1,0 +BRDA:45,5,0,0 +BRDA:45,5,1,0 +BRDA:45,6,0,0 +BRDA:45,6,1,0 +BRDA:45,7,0,0 +BRDA:45,7,1,0 +BRDA:45,8,0,0 +BRDA:45,8,1,0 +BRDA:45,9,0,0 +BRDA:45,9,1,0 +BRDA:45,10,0,0 +BRDA:45,10,1,0 +BRDA:60,11,0,0 +BRDA:60,11,1,0 +BRDA:60,12,0,0 +BRDA:60,12,1,0 +BRDA:60,13,0,0 +BRDA:60,13,1,0 +BRDA:60,14,0,0 +BRDA:60,14,1,0 +BRDA:60,15,0,0 +BRDA:60,15,1,0 +BRDA:60,16,0,0 +BRDA:60,16,1,0 +BRDA:60,17,0,0 +BRDA:60,17,1,0 +BRDA:64,18,0,0 +BRDA:64,19,0,0 +BRDA:64,19,1,0 +BRDA:64,20,0,0 +BRDA:64,20,1,0 +BRDA:71,21,0,0 +BRDA:71,21,1,0 +BRDA:71,22,0,0 +BRDA:71,22,1,0 +BRDA:78,23,0,0 +BRDA:78,23,1,0 +BRDA:78,24,0,0 +BRDA:78,24,1,0 +BRDA:78,25,0,0 +BRDA:78,25,1,0 +BRDA:78,26,0,0 +BRDA:78,26,1,0 +BRDA:78,27,0,0 +BRDA:78,27,1,0 +BRDA:78,28,0,0 +BRDA:78,28,1,0 +BRDA:78,29,0,0 +BRDA:78,29,1,0 +BRDA:101,30,0,0 +BRDA:101,31,0,0 +BRDA:101,31,1,0 +BRDA:101,32,0,0 +BRDA:101,32,1,0 +BRDA:104,33,0,0 +BRDA:104,34,0,0 +BRDA:104,34,1,0 +BRDA:104,35,0,0 +BRDA:104,35,1,0 +BRDA:104,36,0,0 +BRDA:104,36,1,0 +BRDA:104,37,0,0 +BRDA:104,37,1,0 +BRDA:115,38,0,0 +BRDA:124,39,0,0 +BRDA:124,39,1,0 +BRDA:124,40,0,0 +BRDA:124,40,1,0 +BRDA:124,41,0,0 +BRDA:124,41,1,0 +BRDA:124,42,0,0 +BRDA:124,42,1,0 +BRDA:126,43,0,0 +BRDA:126,43,1,0 +BRDA:138,44,0,0 +BRDA:138,44,1,0 +BRDA:141,45,0,0 +BRDA:141,45,1,0 +BRDA:141,46,0,0 +BRDA:141,46,1,0 +BRDA:141,47,0,0 +BRDA:141,47,1,0 +BRDA:145,48,0,0 +BRDA:157,49,0,0 +BRDA:161,50,0,0 +BRDA:161,50,1,0 +BRDA:161,51,0,0 +BRDA:161,51,1,0 +BRDA:161,52,0,0 +BRDA:161,52,1,0 +BRDA:161,53,0,0 +BRDA:161,53,1,0 +BRDA:164,54,0,0 +BRF:99 +BRH:0 +end_of_record +TN: +SF:src/hooks/run-script-step.ts +FN:9,runScriptStep +FNF:1 +FNH:0 +FNDA:0,runScriptStep +DA:2,1 +DA:3,1 +DA:5,1 +DA:6,1 +DA:7,1 +DA:9,1 +DA:14,0 +DA:15,0 +DA:23,0 +DA:24,0 +DA:26,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:36,0 +LF:15 +LH:6 +BRDA:33,0,0,0 +BRDA:33,0,1,0 +BRDA:33,1,0,0 +BRDA:33,1,1,0 +BRDA:33,2,0,0 +BRDA:33,2,1,0 +BRDA:33,3,0,0 +BRDA:33,3,1,0 +BRDA:33,4,0,0 +BRDA:33,4,1,0 +BRDA:33,5,0,0 +BRDA:33,5,1,0 +BRDA:33,6,0,0 +BRDA:33,6,1,0 +BRF:14 +BRH:0 +end_of_record +TN: +SF:src/k8s/index.ts +FN:66,createPod +FN:134,createJob +FN:190,getContainerJobPodName +FN:218,deletePod +FN:228,execPodStep +FN:237,(anonymous_35) +FN:248,(anonymous_36) +FN:265,(anonymous_37) +FN:269,waitForJobToComplete +FN:283,createDockerSecret +FN:322,createSecretForEnvs +FN:347,deleteSecret +FN:351,pruneSecrets +FN:366,(anonymous_53) +FN:393,getUnrecoverableWaitingReasons +FN:408,getUnrecoverableEventReasons +FN:423,getUnrecoverableTerminatedReasons +FN:439,getContainerErrors +FN:459,getPodEventErrors +FN:493,getPodConditionErrors +FN:507,getContainerTerminatedErrors +FN:527,describePodFailure +FN:597,describePodWarningEvents +FN:617,(anonymous_69) +FN:622,(anonymous_70) +FN:626,(anonymous_71) +FN:629,(anonymous_72) +FN:643,waitForPodPhases +FN:696,getPrepareJobTimeoutSeconds +FN:715,readPod +FN:728,parsePodPhase +FN:735,isJobSucceeded +FN:744,getPodLogs +FN:750,(anonymous_87) +FN:755,(anonymous_88) +FN:764,(anonymous_89) +FN:764,(anonymous_90) +FN:767,prunePods +FN:782,(anonymous_94) +FN:787,getPodStatus +FN:794,isAuthPermissionsOK +FN:813,(anonymous_101) +FN:816,isPodContainerAlpine +FN:838,getCurrentNodeName +FN:848,getPodAffinity +FN:868,getPreferredPodAffinity +FN:896,namespace +FN:901,(anonymous_115) +FN:910,(anonymous_116) +FN:913,BackOffManager +FN:919,(anonymous_118) +FN:920,(anonymous_121) +FN:936,containerPorts +FN:958,(anonymous_123) +FN:978,getPodByName +FNF:55 +FNH:3 +FNDA:0,createPod +FNDA:0,createJob +FNDA:0,getContainerJobPodName +FNDA:0,deletePod +FNDA:0,execPodStep +FNDA:0,(anonymous_35) +FNDA:0,(anonymous_36) +FNDA:0,(anonymous_37) +FNDA:0,waitForJobToComplete +FNDA:0,createDockerSecret +FNDA:0,createSecretForEnvs +FNDA:0,deleteSecret +FNDA:0,pruneSecrets +FNDA:0,(anonymous_53) +FNDA:0,getUnrecoverableWaitingReasons +FNDA:0,getUnrecoverableEventReasons +FNDA:0,getUnrecoverableTerminatedReasons +FNDA:0,getContainerErrors +FNDA:0,getPodEventErrors +FNDA:0,getPodConditionErrors +FNDA:0,getContainerTerminatedErrors +FNDA:0,describePodFailure +FNDA:0,describePodWarningEvents +FNDA:0,(anonymous_69) +FNDA:0,(anonymous_70) +FNDA:0,(anonymous_71) +FNDA:0,(anonymous_72) +FNDA:0,waitForPodPhases +FNDA:3,getPrepareJobTimeoutSeconds +FNDA:0,readPod +FNDA:0,parsePodPhase +FNDA:0,isJobSucceeded +FNDA:0,getPodLogs +FNDA:0,(anonymous_87) +FNDA:0,(anonymous_88) +FNDA:0,(anonymous_89) +FNDA:0,(anonymous_90) +FNDA:0,prunePods +FNDA:0,(anonymous_94) +FNDA:0,getPodStatus +FNDA:0,isAuthPermissionsOK +FNDA:0,(anonymous_101) +FNDA:0,isPodContainerAlpine +FNDA:0,getCurrentNodeName +FNDA:0,getPodAffinity +FNDA:0,getPreferredPodAffinity +FNDA:0,namespace +FNDA:0,(anonymous_115) +FNDA:1,(anonymous_116) +FNDA:0,BackOffManager +FNDA:0,(anonymous_118) +FNDA:0,(anonymous_121) +FNDA:3,containerPorts +FNDA:0,(anonymous_123) +FNDA:0,getPodByName +DA:1,1 +DA:2,1 +DA:4,1 +DA:5,1 +DA:13,1 +DA:21,1 +DA:23,1 +DA:25,1 +DA:26,1 +DA:27,1 +DA:29,1 +DA:31,1 +DA:33,1 +DA:66,1 +DA:72,0 +DA:73,0 +DA:74,0 +DA:76,0 +DA:77,0 +DA:80,0 +DA:82,0 +DA:83,0 +DA:85,0 +DA:86,0 +DA:88,0 +DA:89,0 +DA:92,0 +DA:94,0 +DA:95,0 +DA:96,0 +DA:98,0 +DA:99,0 +DA:100,0 +DA:102,0 +DA:104,0 +DA:105,0 +DA:112,0 +DA:113,0 +DA:114,0 +DA:115,0 +DA:117,0 +DA:118,0 +DA:119,0 +DA:122,0 +DA:123,0 +DA:126,0 +DA:127,0 +DA:130,0 +DA:131,0 +DA:134,1 +DA:138,0 +DA:140,0 +DA:141,0 +DA:142,0 +DA:143,0 +DA:144,0 +DA:145,0 +DA:146,0 +DA:148,0 +DA:149,0 +DA:150,0 +DA:151,0 +DA:153,0 +DA:154,0 +DA:155,0 +DA:156,0 +DA:157,0 +DA:158,0 +DA:160,0 +DA:161,0 +DA:162,0 +DA:164,0 +DA:167,0 +DA:168,0 +DA:175,0 +DA:176,0 +DA:178,0 +DA:179,0 +DA:181,0 +DA:182,0 +DA:186,0 +DA:187,0 +DA:190,1 +DA:191,0 +DA:192,0 +DA:193,0 +DA:194,0 +DA:204,0 +DA:205,0 +DA:206,0 +DA:209,0 +DA:210,0 +DA:214,0 +DA:218,1 +DA:219,0 +DA:228,1 +DA:234,0 +DA:235,0 +DA:237,0 +DA:238,0 +DA:250,0 +DA:251,0 +DA:253,0 +DA:259,0 +DA:265,0 +DA:269,1 +DA:270,0 +DA:271,0 +DA:273,0 +DA:274,0 +DA:277,0 +DA:279,0 +DA:283,1 +DA:286,0 +DA:298,0 +DA:300,0 +DA:301,0 +DA:302,0 +DA:303,0 +DA:304,0 +DA:305,0 +DA:306,0 +DA:307,0 +DA:310,0 +DA:311,0 +DA:312,0 +DA:318,0 +DA:319,0 +DA:322,1 +DA:325,0 +DA:327,0 +DA:328,0 +DA:329,0 +DA:330,0 +DA:331,0 +DA:332,0 +DA:334,0 +DA:337,0 +DA:338,0 +DA:339,0 +DA:340,0 +DA:343,0 +DA:344,0 +DA:347,1 +DA:348,0 +DA:351,1 +DA:352,0 +DA:360,0 +DA:361,0 +DA:364,0 +DA:366,0 +DA:371,1 +DA:379,1 +DA:385,1 +DA:391,1 +DA:393,1 +DA:394,0 +DA:395,0 +DA:396,0 +DA:398,0 +DA:399,0 +DA:400,0 +DA:401,0 +DA:402,0 +DA:405,0 +DA:408,1 +DA:409,0 +DA:410,0 +DA:411,0 +DA:413,0 +DA:414,0 +DA:415,0 +DA:416,0 +DA:417,0 +DA:420,0 +DA:423,1 +DA:425,0 +DA:426,0 +DA:427,0 +DA:429,0 +DA:430,0 +DA:431,0 +DA:432,0 +DA:433,0 +DA:436,0 +DA:439,1 +DA:440,0 +DA:441,0 +DA:442,0 +DA:446,0 +DA:447,0 +DA:448,0 +DA:449,0 +DA:456,0 +DA:459,1 +DA:460,0 +DA:463,0 +DA:470,0 +DA:472,0 +DA:477,0 +DA:480,0 +DA:481,0 +DA:482,0 +DA:487,0 +DA:490,0 +DA:493,1 +DA:494,0 +DA:495,0 +DA:496,0 +DA:497,0 +DA:504,0 +DA:507,1 +DA:508,0 +DA:509,0 +DA:510,0 +DA:514,0 +DA:515,0 +DA:516,0 +DA:517,0 +DA:524,0 +DA:527,1 +DA:530,0 +DA:532,0 +DA:537,0 +DA:538,0 +DA:540,0 +DA:541,0 +DA:547,0 +DA:548,0 +DA:551,0 +DA:552,0 +DA:554,0 +DA:555,0 +DA:556,0 +DA:564,0 +DA:568,0 +DA:569,0 +DA:570,0 +DA:571,0 +DA:577,0 +DA:578,0 +DA:579,0 +DA:589,0 +DA:591,0 +DA:592,0 +DA:594,0 +DA:600,0 +DA:607,0 +DA:609,0 +DA:614,0 +DA:617,0 +DA:618,0 +DA:619,0 +DA:622,0 +DA:623,0 +DA:624,0 +DA:626,0 +DA:628,0 +DA:629,0 +DA:630,0 +DA:631,0 +DA:635,0 +DA:636,0 +DA:640,0 +DA:643,1 +DA:647,0 +DA:649,0 +DA:650,0 +DA:651,0 +DA:652,0 +DA:653,0 +DA:654,0 +DA:655,0 +DA:658,0 +DA:659,0 +DA:660,0 +DA:665,0 +DA:666,0 +DA:667,0 +DA:668,0 +DA:675,0 +DA:676,0 +DA:677,0 +DA:678,0 +DA:686,0 +DA:688,0 +DA:689,0 +DA:696,1 +DA:698,3 +DA:700,3 +DA:701,3 +DA:704,0 +DA:705,0 +DA:706,0 +DA:709,0 +DA:712,0 +DA:716,0 +DA:717,0 +DA:720,1 +DA:728,1 +DA:729,0 +DA:730,0 +DA:732,0 +DA:736,0 +DA:737,0 +DA:738,0 +DA:739,0 +DA:741,0 +DA:744,1 +DA:748,0 +DA:749,0 +DA:750,0 +DA:752,0 +DA:755,0 +DA:756,0 +DA:759,0 +DA:764,0 +DA:767,1 +DA:768,0 +DA:776,0 +DA:777,0 +DA:780,0 +DA:782,0 +DA:787,1 +DA:790,0 +DA:791,0 +DA:794,1 +DA:795,0 +DA:796,0 +DA:800,0 +DA:801,0 +DA:802,0 +DA:803,0 +DA:804,0 +DA:805,0 +DA:806,0 +DA:807,0 +DA:808,0 +DA:809,0 +DA:812,0 +DA:813,0 +DA:816,1 +DA:820,0 +DA:822,0 +DA:832,0 +DA:835,0 +DA:839,0 +DA:841,0 +DA:842,0 +DA:843,0 +DA:845,0 +DA:849,0 +DA:850,0 +DA:851,0 +DA:853,0 +DA:865,0 +DA:871,0 +DA:872,0 +DA:875,0 +DA:876,0 +DA:879,0 +DA:880,0 +DA:889,0 +DA:893,0 +DA:896,1 +DA:897,0 +DA:898,0 +DA:901,0 +DA:902,0 +DA:903,0 +DA:907,0 +DA:910,1 +DA:911,0 +DA:912,0 +DA:913,0 +DA:914,0 +DA:915,0 +DA:919,1 +DA:920,0 +DA:921,0 +DA:923,0 +DA:924,0 +DA:925,0 +DA:927,0 +DA:928,0 +DA:930,0 +DA:931,0 +DA:934,1 +DA:936,1 +DA:939,3 +DA:940,3 +DA:941,3 +DA:943,0 +DA:944,0 +DA:945,0 +DA:946,0 +DA:949,0 +DA:950,0 +DA:953,0 +DA:954,0 +DA:955,0 +DA:958,0 +DA:959,0 +DA:960,0 +DA:961,0 +DA:963,0 +DA:966,0 +DA:967,0 +DA:969,0 +DA:970,0 +DA:973,0 +DA:975,0 +DA:978,1 +DA:979,0 +DA:980,0 +LF:415 +LH:56 +BRDA:73,0,0,0 +BRDA:76,1,0,0 +BRDA:76,2,0,0 +BRDA:76,2,1,0 +BRDA:76,3,0,0 +BRDA:76,3,1,0 +BRDA:99,4,0,0 +BRDA:112,5,0,0 +BRDA:114,6,0,0 +BRDA:114,7,0,0 +BRDA:114,7,1,0 +BRDA:114,8,0,0 +BRDA:114,8,1,0 +BRDA:114,9,0,0 +BRDA:114,9,1,0 +BRDA:114,10,0,0 +BRDA:114,10,1,0 +BRDA:122,11,0,0 +BRDA:122,12,0,0 +BRDA:122,12,1,0 +BRDA:122,13,0,0 +BRDA:122,13,1,0 +BRDA:126,14,0,0 +BRDA:126,15,0,0 +BRDA:126,15,1,0 +BRDA:126,16,0,0 +BRDA:126,16,1,0 +BRDA:161,17,0,0 +BRDA:175,18,0,0 +BRDA:176,19,0,0 +BRDA:181,20,0,0 +BRDA:193,21,0,0 +BRDA:204,22,0,0 +BRDA:204,23,0,0 +BRDA:204,23,1,0 +BRDA:204,24,0,0 +BRDA:204,24,1,0 +BRDA:209,25,0,0 +BRDA:209,26,0,0 +BRDA:209,26,1,0 +BRDA:209,27,0,0 +BRDA:209,27,1,0 +BRDA:219,28,0,0 +BRDA:246,29,0,0 +BRDA:246,29,1,0 +BRDA:246,30,0,0 +BRDA:246,30,1,0 +BRDA:250,31,0,0 +BRDA:250,31,1,0 +BRDA:255,32,0,0 +BRDA:255,32,1,0 +BRDA:255,33,0,0 +BRDA:255,33,1,0 +BRDA:256,34,0,0 +BRDA:256,34,1,0 +BRDA:256,35,0,0 +BRDA:256,35,1,0 +BRDA:259,36,0,0 +BRDA:259,36,1,0 +BRDA:259,37,0,0 +BRDA:259,37,1,0 +BRDA:279,38,0,0 +BRDA:271,39,0,0 +BRDA:273,40,0,0 +BRDA:288,41,0,0 +BRDA:288,41,1,0 +BRDA:348,42,0,0 +BRDA:352,43,0,0 +BRDA:360,44,0,0 +BRDA:366,45,0,0 +BRDA:366,45,1,0 +BRDA:366,46,0,0 +BRDA:366,46,1,0 +BRDA:366,47,0,0 +BRDA:366,47,1,0 +BRDA:395,48,0,0 +BRDA:401,49,0,0 +BRDA:410,50,0,0 +BRDA:416,51,0,0 +BRDA:426,52,0,0 +BRDA:432,53,0,0 +BRDA:443,54,0,0 +BRDA:443,54,1,0 +BRDA:443,55,0,0 +BRDA:443,55,1,0 +BRDA:443,56,0,0 +BRDA:443,56,1,0 +BRDA:443,57,0,0 +BRDA:443,57,1,0 +BRDA:444,58,0,0 +BRDA:444,58,1,0 +BRDA:444,59,0,0 +BRDA:444,59,1,0 +BRDA:444,60,0,0 +BRDA:444,60,1,0 +BRDA:444,61,0,0 +BRDA:444,61,1,0 +BRDA:447,62,0,0 +BRDA:447,62,1,0 +BRDA:447,63,0,0 +BRDA:447,63,1,0 +BRDA:448,64,0,0 +BRDA:448,65,0,0 +BRDA:448,65,1,0 +BRDA:448,66,0,0 +BRDA:448,66,1,0 +BRDA:448,67,0,0 +BRDA:448,67,1,0 +BRDA:451,68,0,0 +BRDA:451,68,1,0 +BRDA:474,69,0,0 +BRDA:474,69,1,0 +BRDA:482,70,0,0 +BRDA:483,71,0,0 +BRDA:483,71,1,0 +BRDA:483,71,2,0 +BRDA:487,72,0,0 +BRDA:487,72,1,0 +BRDA:487,73,0,0 +BRDA:487,73,1,0 +BRDA:495,74,0,0 +BRDA:495,74,1,0 +BRDA:495,75,0,0 +BRDA:495,75,1,0 +BRDA:495,76,0,0 +BRDA:495,76,1,0 +BRDA:495,77,0,0 +BRDA:495,77,1,0 +BRDA:496,78,0,0 +BRDA:496,79,0,0 +BRDA:496,79,1,0 +BRDA:496,79,2,0 +BRDA:498,80,0,0 +BRDA:498,80,1,0 +BRDA:498,81,0,0 +BRDA:498,81,1,0 +BRDA:499,82,0,0 +BRDA:499,82,1,0 +BRDA:499,83,0,0 +BRDA:499,83,1,0 +BRDA:511,84,0,0 +BRDA:511,84,1,0 +BRDA:511,85,0,0 +BRDA:511,85,1,0 +BRDA:511,86,0,0 +BRDA:511,86,1,0 +BRDA:511,87,0,0 +BRDA:511,87,1,0 +BRDA:512,88,0,0 +BRDA:512,88,1,0 +BRDA:512,89,0,0 +BRDA:512,89,1,0 +BRDA:512,90,0,0 +BRDA:512,90,1,0 +BRDA:512,91,0,0 +BRDA:512,91,1,0 +BRDA:515,92,0,0 +BRDA:515,92,1,0 +BRDA:515,93,0,0 +BRDA:515,93,1,0 +BRDA:516,94,0,0 +BRDA:516,95,0,0 +BRDA:516,95,1,0 +BRDA:516,96,0,0 +BRDA:516,96,1,0 +BRDA:516,97,0,0 +BRDA:516,97,1,0 +BRDA:519,98,0,0 +BRDA:519,98,1,0 +BRDA:519,99,0,0 +BRDA:519,99,1,0 +BRDA:533,100,0,0 +BRDA:533,100,1,0 +BRDA:540,101,0,0 +BRDA:540,102,0,0 +BRDA:540,102,1,0 +BRDA:540,103,0,0 +BRDA:540,103,1,0 +BRDA:543,104,0,0 +BRDA:543,104,1,0 +BRDA:547,105,0,0 +BRDA:547,106,0,0 +BRDA:547,106,1,0 +BRDA:547,107,0,0 +BRDA:547,107,1,0 +BRDA:554,108,0,0 +BRDA:554,108,1,0 +BRDA:554,109,0,0 +BRDA:554,109,1,0 +BRDA:554,110,0,0 +BRDA:554,110,1,0 +BRDA:554,111,0,0 +BRDA:554,111,1,0 +BRDA:555,112,0,0 +BRDA:558,113,0,0 +BRDA:558,113,1,0 +BRDA:559,114,0,0 +BRDA:559,114,1,0 +BRDA:565,115,0,0 +BRDA:565,115,1,0 +BRDA:565,116,0,0 +BRDA:565,116,1,0 +BRDA:565,117,0,0 +BRDA:565,117,1,0 +BRDA:565,118,0,0 +BRDA:565,118,1,0 +BRDA:566,119,0,0 +BRDA:566,119,1,0 +BRDA:566,120,0,0 +BRDA:566,120,1,0 +BRDA:566,121,0,0 +BRDA:566,121,1,0 +BRDA:566,122,0,0 +BRDA:566,122,1,0 +BRDA:569,123,0,0 +BRDA:569,123,1,0 +BRDA:569,124,0,0 +BRDA:569,124,1,0 +BRDA:570,125,0,0 +BRDA:570,126,0,0 +BRDA:570,126,1,0 +BRDA:570,127,0,0 +BRDA:570,127,1,0 +BRDA:573,128,0,0 +BRDA:573,128,1,0 +BRDA:577,129,0,0 +BRDA:577,129,1,0 +BRDA:577,130,0,0 +BRDA:577,130,1,0 +BRDA:578,131,0,0 +BRDA:581,132,0,0 +BRDA:581,132,1,0 +BRDA:581,133,0,0 +BRDA:581,133,1,0 +BRDA:583,134,0,0 +BRDA:583,134,1,0 +BRDA:591,135,0,0 +BRDA:611,136,0,0 +BRDA:611,136,1,0 +BRDA:618,137,0,0 +BRDA:623,138,0,0 +BRDA:623,138,1,0 +BRDA:623,139,0,0 +BRDA:623,139,1,0 +BRDA:623,140,0,0 +BRDA:623,140,1,0 +BRDA:623,141,0,0 +BRDA:623,141,1,0 +BRDA:624,142,0,0 +BRDA:624,142,1,0 +BRDA:630,143,0,0 +BRDA:630,143,1,0 +BRDA:630,144,0,0 +BRDA:630,144,1,0 +BRDA:631,145,0,0 +BRDA:631,145,1,0 +BRDA:631,146,0,0 +BRDA:631,146,1,0 +BRDA:632,147,0,0 +BRDA:632,147,1,0 +BRDA:632,148,0,0 +BRDA:632,148,1,0 +BRDA:635,149,0,0 +BRDA:647,150,0,0 +BRDA:651,151,0,0 +BRDA:654,152,0,0 +BRDA:658,153,0,0 +BRDA:666,154,0,0 +BRDA:676,155,0,0 +BRDA:700,156,0,3 +BRDA:705,157,0,0 +BRDA:705,158,0,0 +BRDA:705,158,1,0 +BRDA:716,159,0,0 +BRDA:729,160,0,0 +BRDA:729,161,0,0 +BRDA:729,161,1,0 +BRDA:729,162,0,0 +BRDA:729,162,1,0 +BRDA:729,163,0,0 +BRDA:729,163,1,0 +BRDA:736,164,0,0 +BRDA:738,165,0,0 +BRDA:738,166,0,0 +BRDA:738,166,1,0 +BRDA:738,167,0,0 +BRDA:738,167,1,0 +BRDA:741,168,0,0 +BRDA:741,168,1,0 +BRDA:741,169,0,0 +BRDA:741,169,1,0 +BRDA:768,170,0,0 +BRDA:776,171,0,0 +BRDA:782,172,0,0 +BRDA:782,172,1,0 +BRDA:782,173,0,0 +BRDA:782,173,1,0 +BRDA:782,174,0,0 +BRDA:782,174,1,0 +BRDA:790,175,0,0 +BRDA:813,176,0,0 +BRDA:813,176,1,0 +BRDA:813,177,0,0 +BRDA:813,177,1,0 +BRDA:835,178,0,0 +BRDA:839,179,0,0 +BRDA:841,180,0,0 +BRDA:841,180,1,0 +BRDA:841,181,0,0 +BRDA:841,181,1,0 +BRDA:842,182,0,0 +BRDA:897,183,0,0 +BRDA:902,184,0,0 +BRDA:902,185,0,0 +BRDA:902,185,1,0 +BRDA:902,186,0,0 +BRDA:902,186,1,0 +BRDA:914,187,0,0 +BRDA:914,188,0,0 +BRDA:914,188,1,0 +BRDA:920,189,0,0 +BRDA:924,190,0,0 +BRDA:924,191,0,0 +BRDA:924,191,1,0 +BRDA:927,192,0,0 +BRDA:930,193,0,0 +BRDA:940,194,0,3 +BRDA:940,195,0,3 +BRDA:940,195,1,0 +BRDA:940,196,0,3 +BRDA:940,196,1,3 +BRDA:945,197,0,0 +BRDA:951,198,0,0 +BRDA:951,198,1,0 +BRDA:954,199,0,0 +BRDA:960,200,0,0 +BRDA:960,201,0,0 +BRDA:960,201,1,0 +BRDA:960,201,2,0 +BRDA:966,202,0,0 +BRDA:966,202,1,0 +BRDA:979,203,0,0 +BRF:342 +BRH:5 +end_of_record +TN: +SF:src/k8s/utils.ts +FN:18,containerVolumes +FN:112,writeEntryPointScript +FN:168,generateContainerName +FN:187,mergeContainerWithOptions +FN:215,mergePodSpecWithOptions +FN:223,(anonymous_11) +FN:235,mergeObjectMeta +FN:265,readExtensionFromFile +FN:277,useKubeScheduler +FN:281,(anonymous_15) +FN:290,mergeLists +FN:299,fixArgs +FNF:12 +FNH:4 +FNDA:3,containerVolumes +FNDA:0,writeEntryPointScript +FNDA:0,generateContainerName +FNDA:0,mergeContainerWithOptions +FNDA:0,mergePodSpecWithOptions +FNDA:0,(anonymous_11) +FNDA:0,mergeObjectMeta +FNDA:3,readExtensionFromFile +FNDA:0,useKubeScheduler +FNDA:1,(anonymous_15) +FNDA:0,mergeLists +FNDA:3,fixArgs +DA:2,1 +DA:3,1 +DA:4,1 +DA:6,1 +DA:7,1 +DA:8,1 +DA:9,1 +DA:10,1 +DA:12,1 +DA:13,1 +DA:15,1 +DA:16,1 +DA:18,1 +DA:19,6 +DA:20,3 +DA:21,6 +DA:23,3 +DA:30,3 +DA:31,3 +DA:32,0 +DA:33,0 +DA:34,0 +DA:56,0 +DA:59,3 +DA:60,0 +DA:63,3 +DA:81,3 +DA:82,3 +DA:85,0 +DA:86,0 +DA:87,0 +DA:88,0 +DA:89,0 +DA:94,0 +DA:98,0 +DA:101,0 +DA:109,0 +DA:112,1 +DA:119,0 +DA:120,0 +DA:123,0 +DA:124,0 +DA:126,0 +DA:128,0 +DA:129,0 +DA:130,0 +DA:131,0 +DA:137,0 +DA:141,0 +DA:149,0 +DA:152,0 +DA:159,0 +DA:160,0 +DA:161,0 +DA:162,0 +DA:168,1 +DA:169,0 +DA:170,0 +DA:172,0 +DA:173,0 +DA:176,0 +DA:187,1 +DA:191,0 +DA:192,0 +DA:193,0 +DA:194,0 +DA:196,0 +DA:197,0 +DA:198,0 +DA:199,0 +DA:200,0 +DA:201,0 +DA:202,0 +DA:203,0 +DA:204,0 +DA:205,0 +DA:206,0 +DA:207,0 +DA:208,0 +DA:210,0 +DA:215,1 +DA:219,0 +DA:220,0 +DA:221,0 +DA:223,0 +DA:226,0 +DA:227,0 +DA:228,0 +DA:230,0 +DA:235,1 +DA:239,0 +DA:240,0 +DA:244,0 +DA:245,0 +DA:246,0 +DA:247,0 +DA:249,0 +DA:253,0 +DA:254,0 +DA:255,0 +DA:256,0 +DA:260,0 +DA:265,1 +DA:266,3 +DA:267,3 +DA:268,3 +DA:270,0 +DA:271,0 +DA:272,0 +DA:274,0 +DA:277,1 +DA:278,0 +DA:281,1 +DA:282,1 +DA:283,1 +DA:284,1 +DA:285,1 +DA:286,1 +DA:287,1 +DA:291,0 +DA:292,0 +DA:293,0 +DA:295,0 +DA:296,0 +DA:299,1 +DA:300,3 +LF:126 +LH:42 +BRDA:19,0,0,3 +BRDA:20,1,0,0 +BRDA:21,2,0,3 +BRDA:31,3,0,0 +BRDA:59,4,0,0 +BRDA:81,5,0,3 +BRDA:81,6,0,0 +BRDA:81,6,1,3 +BRDA:81,7,0,3 +BRDA:81,7,1,3 +BRDA:87,8,0,0 +BRDA:87,8,1,0 +BRDA:88,9,0,0 +BRDA:120,10,0,0 +BRDA:120,11,0,0 +BRDA:120,11,1,0 +BRDA:120,12,0,0 +BRDA:120,12,1,0 +BRDA:123,13,0,0 +BRDA:123,13,1,0 +BRDA:128,14,0,0 +BRDA:128,15,0,0 +BRDA:128,15,1,0 +BRDA:131,16,0,0 +BRDA:132,17,0,0 +BRDA:132,17,1,0 +BRDA:132,17,2,0 +BRDA:132,17,3,0 +BRDA:156,18,0,0 +BRDA:156,18,1,0 +BRDA:156,19,0,0 +BRDA:156,19,1,0 +BRDA:156,20,0,0 +BRDA:156,20,1,0 +BRDA:170,21,0,0 +BRDA:170,21,1,0 +BRDA:170,22,0,0 +BRDA:170,22,1,0 +BRDA:172,23,0,0 +BRDA:192,24,0,0 +BRDA:192,24,1,0 +BRDA:193,25,0,0 +BRDA:197,26,0,0 +BRDA:197,26,1,0 +BRDA:200,27,0,0 +BRDA:200,27,1,0 +BRDA:203,28,0,0 +BRDA:203,28,1,0 +BRDA:203,29,0,0 +BRDA:203,29,1,0 +BRDA:206,30,0,0 +BRDA:206,30,1,0 +BRDA:206,31,0,0 +BRDA:206,31,1,0 +BRDA:220,32,0,0 +BRDA:220,32,1,0 +BRDA:223,33,0,0 +BRDA:223,33,1,0 +BRDA:223,34,0,0 +BRDA:223,34,1,0 +BRDA:226,35,0,0 +BRDA:226,35,1,0 +BRDA:226,36,0,0 +BRDA:226,36,1,0 +BRDA:239,37,0,0 +BRDA:239,38,0,0 +BRDA:239,38,1,0 +BRDA:239,39,0,0 +BRDA:239,39,1,0 +BRDA:239,40,0,0 +BRDA:239,40,1,0 +BRDA:239,41,0,0 +BRDA:239,41,1,0 +BRDA:239,42,0,0 +BRDA:239,42,1,0 +BRDA:244,43,0,0 +BRDA:244,44,0,0 +BRDA:244,44,1,0 +BRDA:244,45,0,0 +BRDA:244,45,1,0 +BRDA:246,46,0,0 +BRDA:246,47,0,0 +BRDA:246,47,1,0 +BRDA:246,48,0,0 +BRDA:246,48,1,0 +BRDA:246,49,0,0 +BRDA:246,49,1,0 +BRDA:246,50,0,0 +BRDA:246,50,1,0 +BRDA:253,51,0,0 +BRDA:253,52,0,0 +BRDA:253,52,1,0 +BRDA:253,53,0,0 +BRDA:253,53,1,0 +BRDA:255,54,0,0 +BRDA:255,55,0,0 +BRDA:255,55,1,0 +BRDA:255,56,0,0 +BRDA:255,56,1,0 +BRDA:255,57,0,0 +BRDA:255,57,1,0 +BRDA:255,58,0,0 +BRDA:255,58,1,0 +BRDA:267,59,0,3 +BRDA:271,60,0,0 +BRDA:271,61,0,0 +BRDA:271,61,1,0 +BRDA:281,62,0,1 +BRDA:281,62,1,1 +BRDA:291,63,0,0 +BRDA:291,63,1,0 +BRDA:292,64,0,0 +BRDA:292,65,0,0 +BRDA:292,65,1,0 +BRDA:292,66,0,0 +BRDA:292,66,1,0 +BRF:116 +BRH:9 +end_of_record +TN: +SF:tests/test-setup.ts +FN:14,(anonymous_19) +FN:17,TestHelper +FN:22,(anonymous_21) +FN:47,(anonymous_24) +FN:53,(anonymous_27) +FN:62,(anonymous_30) +FN:63,(anonymous_31) +FN:64,(anonymous_32) +FN:67,(anonymous_33) +FN:76,(anonymous_34) +FN:78,(anonymous_35) +FN:84,(anonymous_36) +FN:89,(anonymous_37) +FN:108,(anonymous_40) +FN:154,(anonymous_43) +FN:164,(anonymous_44) +FN:171,(anonymous_45) +FN:183,(anonymous_46) +FNF:18 +FNH:1 +FNDA:1,(anonymous_19) +FNDA:0,TestHelper +FNDA:0,(anonymous_21) +FNDA:0,(anonymous_24) +FNDA:0,(anonymous_27) +FNDA:0,(anonymous_30) +FNDA:0,(anonymous_31) +FNDA:0,(anonymous_32) +FNDA:0,(anonymous_33) +FNDA:0,(anonymous_34) +FNDA:0,(anonymous_35) +FNDA:0,(anonymous_36) +FNDA:0,(anonymous_37) +FNDA:0,(anonymous_40) +FNDA:0,(anonymous_43) +FNDA:0,(anonymous_44) +FNDA:0,(anonymous_45) +FNDA:0,(anonymous_46) +DA:1,1 +DA:2,1 +DA:4,1 +DA:5,1 +DA:7,1 +DA:9,1 +DA:11,1 +DA:12,1 +DA:14,1 +DA:18,0 +DA:19,0 +DA:22,1 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:33,0 +DA:38,0 +DA:40,0 +DA:41,0 +DA:43,0 +DA:47,1 +DA:49,0 +DA:50,0 +DA:53,1 +DA:54,0 +DA:63,0 +DA:64,0 +DA:65,0 +DA:68,0 +DA:78,1 +DA:79,0 +DA:80,0 +DA:81,0 +DA:84,1 +DA:85,0 +DA:86,0 +DA:89,1 +DA:90,0 +DA:96,0 +DA:105,0 +DA:108,1 +DA:109,0 +DA:116,0 +DA:118,0 +DA:134,0 +DA:135,0 +DA:151,0 +DA:154,1 +DA:155,0 +DA:162,0 +DA:163,0 +DA:164,0 +DA:165,0 +DA:168,0 +DA:171,1 +DA:172,0 +DA:179,0 +DA:180,0 +DA:183,1 +DA:184,0 +DA:191,0 +DA:192,0 +DA:193,0 +DA:194,0 +DA:196,1 +LF:70 +LH:20 +BRDA:54,0,0,0 +BRDA:79,1,0,0 +BRDA:79,1,1,0 +BRF:3 +BRH:0 +end_of_record diff --git a/packages/k8s/tests/prepare-job-test.ts b/packages/k8s/tests/prepare-job-test.ts index 8c371536..a9dddf79 100644 --- a/packages/k8s/tests/prepare-job-test.ts +++ b/packages/k8s/tests/prepare-job-test.ts @@ -13,6 +13,7 @@ import { getPodByName, prunePods, waitForPodPhases } from '../src/k8s' import { V1Container } from '@kubernetes/client-node' import * as yaml from 'js-yaml' import { JOB_CONTAINER_NAME } from '../src/hooks/constants' +import * as io from '@actions/io' import * as k8sModule from '../src/k8s' import * as coreModule from '@actions/core' @@ -252,10 +253,12 @@ describe('prepareJob error handling - prunePods try-catch', () => { let prunePodsSpy: jest.SpyInstance let waitForPodPhasesSpy: jest.SpyInstance let createPodSpy: jest.SpyInstance + let ioCpSpy: jest.SpyInstance beforeEach(() => { process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] = 'default' delete process.env[ENV_HOOK_TEMPLATE_PATH] + delete process.env['RUNNER_WORKSPACE'] coreErrorSpy = jest.spyOn(coreModule, 'error').mockImplementation(() => {}) prunePodsSpy = jest.spyOn(k8sModule, 'prunePods').mockResolvedValue(undefined) @@ -265,6 +268,7 @@ describe('prepareJob error handling - prunePods try-catch', () => { waitForPodPhasesSpy = jest .spyOn(k8sModule, 'waitForPodPhases') .mockRejectedValue(new Error('pod failed to come online: unrecoverable condition')) + ioCpSpy = jest.spyOn(io, 'cp').mockResolvedValue(undefined) }) afterEach(() => {