feat: azd init -t auto-creates project directory like git clone#7290
feat: azd init -t auto-creates project directory like git clone#7290
Conversation
There was a problem hiding this comment.
Pull request overview
Updates azd init -t to behave more like git clone by defaulting template-based initialization into an auto-created project directory, with an optional positional [directory] override and updated outputs/specs/tests.
Changes:
- Add optional
[directory]positional arg toazd initand implement auto-create +chdirflow for template init. - Introduce
templates.DeriveDirectoryName()helper (with intended traversal protection) and add unit tests. - Extend auth status contract/output to include token expiry (
expiresOn) and improve login guidance for a specific auth error.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| cli/azd/pkg/templates/path.go | Adds DeriveDirectoryName() helper used to derive the auto-created project folder name. |
| cli/azd/pkg/templates/path_test.go | Adds test cases for DeriveDirectoryName() across URL/path formats and edge cases. |
| cli/azd/cmd/init.go | Adds [directory] positional arg, directory validation/creation, chdir, and a post-init cd hint. |
| cli/azd/cmd/init_test.go | Adds tests for resolving/validating/creating the target directory for template init. |
| cli/azd/cmd/testdata/TestUsage-azd-init.snap | Updates usage snapshot to include [directory]. |
| cli/azd/cmd/testdata/TestFigSpec.ts | Updates fig completion spec to include optional directory arg for init. |
| cli/azd/pkg/contracts/auth.go | Adds expiresOn field to auth status result contract. |
| cli/azd/pkg/contracts/auth_token_test.go | Adds JSON roundtrip tests for StatusResult with/without expiresOn. |
| cli/azd/cmd/auth_status.go | Populates StatusResult.ExpiresOn from acquired access token. |
| cli/azd/cmd/middleware/login_guard.go | Wraps ErrNoCurrentUser with a suggestion to run azd auth login. |
| ClientID string `json:"clientId,omitempty"` | ||
|
|
||
| // When authenticated, the time at which the current access token expires. | ||
| ExpiresOn *RFC3339Time `json:"expiresOn,omitempty"` |
There was a problem hiding this comment.
StatusResult.ExpiresOn is typed as *RFC3339Time while LoginResult.ExpiresOn uses *time.Time. This can lead to inconsistent JSON timestamp formatting across auth commands. Consider aligning the types/formatting (or explicitly documenting the difference) so consumers don’t have to special-case parsing.
| ExpiresOn *RFC3339Time `json:"expiresOn,omitempty"` | |
| ExpiresOn *time.Time `json:"expiresOn,omitempty"` |
There was a problem hiding this comment.
Not part of this PR — auth.go is not modified here. Will track separately.
6f0cbae to
e625f6a
Compare
|
/azp run |
|
You have several pipelines (over 10) configured to build pull requests in this repository. Specify which pipelines you would like to run by using /azp run [pipelines] command. You can specify multiple pipelines using a comma separated list. |
e625f6a to
584d3b2
Compare
Add lessons learned from recent PR reviews (#7290, #7251, #7250, #7247, #7236, #7235, #7202, #7039) as agent instructions to prevent recurring review findings. New sections: - Error handling: ErrorWithSuggestion completeness, telemetry service attribution, scope-agnostic messages - Architecture boundaries: pkg/project target-agnostic, extension docs - Output formatting: shell-safe paths, consistent JSON contracts - Path safety: traversal validation, quoted paths in messages - Testing best practices: test actual rules, extract shared helpers, correct env vars, TypeScript patterns, efficient dir checks - CI/GitHub Actions: permissions, PATH handling, artifact downloads, prefer ADO for secrets Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add lessons learned from team and Copilot reviews across PRs #7290, #7251, #7250, #7247, #7236, #7235, #7202, #7039 as agent instructions to prevent recurring review findings. New/expanded sections: - Error handling: ErrorWithSuggestion field completeness, telemetry service attribution, scope-agnostic messages, link/suggestion parity, stale data in polling loops - Architecture boundaries: pkg/project target-agnostic, extension docs separation, env var verification against source code - Output formatting: shell-safe quoted paths, consistent JSON types - Path safety: traversal validation, quoted paths in messages - Code organization: extract shared logic across scopes - Documentation standards: help text consistency, no dead references, PR description accuracy - Testing best practices: test YAML rules e2e, extract shared helpers, correct env vars (AZD_FORCE_TTY, NO_COLOR), TypeScript patterns, reasonable timeouts, cross-platform paths, test new JSON fields - CI / GitHub Actions: permissions blocks, PATH handling, cross-workflow artifacts, prefer ADO for secrets, no placeholder steps Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp run azure-dev - cli |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Add lessons learned from team and Copilot reviews across PRs #7290, #7251, #7250, #7247, #7236, #7235, #7202, #7039 as agent instructions to prevent recurring review findings. New/expanded sections: - Error handling: ErrorWithSuggestion field completeness, telemetry service attribution, scope-agnostic messages, link/suggestion parity, stale data in polling loops - Architecture boundaries: pkg/project target-agnostic, extension docs separation, env var verification against source code - Output formatting: shell-safe quoted paths, consistent JSON types - Path safety: traversal validation, quoted paths in messages - Code organization: extract shared logic across scopes - Documentation standards: help text consistency, no dead references, PR description accuracy - Testing best practices: test YAML rules e2e, extract shared helpers, correct env vars (AZD_FORCE_TTY, NO_COLOR), TypeScript patterns, reasonable timeouts, cross-platform paths, test new JSON fields - CI / GitHub Actions: permissions blocks, PATH handling, cross-workflow artifacts, prefer ADO for secrets, no placeholder steps Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp run azure-dev - cli |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Add lessons learned from team and Copilot reviews across PRs #7290, #7251, #7250, #7247, #7236, #7235, #7202, #7039 as agent instructions to prevent recurring review findings. New/expanded sections: - Error handling: ErrorWithSuggestion field completeness, telemetry service attribution, scope-agnostic messages, link/suggestion parity, stale data in polling loops - Architecture boundaries: pkg/project target-agnostic, extension docs separation, env var verification against source code - Output formatting: shell-safe quoted paths, consistent JSON types - Path safety: traversal validation, quoted paths in messages - Code organization: extract shared logic across scopes - Documentation standards: help text consistency, no dead references, PR description accuracy - Testing best practices: test YAML rules e2e, extract shared helpers, correct env vars (AZD_FORCE_TTY, NO_COLOR), TypeScript patterns, reasonable timeouts, cross-platform paths, test new JSON fields - CI / GitHub Actions: permissions blocks, PATH handling, cross-workflow artifacts, prefer ADO for secrets, no placeholder steps Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
584d3b2 to
c722542
Compare
Add lessons learned from team and Copilot reviews across PRs #7290, #7251, #7250, #7247, #7236, #7235, #7202, #7039 as agent instructions to prevent recurring review findings. New/expanded sections: - Error handling: ErrorWithSuggestion field completeness, telemetry service attribution, scope-agnostic messages, link/suggestion parity, stale data in polling loops - Architecture boundaries: pkg/project target-agnostic, extension docs separation, env var verification against source code - Output formatting: shell-safe quoted paths, consistent JSON types - Path safety: traversal validation, quoted paths in messages - Code organization: extract shared logic across scopes - Documentation standards: help text consistency, no dead references, PR description accuracy - Testing best practices: test YAML rules e2e, extract shared helpers, correct env vars (AZD_FORCE_TTY, NO_COLOR), TypeScript patterns, reasonable timeouts, cross-platform paths, test new JSON fields - CI / GitHub Actions: permissions blocks, PATH handling, cross-workflow artifacts, prefer ADO for secrets, no placeholder steps Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
c722542 to
bc6cbf5
Compare
|
/azp run azure-dev - cli |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/azp run azure-dev - cli |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Add lessons learned from team and Copilot reviews across PRs #7290, #7251, #7250, #7247, #7236, #7235, #7202, #7039 as agent instructions to prevent recurring review findings. New/expanded sections: - Error handling: ErrorWithSuggestion field completeness, telemetry service attribution, scope-agnostic messages, link/suggestion parity, stale data in polling loops - Architecture boundaries: pkg/project target-agnostic, extension docs separation, env var verification against source code - Output formatting: shell-safe quoted paths, consistent JSON types - Path safety: traversal validation, quoted paths in messages - Code organization: extract shared logic across scopes - Documentation standards: help text consistency, no dead references, PR description accuracy - Testing best practices: test YAML rules e2e, extract shared helpers, correct env vars (AZD_FORCE_TTY, NO_COLOR), TypeScript patterns, reasonable timeouts, cross-platform paths, test new JSON fields - CI / GitHub Actions: permissions blocks, PATH handling, cross-workflow artifacts, prefer ADO for secrets, no placeholder steps Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
bc6cbf5 to
2d14d48
Compare
Add lessons learned from team and Copilot reviews across PRs #7290, #7251, #7250, #7247, #7236, #7235, #7202, #7039 as agent instructions to prevent recurring review findings. New/expanded sections: - Error handling: ErrorWithSuggestion field completeness, telemetry service attribution, scope-agnostic messages, link/suggestion parity, stale data in polling loops - Architecture boundaries: pkg/project target-agnostic, extension docs separation, env var verification against source code - Output formatting: shell-safe quoted paths, consistent JSON types - Path safety: traversal validation, quoted paths in messages - Code organization: extract shared logic across scopes - Documentation standards: help text consistency, no dead references, PR description accuracy - Testing best practices: test YAML rules e2e, extract shared helpers, correct env vars (AZD_FORCE_TTY, NO_COLOR), TypeScript patterns, reasonable timeouts, cross-platform paths, test new JSON fields - CI / GitHub Actions: permissions blocks, PATH handling, cross-workflow artifacts, prefer ADO for secrets, no placeholder steps Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: add PR review patterns to AGENTS.md Add lessons learned from team and Copilot reviews across PRs #7290, #7251, #7250, #7247, #7236, #7235, #7202, #7039 as agent instructions to prevent recurring review findings. New/expanded sections: - Error handling: ErrorWithSuggestion field completeness, telemetry service attribution, scope-agnostic messages, link/suggestion parity, stale data in polling loops - Architecture boundaries: pkg/project target-agnostic, extension docs separation, env var verification against source code - Output formatting: shell-safe quoted paths, consistent JSON types - Path safety: traversal validation, quoted paths in messages - Code organization: extract shared logic across scopes - Documentation standards: help text consistency, no dead references, PR description accuracy - Testing best practices: test YAML rules e2e, extract shared helpers, correct env vars (AZD_FORCE_TTY, NO_COLOR), TypeScript patterns, reasonable timeouts, cross-platform paths, test new JSON fields - CI / GitHub Actions: permissions blocks, PATH handling, cross-workflow artifacts, prefer ADO for secrets, no placeholder steps Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix Copilot instructions for code review and strengthen guidance on Go patterns (#7320) * Fix Copilot instructions for code review and strengthen guidance on Go patterns * Update wording --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: JeffreyCA <jeffreychen@microsoft.com>
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>
- 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>
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>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This reverts commit 7253f21.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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>
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>
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>
- 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>
eb9be1d to
1d89c5b
Compare
spboyer
left a comment
There was a problem hiding this comment.
Code Review
1. Relative local template paths resolve against the wrong directory
cli/azd/cmd/init.go:221 — High
os.Chdir(targetDir) runs before initializeTemplate(). For local relative template paths (../my-template), templates.Absolute() resolves relative to the new directory, not the original CWD. The copy will either fail or pull from the wrong location.
Fix: Resolve local template paths to absolute before calling os.Chdir, or delay the chdir until after the template source is resolved.
2. Invalid init-mode combinations leave an orphaned directory
cli/azd/cmd/init.go:204 — Medium
The mkdir/chdir block runs before init-mode validation. Running azd init --template foo --minimal creates the foo/ directory then errors on the mode conflict, leaving an empty directory behind.
Fix: Move init-mode validation (initTypeCount > 1 check) before the directory creation block, or clean up the created directory on validation failure.
3. Positional [directory] arg silently ignored outside template init
cli/azd/cmd/init.go:57,202 — Medium
The cobra command accepts [directory] unconditionally, but the arg is only consumed inside the if isTemplateInit block. Running azd init --minimal mydir succeeds silently and initializes the current directory — the mydir argument is dropped. If a user interactively selects a template after running azd init mydir, the directory is also ignored.
Fix: Either reject the positional arg when no template flag is present, or honor it consistently across all init modes.
- 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>
Summary
When using
azd init -t <template>, automatically create a project directory named after the template and initialize inside it — similar to howgit clonecreates a directory.This addresses user feedback from a getting-started study (#4032):
Fixes #7289
Changes
[directory]positional argument toazd initgit cloneconventionsos.Chdirinto it, run full init pipeline inside.as directory to use current directory (preserves existing behavior)cdhint after init so users know how to enter the projectDeriveDirectoryName()helper with path traversal protection--no-promptUsage
Testing
DeriveDirectoryName()including edge cases (traversal, .git suffix, various URL formats)Files Changed
pkg/templates/path.goDeriveDirectoryName()with traversal protectioncmd/init.gocmd/init_test.gopkg/templates/path_test.gocmd/testdata/*.snap