Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

The psake/Invoke-Build task drift guard compares nothing against nothing

未关闭
#215 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
3/5
预计耗时
1-2 天
新手友好度
72/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
powershell

调研方向

从 tests/IBTasks.tests.ps1 中名为 'Parseable by invoke-build' 和 'Contains all the tasks that were in the Psake file' 的 It 块开始,然后运行 Pester 测试套件以复现错误通过。将任务名称保护检查与相邻的设置和签名比较进行对比。未修改的文件通过且有意造成的任务名称差异失败,即表示完成。

由索引模型根据 Issue 内容生成。

描述

bug

tests/IBTasks.tests.ps1, the It 'Contains all the tasks that were in the Psake file', is the only guard that psake and Invoke-Build still define the same tasks. It cannot fail. Two independent defects cancel each other out, and fixing either one alone turns it red.

What happens

Defect one: $IBTasksResult is $null inside the It that reads it.

$IBTasksResult = $null                       # Describe body: runs at discovery only
It 'Parseable by invoke-build' {
    $IBTasksResult = Start-Job { ... } | Wait-Job | Receive-Job    # assigned here
    ...
}
It 'Contains all the tasks that were in the Psake file' {
    $IBTaskNames = $IBTasksResult.all.name   # ...and $null here

Each It block runs in its own scope, so the assignment in the first block is not visible in the second, and the $IBTasksResult = $null at the Describe level runs during discovery rather than during the run. $IBTaskNames is therefore $null.

Defect two: $psakeTaskNames is a collection of $null.

$psakeTaskNames = Start-Job -ScriptBlock {
    Invoke-PSake -docs -buildfile $using:psakeFilePath | Where-Object name -notmatch '^(default|\?)$' | ForEach-Object name
} | Wait-Job | Receive-Job

Invoke-PSake -docs formats a table to the output stream. What crosses the job boundary is therefore format records, not task objects, and a format record has no Name property. Measured on this repository at 484f24f:

Deserialized.Microsoft.PowerShell.Commands.Internal.Format.FormatStartData   1
Deserialized.Microsoft.PowerShell.Commands.Internal.Format.GroupStartData    1
Deserialized.Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData  17
Deserialized.Microsoft.PowerShell.Commands.Internal.Format.GroupEndData      1
Deserialized.Microsoft.PowerShell.Commands.Internal.Format.FormatEndData     1

$psakeTaskNames.Count  = 21
non-null entries       = 0

Where-Object name -notmatch ... also passes all 21 through, because $null -notmatch anything is true.

The two cancel. The loop becomes foreach ($taskItem in @($null, $null, ...)), the test is $null -notin $null, which evaluates to False, so the throw never fires. The closing assertion is @($null, $null, ...) | Should -Not -BeNullOrEmpty, which passes because the array has 21 elements even though every one of them is $null.

Measured: the guard does not fire on the divergence it exists to catch

Renaming a single task in the built IB.tasks.ps1 so it no longer matches psakeFile.ps1 — exactly the drift the test was written for:

-Task Sign SignModule, SignCatalog
+Task RenamedSignTask SignModule, SignCatalog
Describing Invoke-Build Tasks
  [+] IB.tasks.ps1 exists
  [+] Parseable by invoke-build
  [+] Contains all the tasks that were in the Psake file      <-- should be red
Tests Passed: 8, Failed: 0

PowerShell 7.6.5, Pester 6.1.0, psake 5.0.4, Windows 11.

Why it matters

Divergence between the two task files is not hypothetical; it is this repository's most productive defect class, and it reaches Invoke-Build consumers only.

  • #178: IB.tasks.ps1 read Test.CodeCoverage.OutputFormat while the defaults define OutputFileFormat, so no Invoke-Build consumer had a working code coverage format.
  • #193: IB.tasks.ps1 never passed SkipValidation, so $PSBPreference.Sign.SkipCertificateValidation was dead for every Invoke-Build consumer while it worked for psake consumers.

Both were found by hand and then covered by the other Describe blocks in this same file — the settings-path comparison and the signing-settings comparison — which do work. The task-name comparison, the oldest of the three and the one everything else was layered on top of, has never worked. A task added to psakeFile.ps1 and forgotten in IB.tasks.ps1 would ship silently today.

Options

  1. Fix both defects and keep the test. Move the whole thing into one It (or hoist the Invoke-Build run into a BeforeAll that assigns to a $script: variable), and get real task names out of psake with Get-PSakeScriptTasks -buildFile $psakeFilePath instead of Invoke-PSake -docs, which returns objects rather than a formatted table. Both halves must change together; either alone makes the test fail for the wrong reason.
  2. Replace it with a static comparison, like its two neighbours. The Settings referenced by the task files and Signing settings referenced by the task files blocks in this same file parse the two task files with a regular expression and compare, with no job, no psake invocation, and no format-record hazard. Task names could be compared the same way, which would also make the test fast and immune to psake's output format changing again.
  3. Delete it. It has never tested anything, and the two working Describe blocks below it cover the settings-level drift that has actually bitten. This is the cheapest option and the one that loses real coverage, since neither of those blocks can see a task that exists in one file and not the other.

(2) looks like the best value: it keeps the coverage, matches the pattern the rest of the file already uses, and removes the job entirely.

Related: #178, #193.

主要语言
PowerShell
星标
145
派生
27
平均合并
10 小时 16 分钟
30 天内合并 PR
34

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

psake/PowerShellBuild 的其他 Issue

查看 psake/PowerShellBuild 的全部 Issue

相似的 Issue

更多 Build System Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。