Code coverage#2165
Open
spetersenms wants to merge 122 commits intomicrosoft:mainfrom
Open
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
PSScriptAnalyzer found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
| # We use global stubs with call recording instead. | ||
| # Only parameters we assert on need to be declared; PowerShell accepts extra named params silently. | ||
| $global:_RunAlTestsCalls = @() | ||
| function global:Run-AlTests { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Code Coverage Feature — Reviewer Guide
Overview
This PR adds opt-in code coverage collection to AL-Go for GitHub. When a user sets
enableCodeCoverage: truein their AL-Go settings, the pipeline collects line-level coverage data during test execution and outputs it in Cobertura XML format — the industry standard supported by tools like SonarQube, Codecov, and Azure DevOps.The feature is off by default and preview. When disabled, zero code paths are affected. The only overhead is an unconditional
MergeCoverageworkflow job (~20s) that no-ops viahashFiles()gating when no coverage files exist.Architecture: What's New vs. What's Ported
The TestRunner module is split into two distinct categories of code. Understanding this split is the key to an efficient review.
Ported from the BC Platform Test Runner (~60% of TestRunner code)
The BC platform ships an internal test runner used for running AL tests against Business Central containers via client services. The original lives at
NAV\BuildArtifacts\w1Development\ALTestRunner\. This PR ports that code into AL-Go with architectural refactoring but minimal functional changes. The core test execution logic (connecting to containers, opening test forms, running tests, collecting results) is unchanged.These files need less review scrutiny — they are a known-good module that ships with BC and is used in production daily:
Internal/ALTestRunnerInternal.psm1Internal/ALTestRunnerInternal.psm1Internal/BCPTTestRunnerInternal.psm1Internal/BCPTTestRunnerInternal.psm1Setup-Enviroment→Setup-Environment), error headers addedInternal/ClientContext.ps1Internal/ClientContext.ps1$disableSSLconstructor parameter for PS7 supportInternal/AadTokenProvider.ps1Internal/AadTokenProvider.ps1Internal/TestRunnerInternalForAIT.psm1Internal/TestRunnerInternalForAIT.psm1ALTestRunner.psm1ALTestRunner.psm1Internal/*.dll(4 files)Internal/*.dllModules extracted from the original
ALTestRunnerInternal.psm1(these are the same functions, just in separate files now):Internal/Constants.ps1Internal/ModuleInit.ps1Internal/ClientSessionManager.psm1Open-ClientSessionWithWait,Open-ClientSession, SSL functionsInternal/TestFormHelpers.psm1Set-*/Open-*/Clear-*functionsInternal/CoverageCollector.psm1CollectCoverageResults,SaveCodeCoverageMapEntirely New Code (~40% of TestRunner code)
These modules have no equivalent in the original BC test runner. These need full review attention:
TestResultFormatter.psm1CoverageProcessor/CoverageProcessor.psm1CoverageProcessor/ALSourceParser.psm1CoverageProcessor/BCCoverageParser.psm1CoverageProcessor/CoberturaFormatter.psm1CoverageProcessor/CoverageUtilities.ps1Test-PropertyExists)RunPipeline.psm1New-ALTestRunnerOverridefunction (the override scriptblock)New Actions
BuildCodeCoverageSummary/cobertura.xmlfrom a build job and writes a markdown summary to the GitHub Step SummaryMergeCoverageSummaries/How It Works: The Override Mechanism
Why an override is needed
AL-Go uses BcContainerHelper's
Run-ALPipelineto build and test apps. Normally,Run-ALPipelineruns tests inside the BC container via its own internal test runner. However, code coverage collection requires a host-side orchestration approach — connecting to the container's client services endpoint, configuring coverage tracking on the test form, running tests, then pulling coverage data back.BcContainerHelper doesn't support this natively. It does, however, support a
RunTestsInBcContainerparameter that accepts a custom scriptblock to replace the default test execution.The flow
Custom override compatibility
If a user already has a custom
RunTestsInBcContainer.ps1override in their.AL-Gofolder, AL-Go detects this and emits a warning instead of overriding. The user's custom script takes precedence. They can still use coverage by callingRun-AlTestsdirectly in their custom override with the appropriate coverage parameters.Coverage Processing Pipeline (New Code)
The coverage processing converts BC's proprietary format to industry-standard Cobertura XML. This is the most substantial new code in the PR.
Data flow
Multi-job merge
When a repo has multiple AL-Go projects (each built in a separate job), the
MergeCoverageSummariesaction merges their individualcobertura.xmlfiles using union semantics:Changes to Existing AL-Go Files
ReadSettings.psm1enableCodeCoverage(default:false) andcodeCoverageSetupdefaultssettings.schema.jsonRunPipeline.ps1RunPipeline.ps1.dat→ Cobertura conversion)CalculateArtifactNames/CalculateArtifactNames.ps1CodeCoverageto artifact name listCalculateArtifactNames/action.yamlCodeCoverageArtifactsNameoutputCheckForUpdates.HelperFunctions.ps1MergeCoverageto PostProcess needsRunPSScriptAnalyzer.ps1_BuildALGoProject.yaml(both templates)CICD.yaml(both templates)PullRequestHandler.yaml(both templates)Settings
{ "enableCodeCoverage": true, "codeCoverageSetup": { "trackingType": "PerRun", "produceCodeCoverageMap": "PerCodeunit", "excludeFilesPattern": ["*.PermissionSet.al"] } }enableCodeCoveragefalsetrackingTypePerRunPerRun(one file per run),PerCodeunit(per codeunit),PerTest(per test function). Higher granularity = more overhead.produceCodeCoverageMapPerCodeunitDisabled,PerCodeunit,PerTestexcludeFilesPattern[]Test Coverage
Unit Tests (220 tests)
ALSourceParser.Test.ps1BCCoverageParser.Test.ps1CoberturaFormatter.Test.ps1CoberturaMerger.Test.ps1CoverageProcessor.Test.ps1CoverageReportGenerator.Test.ps1BuildCodeCoverageSummary.Test.ps1MergeCoverageSummaries.Test.ps1NewALTestRunnerOverride.Test.ps1TestResultFormatter.Test.ps1What's NOT unit tested (and why)
The ported BC test runner internals (
Run-AlTestsInternal,ClientContext,ClientSessionManager,TestFormHelpers,CoverageCollector) require a running BC container to test meaningfully. These are covered by BC's own test infrastructure and by the AL-Go E2E tests that run against real containers. Unit testing them would require mocking the entire BC client services stack, which provides little value for code that is already proven in production.Risk Assessment
enableCodeCoveragecheckReview Priorities
High priority (new logic — review carefully):
CoverageProcessor/— all 5 modules (core new feature)RunPipeline.psm1— override scriptblockRunPipeline.ps1— coverage integration points (lines 465-497, 762-835)BuildCodeCoverageSummary/andMergeCoverageSummaries/— new actionsMedium priority (modified existing code):
5.
ALTestRunner.psm1— JUnit support addition6.
TestResultFormatter.psm1— new result formatting7. Workflow template changes (6 YAML files)
8.
CalculateArtifactNameschangesLow priority (ported code — minimal changes):
9.
Internal/modules — decomposed from original, functionally identical10. DLL files — identical to BC platform originals