A procedure for proving, on GitHub, the whole loop between this repository and CSharpSchema_Test (the C# repository that owns the classes for now). It has three exercises, each ending with the Python and the C# matching again:
| Exercise | You change in Python | Expected in C# |
|---|---|---|
| A. Reuse a class | a new class that uses an existing one (Beam) |
one new file; Beam is not touched |
| B. Update a class | a property of Beam (added, then changed or removed) |
the lines of that property change in the existing file; breaking changes are labelled |
| C. Add a class | a new class and its file | one new file in the right folder and namespace |
Separately, "Testing the build cache" proves that the PR checks build only the C# repositories that changed. This procedure has not been run
yet. Part 0 is done once; the three exercises can be done in any order. How each workflow works is in
Workflows.md; the Python authoring rules are checked by py2cs check.
Setup (an administrator, once). Everything in "One-time setup" of Workflows.md: the GitHub App installed on
CSharpSchema_Test with Contents and Pull requests write access, the secrets BHOM_APP_ID and BHOM_APP_PRIVATE_KEY, and the
App (or github-actions[bot]) allowed to push to develop if it is protected. CSharpSchema_Test must be public.
Protect the develop branch of the C# repository (once per C# repository). The tooling of the linked PR runs from the Python pull
request, with a token that has Contents: write. Protecting develop means that token can open pull requests but never push to develop.
In CSharpSchema_Test: Settings, Rules, Rulesets, New ruleset, New branch ruleset:
- Name it
Protect develop, set Enforcement status to Active, and leave the Bypass list empty (the App must not be on it). - Under Target branches, Add target, Include by pattern,
develop. - Tick Restrict deletions, Block force pushes and Require a pull request before merging (required approvals can be 0 for this test repository).
- Create. Then check it: a direct
git push origin developfrom a clone must be refused, while merging a pull request still works.
(The older equivalent is Settings, Branches, Add branch protection rule, branch name pattern develop, with Require a pull request before
merging ticked. The real BHoM repositories already have this.)
Check the starting point.
- Run Python schema generation from the Actions tab (branch
develop,dry_runticked). It must be green. Open the attachedgeneration-report: no failed types. - Run it again with
dry_rununticked. The log must end withNo changes: the Python already matches the C#. If it commits instead, that commit is the difference between the C# and what is indevelop; look at it before going on, because every exercise below assumes the two are in step. - Check that
develophassrc/bhom_schema/FixtureAlpha_oM/Beam.pyand that CSharpSchema_Testdevelophas no openpython-schema/pr-*branch left over from an earlier test.
For every exercise.
-
Work on a branch of this repository (not a fork: forks get no linked C# pull request) and open a pull request to
develop. -
Check it locally first, so GitHub is not the first place to find a mistake. In a clone with the C# repository next to it:
$env:PYTHONPATH = ".ci/generation" .venv\Scripts\python -m py2cs check --root src/bhom_schema --base-root <the same folder at develop>
checkreports every problem, including missing descriptions on new classes and fields. -
After pushing, three things start by themselves; Part "What to look at" below lists what each should show.
Goal: a new class that has a Beam inside it, and a C# file that refers to Beam without changing it.
-
Add
src/bhom_schema/FixtureAlpha_oM/BeamPair.py. Copy the header comments and the__bhom__marker style ofBeam.py, then:from __future__ import annotations from typing import Any, ClassVar from pydantic import Field from bhom_schema.BHoM.BHoMObject import BHoMObject from bhom_schema.FixtureAlpha_oM.Beam import Beam class BeamPair(BHoMObject): __bhom__: ClassVar[dict[str, Any]] = { 'clr_name': 'BH.oM.FixtureAlpha.BeamPair', 'assembly': 'FixtureAlpha_oM', 'namespace': 'BH.oM.FixtureAlpha', 'repo': 'BHoM/CSharpSchema_Test', 'kind': 'class', } First: Beam | None = Field(default=None, description='The first beam of the pair.') Second: Beam | None = Field(default=None, description='The second beam of the pair.')
Variation to try afterwards: a subclass,
class TallBeam(Beam), with'clr_name': 'BH.oM.FixtureAlpha.TallBeam'. -
Open the pull request and follow "What to look at". Expected in the linked C# draft: one new file
BeamPair.cs, with properties typedBeam, and no change toBeam.cs. The plan listsBeamonly as something the new class refers to. -
Finish with "Closing the loop".
Goal: change Beam and see only the changed lines change in Beam.cs.
Do these as three separate pull requests (or three commits that you test one at a time), so each result is clear.
-
Add a property to
src/bhom_schema/FixtureAlpha_oM/Beam.py, with a description:Material: str = Field(default='Steel', description='Name of the material.')
Expected: the draft adds one property to
Beam.cs. Everything else in the file (other members, comments, formatting) is unchanged, and there is nobreaking-changelabel. -
Change it: for example the default
'Steel'to'Concrete', or its description. Expected: only that property changes. -
Break it: remove
Material, or change its type fromstrtoint. Expected: the draft is labelledbreaking-change, and the pull request text has a "Breaking changes" section naming the class and the change. Whoever reviews the C# decides whether it needs a versioning upgrade; nothing is merged by itself.
Goal: a class that nothing else uses, written from scratch.
-
Add
src/bhom_schema/FixtureAlpha_oM/Column.pyin the style ofBeamPair.py, with its own fields:Height: float = Field(default=3.0, description='Height of the column.') Label: str = Field(default='', description='Name shown to the user.')
Use a
clr_namein a namespace that already exists in CSharpSchema_Test, then repeat with a new sub-namespace ('BH.oM.FixtureAlpha.Columns') to see where the file is placed. -
Expected: one new file in the matching folder of
FixtureAlpha_oM, with the namespace of itsclr_name. The draft pull request lists it as an added class. -
Try one mistake on purpose: remove a
descriptionor give aclr_namethat names no repository inConverted-repositories.txt. Expected:pr-checksfails with a message that names the file and line, and no C# pull request is raised for a class that cannot be placed.
| Where | What you should see |
|---|---|
| PR / Build and tests on the Python PR | Build, NUnit, pytest and Pyright pass. py2cs check passes |
| PR / C# alignment on the Python PR | Fails until the linked C# PR is merged, with an explanation in the job summary: it compares the Python with what the C# develop generates. That failure is the proof that the two are not in step yet |
| C# PR / Raise or update draft | Green. The step Which repositories does the change touch? names BHoM/CSharpSchema_Test; Push the branch and open or update the draft pull request pushes python-schema/pr-<N> and opens a draft PR |
| The C# draft PR | The files and lines in the table at the top of the exercise, a link back to the Python PR, labels, and nothing else changed. Open the diff and read it as a C# reviewer would. Check that it builds |
| Comment on the Python PR | Draft C# pull request: <link>, written once and updated in place on later pushes |
| The Python PR after a push | Pushing again updates the same branch and the same draft; no second PR |
To try the flow before relying on the automatic run, start C# PR by hand with the Python PR number: with dry_run ticked it
prints what it would do and proves the App token; unticked it does it.
- In CSharpSchema_Test, review the draft, fix anything wrong in C# (the C# is the source of truth), mark it ready and merge it.
- Back on the Python PR, re-run C# alignment by hand (Re-run jobs); nothing re-runs it for you.
- Check C# alignment. It must now pass: the Python generated from the merged C# equals the Python in the PR.
If it still fails, the message lists what differs; either the C# review changed something (copy the change into the Python)
or the generator and
py2csdisagree (a bug to fix in this repository). The NUnit tests and their golden files use their own test classes (.ci/unit-tests/csharp/Fixtures), so a merged C# change never needs a golden update. A test that deletes a fixture class file must pick a class that no other fixture imports. - Merge the Python PR.
- Run Python schema generation live (or wait for Saturday). Expected:
No changes: the Python already matches the C#. If it commits, the commit shows exactly how the generated Python differs from what was written by hand (often only formatting or ordering); that is the real result of the exercise and what to improve next.
A pull request that is closed without merging closes its draft with a comment; delete the python-schema/pr-<N> branch in C# by hand.
The PR checks keep a build cache with one entry per C# repository (see Per-Repository-Build-Cache-Plan.md).
These tests prove that a repository is built only when its commit, or a dependency's commit, changed, and that develop shares the build
with every pull request.
Part D1 can run from the ImproveCaching pull request before it is merged. Part D2 needs it merged into develop first. A pull request runs
the pr-checks.yml of its own branch, so D1 tests the new action as it is. build-cache.yml is different: GitHub starts a workflow_run
workflow, and lists a workflow under Run workflow, only from the default branch, so before the merge it never runs. And only a run on
develop can save the cache that every pull request reads.
| Where | What it tells you |
|---|---|
| Step Plan the build of the job | The commit and entry name of each repository, and the cache key |
| Step Restore the build cache | Cache restored from key: <key>; when that key differs from the planned key it was a prefix hit, an earlier state. Cache not found means nothing could be restored |
| Step Build the repositories in dependency order | The same table with hit or miss per repository, then Restoring <name> from the cache... for a hit, Cloning <repo> at <commit>... and Building <name>... for a miss, Deleting the old entry <entry>, and finally Built: <names> or Built: nothing |
| Step Save the build cache | Skipped when nothing was built |
| Actions tab, Caches (under Management) | Each bhom-build-cache-v1-Windows-... entry and its branch: refs/pull/<N>/merge for a pull request, refs/heads/develop for develop |
- First run, everything is built. Open the pull request from
ImproveCachingtodevelop. In PR / Build and tests: the restore saysCache not found(the oldbhom-assemblies-v1-...entries do not match the new prefix), the build clones the four repositories at the commits of the plan and ends withBuilt: BHoM, BHoM_Engine, JSONSchema_Toolkit, CSharpSchema_Test, and the save runs. Every test passes, which shows that the assemblies installed this way are the ones the tests need. Caches shows one new entry onrefs/pull/<N>/merge. - The alignment job waits. PR / C# alignment starts only once Build and tests has finished. This pull request does not change
src/bhom_schema, so its steps are skipped; D2 step 5 tests it with a build. - A re-run builds nothing. Re-run all jobs. The restore names the planned key exactly, the build table says
hitfor all four, the log has fourRestoring ... from the cache...lines andBuilt: nothing, and the save is skipped. Note how long Build the repositories takes compared with step 1. - One changed repository is built alone. Make a commit on
developof CSharpSchema_Test (for example merge the C# draft of an exercise, or a small pull request there), then re-run the jobs. The table saysmissfor CSharpSchema_Test andhitfor the others, the log ends withBuilt: CSharpSchema_Test, the old entry of CSharpSchema_Test is deleted, and the save runs under a new key. If BHoM_Engine or BHoM changed upstream in the meantime, that repository and the ones that depend on it are built too. Compare the commits in the table with the repositories to check it. - Nothing runs on
developyet. No Build cache run appears in the Actions tab. That is expected before the merge.
- Fill the
developcache by hand. Actions, Build cache, Run workflow, branchdevelop. The gate printsdevelop has no entry starting with bhom-build-cache-v1-Windows-..., then Build and save on develop builds the four repositories (developcannot read a pull request's cache) and saves. Caches shows an entry onrefs/heads/develop. - Try a manual run from another branch. Run Build cache from
ImproveCachingor any other branch: both jobs are skipped, so nothing butdevelopcan write to thedevelopcache. - A new pull request builds nothing. Open a new pull request that changes
src/bhom_schema(Exercise A is a good one). Its first run restores the exact key fromdevelopand logsBuilt: nothingin Build and tests, and C# alignment logsBuilt: nothingtoo. - No refresh when
developis up to date. When that PR run completes, Build cache starts by itself. The gate printsdevelop has: <key>and the refresh job is skipped. - One changed repository is built once, then shared. Make a commit on
developof CSharpSchema_Test (closing the loop of an exercise does this), then push to the pull request or re-run its jobs.- Build and tests builds only CSharpSchema_Test.
- C# alignment waits for it and logs
Built: nothing, because it restores what the first job just saved. Without the wait it would have built CSharpSchema_Test a second time. - The Build cache run that follows finds no entry for the new state on
develop. Its refresh builds only CSharpSchema_Test, from thedevelopentries of the others, and saves ondevelop. - Open, or re-run, a second pull request. It restores that
developentry and builds nothing.
- The C# alignment still runs when a test fails (optional). Push a commit that makes one pytest test fail. Build and tests fails, and C# alignment still runs.
- A fork gets no refresh (optional, needs a fork). A pull request from a fork runs the PR checks with its own cache, and the Build cache run that follows skips both jobs.
- Switching the cache off (optional). On a branch, give the action
with: no-cache: 'true'inpr-checks.yml. The restore and save are skipped, and every repository is built, as before this cache. Do not merge that change.
| Symptom | Likely cause |
|---|---|
linked-csharp-pr fails with No module named py2cs |
the base branch has no py2cs yet (only for the very first pull request) |
repos reports [] and nothing is raised |
the class changed is not under a repository in Converted-repositories.txt, or its repo marker is wrong |
raise fails when making the token |
the App is not installed on CSharpSchema_Test, or the secrets are missing |
| the draft changes more than the lines you changed | report it: that is a bug in the patcher, with the file and your Python diff |
py2cs align still fails after the C# merge |
the C# develop clone in the workflow is older than the merge, or the C# review changed the class; read the listed differences |
| the weekly run commits after everything merged | the generator writes the class differently from what py2cs drafted: look at the commit |
| Build cache never runs after a PR run | build-cache.yml is not on develop yet, or the PR workflow was renamed (the trigger names PR) |
the gate fails on gh cache list |
the gh of the ubuntu runner is too old for --ref; the log shows the error |
| every pull request builds everything | develop has no entry, or one made with other build tools after an MSBuild update on the runner: run Build cache by hand on develop |
Building <name> failed |
the C# of that repository does not build at its planned commit. The run stops so a failed build never becomes an entry |
tests fail after a restore but pass with no-cache |
a wrong entry: bump -Salt (the v1) in Build-Repositories.ps1 to throw every cache away, and report it with both logs |
For each exercise note the Python PR, the C# PR, whether the draft matched "Expected", and the final generation result. Anything that did not match is a finding for audit-1.