Skip to content

Commit b29c225

Browse files
Copilotjongio
andauthored
Add --fix flag to azd app reqs for automatic PATH resolution (#48)
* Initial plan * Add --fix flag to reqs command for automatic PATH resolution Co-authored-by: jongio <2163001+jongio@users.noreply.github.com> * Add documentation for --fix flag Co-authored-by: jongio <2163001+jongio@users.noreply.github.com> * Initial plan * Fix: Add missing strings import to reqs_test.go * Add tests for automatic PATH resolution and error handling * Refactor runner functions to accept context for improved cancellation and timeout handling - Updated RunAspire, RunPnpmScript, RunDockerCompose, RunNode, RunPython, and RunDotnet functions to accept a context.Context parameter. - Modified integration and unit tests to pass context when calling updated functions. - Added ValidateFilePermissions function to check file permissions on Unix systems. - Enhanced OrchestrateServices function to include timeout handling for service startup. - Added error handling improvements and structured logging for orchestration events. - Introduced benchmarks for cache management and project detection functions. - Implemented error types for dependency installation and virtual environment setup. - Added constants for port management and service configurations. - Created fuzz tests for path validation and script name sanitization. * Add integration tests for azd CLI's PATH resolution and fix functionality - Created integration test suite in `integration-tests.md` to document and run tests for the `azd app reqs --fix` command. - Implemented `reqs_fix_integration_test.go` to cover various scenarios including basic PATH resolution, version mismatch, tool not found, and cache clearing. - Added tests for WebSocket origin validation in `server_security_test.go` to ensure only localhost origins are accepted. - Developed a test tool for simulating PATH resolution scenarios, including setup instructions and test scenarios in `README.md` and `test-scenarios.ps1`. - Enhanced `test-tool.go` to provide version and help commands for better usability during testing. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jongio <2163001+jongio@users.noreply.github.com>
1 parent 135adef commit b29c225

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+3721
-536
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ bin/
1414
*.out
1515
*.coverage
1616
coverage
17+
coverage-*
1718
*_coverage
1819
*_coverage.out
1920
src/coverage
@@ -82,6 +83,10 @@ obj/
8283
.azure/
8384
!tests/**/.azure/
8485

86+
# But ignore runtime artifacts within test .azure directories
87+
tests/**/.azure/logs/
88+
tests/**/.azure/cache/
89+
8590
# Test fixtures - preserve lock files and manifests in tests/
8691
!tests/projects/**/package.json
8792
!tests/projects/**/package-lock.json

cli/docs/commands/reqs.md

Lines changed: 176 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ azd app reqs [flags]
2626
| `--dry-run` | | bool | `false` | Preview changes without modifying azure.yaml |
2727
| `--no-cache` | | bool | `false` | Force fresh reqs check and bypass cached results |
2828
| `--clear-cache` | | bool | `false` | Clear cached reqs results |
29+
| `--fix` | | bool | `false` | Attempt to fix PATH issues for missing tools |
2930

3031
## Execution Flow
3132

@@ -147,6 +148,54 @@ azd app reqs [flags]
147148
└─────────────────┘
148149
```
149150

151+
### Fix Mode Flow
152+
153+
```
154+
┌─────────────────────────────────────────────────────────────┐
155+
│ azd app reqs --fix │
156+
└─────────────────────────────────────────────────────────────┘
157+
158+
┌─────────────────────────────────────────────────────────────┐
159+
│ Run Initial Requirements Check │
160+
│ - Identify failed prerequisites │
161+
└─────────────────────────────────────────────────────────────┘
162+
163+
┌───────┴────────┐
164+
│ │
165+
All Satisfied? Some Failed
166+
│ │
167+
↓ ↓
168+
┌─────────────┐ ┌──────────────────────┐
169+
│ Report │ │ Refresh System PATH │
170+
│ Success │ │ - Windows: Read from│
171+
│ │ │ Machine + User env│
172+
└─────────────┘ │ - Unix: Current PATH│
173+
└──────────────────────┘
174+
175+
176+
┌──────────────────────────┐
177+
│ For Each Failed Tool: │
178+
│ 1. Search in PATH │
179+
│ 2. Search common dirs │
180+
│ 3. Re-verify version │
181+
└──────────────────────────┘
182+
183+
184+
┌──────────────────────────┐
185+
│ Re-check All Reqs │
186+
│ - After PATH refresh │
187+
└──────────────────────────┘
188+
189+
190+
┌──────────────────────────┐
191+
│ Report Results: │
192+
│ - Fixed count │
193+
│ - Still missing │
194+
│ - Install suggestions │
195+
└──────────────────────────┘
196+
```
197+
198+
150199
## Prerequisite Checking Details
151200

152201
### Version Extraction Process
@@ -577,6 +626,19 @@ azd app reqs --clear-cache
577626
azd app reqs --no-cache
578627
```
579628

629+
### 5. Fixing PATH Issues
630+
631+
```bash
632+
# When tools are installed but not detected
633+
azd app reqs --fix
634+
635+
# The fix command will:
636+
# 1. Refresh environment PATH from system settings
637+
# 2. Search for missing tools in common locations
638+
# 3. Re-verify requirements after PATH update
639+
# 4. Provide installation instructions for truly missing tools
640+
```
641+
580642
## Integration with Other Commands
581643

582644
The `reqs` command is the **foundation** of the command dependency chain:
@@ -597,9 +659,26 @@ This ensures prerequisites are always validated before:
597659

598660
### Issue: "Tool not found" but it's installed
599661

600-
**Cause**: Tool not in PATH
662+
**Cause**: Tool not in PATH or PATH needs refresh
601663

602-
**Solution**:
664+
**Solution 1: Use --fix flag**:
665+
```bash
666+
# Automatically refresh PATH and search for tools
667+
azd app reqs --fix
668+
```
669+
670+
**Important: PATH Refresh Behavior**
671+
672+
**Windows**: The `--fix` command refreshes PATH from the Windows registry, but changes only affect the current `azd app` process and its child processes. If you've recently installed a tool and added it to your system PATH, you may need to:
673+
1. Close all terminal windows
674+
2. Open a new terminal
675+
3. Run `azd app reqs --fix` again
676+
677+
This limitation exists because Windows processes inherit environment variables at startup and cannot reload system-wide PATH changes dynamically.
678+
679+
**Unix/macOS**: The `--fix` command uses the current session's PATH. If you've modified shell profile files (`.bashrc`, `.zshrc`, etc.), you must restart your terminal for changes to take effect.
680+
681+
**Solution 2: Manual PATH configuration**:
603682
```bash
604683
# Check PATH
605684
echo $PATH
@@ -734,3 +813,98 @@ $ azd app reqs
734813
✓ postgresql: 15.4.0 (required: 15.0.0)
735814
- ✓ RUNNING
736815
```
816+
817+
### Example 4: Fix PATH Issues
818+
819+
```bash
820+
# Initial check shows tools missing
821+
$ azd app reqs
822+
823+
✓ Checking prerequisites
824+
825+
✗ node: NOT INSTALLED (required: 20.0.0)
826+
✗ docker: NOT INSTALLED (required: 20.10.0)
827+
✓ python: 3.12.0 (required: 3.11.0)
828+
829+
✗ Some prerequisites are not satisfied
830+
831+
# Run fix to resolve PATH issues
832+
$ azd app reqs --fix
833+
834+
🔧 Attempting to fix requirement issues...
835+
✗ node: NOT INSTALLED (required: 20.0.0)
836+
✗ docker: NOT INSTALLED (required: 20.10.0)
837+
838+
🔄 Refreshing environment PATH...
839+
✓ PATH refreshed successfully
840+
841+
🔍 Searching for node...
842+
✓ Found: C:\Program Files\nodejs\node.exe
843+
✓ Version verified successfully
844+
845+
🔍 Searching for docker...
846+
✓ Found: C:\Program Files\Docker\Docker\resources\bin\docker.exe
847+
✓ Version verified successfully
848+
849+
📋 Re-checking requirements...
850+
✓ node: 24.11.0 (required: 20.0.0)
851+
✓ docker: 28.5.1 (required: 20.10.0)
852+
✓ python: 3.12.0 (required: 3.11.0)
853+
854+
✓ Fixed 2 of 2 issues!
855+
856+
✓ All requirements now satisfied!
857+
858+
# JSON output mode
859+
$ azd app reqs --fix --output json
860+
{
861+
"success": true,
862+
"fixed": 2,
863+
"total": 2,
864+
"allSatisfied": true,
865+
"fixes": [
866+
{
867+
"name": "node",
868+
"fixed": true,
869+
"found": true,
870+
"path": "C:\\Program Files\\nodejs\\node.exe",
871+
"message": "Found and verified: C:\\Program Files\\nodejs\\node.exe",
872+
"satisfied": true
873+
},
874+
{
875+
"name": "docker",
876+
"fixed": true,
877+
"found": true,
878+
"path": "C:\\Program Files\\Docker\\Docker\\resources\\bin\\docker.exe",
879+
"message": "Found and verified: C:\\Program Files\\Docker\\Docker\\resources\\bin\\docker.exe",
880+
"satisfied": true
881+
}
882+
],
883+
"results": [
884+
{
885+
"name": "node",
886+
"installed": true,
887+
"version": "24.11.0",
888+
"required": "20.0.0",
889+
"satisfied": true,
890+
"message": "Satisfied"
891+
},
892+
{
893+
"name": "docker",
894+
"installed": true,
895+
"version": "28.5.1",
896+
"required": "20.10.0",
897+
"satisfied": true,
898+
"message": "Satisfied"
899+
},
900+
{
901+
"name": "python",
902+
"installed": true,
903+
"version": "3.12.0",
904+
"required": "3.11.0",
905+
"satisfied": true,
906+
"message": "Satisfied"
907+
}
908+
]
909+
}
910+
```

cli/docs/dev/integration-tests.md

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# Integration Tests
2+
3+
This document describes the integration test suite for the azd CLI extension.
4+
5+
## Running Integration Tests
6+
7+
Integration tests are tagged with `// +build integration` and must be explicitly enabled:
8+
9+
```powershell
10+
# Run all integration tests
11+
go test -tags=integration -v ./src/cmd/app/commands -timeout 10m
12+
13+
# Run specific integration test
14+
go test -tags=integration -v ./src/cmd/app/commands -run TestReqsFixIntegration_BasicPATHResolution -timeout 10m
15+
```
16+
17+
## PATH Resolution Integration Tests
18+
19+
The `reqs_fix_integration_test.go` file contains comprehensive integration tests for the `--fix` flag functionality.
20+
21+
### Test Coverage
22+
23+
#### TestReqsFixIntegration_BasicPATHResolution
24+
Tests the complete PATH resolution workflow:
25+
1. Builds a test-tool binary
26+
2. Installs it to a custom directory
27+
3. Adds directory to User PATH (Windows registry)
28+
4. Verifies tool is NOT in current session PATH
29+
5. Runs `azd app reqs --fix`
30+
6. Verifies tool is found via registry PATH refresh
31+
7. Validates version checking works correctly
32+
33+
**Expected Result**: Fix succeeds and finds tool in registry PATH
34+
35+
#### TestReqsFixIntegration_VersionMismatch
36+
Tests version validation during fix:
37+
1. Builds test-tool (version 2.5.0)
38+
2. Adds to registry PATH
39+
3. Creates project requiring version 10.0.0
40+
4. Runs `azd app reqs --fix`
41+
42+
**Expected Result**: Fix fails with version mismatch error
43+
44+
#### TestReqsFixIntegration_ToolNotFound
45+
Tests behavior when tool doesn't exist anywhere:
46+
1. Creates project requiring nonexistent tool
47+
2. Runs `azd app reqs --fix`
48+
49+
**Expected Result**: Fix fails with "not found" error
50+
51+
#### TestReqsFixIntegration_CacheClearing
52+
Tests that cache is properly invalidated after successful fix:
53+
1. Creates fake cache entry
54+
2. Runs `azd app reqs --fix`
55+
3. Verifies cache was cleared
56+
57+
**Expected Result**: Old cache is removed after fix
58+
59+
### Platform Support
60+
61+
Currently, these integration tests only run on Windows because they test registry-based PATH resolution. Future versions should add Unix-specific tests for shell profile PATH resolution.
62+
63+
### Test Requirements
64+
65+
- **Windows**: Administrator privileges not required (uses User PATH)
66+
- **Go compiler**: Required to build test-tool
67+
- **Temporary directories**: Tests use `t.TempDir()` for isolation
68+
- **PATH cleanup**: Tests automatically restore PATH state after completion
69+
70+
### Manual Testing
71+
72+
For manual testing scenarios, use the PowerShell test scripts:
73+
74+
```powershell
75+
cd cli\tests\test-tool
76+
.\test-scenarios.ps1 -Action test-basic
77+
.\test-scenarios.ps1 -Action test-version-mismatch
78+
.\test-scenarios.ps1 -Action test-not-found
79+
.\test-scenarios.ps1 -Action cleanup
80+
```
81+
82+
See [test-tool README](../../tests/test-tool/README.md) for details.
83+
84+
## Adding New Integration Tests
85+
86+
When adding integration tests:
87+
88+
1. **Tag with build constraint**: Add `// +build integration` at the top
89+
2. **Use short mode skip**: Add `if testing.Short() { t.Skip(...) }`
90+
3. **Clean up resources**: Use `defer` to ensure cleanup happens
91+
4. **Use temp directories**: Use `t.TempDir()` for isolation
92+
5. **Document expected behavior**: Add clear comments about what's being tested
93+
94+
Example:
95+
96+
```go
97+
// +build integration
98+
99+
package commands
100+
101+
func TestMyIntegration(t *testing.T) {
102+
if testing.Short() {
103+
t.Skip("Skipping integration test in short mode")
104+
}
105+
106+
testDir := t.TempDir()
107+
defer cleanup(t, testDir)
108+
109+
// Test implementation
110+
}
111+
```
112+
113+
## Debugging Integration Tests
114+
115+
To debug integration tests:
116+
117+
```powershell
118+
# Run with verbose output
119+
go test -tags=integration -v ./src/cmd/app/commands -run TestReqsFixIntegration
120+
121+
# Run specific test with more detail
122+
go test -tags=integration -v ./src/cmd/app/commands -run TestReqsFixIntegration_BasicPATHResolution -timeout 10m
123+
124+
# Check what PATH modifications were made
125+
$env:PATH -split ';' | Select-String "CustomTools"
126+
127+
# Verify User PATH in registry
128+
[Environment]::GetEnvironmentVariable('Path', 'User')
129+
```
130+
131+
## CI/CD Integration
132+
133+
Integration tests should run in CI:
134+
135+
```yaml
136+
- name: Run Integration Tests
137+
run: go test -tags=integration -v ./src/cmd/app/commands -timeout 10m
138+
env:
139+
GO111MODULE: on
140+
```
141+
142+
For Windows-specific tests, use conditional execution:
143+
144+
```yaml
145+
- name: Run Windows Integration Tests
146+
if: runner.os == 'Windows'
147+
run: go test -tags=integration -v ./src/cmd/app/commands -run TestReqsFixIntegration -timeout 10m
148+
```

0 commit comments

Comments
 (0)