Bug Description
Running azldev with --dry-run (-n) skips extraction of the embedded default
configuration into azldev's temporary directory. Project configuration loading then
immediately tries to read the skipped defaults.toml file and fails.
This is a global dry-run/config-loading issue, not specific to a particular command.
Commands that require a valid project fail before they can run.
Reproduction Steps
From a valid azldev project that uses the built-in default configuration, run:
azldev -n -O json config dump
The same initialization error occurs for component commands:
azldev -n -O json component list -a
Expected Behavior
Dry-run should suppress changes to the target project and external systems, while still
allowing internal temporary setup required to calculate and report what the command
would do. Both commands should load the resolved project configuration without writing
to the project.
Actual Behavior
The embedded defaults copy is skipped and configuration loading reads a path that was
never populated:
INF Dry run; would recursively copy dir source=/content dest=/tmp/azldev-tmp-.../azl-defconfigs-...
ERR Error loading configuration, execution may fail later; err="error loading project configuration:
failed to load project configuration:
failed to open project config file at '/tmp/azldev-tmp-.../azl-defconfigs-.../defaults.toml':
open /tmp/azldev-tmp-.../azl-defconfigs-.../defaults.toml: no such file or directory"
Observed command behavior:
azldev -n -O json config dump exits nonzero because it requires a valid config.
azldev -n -O json component list -a fails with the same initialization error.
Root Cause
internal/projectconfig.LoadProjectConfig creates a temporary destination and calls
defaultconfigs.CopyTo with the command's opctx.DryRunnable. CopyTo delegates to
fileutils.CopyDirRecursiveCrossFS, which returns successfully without copying when
DryRun() is true. LoadProjectConfig then appends the returned, nonexistent
defaults.toml path and attempts to load it.
There is also a contract mismatch in internal/utils/fileutils/copy.go:
CopyDirRecursive is documented as dry-run-aware.
CopyDirRecursiveCrossFS is documented as not dry-run-aware, but currently contains
the dry-run check.
The affected path dates back to commit b41e1cd4, where embedded default extraction and
the current dry-run behavior were introduced together.
Proposed Fix
Treat embedded default extraction as internal temporary setup, not a user-visible
mutation:
- Move the dry-run guard and "would recursively copy" log from
CopyDirRecursiveCrossFS into the same-filesystem CopyDirRecursive wrapper.
- Remove the
DryRunnable parameter from CopyDirRecursiveCrossFS; it should always
perform the cross-filesystem copy, matching its existing documentation.
- Remove the
DryRunnable parameter from defaultconfigs.CopyTo and use the
unconditional cross-filesystem copy for embedded defaults.
- Update
LoadProjectConfig to call the simplified defaultconfigs.CopyTo.
This preserves dry-run behavior for ordinary filesystem copies while allowing azldev to
materialize read-only inputs in its own temporary directory.
Acceptance Criteria
azldev -n -O json config dump succeeds in a valid project that uses built-in defaults.
azldev -n -O json component list -a succeeds without a configuration-loading error.
- Dry-run writes nothing to the target project.
- Internal default files may be written only under azldev's temporary directory and are
cleaned up through the existing temp-directory lifecycle.
CopyDirRecursive still skips normal same-filesystem copies during dry-run.
- A regression test loads project configuration with
DryRun() == true and built-in
defaults enabled.
Workaround
--no-default-config avoids this code path, but is only valid for projects that do not
depend on the built-in defaults and is not a general solution.
Bug Description
Running azldev with
--dry-run(-n) skips extraction of the embedded defaultconfiguration into azldev's temporary directory. Project configuration loading then
immediately tries to read the skipped
defaults.tomlfile and fails.This is a global dry-run/config-loading issue, not specific to a particular command.
Commands that require a valid project fail before they can run.
Reproduction Steps
From a valid azldev project that uses the built-in default configuration, run:
The same initialization error occurs for component commands:
Expected Behavior
Dry-run should suppress changes to the target project and external systems, while still
allowing internal temporary setup required to calculate and report what the command
would do. Both commands should load the resolved project configuration without writing
to the project.
Actual Behavior
The embedded defaults copy is skipped and configuration loading reads a path that was
never populated:
Observed command behavior:
azldev -n -O json config dumpexits nonzero because it requires a valid config.azldev -n -O json component list -afails with the same initialization error.Root Cause
internal/projectconfig.LoadProjectConfigcreates a temporary destination and callsdefaultconfigs.CopyTowith the command'sopctx.DryRunnable.CopyTodelegates tofileutils.CopyDirRecursiveCrossFS, which returns successfully without copying whenDryRun()is true.LoadProjectConfigthen appends the returned, nonexistentdefaults.tomlpath and attempts to load it.There is also a contract mismatch in
internal/utils/fileutils/copy.go:CopyDirRecursiveis documented as dry-run-aware.CopyDirRecursiveCrossFSis documented as not dry-run-aware, but currently containsthe dry-run check.
The affected path dates back to commit
b41e1cd4, where embedded default extraction andthe current dry-run behavior were introduced together.
Proposed Fix
Treat embedded default extraction as internal temporary setup, not a user-visible
mutation:
CopyDirRecursiveCrossFSinto the same-filesystemCopyDirRecursivewrapper.DryRunnableparameter fromCopyDirRecursiveCrossFS; it should alwaysperform the cross-filesystem copy, matching its existing documentation.
DryRunnableparameter fromdefaultconfigs.CopyToand use theunconditional cross-filesystem copy for embedded defaults.
LoadProjectConfigto call the simplifieddefaultconfigs.CopyTo.This preserves dry-run behavior for ordinary filesystem copies while allowing azldev to
materialize read-only inputs in its own temporary directory.
Acceptance Criteria
azldev -n -O json config dumpsucceeds in a valid project that uses built-in defaults.azldev -n -O json component list -asucceeds without a configuration-loading error.cleaned up through the existing temp-directory lifecycle.
CopyDirRecursivestill skips normal same-filesystem copies during dry-run.DryRun() == trueand built-indefaults enabled.
Workaround
--no-default-configavoids this code path, but is only valid for projects that do notdepend on the built-in defaults and is not a general solution.