diff --git a/core/src/actions/base.ts b/core/src/actions/base.ts index a0c66b280d..255a8cf44e 100644 --- a/core/src/actions/base.ts +++ b/core/src/actions/base.ts @@ -422,7 +422,7 @@ export abstract class BaseAction< return true } - const path = this.basePath() + const path = this.sourcePath() for (const source of linkedSources) { if (path === source.path || pathIsInside(path, source.path)) { @@ -443,14 +443,13 @@ export abstract class BaseAction< return internal?.groupName } - // TODO: rename to sourcePath - basePath(): string { + sourcePath(): string { const basePath = this.remoteSourcePath || this._config.internal.basePath const sourceRelPath = this._config.source?.path if (sourceRelPath) { // TODO: validate that this is a directory here? - return joinWithPosix(basePath, sourceRelPath) + return getSourceAbsPath(basePath, sourceRelPath) } else { return basePath } @@ -670,7 +669,7 @@ export abstract class RuntimeAction< */ getBuildPath() { const buildAction = this.getBuildAction() - return buildAction?.getBuildPath() || this.basePath() + return buildAction?.getBuildPath() || this.sourcePath() } } @@ -852,6 +851,11 @@ export function actionRefMatches(a: ActionReference, b: ActionReference) { return a.kind === b.kind && a.name === b.name } +export function getSourceAbsPath(basePath: string, sourceRelPath: string) { + // TODO: validate that this is a directory here? + return joinWithPosix(basePath, sourceRelPath) +} + export function describeActionConfig(config: ActionConfig) { const d = `${config.type} ${config.kind} ${config.name}` if (config.internal?.moduleName) { diff --git a/core/src/actions/build.ts b/core/src/actions/build.ts index dc4ffd9e7c..1e422306ba 100644 --- a/core/src/actions/build.ts +++ b/core/src/actions/build.ts @@ -188,7 +188,7 @@ export class BuildAction< */ getBuildPath() { if (this._config.buildAtSource) { - return this.basePath() + return this.sourcePath() } else { return join(this.baseBuildDirectory, this.name) } diff --git a/core/src/actions/helpers.ts b/core/src/actions/helpers.ts index b157d3d8d5..e52fbbc43a 100644 --- a/core/src/actions/helpers.ts +++ b/core/src/actions/helpers.ts @@ -83,7 +83,7 @@ export async function warnOnLinkedActions(garden: Garden, log: Log, actions: Act const linkedActionsMsg = actions .filter((a) => a.isLinked(linkedSources)) - .map((a) => `${a.longDescription()} linked to path ${chalk.white(a.basePath())}`) + .map((a) => `${a.longDescription()} linked to path ${chalk.white(a.sourcePath())}`) .map((msg) => " " + msg) // indent list if (linkedActionsMsg.length > 0) { diff --git a/core/src/build-staging/build-staging.ts b/core/src/build-staging/build-staging.ts index 46bbafe4f4..92613ad64f 100644 --- a/core/src/build-staging/build-staging.ts +++ b/core/src/build-staging/build-staging.ts @@ -61,13 +61,13 @@ export class BuildStaging { } // Normalize to relative POSIX-style paths - const files = action.getFullVersion().files.map((f) => normalizeRelativePath(action.basePath(), f)) + const files = action.getFullVersion().files.map((f) => normalizeRelativePath(action.sourcePath(), f)) const buildPath = action.getBuildPath() await this.ensureDir(buildPath) await this.sync({ - sourceRoot: resolve(this.projectRoot, action.basePath()), + sourceRoot: resolve(this.projectRoot, action.sourcePath()), targetRoot: buildPath, withDelete, log, diff --git a/core/src/config/base.ts b/core/src/config/base.ts index 6a6bcefeb2..cd46dad812 100644 --- a/core/src/config/base.ts +++ b/core/src/config/base.ts @@ -48,7 +48,21 @@ export interface YamlDocumentWithSource extends Document { } export interface GardenResourceInternalFields { + /** + * The path/working directory where commands and operations relating to the config should be executed. This is + * most commonly the directory containing the config file. + * + * Note: WHen possible, use `action.getSourcePath()` instead, since it factors in remote source paths and source + * overrides (i.e. `BaseActionConfig.source.path`). This is a lower-level field that doesn't contain template strings, + * and can thus be used early in the resolution flow. + */ basePath: string + /** + * The path to the resource's config file, if any. + * + * Configs that are read from a file should always have this set, but generated configs (e.g. from templates + * or `augmentGraph` handlers) don't necessarily have a path on disk. + */ configFilePath?: string // -> set by templates inputs?: DeepPrimitiveMap diff --git a/core/src/config/template-contexts/actions.ts b/core/src/config/template-contexts/actions.ts index 497db74d89..697e1b7b0a 100644 --- a/core/src/config/template-contexts/actions.ts +++ b/core/src/config/template-contexts/actions.ts @@ -219,7 +219,7 @@ class ActionReferencesContext extends ConfigContext { version: action.versionString(), disabled: action.isDisabled(), buildPath: action.getBuildPath(), - sourcePath: action.basePath(), + sourcePath: action.sourcePath(), mode: action.mode(), variables: action.getVariables(), }) @@ -297,7 +297,7 @@ export class ActionSpecContext extends OutputConfigContext { const name = action.name const buildPath = action.getBuildPath() - const sourcePath = action.basePath() + const sourcePath = action.sourcePath() const parentName = internal?.parentName const templateName = internal?.templateName diff --git a/core/src/graph/actions.ts b/core/src/graph/actions.ts index db73c0294f..bcc98e00b0 100644 --- a/core/src/graph/actions.ts +++ b/core/src/graph/actions.ts @@ -63,7 +63,7 @@ import { LinkedSource, LinkedSourceMap } from "../config-store/local" import { relative } from "path" import { profileAsync } from "../util/profiling" import { uuidv4 } from "../util/random" -import { getConfigBasePath } from "../vcs/vcs" +import { getSourcePath } from "../vcs/vcs" import { actionIsDisabled } from "../actions/base" export const actionConfigsToGraph = profileAsync(async function actionConfigsToGraph({ @@ -125,7 +125,7 @@ export const actionConfigsToGraph = profileAsync(async function actionConfigsToG } // Optimize file scanning by avoiding unnecessarily broad scans when project is not in repo root. - const allPaths = Object.values(configsByKey).map((c) => getConfigBasePath(c)) + const allPaths = Object.values(configsByKey).map((c) => getSourcePath(c)) const minimalRoots = await garden.vcs.getMinimalRoots(log, allPaths) const router = await garden.getActionRouter() @@ -177,7 +177,7 @@ export const actionConfigsToGraph = profileAsync(async function actionConfigsToG configsByKey, mode, linkedSources, - scanRoot: minimalRoots[getConfigBasePath(config)], + scanRoot: minimalRoots[getSourcePath(config)], }) if (!action.supportsMode(mode)) { diff --git a/core/src/plugins/hadolint/hadolint.ts b/core/src/plugins/hadolint/hadolint.ts index 64aa233544..c4ef382ea7 100644 --- a/core/src/plugins/hadolint/hadolint.ts +++ b/core/src/plugins/hadolint/hadolint.ts @@ -179,7 +179,7 @@ provider.addHandler("augmentGraph", async ({ ctx, actions }) => { .filter(isHadolintTest) // Can't really reason about templated dockerfile spec field .filter((a) => !mayContainTemplateString(a.getConfig("spec").dockerfilePath)) - .map((a) => resolve(a.basePath(), a.getConfig("spec").dockerfilePath)) + .map((a) => resolve(a.sourcePath(), a.getConfig("spec").dockerfilePath)) const pickCompatibleAction = (action: BaseAction): action is BuildAction | HadolintTest => { // Make sure we don't step on an existing custom hadolint module @@ -187,7 +187,7 @@ provider.addHandler("augmentGraph", async ({ ctx, actions }) => { const dockerfilePath = action.getConfig("spec").dockerfilePath if ( !mayContainTemplateString(dockerfilePath) && - existingHadolintDockerfiles.includes(resolve(action.basePath(), dockerfilePath)) + existingHadolintDockerfiles.includes(resolve(action.sourcePath(), dockerfilePath)) ) { return false } @@ -222,7 +222,7 @@ provider.addHandler("augmentGraph", async ({ ctx, actions }) => { description: `hadolint test for '${action.longDescription()}' (auto-generated)`, include, internal: { - basePath: action.basePath(), + basePath: action.sourcePath(), }, timeout: action.getConfig().timeout, spec: { @@ -286,7 +286,7 @@ hadolintTest.addHandler("configure", async ({ ctx, config }) => { hadolintTest.addHandler("run", async ({ ctx, log, action }) => { const spec = action.getSpec() - const dockerfilePath = join(action.basePath(), spec.dockerfilePath) + const dockerfilePath = join(action.sourcePath(), spec.dockerfilePath) const startedAt = new Date() let dockerfile: string @@ -294,12 +294,12 @@ hadolintTest.addHandler("run", async ({ ctx, log, action }) => { dockerfile = (await readFile(dockerfilePath)).toString() } catch { throw new ConfigurationError({ - message: `hadolint: Could not find Dockerfile at ${spec.dockerfilePath}. Action path: ${action.basePath()}`, + message: `hadolint: Could not find Dockerfile at ${spec.dockerfilePath}. Action path: ${action.sourcePath()}`, }) } let configPath: string - const moduleConfigPath = join(action.basePath(), configFilename) + const moduleConfigPath = join(action.sourcePath(), configFilename) const projectConfigPath = join(ctx.projectRoot, configFilename) if (await pathExists(moduleConfigPath)) { diff --git a/core/src/plugins/kubernetes/container/deployment.ts b/core/src/plugins/kubernetes/container/deployment.ts index 41a925e7cd..839080c574 100644 --- a/core/src/plugins/kubernetes/container/deployment.ts +++ b/core/src/plugins/kubernetes/container/deployment.ts @@ -609,7 +609,7 @@ export function configureVolumes( volumes.push({ name: volumeName, hostPath: { - path: resolve(action.basePath(), volume.hostPath), + path: resolve(action.sourcePath(), volume.hostPath), }, }) } else if (volume.action) { diff --git a/core/src/plugins/kubernetes/container/sync.ts b/core/src/plugins/kubernetes/container/sync.ts index a25114dd9a..855c689234 100644 --- a/core/src/plugins/kubernetes/container/sync.ts +++ b/core/src/plugins/kubernetes/container/sync.ts @@ -33,7 +33,7 @@ export const k8sContainerStartSync: DeployActionHandler<"startSync", ContainerDe log, action, actionDefaults: {}, - basePath: action.basePath(), + basePath: action.sourcePath(), defaultNamespace, defaultTarget: target, deployedResources, @@ -75,7 +75,7 @@ export const k8sContainerGetSyncStatus: DeployActionHandler<"getSyncStatus", Con log, action, actionDefaults: {}, - basePath: action.basePath(), + basePath: action.sourcePath(), defaultNamespace, defaultTarget: target, deployedResources, diff --git a/core/src/plugins/kubernetes/helm/sync.ts b/core/src/plugins/kubernetes/helm/sync.ts index ed24433d02..5597431078 100644 --- a/core/src/plugins/kubernetes/helm/sync.ts +++ b/core/src/plugins/kubernetes/helm/sync.ts @@ -41,7 +41,7 @@ export const helmStartSync: DeployActionHandler<"startSync", HelmDeployAction> = action, actionDefaults: spec.sync.defaults || {}, defaultTarget: spec.defaultTarget, - basePath: action.basePath(), + basePath: action.sourcePath(), defaultNamespace: namespace, deployedResources, syncs: spec.sync.paths, @@ -79,7 +79,7 @@ export const helmGetSyncStatus: DeployActionHandler<"getSyncStatus", HelmDeployA action, actionDefaults: spec.sync.defaults || {}, defaultTarget: spec.defaultTarget, - basePath: action.basePath(), + basePath: action.sourcePath(), defaultNamespace: namespace, deployedResources, syncs: spec.sync.paths, diff --git a/core/src/plugins/kubernetes/kubernetes-type/sync.ts b/core/src/plugins/kubernetes/kubernetes-type/sync.ts index 1363b37ee9..1d978fd9a7 100644 --- a/core/src/plugins/kubernetes/kubernetes-type/sync.ts +++ b/core/src/plugins/kubernetes/kubernetes-type/sync.ts @@ -44,7 +44,7 @@ export const kubernetesStartSync: DeployActionHandler<"startSync", KubernetesDep action, actionDefaults: spec.sync.defaults || {}, defaultTarget: spec.defaultTarget, - basePath: action.basePath(), + basePath: action.sourcePath(), defaultNamespace: namespace, deployedResources, syncs: spec.sync.paths, @@ -84,7 +84,7 @@ export const kubernetesGetSyncStatus: DeployActionHandler<"getSyncStatus", Kuber action, actionDefaults: spec.sync.defaults || {}, defaultTarget: spec.defaultTarget, - basePath: action.basePath(), + basePath: action.sourcePath(), defaultNamespace: namespace, deployedResources, syncs: spec.sync.paths, diff --git a/core/src/plugins/kubernetes/local-mode.ts b/core/src/plugins/kubernetes/local-mode.ts index c84f10f688..e290a7ae11 100644 --- a/core/src/plugins/kubernetes/local-mode.ts +++ b/core/src/plugins/kubernetes/local-mode.ts @@ -540,7 +540,7 @@ function getLocalAppCommand({ spec: localModeSpec, action }: StartLocalModeParam } const commandName = command[0] const commandArgs = command.slice(1) - const cwd = isAbsolute(commandName) ? undefined : action.basePath() + const cwd = isAbsolute(commandName) ? undefined : action.sourcePath() return { command: commandName, args: commandArgs, cwd, description: "Local app" } } diff --git a/core/src/plugins/kubernetes/sync.ts b/core/src/plugins/kubernetes/sync.ts index 6f85538622..e0d10a4af8 100644 --- a/core/src/plugins/kubernetes/sync.ts +++ b/core/src/plugins/kubernetes/sync.ts @@ -264,7 +264,7 @@ export function convertContainerSyncSpec( const spec = action.getSpec() const kind: SyncableKind = spec.daemon ? "DaemonSet" : "Deployment" const target = { kind, name: action.name } - const sourcePath = action.basePath() + const sourcePath = action.sourcePath() const syncSpec = spec.sync if (!syncSpec || !target) { @@ -832,7 +832,7 @@ function getSyncKeyPrefix(ctx: PluginContext, action: SupportedRuntimeAction) { * It cannot contain any characters that can break the command execution (like / \ < > | :). */ function getSyncKey({ ctx, action, spec }: PrepareSyncParams, target: SyncableResource): string { - const sourcePath = relative(action.basePath(), spec.sourcePath) + const sourcePath = relative(action.sourcePath(), spec.sourcePath) const containerPath = spec.containerPath return kebabCase( `${getSyncKeyPrefix(ctx, action)}${target.kind}--${target.metadata.name}--${sourcePath}--${containerPath}` diff --git a/core/src/plugins/kubernetes/volumes/configmap.ts b/core/src/plugins/kubernetes/volumes/configmap.ts index 215bdf114e..e9cd89bf86 100644 --- a/core/src/plugins/kubernetes/volumes/configmap.ts +++ b/core/src/plugins/kubernetes/volumes/configmap.ts @@ -161,7 +161,7 @@ function getKubernetesAction(action: Resolved) { type: "kubernetes", name: action.name, internal: { - basePath: action.basePath(), + basePath: action.sourcePath(), }, include: [], timeout: KUBECTL_DEFAULT_TIMEOUT, diff --git a/core/src/plugins/kubernetes/volumes/persistentvolumeclaim.ts b/core/src/plugins/kubernetes/volumes/persistentvolumeclaim.ts index f7ae133182..d5d2228765 100644 --- a/core/src/plugins/kubernetes/volumes/persistentvolumeclaim.ts +++ b/core/src/plugins/kubernetes/volumes/persistentvolumeclaim.ts @@ -207,7 +207,7 @@ function getKubernetesAction(action: Resolved) { type: "kubernetes", name: action.name, internal: { - basePath: action.basePath(), + basePath: action.sourcePath(), }, include: [], timeout: KUBECTL_DEFAULT_TIMEOUT, diff --git a/core/src/tasks/resolve-action.ts b/core/src/tasks/resolve-action.ts index abf7def209..c41acb550c 100644 --- a/core/src/tasks/resolve-action.ts +++ b/core/src/tasks/resolve-action.ts @@ -147,7 +147,7 @@ export class ResolveActionTask extends BaseActionTask extends BaseActionTask { // the version file is used internally to specify versions outside of source control - const path = getConfigBasePath(params.config) + const path = getSourcePath(params.config) const versionFilePath = join(path, GARDEN_TREEVERSION_FILENAME) const fileVersion = await readTreeVersionFile(versionFilePath) return fileVersion || (await this.getTreeVersion(params)) @@ -445,7 +445,7 @@ export function hashStrings(hashes: string[]) { } export function getResourceTreeCacheKey(config: ModuleConfig | BaseActionConfig) { - const cacheKey = ["source", getConfigBasePath(config)] + const cacheKey = ["source", getSourcePath(config)] if (config.include) { cacheKey.push("include", hashStrings(config.include.sort())) @@ -461,8 +461,14 @@ export function getConfigFilePath(config: ModuleConfig | BaseActionConfig) { return isActionConfig(config) ? config.internal?.configFilePath : config.configPath } -export function getConfigBasePath(config: ModuleConfig | BaseActionConfig) { - return isActionConfig(config) ? config.internal.basePath : config.path +export function getSourcePath(config: ModuleConfig | BaseActionConfig) { + if (isActionConfig(config)) { + const basePath = config.internal.basePath + const sourceRelPath = config.source?.path + return sourceRelPath ? getSourceAbsPath(basePath, sourceRelPath) : basePath + } else { + return config.path + } } export function describeConfig(config: ModuleConfig | BaseActionConfig) { diff --git a/core/test/data/test-projects/action-source-path/project.garden.yml b/core/test/data/test-projects/action-source-path/project.garden.yml new file mode 100644 index 0000000000..8afa2d120a --- /dev/null +++ b/core/test/data/test-projects/action-source-path/project.garden.yml @@ -0,0 +1,7 @@ +apiVersion: garden.io/v1 +kind: Project +name: action-source-path +environments: + - name: local +providers: + - name: test-plugin diff --git a/core/test/data/test-projects/action-source-path/some-dir/some-other-file.txt b/core/test/data/test-projects/action-source-path/some-dir/some-other-file.txt new file mode 100644 index 0000000000..1910281566 --- /dev/null +++ b/core/test/data/test-projects/action-source-path/some-dir/some-other-file.txt @@ -0,0 +1 @@ +foo \ No newline at end of file diff --git a/core/test/data/test-projects/action-source-path/some-dir/tps-report.txt b/core/test/data/test-projects/action-source-path/some-dir/tps-report.txt new file mode 100644 index 0000000000..9b6855708a --- /dev/null +++ b/core/test/data/test-projects/action-source-path/some-dir/tps-report.txt @@ -0,0 +1 @@ +We're putting the new cover letter on all of these now, Peter. Didn't you get the memo? \ No newline at end of file diff --git a/core/test/data/test-projects/action-source-path/some-dir/with-source.garden.yml b/core/test/data/test-projects/action-source-path/some-dir/with-source.garden.yml new file mode 100644 index 0000000000..28461e092d --- /dev/null +++ b/core/test/data/test-projects/action-source-path/some-dir/with-source.garden.yml @@ -0,0 +1,7 @@ +kind: Build +type: test +name: with-source +source: + path: ../ +include: [some-dir/**/*] +exclude: [some-dir/tps-report.txt] diff --git a/core/test/integ/src/plugins/hadolint/hadolint.ts b/core/test/integ/src/plugins/hadolint/hadolint.ts index bd90cdbd9e..18c3eb0681 100644 --- a/core/test/integ/src/plugins/hadolint/hadolint.ts +++ b/core/test/integ/src/plugins/hadolint/hadolint.ts @@ -95,7 +95,7 @@ describe("hadolint provider", () => { const graph = await garden.getConfigGraph({ log: garden.log, emit: false }) const testAction = graph.getTest("hadolint-foo") - expect(testAction.basePath()).to.equal(tmpPath) + expect(testAction.sourcePath()).to.equal(tmpPath) expect(testAction.getConfig("spec")).to.eql({ dockerfilePath: "foo.Dockerfile" }) expect(testAction.getConfig().description).to.include("auto-generated") }) @@ -143,7 +143,7 @@ describe("hadolint provider", () => { const graph = await garden.getConfigGraph({ log: garden.log, emit: false }) const testAction = graph.getTest("hadolint-foo") - expect(testAction.basePath()).to.equal(tmpPath) + expect(testAction.sourcePath()).to.equal(tmpPath) expect(testAction.getConfig("spec")).to.eql({ dockerfilePath: "foo.Dockerfile" }) expect(testAction.getConfig().description).to.include("auto-generated") }) diff --git a/core/test/integ/src/plugins/kubernetes/sync-mode.ts b/core/test/integ/src/plugins/kubernetes/sync-mode.ts index 5dd7d96d90..b98534cbc0 100644 --- a/core/test/integ/src/plugins/kubernetes/sync-mode.ts +++ b/core/test/integ/src/plugins/kubernetes/sync-mode.ts @@ -122,7 +122,7 @@ describe("sync mode deployments and sync behavior", () => { const workload = status.detail?.detail.workload! // First, we create a file locally and verify that it gets synced into the pod - const actionPath = action.basePath() + const actionPath = action.sourcePath() await writeFile(join(actionPath, "made_locally"), "foo") await sleep(300) const execRes = await execInPod(["/bin/sh", "-c", "cat /tmp/made_locally"], log, workload) @@ -183,7 +183,7 @@ describe("sync mode deployments and sync behavior", () => { }) const workload = status.detail?.detail.workload! - const actionPath = action.basePath() + const actionPath = action.sourcePath() // First, we create a non-ignored file locally await writeFile(join(actionPath, "made_locally"), "foo") @@ -394,7 +394,7 @@ describe("sync mode deployments and sync behavior", () => { mode: "two-way", defaultDirectoryMode: 0o755, defaultFileMode: 0o644, - sourcePath: join(action.basePath(), "src"), + sourcePath: join(action.sourcePath(), "src"), containerPath: "/app/src", }, ], diff --git a/core/test/unit/src/actions/action-configs-to-graph.ts b/core/test/unit/src/actions/action-configs-to-graph.ts index 044eae240d..9d96bbeada 100644 --- a/core/test/unit/src/actions/action-configs-to-graph.ts +++ b/core/test/unit/src/actions/action-configs-to-graph.ts @@ -61,7 +61,7 @@ describe("actionConfigsToGraph", () => { expect(actions.length).to.equal(1) expect(action.kind).to.equal("Build") expect(action.name).to.equal("foo") - expect(action.basePath()).to.equal(tmpDir.path) + expect(action.sourcePath()).to.equal(tmpDir.path) }) it("resolves a Deploy action", async () => { @@ -93,7 +93,7 @@ describe("actionConfigsToGraph", () => { expect(actions.length).to.equal(1) expect(action.kind).to.equal("Deploy") expect(action.name).to.equal("foo") - expect(action.basePath()).to.equal(tmpDir.path) + expect(action.sourcePath()).to.equal(tmpDir.path) }) it("resolves a Run action", async () => { @@ -125,7 +125,7 @@ describe("actionConfigsToGraph", () => { expect(actions.length).to.equal(1) expect(action.kind).to.equal("Run") expect(action.name).to.equal("foo") - expect(action.basePath()).to.equal(tmpDir.path) + expect(action.sourcePath()).to.equal(tmpDir.path) }) it("resolves a Test action", async () => { @@ -157,7 +157,7 @@ describe("actionConfigsToGraph", () => { expect(actions.length).to.equal(1) expect(action.kind).to.equal("Test") expect(action.name).to.equal("foo") - expect(action.basePath()).to.equal(tmpDir.path) + expect(action.sourcePath()).to.equal(tmpDir.path) }) it("resolves actions in groups", async () => { @@ -196,7 +196,7 @@ describe("actionConfigsToGraph", () => { expect(actions.length).to.equal(1) expect(action.kind).to.equal("Test") expect(action.name).to.equal("foo") - expect(action.basePath()).to.equal(tmpDir.path) + expect(action.sourcePath()).to.equal(tmpDir.path) }) it("adds dependencies from copyFrom on Build actions", async () => { diff --git a/core/test/unit/src/build-staging/build-staging.ts b/core/test/unit/src/build-staging/build-staging.ts index 6b6ce121fc..4a0045d6b8 100644 --- a/core/test/unit/src/build-staging/build-staging.ts +++ b/core/test/unit/src/build-staging/build-staging.ts @@ -452,7 +452,7 @@ function commonSyncTests(legacyBuildSync: boolean) { const graph = await garden.getConfigGraph({ log: garden.log, emit: false }) const buildActionA = graph.getBuild("module-a") - buildActionA.getFullVersion().files = [join(buildActionA.basePath(), defaultConfigFilename)] + buildActionA.getFullVersion().files = [join(buildActionA.sourcePath(), defaultConfigFilename)] await buildStaging.syncFromSrc({ action: buildActionA, log: garden.log }) const buildDirA = buildStaging.getBuildPath(buildActionA.getConfig()) diff --git a/core/test/unit/src/plugins/container/build.ts b/core/test/unit/src/plugins/container/build.ts index 96cef25baf..3b0c3fcec1 100644 --- a/core/test/unit/src/plugins/container/build.ts +++ b/core/test/unit/src/plugins/container/build.ts @@ -106,7 +106,7 @@ context("build.ts", () => { const action = await getAction() action["_config"].spec.dockerfile = "docker-dir/Dockerfile" - action.treeVersion().files.push(join(action.basePath(), "docker-dir", "Dockerfile")) + action.treeVersion().files.push(join(action.sourcePath(), "docker-dir", "Dockerfile")) sinon.replace(action, "getOutputs", () => ({ localImageId: "some/image" })) diff --git a/core/test/unit/src/vcs/vcs.ts b/core/test/unit/src/vcs/vcs.ts index 9119e814fd..b4a469363e 100644 --- a/core/test/unit/src/vcs/vcs.ts +++ b/core/test/unit/src/vcs/vcs.ts @@ -20,7 +20,7 @@ import { NamedModuleVersion, NamedTreeVersion, describeConfig, - getConfigBasePath, + getSourcePath, getConfigFilePath, GetTreeVersionParams, } from "../../../../src/vcs/vcs" @@ -61,7 +61,7 @@ export class TestVcsHandler extends VcsHandler { } override async getTreeVersion(params: GetTreeVersionParams) { - return this.testTreeVersions[getConfigBasePath(params.config)] || super.getTreeVersion(params) + return this.testTreeVersions[getSourcePath(params.config)] || super.getTreeVersion(params) } setTestTreeVersion(path: string, version: TreeVersion) { @@ -194,6 +194,21 @@ describe("VcsHandler", () => { expect(version.files).to.eql([resolve(moduleConfig.path, "yes.txt")]) }) + it("should join the config's base path with source.path (if provided) when calling getFiles", async () => { + const projectRoot = getDataDir("test-projects", "action-source-path") + const garden = await makeTestGarden(projectRoot) + const log = garden.log + const graph = await garden.getConfigGraph({ emit: false, log }) + const action = graph.getActionByRef("build.with-source") + const config = action.getConfig() + const treeVersion = await garden.vcs.getTreeVersion({ + log, + projectName: garden.projectName, + config, + }) + expect(treeVersion.files).to.eql([join(config.internal.basePath, "../", "/some-dir/some-other-file.txt")]) + }) + it("should not be affected by changes to the module's garden.yml that don't affect the module config", async () => { const projectRoot = getDataDir("test-projects", "multiple-module-config") const garden = await makeTestGarden(projectRoot) @@ -649,7 +664,7 @@ describe("helpers", () => { }) it("getConfigBasePath", () => { - const configBasePath = getConfigBasePath(baseActionConfig) + const configBasePath = getSourcePath(baseActionConfig) expect(configBasePath).to.equal(baseActionConfig.internal.basePath) }) @@ -681,7 +696,7 @@ describe("helpers", () => { }) it("getConfigBasePath", () => { - const configBasePath = getConfigBasePath(moduleConfig) + const configBasePath = getSourcePath(moduleConfig) expect(configBasePath).to.equal(moduleConfig.path) }) diff --git a/plugins/conftest-container/src/index.ts b/plugins/conftest-container/src/index.ts index b0ad630c29..f52dd8f23f 100644 --- a/plugins/conftest-container/src/index.ts +++ b/plugins/conftest-container/src/index.ts @@ -53,7 +53,7 @@ export const gardenPlugin = () => name, description: `conftest test for module '${action.name}' (auto-generated by conftest-container)`, internal: { - basePath: action.basePath(), + basePath: action.sourcePath(), }, timeout: action.getConfig().timeout, spec: { diff --git a/plugins/conftest-kubernetes/src/index.ts b/plugins/conftest-kubernetes/src/index.ts index 9b135f5bb5..7ec59dbd4f 100644 --- a/plugins/conftest-kubernetes/src/index.ts +++ b/plugins/conftest-kubernetes/src/index.ts @@ -64,7 +64,7 @@ export const gardenPlugin = () => // Make sure the policy path is valid POSIX on Windows const policyPath = slash( - relative(action.basePath(), resolve(ctx.projectRoot, provider.config.policyPath)) + relative(action.sourcePath(), resolve(ctx.projectRoot, provider.config.policyPath)) ) const isHelmModule = action.isCompatible("helm") @@ -77,7 +77,7 @@ export const gardenPlugin = () => name, description: `conftest test for '${action.longDescription()}' (auto-generated by conftest-kubernetes)`, internal: { - basePath: action.basePath(), + basePath: action.sourcePath(), }, timeout: action.getConfig().timeout, spec: { @@ -96,7 +96,7 @@ export const gardenPlugin = () => name, description: `conftest test for module '${action.longDescription()}' (auto-generated by conftest-kubernetes)`, internal: { - basePath: action.basePath(), + basePath: action.sourcePath(), }, timeout: action.getConfig().timeout, spec: { diff --git a/plugins/conftest/src/index.ts b/plugins/conftest/src/index.ts index 80033192bb..7548b852c3 100644 --- a/plugins/conftest/src/index.ts +++ b/plugins/conftest/src/index.ts @@ -171,7 +171,7 @@ export const gardenPlugin = () => } } - const args = prepareArgs(ctx, provider, action.basePath(), spec) + const args = prepareArgs(ctx, provider, action.sourcePath(), spec) args.push(...files) const result = await ctx.tools["conftest.conftest"].exec({ log, args, ignoreError: true, cwd: buildPath }) @@ -276,7 +276,7 @@ export const gardenPlugin = () => }) // Run conftest, piping the rendered chart to stdin - const args = prepareArgs(ctx, provider, action.basePath(), spec) + const args = prepareArgs(ctx, provider, action.sourcePath(), spec) args.push("-") const result = await ctx.tools["conftest.conftest"].exec({ diff --git a/plugins/jib/src/index.ts b/plugins/jib/src/index.ts index 9486ff0e4c..c85965997b 100644 --- a/plugins/jib/src/index.ts +++ b/plugins/jib/src/index.ts @@ -236,7 +236,7 @@ export const gardenPlugin = () => await mvn({ ctx, log, - cwd: action.basePath(), + cwd: action.sourcePath(), args: [...mavenPhases, ...args], openJdkPath, binaryPath: mavenPath, @@ -247,7 +247,7 @@ export const gardenPlugin = () => await mvnd({ ctx, log, - cwd: action.basePath(), + cwd: action.sourcePath(), args: [...mavenPhases, ...args], openJdkPath, binaryPath: mavendPath, @@ -258,7 +258,7 @@ export const gardenPlugin = () => await gradle({ ctx, log, - cwd: action.basePath(), + cwd: action.sourcePath(), args, openJdkPath, binaryPath: gradlePath, diff --git a/plugins/jib/src/util.ts b/plugins/jib/src/util.ts index 21764f0838..641864dec1 100644 --- a/plugins/jib/src/util.ts +++ b/plugins/jib/src/util.ts @@ -121,7 +121,7 @@ export function getBuildFlags(action: Resolved, projectType: Jib // TODO: don't assume action path is the project root // Unlike many other types, // jib-container builds are done from the source directory instead of the build staging directory. - const tarPath = resolve(action.basePath(), targetDir, tarFilename) + const tarPath = resolve(action.sourcePath(), targetDir, tarFilename) const dockerBuildArgs = getDockerBuildArgs(action.versionString(), buildArgs) const outputs = action.getOutputs() diff --git a/plugins/jib/test/index.ts b/plugins/jib/test/index.ts index c0975404d2..bc170d1044 100644 --- a/plugins/jib/test/index.ts +++ b/plugins/jib/test/index.ts @@ -79,7 +79,9 @@ describe("jib-container", function () { const tarPath = res.detail?.details.tarPath as string - expect(tarPath).to.equal(join(action.basePath(), "target", `jib-image-foo-${module.version.versionString}.tar`)) + expect(tarPath).to.equal( + join(action.sourcePath(), "target", `jib-image-foo-${module.version.versionString}.tar`) + ) }) it("builds a gradle project", async () => { @@ -97,7 +99,9 @@ describe("jib-container", function () { const tarPath = res.detail?.details.tarPath as string - expect(tarPath).to.equal(join(action.basePath(), "build", `jib-image-foo-${module.version.versionString}.tar`)) + expect(tarPath).to.equal( + join(action.sourcePath(), "build", `jib-image-foo-${module.version.versionString}.tar`) + ) }) }) diff --git a/plugins/pulumi/src/helpers.ts b/plugins/pulumi/src/helpers.ts index 22999dabd7..4ff4478545 100644 --- a/plugins/pulumi/src/helpers.ts +++ b/plugins/pulumi/src/helpers.ts @@ -239,7 +239,7 @@ export function getStackName(action: Resolved): string { } export function getActionStackRoot(action: Resolved): string { - return join(action.basePath(), action.getSpec("root")) + return join(action.sourcePath(), action.getSpec("root")) } /** @@ -537,7 +537,7 @@ async function loadPulumiVarfile({ log: Log varfilePath: string }): Promise { - const resolvedPath = resolve(action.basePath(), varfilePath) + const resolvedPath = resolve(action.sourcePath(), varfilePath) if (!(await pathExists(resolvedPath))) { log.verbose(`Could not find varfile at path '${resolvedPath}' for pulumi action ${action.name}`) return {} diff --git a/plugins/pulumi/src/index.ts b/plugins/pulumi/src/index.ts index b9f306f76c..bb560714a5 100644 --- a/plugins/pulumi/src/index.ts +++ b/plugins/pulumi/src/index.ts @@ -56,7 +56,7 @@ export const gardenPlugin = () => validate: async ({ action }) => { const root = action.getSpec("root") if (root) { - const absRoot = join(action.basePath(), root) + const absRoot = join(action.sourcePath(), root) const exists = await pathExists(absRoot) if (!exists) { diff --git a/plugins/terraform/src/commands.ts b/plugins/terraform/src/commands.ts index 4e1b2d61e0..027cf987a2 100644 --- a/plugins/terraform/src/commands.ts +++ b/plugins/terraform/src/commands.ts @@ -89,7 +89,7 @@ function makeActionCommand(commandName: string): PluginCommand { const resolvedAction = await garden.resolveAction({ graph, action, log }) const spec = resolvedAction.getSpec() - const root = join(action.basePath(), spec.root) + const root = join(action.sourcePath(), spec.root) const provider = ctx.provider as TerraformProvider const workspace = spec.workspace || null diff --git a/plugins/terraform/src/index.ts b/plugins/terraform/src/index.ts index 1e34158c02..5111403151 100644 --- a/plugins/terraform/src/index.ts +++ b/plugins/terraform/src/index.ts @@ -101,7 +101,7 @@ export const gardenPlugin = () => validate: async ({ action }) => { const root = action.getSpec("root") if (root) { - const absRoot = join(action.basePath(), root) + const absRoot = join(action.sourcePath(), root) const exists = await pathExists(absRoot) if (!exists) {