Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# This file is managed by the BHoM platform team and centrally distributed to all active repos.
# It is used by CI to enforce code formatting and naming standards via dotnet format.
# Do not edit this file directly in your repository — changes will be overwritten.
# To propose a change, open an issue or PR in BuroHappoldEngineeringAdmin/CI_Toolkit.
# Do not edit this file directly in your repository. Changes will be overwritten.
# To propose a change, open an issue or PR in BHoM/CI_Toolkit.

root = true

# All files — space indent (4), LF line endings, trim trailing whitespace, insert final newline, UTF-8.
# All files: space indent (4), LF line endings, trim trailing whitespace, insert final newline, UTF-8.
[*]
indent_style = space
indent_size = 4
Expand All @@ -26,14 +26,14 @@ indent_size = 2
trim_trailing_whitespace = false

[*.cs]
# IDE1006 — Method names must be PascalCase.
# IDE1006: Method names must be PascalCase.
dotnet_naming_rule.methods_pascal_case.symbols = method_symbols
dotnet_naming_rule.methods_pascal_case.style = pascal_case_style
dotnet_naming_rule.methods_pascal_case.severity = error

dotnet_naming_symbols.method_symbols.applicable_kinds = method

# IDE1006 — Parameter names must be camelCase.
# IDE1006: Parameter names must be camelCase.
dotnet_naming_rule.parameters_camel_case.symbols = parameter_symbols
dotnet_naming_rule.parameters_camel_case.style = camel_case_style
dotnet_naming_rule.parameters_camel_case.severity = error
Expand All @@ -43,17 +43,17 @@ dotnet_naming_symbols.parameter_symbols.applicable_kinds = parameter
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
dotnet_naming_style.camel_case_style.capitalization = camel_case

# IDE0005 — Remove unnecessary using directives.
# IDE0005: Remove unnecessary using directives.
dotnet_diagnostic.IDE0005.severity = warning

# IDE0036 — Enforce consistent modifier order (e.g. public static, not static public).
# IDE0036: Enforce consistent modifier order (e.g. public static, not static public).
csharp_preferred_modifier_order = public, private, protected, internal, file, static, extern, new, virtual, abstract, sealed, override, readonly, required, unsafe, volatile, async
dotnet_diagnostic.IDE0036.severity = warning

# IDE0044 — Add readonly to fields never reassigned after construction.
# IDE0044: Add readonly to fields never reassigned after construction.
dotnet_style_readonly_field = true
dotnet_diagnostic.IDE0044.severity = suggestion

# IDE0060 — Remove unused parameters.
# IDE0060: Remove unused parameters.
dotnet_code_quality_unused_parameters = all
dotnet_diagnostic.IDE0060.severity = warning
3 changes: 2 additions & 1 deletion .github/actions/ci-build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ runs:
uses: BHoM/CI_Toolkit/.github/actions/compute-changed-files@develop
with:
# :(exclude)*AssemblyInfo.cs matches ci-versioning and ci-serialisation, and
# matches what BHoMBot's core check did (Checks/Core.cs:30).
# matches BHoMBot's core check, which excluded AssemblyInfo.cs from the
# changed-file set the same way.
#
# It is inert today, and is here for consistency rather than for effect. Two
# measurements, both worth recording so nobody reads this as protection against
Expand Down
39 changes: 25 additions & 14 deletions .github/actions/ci-compliance/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,29 @@ runs:
$runnerOutput | ForEach-Object { Write-Host $_ }
Write-Host "::endgroup::"

# Which engine produced this verdict. resolve-dependencies already records it, in a
# dependency table further up the job, and someone diagnosing a red is looking here.
# A compliance failure is nearly always either the file or the rules, and nothing
# else on this surface names the rules. The rules track Test_Toolkit's branch by
# decision rather than by default, so the version has to be visible instead.
#
# Built once and emitted twice, deliberately. The job summary is the right place for
# a human, but GitHub exposes no API for job summaries, so a line written only there
# can never be read back and any claim resting on it stays derived. The log can be
# fetched. Keep both, and keep them built from one string so they cannot drift.
$ttSha = '${{ steps.tt-sha.outputs.sha }}'
if ($ttSha.Length -ge 7) {
$ttLine = 'Rules from Test_Toolkit `' + $ttSha.Substring(0, 7) + '`.'
} else {
# Said rather than left blank. An absent SHA means the dependency metadata did not
# record it, which also means the runner cache key lost its Test_Toolkit component
# on this run, so it is worth seeing rather than reading as "no engine involved".
$ttLine = 'Rules from Test_Toolkit, commit not recorded.'
}

# Backticks are summary markdown. They are noise in a log line, so drop them there.
Write-Host ($ttLine -replace '`', '')

if ($env:GITHUB_STEP_SUMMARY) {
$status = if ($exitCode -eq 0) { "passed" } else { "**failed**" }

Expand All @@ -194,21 +217,9 @@ runs:
$summary += $coverage
}

# Which engine produced this verdict. resolve-dependencies already records it, in a
# dependency table further up the job, and someone diagnosing a red is looking here.
# A compliance failure is nearly always either the file or the rules, and nothing
# else on this surface names the rules. The rules track Test_Toolkit's branch by
# decision rather than by default, so the version has to be visible instead.
$ttSha = '${{ steps.tt-sha.outputs.sha }}'
# Same string as the log line above, so the two cannot disagree.
$summary += ""
if ($ttSha.Length -ge 7) {
$summary += 'Rules from Test_Toolkit `' + $ttSha.Substring(0, 7) + '`.'
} else {
# Said rather than left blank. An absent SHA means the dependency metadata did not
# record it, which also means the runner cache key lost its Test_Toolkit component
# on this run, so it is worth seeing rather than reading as "no engine involved".
$summary += "Rules from Test_Toolkit, commit not recorded."
}
$summary += $ttLine

$summary | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8
}
Expand Down
6 changes: 3 additions & 3 deletions .github/actions/ci-serialisation/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ runs:
id: changed
uses: BHoM/CI_Toolkit/.github/actions/compute-changed-files@develop
with:
# AssemblyInfo.cs is excluded to match BHoMBot's serialisation gate
# (Serialisation.cs:35). A version bump cannot change the verdict: the
# AssemblyInfo.cs is excluded to match BHoMBot's serialisation gate, which
# skipped it for the same reason. A version bump cannot change the verdict: the
# comparator keys on IToText, which carries no assembly version, and the
# round trip happens within a single run. .csproj stays in, unlike
# BHoMBot, because a project file can add a reference and so genuinely
Expand Down Expand Up @@ -117,7 +117,7 @@ runs:
if: steps.changed.outputs.count != '0'
shell: pwsh
run: |
# -clp:ErrorsOnly, as #179 applied to dependency builds: this build is a means
# -clp:ErrorsOnly, as on dependency builds: this build is a means
# to an end and its compiler warnings would otherwise become annotations on a
# serialisation check. ci-build is where build warnings belong.
dotnet restore "${{ steps.solution.outputs.path }}"
Expand Down
42 changes: 21 additions & 21 deletions .github/actions/ci-versioning/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ runs:
id: changed
uses: BHoM/CI_Toolkit/.github/actions/compute-changed-files@develop
with:
# AssemblyInfo.cs is excluded to match BHoMBot's Versioning.cs:49: a
# milestone version bump touches it fleet-wide and cannot change the
# outcome, because the result is a function of the built assemblies and
# the datasets, not of the file that changed. Same exclusion as
# AssemblyInfo.cs is excluded to match BHoMBot's versioning check, which
# skipped it too: a milestone version bump touches it fleet-wide and cannot
# change the outcome, because the result is a function of the built
# assemblies and the datasets, not of the file that changed. Same exclusion as
# ci-serialisation. The token is wildcarded so it matches at any depth;
# a bare 'AssemblyInfo.cs' would anchor to the repo root and match
# nothing (see tests/test-changed-file-patterns.sh).
Expand Down Expand Up @@ -176,7 +176,7 @@ runs:
if: steps.changed.outputs.count != '0'
shell: pwsh
run: |
# -clp:ErrorsOnly for the same reason as #179 on dependency builds: this build
# -clp:ErrorsOnly for the same reason as on dependency builds: this build
# is a means to an end, and its compiler warnings become annotations on a
# versioning check. Measured on BHoM/Revit_Toolkit#1683: 24 annotations, of
# which 2 were versioning findings and 9 were 'ParameterType' is obsolete.
Expand Down Expand Up @@ -246,9 +246,9 @@ runs:
# canonical DLL in it was present in ProgramData. It was removed 2026-08-07 as a
# latent fleet-wide outage, on two measurements:
#
# 1. It had never executed. Zero of the last 100 BHoM/BHoM_Installer releases and
# zero of the last 30 BuroHappoldEngineering/BuroHappold_Installer releases
# carry IncludedDLLs.txt, so all eight prod runs sampled that day logged
# 1. It had never executed. Zero of the last 100 BHoM/BHoM_Installer releases,
# and zero of the last 30 from the other installer, carry IncludedDLLs.txt,
# so all eight prod runs sampled that day logged
# "No release carrying IncludedDLLs.txt ... Skipping fast-fail".
# 2. Had a baseline ever appeared it would have failed almost every repo. The
# expected set is the whole installer payload (measured: 165 canonical DLLs,
Expand All @@ -258,8 +258,8 @@ runs:
# ETABS_Adapter.dll. Each repo also gets its own resolve-dependencies cache
# key, so nothing accumulates across repos.
#
# It worked on BHoMBot only because CloneInstaller builds the entire installer set
# before versioning, making its ProgramData fleet-complete. That precondition does
# It worked on BHoMBot only because it builds the entire installer set before
# versioning, making its ProgramData fleet-complete. That precondition does
# not hold in per-repo CI, which is the same mistake as the old 3-segment
# attribution filter and the Revit mock closure dependency.
#
Expand Down Expand Up @@ -356,8 +356,8 @@ runs:
# Ordering matters twice. After resolve-dependencies, because that action saves
# the ProgramData cache with an explicit save step, so anything written here
# cannot leak into the cached assembly set other checks restore. Before
# Verification.sln, matching BHoMBot's CloneInstaller.cs, which places the mocks
# ahead of the versioning build so [PreviousVersion] attributes are scraped.
# Verification.sln, matching BHoMBot, which places the mocks ahead of the
# versioning build so [PreviousVersion] attributes are scraped.
#
# Every failure path is a soft skip: without mocks the check still runs and
# reports those methods as unverified, which is the pre-existing behaviour. A
Expand Down Expand Up @@ -458,9 +458,9 @@ runs:
#
# Re-run the same command the csproj runs, from the same working directory,
# differing only in when: after this repo's build and after the Revit mocks, so
# the scrape sees both. BHoMBot gets this for free because CloneInstaller builds
# the whole installer set before rebuilding Versioning_Toolkit ("just to be
# safe"). Re-running is safe: CollectMethodVersioning keys entries on the old
# the scrape sees both. BHoMBot gets this for free because it builds the whole
# installer set before rebuilding Versioning_Toolkit ("just to be safe").
# Re-running is safe: CollectMethodVersioning keys entries on the old
# signature and replaces a same-key entry, so this refreshes rather than
# duplicating. Note it only collects attributes whose FromVersion equals
# PostBuild.exe's own FileVersion truncated to two segments, so an attribute
Expand Down Expand Up @@ -540,8 +540,8 @@ runs:
# test was ignored, so a declared rename or a MessageForDeleted entry did not
# count and the check failed a repo that followed the documented convention.
# BHoMBot is immune for the same reason it escaped the attribute-ordering defect:
# CloneInstaller puts every repo, subject included, in one folder, so its
# '..\..\' root already contains the subject.
# it puts every repo, subject included, in one folder, so its '..\..\' root
# already contains the subject.
#
# The exe is pointed at the workspace's PARENT, because the glob needs the repo
# directory to be the first level. resolve-dependencies also junctions each
Expand Down Expand Up @@ -675,7 +675,7 @@ runs:
# The failure mode is deliberately asymmetric. If this finds nothing, no file is written
# and no flag is passed, so every finding records VersionConditional=Unknown. An empty
# result must not read as "not version-conditional": those are different states and the
# register in CI_Toolkit#173 treats them differently.
# scoring register treats them differently.
- name: Collect version-conditional methods
id: vercond
if: steps.changed.outputs.count != '0'
Expand Down Expand Up @@ -709,7 +709,7 @@ runs:
# present-but-empty file is the assertion "scanned, none found", which lets the
# runner record No. Most of the fleet is non-Revit and will land here: 75 of the 92
# alpha and beta repos. Withholding the file for them would leave every versioning
# divergence unscored and the gate in CI_Toolkit#173 unsatisfiable.
# divergence unscored and the scoring gate unsatisfiable.
#
# The file is withheld only if the scan itself could not run, which is the honest
# Unknown case.
Expand Down Expand Up @@ -767,7 +767,7 @@ runs:
# An infrastructure failure and a versioning finding need different action
# from the developer, and the job conclusion does not distinguish them. A
# dependency build failure previously showed as a red versioning check with
# no indication that versioning never ran. Measured on Revit_UI#696.
# no indication that versioning never ran. Measured on a real pull request.
$infraStep = ''
if ("${{ steps.deps.conclusion }}" -eq 'failure') { $infraStep = 'Resolve dependencies' }
elseif ("${{ steps.build_subject.conclusion }}" -eq 'failure') { $infraStep = 'Build primary repo' }
Expand Down Expand Up @@ -815,7 +815,7 @@ runs:
# "Could not resolve it" is a closure gap: a type the record needs is absent and so
# is its namespace, so nothing here could have supplied it. "Could not attribute it"
# is an ownership problem: the record resolved, but ownership was inferred from a
# namespace prefix. Different fixes, tracked separately (internal-tickets #32, #31).
# namespace prefix. They need different fixes and are tracked separately.
$unresolved = 0
$unattributed = 0
$coverage = $null
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/resolve-dependencies/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ runs:
shell: pwsh
run: |
# Junctions D:\a\<Repo>\<DepName> -> C:\bhom-deps\<DepName> so relative
# HintPaths in .csproj files (e.g. ..\..\Revit_UI\libs\...) resolve
# HintPaths in .csproj files (e.g. ..\..\<DepName>\libs\...) resolve
# when building the caller. No-op for repos without such paths.
$workspaceParent = Split-Path $env:GITHUB_WORKSPACE
foreach ($dep in Get-ChildItem "C:\bhom-deps" -Directory -ErrorAction SilentlyContinue) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ foreach ($ownerRepo in $order) {
Invoke-BHoMBuild -Target $solution.FullName -Config $Configuration

# Build alt configurations for this dependency (Release* only, matching CI config).
# Required so that version-specific assemblies (e.g. Revit_UI_oM_2023.dll) exist
# Required so that version-specific assemblies (e.g. <Name>_oM_2023.dll) exist
# before the caller repo builds its own alt configs.
$depAltConfigFile = Join-Path $repoPath "altConfigs.txt"
if (Test-Path $depAltConfigFile) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ function Clone-And-Checkout([string]$ownerRepo, [string]$ref) {
# compared two legs that shared the same dependency code. A regression introduced on the
# dependency side appeared in both and cancelled out.
#
# This is BHoMBot's shape, deliberately. LoadDependencies (CodeBuild_Engine) cloned if
# This is BHoMBot's shape, deliberately. Its dependency loader cloned if
# absent and then always called CheckoutBranch with the branch as an explicit argument, and
# ResetBuiltRepos() cleared the memo that would otherwise have skipped the re-checkout. The
# divergence from BHoMBot is that the memo has no equivalent here and needs none: there is
Expand Down
6 changes: 3 additions & 3 deletions .github/scripts/Select-AltConfigs.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ function Select-AltConfigs {

- Real altConfigs.txt files carry both. Every Revit-family repo sampled lists
five Debug20NN and five Release20NN entries.
- The installer ships Release* only. BuroHappold_Installer's own
IncludedRepos/altConfigs.txt contains Release entries exclusively, no Debug.
So building Debug20NN in CI verifies configurations that are never shipped.
- The installer ships Release* only. Its own IncludedRepos/altConfigs.txt
contains Release entries exclusively, no Debug. So building Debug20NN in
CI verifies configurations that are never shipped.
- resolve-dependencies already filters the same way for dependency repos
(Build-Dependencies.ps1), and caller Debug builds succeeded in production
against a Release-only dependency closure, so the two sides were not
Expand Down
18 changes: 18 additions & 0 deletions .github/scripts/tests/ci-compliance-action.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,24 @@ Describe 'ci-compliance action.yml' {
It 'says so when the commit was not recorded, rather than omitting the line' {
$text | Should -Match 'commit not recorded'
}

# GitHub exposes no API for job summaries, so a line written only there can never be
# read back and any claim resting on it stays derived rather than observed. The log
# can be fetched. Asserted by position rather than by presence, because moving the
# emission back inside the summary guard would still match a plain text search and
# would silently undo the only thing that makes this checkable.
It 'emits the engine line to the log as well as the summary' {
$logEmit = $text.IndexOf('Write-Host ($ttLine')
$summaryGuard = $text.IndexOf('if ($env:GITHUB_STEP_SUMMARY)')

$logEmit | Should -BeGreaterThan -1 -Because 'the summary is unreadable by any API'
$summaryGuard | Should -BeGreaterThan -1
$logEmit | Should -BeLessThan $summaryGuard -Because 'inside the guard it would not reach the log'
}

It 'builds the log line and the summary line from one string' {
$text | Should -Match '\$summary \+= \$ttLine' -Because 'two independently built strings drift'
}
}

Context 'a self-skip says so' {
Expand Down
Loading
Loading