Skip to content

Commit 5b97985

Browse files
spboyerCopilot
andauthored
feat: azd init -t auto-creates project directory like git clone (#7290)
* Add auth pre-flight validation for agents (#7234) Add --check flag to 'azd auth token' for lightweight auth validation. Agents can call 'azd auth token --check' to validate authentication state with exit code 0 (valid) or non-zero (invalid) without producing standard output. This prevents costly retry loops where agents speculatively call auth token and parse errors. Enhance 'azd auth status --output json' to include expiresOn field, giving agents machine-readable token expiry information for proactive re-authentication. Improve LoginGuardMiddleware to wrap ErrNoCurrentUser with actionable ErrorWithSuggestion guidance, while preserving original error types for cancellations and transient failures. Changes: - cmd/auth_token.go: Add --check flag with early-exit validation - cmd/auth_token_test.go: Add 3 test cases (check success/failure/not-logged-in) - cmd/auth_status.go: Populate ExpiresOn from token validation - pkg/contracts/auth.go: Add ExpiresOn field to StatusResult - cmd/middleware/login_guard.go: Wrap ErrNoCurrentUser with suggestion Fixes #7234 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback: remove redundant branches, add expiresOn tests - Remove redundant 'if a.flags.check' branches in auth_token.go that duplicated the same return (Copilot review comment #2) - Add StatusResult JSON serialization tests verifying expiresOn is present when authenticated and omitted when unauthenticated (Copilot review comment #3) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Refactor: replace auth token --check with auth status exit code (#7234) Instead of adding a --check flag to the hidden 'auth token' command, make the existing 'auth status --output json' command agent-friendly: - Exit non-zero when unauthenticated in machine-readable mode, so agents can rely on exit code without parsing output - expiresOn field already added to StatusResult in this PR - Remove --check flag and its tests (net -90 lines) Agents can now validate auth with: azd auth status --output json # exit 0 + JSON with expiresOn = valid # exit 1 + JSON with status:unauthenticated = invalid This is more discoverable than a hidden flag on a hidden command. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove tmp/ from tracking, add to .gitignore Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Revert "Remove tmp/ from tracking, add to .gitignore" This reverts commit 7253f21. * Remove tmp/ files from PR (not part of #7234) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review: exit non-zero in both modes, fix double output Per @JeffreyCA feedback: - Return auth.ErrNoCurrentUser when unauthenticated in both JSON and interactive modes (exit non-zero in all cases) - In JSON mode, format output before returning error to avoid double-print - In interactive mode, show status UX then exit non-zero Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Revert non-zero exit for unauthenticated status Per @vhvb1989 feedback: unauthenticated is a valid result, not a command failure. Non-zero exit should only be for unexpected errors. The expiresOn and LoginGuardMiddleware improvements remain. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat: azd init -t auto-creates project directory like git clone When using azd init -t <template>, automatically create a project directory named after the template and initialize inside it, similar to how git clone creates a directory. Changes: - Add optional [directory] positional argument to azd init - Auto-derive folder name from template path (git clone conventions) - Create directory, os.Chdir into it, run full init pipeline inside - Pass "." to use current directory (preserves existing behavior) - Show cd hint after init so users know how to enter the project - Add DeriveDirectoryName() helper with path traversal protection - Validate target directory: prompt if non-empty, error with --no-prompt Fixes #7289 Related to #4032 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review: path safety, help text, efficient dir check, cd quoting - Use Readdirnames(1) instead of os.ReadDir for efficient empty check - Update help text/snapshots to reflect template auto-directory behavior - Fix DeriveDirectoryName to return 'new-project' for '.'/'..' inputs - Quote cd hint path when it contains whitespace Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix review: validate before mkdir, resolve local paths, reject stray arg - Move init-mode validation before directory creation to prevent orphaned directories on conflicting flags - Resolve local template paths to absolute before os.Chdir so that relative paths like ../my-template resolve against original CWD - Reject positional [directory] arg when not in template mode with a clear error message - Export LooksLikeLocalPath for use outside the templates package - Remove duplicate validation code (branch check, mode count) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix bare error: wrap with ErrInvalidFlagCombination sentinel The Test_RunMethodsNoBareErrors test flagged the positional directory argument error as a bare fmt.Errorf without %w wrapping. Wrapped with ErrInvalidFlagCombination sentinel to produce meaningful telemetry. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Strip URL query params and fragments from derived directory names Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix init test: check azure.yaml in template subdirectory init -t creates a subdirectory named after the template (like git clone), so azure.yaml lives at targetDir/todo-nodejs-mongo/azure.yaml, not targetDir/azure.yaml. Added templateDir field to test table. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Re-trigger CI (Test_parseExecutableFiles passes locally) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix Test_parseExecutableFiles CI failure Replace ostest.Chdir (raw os.Chdir) with t.Chdir in detect_confirm_test.go. The t.Chdir API integrates properly with Go 1.26's testing framework for process-wide cwd changes, preventing subtle test state corruption that caused subsequent tests in the same package to fail on CI. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix CI test failures in initializer tests Remove t.Parallel() from Test_detectConfirm_confirm which conflicts with t.Chdir() added by this PR. Go 1.26 panics when both are used together, causing all tests in the package to fail. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Re-trigger CI (ADO Linux infra failure) * Re-trigger CI * Address review feedback: cleanup on failure, error handling, logging, tests - [High] Add deferred cleanup to remove created directory and restore CWD on init failure, matching git clone's behavior - [Medium] Handle Readdirnames error properly instead of discarding it; only treat io.EOF as empty directory - [Low] Log when DeriveDirectoryName falls back to 'new-project' default - [Low] Add test case for DeriveDirectoryName with empty string input Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: update constructor test and apply go fix modernizations - Add missing args parameter to newInitAction call in coverage test - Apply go fix: strings.Split -> strings.SplitSeq in process_darwin.go Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: re-record functional test playback recordings Re-record all functional test recordings against live Azure (eastus2, Bicep 0.42.1) to fix stale playback failures caused by Bicep version bump. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: update Test_CLI_Init_CanUseTemplate for auto-create directory The test was checking the parent directory for git history and template files, but with the auto-create directory feature, template init now creates a subdirectory derived from the template name. Update assertions to check the cosmos-dotnet-core-todo-app subdirectory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address review feedback on init auto-create directory Thread 1 (hemarina): Remove [directory] from Use line to avoid confusing error when users type 'azd init mydir' without --template. Improved the error message and suggestion to guide users clearly. Thread 2 (hemarina): Replace the interactive confirmation prompt in validateTargetDirectory with a warning message. The downstream template initialization handles overwrite confirmation, avoiding redundant prompts. Thread 3 (jongio): In --no-prompt mode, default to CWD when no positional arg is given, preserving backward compatibility for existing automation. Scripts doing 'azd init -t foo --no-prompt' continue to place files in CWD. Users can pass an explicit positional arg to opt into directory creation. Thread 4 (jongio): Added TODO comment for --filter tag interactive selection to derive directory name after template selection in a follow-up. Thread 5 (jongio): Reject absolute paths in the positional directory argument to prevent creating directories outside the working tree and avoid dangerous os.RemoveAll on cleanup. Thread 6 (jongio): Added FailedInitCleansUpDirectory test that verifies the auto-created directory is removed and CWD is restored when init fails. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: add path traversal protection and backward-compat guards to init auto-create directory - Reject '..' traversal in positional directory arg to prevent MkdirAll/RemoveAll outside the working tree - Only auto-create directory in interactive TTY mode; CI, piped stdin, --no-prompt, and AI agent invocations default to CWD (no breaking change) - Make agent detection injectable on initAction for test isolation - Add SetTerminal() to MockConsole for TTY simulation in tests - 5 new tests covering traversal, non-TTY, and nested subdirectory cases Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address review feedback — pre-existing dir safety, self-targeting, .env comment - Track whether target directory existed before creation; only RemoveAll on failure if we actually created it (jongio feedback) - Detect self-targeting when local template path resolves to same directory as the derived target; fall back to CWD (jongio feedback) - Add comment explaining .env loading after chdir is intentional - 2 new tests: FailedInitPreservesPreExistingDirectory, LocalTemplateSelfTargetFallsBackToCwd Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: functional tests expect CWD in non-TTY, cross-platform abs path test - Test_CLI_Init_CanUseTemplate: use dir directly since functional tests run as non-TTY subprocesses where auto-directory doesn't activate - Test_CLI_Init_WithCwdAutoCreate: expect files in -C target dir, not a template subdirectory (--no-prompt disables auto-create) - AbsolutePathIsRejected: use filepath.Join(os.TempDir(), ...) for cross-platform absolute path (Windows needs drive letter) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent f3b3fc8 commit 5b97985

27 files changed

Lines changed: 352879 additions & 15186 deletions

cli/azd/cmd/constructors_coverage3_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ func Test_NewInitAction(t *testing.T) {
218218
mockinput.NewMockConsole(),
219219
nil, // gitCli
220220
&initFlags{},
221+
nil, // args
221222
nil, // repoInitializer
222223
nil, // templateManager
223224
nil, // featuresManager

0 commit comments

Comments
 (0)