Skip to content

Commit 0924fb8

Browse files
committed
feat(#161): enforce single top-level function in src/public files
- Stop build-driven workflows when a src/public file contains zero or multiple top-level functions to prevent accidental public API leaks. - Introduce -OverrideWarning option to allow intentional bypass of this guard during builds, tests, packaging, and releases. - Update documentation to reflect new behavior and usage of -OverrideWarning.
1 parent 9b8b1a3 commit 0924fb8

37 files changed

Lines changed: 701 additions & 82 deletions

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ Keep stable `Update-NovaModuleVersion` / `% nova bump` releases on the SemVer ma
4040

4141
### Fixed
4242

43+
- Stop build-driven workflows when a `src/public` file contains zero or multiple top-level functions.
44+
- This prevents helper functions from being exported accidentally just because they live in a public file.
45+
- `Invoke-NovaBuild`, `Test-NovaBuild -Build`, packaging, publishing, and release flows now surface the warning
46+
consistently.
47+
- PowerShell supports `-OverrideWarning`, and the `nova` CLI supports `--override-warning` / `-o` when maintainers
48+
intentionally want to continue past the warning.
4349
- Fix `Invoke-NovaBuild` help discovery so it only scans `docs/<ProjectName>/` for PlatyPS
4450
markdown.
4551
- Regular markdown elsewhere under `docs/` no longer breaks the help-generation step.

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ PS> Invoke-NovaBuild
6868

6969
This creates the built module under `dist/NovaModuleTools/`.
7070

71+
Files under `src/public/` are expected to contain exactly one top-level function each. Nova now stops build-driven
72+
workflows when a public file contains zero or multiple top-level functions, because that layout can accidentally export
73+
helpers as part of the public API surface. Use `-OverrideWarning` / `--override-warning` / `-o` only when you
74+
intentionally want to bypass that guard for a specific build, test-build, package, publish, or release run.
75+
7176
When you want the test workflow to rebuild first, use:
7277

7378
```powershell

docs/NovaModuleTools/en-US/Invoke-NovaBuild.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Builds the current NovaModuleTools project into a ready-to-import PowerShell mod
2020
### __AllParameterSets
2121

2222
```text
23-
PS> Invoke-NovaBuild [-ContinuousIntegration] [-WhatIf] [-Confirm] [<CommonParameters>]
23+
PS> Invoke-NovaBuild [-ContinuousIntegration] [-OverrideWarning] [-WhatIf] [-Confirm] [<CommonParameters>]
2424
```
2525

2626
## DESCRIPTION
@@ -33,6 +33,10 @@ build target without clearing `dist/` or generating new build output.
3333
Use `-ContinuousIntegration` when the same PowerShell session needs to keep using the freshly built `dist/` module after
3434
the build completes. In CI/self-hosting flows, that re-activates the built module before the command returns.
3535

36+
Use `-OverrideWarning` only when you intentionally want to continue a build even though a file under `src/public`
37+
contains zero or multiple top-level functions. The normal build guard stops there because those layouts can leak helper
38+
functions into the public API surface.
39+
3640
The command:
3741

3842
1. clears the existing `dist/` output
@@ -126,6 +130,30 @@ AcceptedValues: [ ]
126130
HelpMessage: ''
127131
```
128132
133+
### -OverrideWarning
134+
135+
Continue the build when the `src/public` layout guard reports that a public file does not contain exactly one top-level
136+
function.
137+
138+
Use this only when you intentionally accept the warning and still want the current build to proceed.
139+
140+
```yaml
141+
Type: System.Management.Automation.SwitchParameter
142+
DefaultValue: False
143+
SupportsWildcards: false
144+
Aliases: [ ]
145+
ParameterSets:
146+
- Name: (All)
147+
Position: Named
148+
IsRequired: false
149+
ValueFromPipeline: false
150+
ValueFromPipelineByPropertyName: false
151+
ValueFromRemainingArguments: false
152+
DontShow: false
153+
AcceptedValues: [ ]
154+
HelpMessage: ''
155+
```
156+
129157
### CommonParameters
130158

131159
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable,
@@ -155,6 +183,9 @@ Run this command from the project root so `project.json`, `src/`, `docs/<Project
155183
When `-ContinuousIntegration` is used together with a real build, the command re-imports the freshly built module after
156184
the build succeeds. `-WhatIf` previews remain side-effect free and do not change the loaded module state.
157185

186+
Files under `src/public` are expected to contain exactly one top-level function each. Use `-OverrideWarning` only when
187+
you intentionally want to bypass that guard for the current build.
188+
158189
## RELATED LINKS
159190

160191
- https://github.com/stiwicourage/NovaModuleTools/blob/main/docs/NovaModuleTools/en-US/Get-NovaProjectInfo.md

docs/NovaModuleTools/en-US/Invoke-NovaRelease.md

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,19 @@ Runs the Nova release pipeline (build, test, version bump, rebuild, publish).
2020
### Local
2121

2222
```text
23-
PS> Invoke-NovaRelease [-Local] [[-ModuleDirectoryPath] <string>] [[-ApiKey] <string>] [-SkipTests] [-ContinuousIntegration] [[-Path] <string>] [-WhatIf] [-Confirm] [<CommonParameters>]
23+
PS> Invoke-NovaRelease [-Local] [[-ModuleDirectoryPath] <string>] [[-ApiKey] <string>] [-SkipTests] [-ContinuousIntegration] [-OverrideWarning] [[-Path] <string>] [-WhatIf] [-Confirm] [<CommonParameters>]
2424
```
2525

2626
### Repository
2727

2828
```text
29-
PS> Invoke-NovaRelease -Repository <string> [[-ModuleDirectoryPath] <string>] [[-ApiKey] <string>] [-SkipTests] [-ContinuousIntegration] [[-Path] <string>] [-WhatIf] [-Confirm] [<CommonParameters>]
29+
PS> Invoke-NovaRelease -Repository <string> [[-ModuleDirectoryPath] <string>] [[-ApiKey] <string>] [-SkipTests] [-ContinuousIntegration] [-OverrideWarning] [[-Path] <string>] [-WhatIf] [-Confirm] [<CommonParameters>]
3030
```
3131

3232
### PublishOption
3333

3434
```text
35-
PS> Invoke-NovaRelease -PublishOption <hashtable> [-SkipTests] [-ContinuousIntegration] [[-Path] <string>] [-WhatIf] [-Confirm] [<CommonParameters>]
35+
PS> Invoke-NovaRelease -PublishOption <hashtable> [-SkipTests] [-ContinuousIntegration] [-OverrideWarning] [[-Path] <string>] [-WhatIf] [-Confirm] [<CommonParameters>]
3636
```
3737

3838
## DESCRIPTION
@@ -58,6 +58,9 @@ Use `-ContinuousIntegration` when the same CI/self-hosting session should re-act
5858
release workflow boundaries where session state matters. Nova forwards that CI intent into the nested build and version
5959
bump steps and restores the built module again after publish.
6060

61+
Use `-OverrideWarning` only when you intentionally want the nested release builds to continue even though a file under
62+
`src/public` contains zero or multiple top-level functions.
63+
6164
When local release mode is selected, the resolved local publish target is previewed consistently with
6265
`Publish-NovaModule -Local`. Unlike `Publish-NovaModule -Local`, `Invoke-NovaRelease` does not import the published
6366
module into the current session after publishing; it returns the version result for automation-friendly release flows.
@@ -316,6 +319,32 @@ AcceptedValues: [ ]
316319
HelpMessage: ''
317320
```
318321

322+
### -OverrideWarning
323+
324+
Continue the nested release builds even if the `src/public` layout guard reports that a public file does not contain
325+
exactly one top-level function.
326+
327+
```yaml
328+
Type: System.Management.Automation.SwitchParameter
329+
DefaultValue: False
330+
SupportsWildcards: false
331+
Aliases: [ ]
332+
ParameterSets:
333+
- Name: Local
334+
Position: Named
335+
- Name: Repository
336+
Position: Named
337+
- Name: PublishOption
338+
Position: Named
339+
IsRequired: false
340+
ValueFromPipeline: false
341+
ValueFromPipelineByPropertyName: false
342+
ValueFromRemainingArguments: false
343+
DontShow: false
344+
AcceptedValues: [ ]
345+
HelpMessage: ''
346+
```
347+
319348
### CommonParameters
320349

321350
This cmdlet supports the common parameters: `-Debug`, `-ErrorAction`, `-ErrorVariable`, `-InformationAction`,

docs/NovaModuleTools/en-US/New-NovaModulePackage.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Builds, tests, and packages the current project as one or more configured packag
2020
### __AllParameterSets
2121

2222
```text
23-
PS> New-NovaModulePackage [-SkipTests] [-WhatIf] [-Confirm] [<CommonParameters>]
23+
PS> New-NovaModulePackage [-SkipTests] [-OverrideWarning] [-WhatIf] [-Confirm] [<CommonParameters>]
2424
```
2525

2626
## DESCRIPTION
@@ -31,6 +31,9 @@ PS> New-NovaModulePackage [-SkipTests] [-WhatIf] [-Confirm] [<CommonParameters>]
3131
Use `-SkipTests` when tests already ran earlier in your pipeline and you only want to skip `Test-NovaBuild` for this
3232
packaging run. `Invoke-NovaBuild` still runs so the package is created from fresh built output.
3333

34+
Use `-OverrideWarning` only when you intentionally want the nested build to continue even though a file under
35+
`src/public` contains zero or multiple top-level functions.
36+
3437
The package is written to `artifacts/packages/` by default. You can override generic package metadata through the
3538
optional `Package` section in `project.json`.
3639

@@ -172,6 +175,28 @@ AcceptedValues: [ ]
172175
HelpMessage: ''
173176
```
174177
178+
### -OverrideWarning
179+
180+
Continue the nested build even if the `src/public` layout guard reports that a public file does not contain exactly one
181+
top-level function.
182+
183+
```yaml
184+
Type: System.Management.Automation.SwitchParameter
185+
DefaultValue: False
186+
SupportsWildcards: false
187+
Aliases: [ ]
188+
ParameterSets:
189+
- Name: (All)
190+
Position: Named
191+
IsRequired: false
192+
ValueFromPipeline: false
193+
ValueFromPipelineByPropertyName: false
194+
ValueFromRemainingArguments: false
195+
DontShow: false
196+
AcceptedValues: [ ]
197+
HelpMessage: ''
198+
```
199+
175200
### -WhatIf
176201

177202
Shows what would happen if the cmdlet runs. The cmdlet is not run.
@@ -259,6 +284,9 @@ separate
259284

260285
When `-SkipTests` is used, only `Test-NovaBuild` is skipped. Build still runs.
261286

287+
Files under `src/public` are expected to contain exactly one top-level function each. `-OverrideWarning` bypasses that
288+
guard only for the current packaging run.
289+
262290
## RELATED LINKS
263291

264292
- https://github.com/stiwicourage/NovaModuleTools/blob/main/docs/NovaModuleTools/en-US/Invoke-NovaBuild.md

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

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ Builds, tests, and publishes the current project either locally or to a PowerShe
2020
### Local
2121

2222
```text
23-
PS> Publish-NovaModule [-Local] [[-ModuleDirectoryPath] <string>] [[-ApiKey] <string>] [-SkipTests] [-ContinuousIntegration] [-WhatIf] [-Confirm] [<CommonParameters>]
23+
PS> Publish-NovaModule [-Local] [[-ModuleDirectoryPath] <string>] [[-ApiKey] <string>] [-SkipTests] [-ContinuousIntegration] [-OverrideWarning] [-WhatIf] [-Confirm] [<CommonParameters>]
2424
```
2525

2626
### Repository
2727

2828
```text
29-
PS> Publish-NovaModule [-Repository] <string> [[-ModuleDirectoryPath] <string>] [[-ApiKey] <string>] [-SkipTests] [-ContinuousIntegration] [-WhatIf] [-Confirm] [<CommonParameters>]
29+
PS> Publish-NovaModule [-Repository] <string> [[-ModuleDirectoryPath] <string>] [[-ApiKey] <string>] [-SkipTests] [-ContinuousIntegration] [-OverrideWarning] [-WhatIf] [-Confirm] [<CommonParameters>]
3030
```
3131

3232
## DESCRIPTION
@@ -47,6 +47,9 @@ Use `-ContinuousIntegration` when the same CI/self-hosting session should switch
4747
publish completes. This keeps later commands aligned with the built module state instead of whatever publish imported or
4848
left loaded.
4949

50+
Use `-OverrideWarning` only when you intentionally want the nested build to continue even though a file under
51+
`src/public` contains zero or multiple top-level functions.
52+
5053
This command supports `-WhatIf` and `-Confirm` through PowerShell `SupportsShouldProcess`. Use `-WhatIf` to preview the
5154
resolved publish target and workflow without building, testing, or publishing.
5255

@@ -255,6 +258,30 @@ AcceptedValues: [ ]
255258
HelpMessage: ''
256259
```
257260

261+
### -OverrideWarning
262+
263+
Continue the nested build even if the `src/public` layout guard reports that a public file does not contain exactly one
264+
top-level function.
265+
266+
```yaml
267+
Type: System.Management.Automation.SwitchParameter
268+
DefaultValue: False
269+
SupportsWildcards: false
270+
Aliases: [ ]
271+
ParameterSets:
272+
- Name: Local
273+
Position: Named
274+
- Name: Repository
275+
Position: Named
276+
IsRequired: false
277+
ValueFromPipeline: false
278+
ValueFromPipelineByPropertyName: false
279+
ValueFromRemainingArguments: false
280+
DontShow: false
281+
AcceptedValues: [ ]
282+
HelpMessage: ''
283+
```
284+
258285
### CommonParameters
259286

260287
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable,

docs/NovaModuleTools/en-US/Test-NovaBuild.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Runs Pester tests for the current NovaModuleTools project.
2020
### __AllParameterSets
2121

2222
```text
23-
PS> Test-NovaBuild [-Build] [[-TagFilter] <string[]>] [[-ExcludeTagFilter] <string[]>]
23+
PS> Test-NovaBuild [-Build] [-OverrideWarning] [[-TagFilter] <string[]>] [[-ExcludeTagFilter] <string[]>]
2424
[[-OutputVerbosity] <string>] [[-OutputRenderMode] <string>] [-WhatIf] [-Confirm] [<CommonParameters>]
2525
```
2626

@@ -31,6 +31,9 @@ suite against the current project.
3131

3232
Use `-Build` when you want Nova to rebuild the project output before the Pester run starts.
3333

34+
When `-Build` is used, `-OverrideWarning` lets that nested build continue even if the `src/public` layout guard reports
35+
zero or multiple top-level functions in a public file.
36+
3437
With the default
3538
`BuildRecursiveFolders=true`, test files in nested folders under `tests` are discovered and run. Set
3639
`BuildRecursiveFolders=false` to limit discovery to top-level `tests/*.Tests.ps1` files, following Pester's normal
@@ -120,6 +123,28 @@ AcceptedValues: [ ]
120123
HelpMessage: ''
121124
```
122125
126+
### -OverrideWarning
127+
128+
When `-Build` is also used, continue the nested build even if the `src/public` layout guard reports that a public file
129+
does not contain exactly one top-level function.
130+
131+
```yaml
132+
Type: System.Management.Automation.SwitchParameter
133+
DefaultValue: False
134+
SupportsWildcards: false
135+
Aliases: [ ]
136+
ParameterSets:
137+
- Name: (All)
138+
Position: Named
139+
IsRequired: false
140+
ValueFromPipeline: false
141+
ValueFromPipelineByPropertyName: false
142+
ValueFromRemainingArguments: false
143+
DontShow: false
144+
AcceptedValues: [ ]
145+
HelpMessage: ''
146+
```
147+
123148
### -ExcludeTagFilter
124149

125150
Array of Pester tags to exclude from the run.

0 commit comments

Comments
 (0)