Repository navigation
Releases: Fortigi/PSComplexity
Release list
v0.7.1
For consumers
Config paths are resolved the same way on every supported PowerShell. PowerShell 7.6 made
Join-Path -ChildPath take a list, which left the -join that turned a .pscomplexity.json path into
a full one doing nothing on 7.6 and all the work on 7.0 to 7.5 -- correct on both, but impossible to
test on the newest, where the suite runs. The path's segments now go in through
-AdditionalChildPath, which behaves the same from PowerShell 6.0 on. Every path resolves exactly as
before; no score moves and no command changed.
What's Changed
- ci: self-mutation on PSMutant 0.8.0 by @TaekeK in #214
- Self-mutation with PSMutant 0.8.0's new operators; config paths resolved the same on every PowerShell by @TaekeK in #215
Full Changelog: v0.7.0...v0.7.1
v0.7.0
For consumers
-Detailed reports each unit's lines of code. Complexity says nothing about size -- a long
function of straight-line code scores 1 and 0 -- so -Detailed now adds LinesOfCode, counted
exactly as SonarQube counts ncloc: a physical line holding at least one character that is neither
whitespace nor part of a comment. A brace on its own line, each line of a continued statement and
the non-blank lines of a here-string count; blank lines, comments and comment-based help do not.
Each line belongs to the innermost unit, so a nested function's lines are not its parent's. It is
information only, with no threshold, and a run without -Detailed is unchanged. The JSON report
carries it for a -Detailed run, as an optional field of each unit.
The gate's policy can live in a committed .pscomplexity.json. Ceilings, per-path overrides,
excludes, acceptances with their reasons and the baseline file, in one place for CI and for a run by
hand. Test-PSComplexity takes -ConfigFile, or finds the nearest .pscomplexity.json from each
path up to the repository root -- never above it, and not at all outside a repository -- and
-NoConfig turns that off. The file used is printed and recorded in the JSON report as config,
beside scope.exclude, scope.excluded and thresholds.overrides. The command line wins wherever
it says something. A config that is not valid is refused, naming every fault, and its format ships
as schemas/v1/config.schema.json. Without a config nothing changes: the ceilings are still 15 and
15. Measure-PSComplexity reads no config.
An acceptance can be written in the code. A # PSCx-Accept: <reason> line comment directly
above a function, method or constructor excuses that unit, with exactly the checks -Accept has:
the gate fails when the unit is back within its ceilings or the reason is empty. The argument then
moves with the code instead of going stale in a File + Unit list. A declaration that excuses
nothing -- separated by a blank line, sharing a line with code, or above something that is not a
unit -- is refused rather than ignored, and so is a unit accepted both in its code and in a list.
Whole units only. The report's accepted entries now say where each argument is written, as
source (inline or list) and the line of an inline one.
A Markdown summary, for a CI step summary or a pull request comment. -MarkdownPath on both
commands writes the run as Markdown: the verdict and every unit over a ceiling (the gate), the ten
most complex units (-MarkdownTop changes the number), per-file totals, and what the numbers do not
cover. With -CompareTo and a previous JSON report it also lists the units that are new, worse or
better than in that report; a report from another metric version is refused. Rendered from the same
scan as the records and the JSON report, so it holds no number they do not.
Gate only the functions a change touched. -ChangedDiff on both commands takes a unified diff
-- git diff --unified=0 origin/main...HEAD -- and restricts the run to the units owning a changed
line, where -ChangedFile takes every unit in a touched file. A changed line belongs to the
innermost unit holding it, so editing a nested function does not drag in its parent; a pure deletion
belongs to the unit it was deleted from; a line outside every function belongs to the script body.
Only the +++ and @@ headers are read, and the module still runs no git. An empty diff, text that
is not a diff, a PowerShell file the diff names that is not there, and -ChangedFile beside it are
refused. Acceptances and baseline entries are still checked against every unit of the changed files.
The JSON report records the hunks as scope.changedLines.
A PSScriptAnalyzer rule, for warnings in the editor. The package now ships
rules/PSComplexity.Rules.psm1; point PSScriptAnalyzer's CustomRulePath at it and VS Code marks
each unit over its ceiling as you type. It uses the module's own scoring and the gate's verdict --
the .pscomplexity.json the file sits under or 15 and 15, per-path ceilings, excludes, acceptances
in the config and in the code, and the config's baseline -- so the editor and the gate cannot
disagree. It measures the editor's text, gives an unsaved buffer the defaults, warns on the first
line of the unit's declaration, and never refuses: stale policy stays the gate's to report.
Fixed
A run over the changed files no longer refuses policy for the files it did not read (#203). With
a baseline, or any acceptance, -ChangedFile threw that a unit "was not measured" for every entry
naming another file, so a repository using either could not gate a pull request on its changed
files. Such an entry is now left out of the checks and of the report's accepted; entries for the
files the run did read are checked as before. And -UpdateBaseline together with -ChangedFile is
refused: the update records what the run measured, and it silently dropped every baseline entry for
the rest of the tree.
What's Changed
- ci: self-mutation on PSMutant 0.7.0 by @TaekeK in #196
- feat: -Detailed reports each unit's lines of code, counted as SonarQube's ncloc (#166) by @TaekeK in #198
- test: read Test-Json's verdict from its return value (#197) by @TaekeK in #199
- feat: the gate's policy in a committed .pscomplexity.json (#164) by @TaekeK in #200
- feat: accept a unit with a comment above its declaration (#165) by @TaekeK in #201
- feat: a Markdown summary of the run, for step summaries and PR comments (#167) by @TaekeK in #202
- fix: a -ChangedFile run checks policy only for the files it read (#203) by @TaekeK in #204
- feat: gate only the units a diff changed, with -ChangedDiff (#168) by @TaekeK in #205
- feat: a PSScriptAnalyzer rule, so the editor warns as the gate would (#163) by @TaekeK in #206
- docs: the Pester failure blamed on PSMutant was a damaged install by @TaekeK in #207
- ci: create the GitHub release once the gallery accepts the version by @TaekeK in #208
- ci: bump github/codeql-action/upload-sarif from 4.38.3 to 4.39.0 by @dependabot[bot] in #209
- ci: PowerShell compatibility legs to 7.4.21 and 7.5.12 by @TaekeK in #210
- test: pin list separators and nested override paths by @TaekeK in #211
- release: date PSComplexity 0.7.0 by @TaekeK in #212
- ci: readable release notes on the gallery and the GitHub release by @TaekeK in #213
Full Changelog: v0.6.0...v0.7.0
v0.6.0
What's Changed
- ci: bump github/codeql-action/upload-sarif from 4.38.2 to 4.38.3 by @dependabot[bot] in #149
- fix: index units once per run for baseline and acceptance checks (#153) by @TaekeK in #169
- fix: score the .ForEach() and .Where() methods as the cmdlets (#159) by @TaekeK in #170
- ci: mutate parameter declarations too, and pin the positional path by @TaekeK in #172
- fix: resolve UNC and provider-qualified paths to the file-system form (#171) by @TaekeK in #173
- fix: compare file paths as the platform does -- case-sensitively on Linux (#151) by @TaekeK in #174
- fix: read case sensitivity from the file system, and never drop a case twin (#151) by @TaekeK in #175
- fix: -UpdateBaseline refuses to add a unit it has never recorded, unless -AllowNew (#152) by @TaekeK in #176
- perf: build the AST index through indexers, not .NET method calls (#154) by @TaekeK in #177
- perf: per-row cache reads through indexers, unit table from the index (#155) by @TaekeK in #178
- docs: record how a construct in a condition is scored (#156) by @TaekeK in #179
- fix: -Detailed rows per if clause, and method recursion named (#157) by @TaekeK in #180
- fix: recursion through a qualified name; scope modifier not in unit name (#158) by @TaekeK in #181
- fix: refuse a -ChangedFile list naming PowerShell files that are not there (#160) by @TaekeK in #183
- fix: measure dot-directories on every OS; name host-dependent skips (#161) by @TaekeK in #189
- fix: the gallery description names the .ForEach()/.Where() methods, and is checked (#184) by @TaekeK in #190
- docs: correct the CLAUDE.md statements later PRs made false (#187) by @TaekeK in #191
- test: hold the property parallel self-mutation rests on (#188) by @TaekeK in #192
- fix: count recursion through ${function:Name}, $MyInvocation, and a script calling itself (#182) by @TaekeK in #193
- fix: -Detailed rows on one line are in source order (#186) by @TaekeK in #194
- fix: no issue references in the release notes the gallery shows by @TaekeK in #195
Full Changelog: v0.5.2...v0.6.0
v0.5.2
What's Changed
- docs: stop naming the paired module in the shared parity rule set by @TaekeK in #127
- ci: bump github/codeql-action/upload-sarif from 4.37.8 to 4.37.9 by @dependabot[bot] in #128
- Run the self-mutation gate three-wide on PSMutant 0.5.0 by @TaekeK in #130
- ci: bump github/codeql-action/upload-sarif from 4.37.9 to 4.38.2 by @dependabot[bot] in #134
- ci: take the watcher's first harvest -- Pester 6.2.0 and two patch legs by @TaekeK in #135
- Azure DevOps: SARIF accepted by Advanced Security, Azure Pipelines docs (0.5.2) by @TaekeK in #139
- ci: skip the expensive gates a pull request cannot affect by @TaekeK in #142
- ci: check that an exempted PowerShell is still the runner's own (#140) by @TaekeK in #143
- docs: check the Pester pins CLAUDE.md states (#137) by @TaekeK in #144
- docs: a README-only change takes no version bump by @TaekeK in #145
- pins: declare the Pester exemption list, empty on purpose (#136) by @TaekeK in #146
- fix: three lookups return an empty array, not $null (#129) by @TaekeK in #147
- ci: gate self-mutation on PSMutant 0.6.0 (#141) by @TaekeK in #148
Full Changelog: v0.5.1...v0.5.2
v0.5.1
What's Changed
- fix: let the compatibility gate reach the floor it defends (#115) by @TaekeK in #116
- feat: execute the PowerShell floor instead of declaring it (#117) by @TaekeK in #118
- ci: one rule for every compatibility leg -- the newest patch of its minor by @TaekeK in #120
- chore: pin PSMutant 0.4.0, and take the ternaries it unblocks by @TaekeK in #121
- feat: watch the compatibility lists in three tiers (#119) by @TaekeK in #122
- Describe the other module by what it does, not as a sibling to consult by @TaekeK in #123
- Stop calling a function once per AST node when indexing (#124) by @TaekeK in #125
- Record 0.5.1's performance work, and a guard that was tried and reverted by @TaekeK in #126
Full Changelog: v0.5.0...v0.5.1
v0.5.0
v0.4.0
What's Changed
- test: pin the output record, which is the whole public API by @TaekeK in #79
- fix: give a unit an identity that is unique and portable (0.4.0) by @TaekeK in #80
- fix: fail when main claims a version that has already shipped by @TaekeK in #81
- test: pin every entry in the construct vocabulary by @TaekeK in #82
- feat: stamp every score with the metric that produced it by @TaekeK in #84
- fix: resolve a relative path against Root, not the working directory by @TaekeK in #86
- test: close the construct vocabulary against the parser by @TaekeK in #87
- feat: name each file before measuring it by @TaekeK in #88
- test: attribute every reference score to its source by @TaekeK in #89
- feat: watch the pinned dependencies instead of only writing them down by @TaekeK in #90
- ci: bump actions/checkout from 7.0.0 to 7.0.1 by @dependabot[bot] in #91
- ci: bump github/codeql-action/upload-sarif from 4.36.3 to 4.37.8 by @dependabot[bot] in #92
- feat: attribute every cognitive increment, and let a score say where it came from by @TaekeK in #93
- docs: record what the number does not say by @TaekeK in #95
- refactor: give measurement a noun, and make the output a projection of it by @TaekeK in #94
- feat: let somebody disagree with a number, and make the disagreement checkable by @TaekeK in #97
- feat: let a run leave the process, as JSON and as SARIF by @TaekeK in #98
- fix: make an analyzer run a verdict, not a return value by @TaekeK in #99
- docs: give the one unpinnable vocabulary entry a reason and a test by @TaekeK in #100
- test: make a new dependency edge in src/ a decision by @TaekeK in #103
- test: check the suite gives the same answer in a different order by @TaekeK in #104
- feat: a committed baseline, so the gate ratchets instead of only gating by @TaekeK in #105
- perf: give Ast.ps1 a covering suite that does not measure real source by @TaekeK in #106
- perf: split the scan out of the public API, and give it a cheap suite by @TaekeK in #107
- feat: gate on what a pull request changed by @TaekeK in #108
- perf: walk the AST once, not once per node (#36, #37) by @TaekeK in #109
- ci: compare the two repos' CI with a shared rule set (#56) by @TaekeK in #110
- docs: stop pointing at a roadmap that no longer exists by @TaekeK in #111
Full Changelog: v0.3.0...v0.4.0
v0.3.0
What's Changed
- docs: record the practices this repo has, and the rules the gaps imply by @TaekeK in #40
- fix: measure a flat directory, and a path with a bracket in it by @TaekeK in #49
- fix: refuse to pass when the gate measured nothing by @TaekeK in #51
- ci: move the estate to Pester 6.1.0, and prove Pester 5 consumers still work by @TaekeK in #52
- refactor: migrate the suite to Pester 6 assertions and make the v5 form an error by @TaekeK in #57
- test: assert the exact answer, and widen the mutation gate to see structure by @TaekeK in #58
- feat: make the CHANGELOG the source of the release notes, and gate the agreement by @TaekeK in #59
- ci: one analyzer script, one pins file, called by every gate by @TaekeK in #60
- ci: measure the coverage this repo has been claiming by @TaekeK in #61
- ci: give every workflow a concurrency group, a timeout and least privilege by @TaekeK in #62
- ci: pin line endings so a checkout cannot change what a gate compares by @TaekeK in #63
- ci: require the merge gate to have passed, and load the package before shipping it by @TaekeK in #64
- fix: score the flow constructs PowerShell actually has by @TaekeK in #65
- fix: refuse a verdict for a file the gate could not read by @TaekeK in #66
- fix: emit rows in source order rather than hashtable order by @TaekeK in #67
- fix: measure a file once, and stop counting enum labels as units by @TaekeK in #68
- fix: make the gates see a test file that never ran by @TaekeK in #69
- fix: gate every piped path, and declare the types callers actually get by @TaekeK in #70
- docs: correct the claims the code does not support by @TaekeK in #71
- docs: describe the whole release, not the third of it written first by @TaekeK in #72
Full Changelog: v0.2.0...v0.3.0
v0.2.0
What's Changed
- 100% coverage and 100% self-mutation (tests only, no release) by @TaekeK in #8
- Measure PowerShell class members as units by @TaekeK in #9
- Add CLAUDE.md: the standard this module owes itself, and the traps that have cost time by @TaekeK in #11
- Skip the publish step when that version is already on the gallery by @TaekeK in #12
Full Changelog: v0.1.0...v0.2.0
v0.1.0
Full Changelog: https://github.com/Fortigi/PSComplexity/commits/v0.1.0