Skip to content

Commit 2c06074

Browse files
committed
#215 feat: enhance scaffold feedback and error handling in Initialize-NovaModule
1 parent 14d15bd commit 2c06074

7 files changed

Lines changed: 122 additions & 13 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
2020
- `Deploy-NovaPackage` now shows a concise resolved-upload summary before execution, reports progress while multiple artifacts are uploading, and prints a short completion summary with a suggested verification step after successful raw uploads.
2121
- `Get-NovaProjectInfo` now fails with clearer recovery guidance when `-Path` does not exist, points to a file, or the target folder is missing `project.json`.
2222
- `Get-NovaUpdateNotificationPreference -Verbose` now explains whether Nova is reading a stored preference or the built-in default, and the command help now points read-only PowerShell users to the matching `% nova notification` workflow.
23+
- `Initialize-NovaModule` now shows scaffold progress, ends with the created project root plus the next suggested cmdlet, and fails with clearer guidance when the target project folder already exists.
2324

2425
### Deprecated
2526

RELEASE_NOTE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ This file summarizes the release notes for NovaModuleTools. **UNRELEASED** chang
1616
- `Deploy-NovaPackage` now shows clearer terminal feedback during raw package uploads, including a concise pre-flight summary, progress across multiple artifacts, and a short verification hint after success.
1717
- `Get-NovaProjectInfo` now explains how to recover when `-Path` is invalid or the target folder is not a Nova project root.
1818
- `Get-NovaUpdateNotificationPreference -Verbose` now tells you whether Nova is using a stored update-notification preference or the built-in default, and the help now points to the matching `% nova notification` workflow.
19+
- `Initialize-NovaModule` now shows scaffold progress, ends with the project root and the next suggested cmdlet, and gives clearer recovery guidance when the target project folder already exists.
1920

2021
### Deprecated
2122

docs/NovaModuleTools/en-US/Initialize-NovaModule.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ Use `-Example` when you want the scaffold to start from the packaged example pro
4545

4646
This command supports `-WhatIf` and `-Confirm` through PowerShell `SupportsShouldProcess`. Use `-WhatIf` to preview the scaffold target after the interactive answers have been collected, without creating folders, writing `project.json`, or initializing Git.
4747

48+
During scaffold creation, Nova shows progress for the main setup phases and finishes with the created project root plus the next cmdlet to run.
49+
4850
## EXAMPLES
4951

5052
### EXAMPLE 1
@@ -150,6 +152,8 @@ Generated projects start with NovaModuleTools defaults for recursive discovery,
150152
`-WhatIf` and
151153
`-Confirm` support.
152154

155+
Press `Ctrl+C` during the interactive prompt flow if you want to cancel before Nova creates the scaffold.
156+
153157
## RELATED LINKS
154158

155159
- [Invoke-NovaBuild](./Invoke-NovaBuild.md)

src/private/scaffold/InitializeNovaModuleScaffold.ps1

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ function Initialize-NovaModuleScaffold {
66
[switch]$Example
77
)
88

9-
if (Test-Path $Paths.Project) {
10-
Stop-NovaOperation -Message 'Project already exists, aborting' -ErrorId 'Nova.Workflow.ScaffoldProjectAlreadyExists' -Category ResourceExists -TargetObject $Paths.Project
9+
if (Test-Path -LiteralPath $Paths.Project) {
10+
Stop-NovaOperation -Message "Project folder already exists: $( $Paths.Project ). Choose a different project name or remove or move the existing folder before running Initialize-NovaModule again." -ErrorId 'Nova.Workflow.ScaffoldProjectAlreadyExists' -Category ResourceExists -TargetObject $Paths.Project
1111
}
1212

13-
Write-Message "`nStarted Module Scaffolding" -color Green
14-
Write-Message 'Setting up Directories'
13+
Write-Message 'Starting Nova module scaffold' -color Green
14+
Write-Message 'Creating project directories'
1515

1616
if ($Example) {
1717
Initialize-NovaExampleModuleScaffold -Paths $Paths
@@ -21,7 +21,7 @@ function Initialize-NovaModuleScaffold {
2121

2222
if ($Answer.EnableGit -eq 'Yes') {
2323
Update-NovaGitIgnore -ProjectRoot $Paths.Project -Confirm:$false
24-
Write-Message 'Initialize Git Repo'
24+
Write-Message 'Initializing Git repository'
2525
New-InitiateGitRepo -DirectoryPath $Paths.Project
2626
}
2727
}
@@ -39,7 +39,7 @@ function Initialize-NovaDefaultModuleScaffold {
3939
}
4040

4141
if ($Answer.EnablePester -eq 'Yes') {
42-
Write-Message 'Include Pester Configs'
42+
Write-Message 'Creating tests folder'
4343
New-Item -ItemType Directory -Path $Paths.Tests | Out-Null
4444
}
4545
}
@@ -50,7 +50,7 @@ function Initialize-NovaExampleModuleScaffold {
5050
[Parameter(Mandatory)][pscustomobject]$Paths
5151
)
5252

53-
Write-Message 'Copy example project template'
53+
Write-Message 'Copying packaged example project'
5454
New-Item -ItemType Directory -Path $Paths.Project | Out-Null
5555
Copy-NovaExampleProjectTemplate -DestinationPath $Paths.Project
5656
}

src/private/scaffold/InvokeNovaModuleInitializationWorkflow.ps1

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,72 @@ function Invoke-NovaModuleInitializationWorkflow {
44
[Parameter(Mandatory)][pscustomobject]$WorkflowContext
55
)
66

7-
Initialize-NovaModuleScaffold -Answer $WorkflowContext.AnswerSet -Paths $WorkflowContext.Layout -Example:$WorkflowContext.Example
8-
Write-NovaModuleProjectJson -Answer $WorkflowContext.AnswerSet -ProjectJsonFile $WorkflowContext.Layout.ProjectJsonFile -Example:$WorkflowContext.Example
9-
if ($WorkflowContext.AnswerSet.EnableAgenticCopilot -eq 'Yes') {
10-
Initialize-NovaModuleAgenticCopilotScaffold -Answer $WorkflowContext.AnswerSet -ProjectRoot $WorkflowContext.Layout.Project -Example:$WorkflowContext.Example
7+
$progressActivity = 'Creating Nova module scaffold'
8+
9+
try {
10+
Invoke-NovaModuleInitializationStep -Activity $progressActivity -Status 'Creating scaffold files' -PercentComplete 25 -Action {
11+
Initialize-NovaModuleScaffold -Answer $WorkflowContext.AnswerSet -Paths $WorkflowContext.Layout -Example:$WorkflowContext.Example
12+
}
13+
14+
Invoke-NovaModuleInitializationStep -Activity $progressActivity -Status 'Writing project.json' -PercentComplete 60 -Action {
15+
Write-NovaModuleProjectJson -Answer $WorkflowContext.AnswerSet -ProjectJsonFile $WorkflowContext.Layout.ProjectJsonFile -Example:$WorkflowContext.Example
16+
}
17+
18+
if ($WorkflowContext.AnswerSet.EnableAgenticCopilot -eq 'Yes') {
19+
Invoke-NovaModuleInitializationStep -Activity $progressActivity -Status 'Applying Agentic Copilot starter' -PercentComplete 85 -Action {
20+
Initialize-NovaModuleAgenticCopilotScaffold -Answer $WorkflowContext.AnswerSet -ProjectRoot $WorkflowContext.Layout.Project -Example:$WorkflowContext.Example
21+
}
22+
}
23+
} finally {
24+
Write-Progress -Activity $progressActivity -Completed
25+
}
26+
27+
Write-NovaModuleInitializationResult -WorkflowContext $WorkflowContext
28+
}
29+
30+
function Invoke-NovaModuleInitializationStep {
31+
[CmdletBinding()]
32+
param(
33+
[Parameter(Mandatory)][string]$Activity,
34+
[Parameter(Mandatory)][string]$Status,
35+
[Parameter(Mandatory)][int]$PercentComplete,
36+
[Parameter(Mandatory)][scriptblock]$Action
37+
)
38+
39+
Write-Progress -Activity $Activity -Status $Status -PercentComplete $PercentComplete
40+
& $Action
41+
}
42+
43+
function Write-NovaModuleInitializationResult {
44+
[CmdletBinding()]
45+
param(
46+
[Parameter(Mandatory)][pscustomobject]$WorkflowContext
47+
)
48+
49+
Write-Message ("Created Nova module scaffold: $( $WorkflowContext.AnswerSet.ProjectName )") -color Green
50+
Write-Message ("Project root: $( $WorkflowContext.Layout.Project )")
51+
52+
foreach ($line in (Get-NovaModuleInitializationNextStepLine -WorkflowContext $WorkflowContext)) {
53+
Write-Message $line
54+
}
55+
}
56+
57+
function Get-NovaModuleInitializationNextStepLine {
58+
[CmdletBinding()]
59+
param(
60+
[Parameter(Mandatory)][pscustomobject]$WorkflowContext
61+
)
62+
63+
$nextSteps = @(
64+
'Next steps:'
65+
"Set-Location $( $WorkflowContext.Layout.Project )"
66+
)
67+
68+
if ($WorkflowContext.Example) {
69+
$nextSteps += 'Test-NovaBuild'
70+
return $nextSteps
1171
}
1272

13-
'Module {0} scaffolding complete' -f $WorkflowContext.AnswerSet.ProjectName | Write-Message -color Green
73+
$nextSteps += 'Invoke-NovaBuild'
74+
return $nextSteps
1475
}

tests/private/scaffold/InitializeNovaModuleScaffold.Tests.ps1

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,18 @@ BeforeAll {
88
}
99

1010
Describe 'Initialize-NovaModuleScaffold' {
11+
It 'fails with recovery guidance when the project folder already exists' {
12+
$paths = [pscustomobject]@{Project = (Join-Path $TestDrive 'ExistingProject')}
13+
$null = New-Item -ItemType Directory -Path $paths.Project -Force
14+
15+
{
16+
Initialize-NovaModuleScaffold -Answer @{
17+
EnableGit = 'No'
18+
EnableAgenticCopilot = 'No'
19+
} -Paths $paths
20+
} | Should -Throw '*Project folder already exists:*Choose a different project name or remove or move the existing folder before running Initialize-NovaModule again.*'
21+
}
22+
1123
It 'creates the default .gitignore for the standard scaffold when Git is enabled' {
1224
$paths = Get-NovaModuleScaffoldLayout -Path $TestDrive -ProjectName 'StandardWithGit'
1325
Mock Write-Message {}

tests/private/scaffold/InvokeNovaModuleInitializationWorkflow.Tests.ps1

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,29 @@ Describe 'Invoke-NovaModuleInitializationWorkflow' {
1919
Mock Write-NovaModuleProjectJson {}
2020
Mock Initialize-NovaModuleAgenticCopilotScaffold {}
2121
Mock Write-Message {}
22+
Mock Write-Progress {}
2223

2324
Invoke-NovaModuleInitializationWorkflow -WorkflowContext $script:context
2425

2526
Assert-MockCalled Initialize-NovaModuleScaffold -Times 1
2627
Assert-MockCalled Write-NovaModuleProjectJson -Times 1
2728
Assert-MockCalled Initialize-NovaModuleAgenticCopilotScaffold -Times 0
28-
Assert-MockCalled Write-Message -Times 1
29+
Assert-MockCalled Write-Progress -Times 3
30+
Assert-MockCalled Write-Message -Times 4
31+
Assert-MockCalled Write-Message -Times 1 -ParameterFilter {
32+
$InputObject -eq 'Created Nova module scaffold: DemoModule' -and $color -eq 'Green'
33+
}
34+
Assert-MockCalled Write-Message -Times 1 -ParameterFilter {
35+
$InputObject -eq 'Invoke-NovaBuild'
36+
}
2937
}
3038

3139
It 'invokes the Agentic Copilot scaffold step when the answer set requests it' {
3240
Mock Initialize-NovaModuleScaffold {}
3341
Mock Write-NovaModuleProjectJson {}
3442
Mock Initialize-NovaModuleAgenticCopilotScaffold {}
3543
Mock Write-Message {}
44+
Mock Write-Progress {}
3645

3746
$contextWithAgentic = [pscustomobject]@{
3847
AnswerSet = @{ProjectName = 'DemoModule'; EnableAgenticCopilot = 'Yes'}
@@ -42,5 +51,26 @@ Describe 'Invoke-NovaModuleInitializationWorkflow' {
4251
Invoke-NovaModuleInitializationWorkflow -WorkflowContext $contextWithAgentic
4352

4453
Assert-MockCalled Initialize-NovaModuleAgenticCopilotScaffold -Times 1
54+
Assert-MockCalled Write-Progress -Times 4
55+
}
56+
57+
It 'suggests Test-NovaBuild as the next step for the example scaffold' {
58+
Mock Initialize-NovaModuleScaffold {}
59+
Mock Write-NovaModuleProjectJson {}
60+
Mock Initialize-NovaModuleAgenticCopilotScaffold {}
61+
Mock Write-Message {}
62+
Mock Write-Progress {}
63+
64+
$exampleContext = [pscustomobject]@{
65+
AnswerSet = @{ProjectName = 'DemoModule'; EnableAgenticCopilot = 'No'}
66+
Layout = [pscustomobject]@{Project = '/tmp/DemoModule'; ProjectJsonFile = '/tmp/DemoModule/project.json'}
67+
Example = $true
68+
}
69+
70+
Invoke-NovaModuleInitializationWorkflow -WorkflowContext $exampleContext
71+
72+
Assert-MockCalled Write-Message -Times 1 -ParameterFilter {
73+
$InputObject -eq 'Test-NovaBuild'
74+
}
4575
}
4676
}

0 commit comments

Comments
 (0)