Skip to content

Add NUKE build aligned with pipenv build products#3129

Open
OnePowerUser88 wants to merge 5 commits intopyrevitlabs:developfrom
OnePowerUser88:NUKE-build
Open

Add NUKE build aligned with pipenv build products#3129
OnePowerUser88 wants to merge 5 commits intopyrevitlabs:developfrom
OnePowerUser88:NUKE-build

Conversation

@OnePowerUser88
Copy link
Contributor

Add NUKE build (replace pipenv for build products)

Description

Disclamer the PR is largely created by Cursor, someone familiar with the build process needs to review this PR!
The main reason I created this PR is because I had problems with pipenv and @jmcouffin and @sanzoghenzo mentioned that NUKE was considered as an option.

This PR adds a NUKE-based build so the repo can be built without Python or pipenv. Running .\build.ps1 BuildProducts from the folder that contains build/ produces the same artifacts as pipenv run pyrevit build products. Pipenv is not removed or changed — developers can use either pipenv run pyrevit build products or .\build.ps1 BuildProducts.

Included:

  • build/Build.cs, build.ps1, README.md, build.csproj, nuget.config. Targets: BuildDeps → BuildLabs → BuildLoaders → BuildRuntime → DeployLibsToEngines → BuildTelem → BuildAutocmp, plus Clean and Check.
  • BuildLoaders – Uses RunProcess with captured MSBuild output on failure, and /m:1 so Deploy targets don’t race; Clean then BuildProducts succeeds on first run.
  • BuildAutocmp – Builds pyrevit-autocomplete.exe from the checked-in Go source (regenerate via pipenv run pyrevit build autocmp when CLI usage changes).
  • .gitignore.nuke/, build/bin/ (NUKE runner output; not committed).
  • Supporting changes – ScriptConsole WPF theme fallback, loader Directory.Build.targets Copy retries, telemetry mongo.go updates.
  • bin/ and dev/libs/ – Build output committed for dev-branch PR testing (per maintainers).

CI can be switched to NUKE later if desired.


Checklist

Before submitting your pull request, ensure the following requirements are met:

  • Build follows the existing structure (deps → labs → loaders → runtime → deploy libs → telem → autocmp).
  • .\build.ps1 Check passes (dotnet and go on PATH).
  • .\build.ps1 Clean then .\build.ps1 BuildProducts succeeds.
  • C# and project changes follow the project’s conventions.

Related Issues

  • N/A (build system addition; no linked issue).

Additional Notes

  • To test: From the folder that contains build/, run .\build.ps1 Check then .\build.ps1 BuildProducts (requires .NET SDK and Go). No pipenv needed.
  • build/README.md has target list, examples, and troubleshooting.

@devloai
Copy link
Contributor

devloai bot commented Feb 23, 2026

Unable to trigger custom agent "Code Reviewer". You have run out of credits 😔
Please upgrade your plan or buy additional credits from the subscription page.

@OnePowerUser88
Copy link
Contributor Author

Important note:
This is tested and gives no errors in Revit 2026, but has not been tested in older Revit versions.

@sanzoghenzo
Copy link
Contributor

Hi @OnePowerUser88 , thanks for the contribution.

The goal of using nuke is to completely remove the pipenv environment, also in the CI/CD.

There are other commands in the dev\pyrevit.py script that needs to be ported, and then we can remove those python files.

Do you think you can address these as well, or do you believe it should be done on a separate PR?
(I am an all-or-nothing kind of guy, that's why I never follow through this task...)

Also, can you please omit the not strictly needed files? This move to nuke should't change the DLLs.
Were the source code (and thus DLL) changes made by Cursor just to be able to finish its task? try to ask it to not touch them 😉

@OnePowerUser88
Copy link
Contributor Author

Will look into it!

Just to make sure:
Should I leave pipenv for now, if both can be supported until nuke setup is finished?
What dlls should be included in PRs for testing the C# changes (I know this PR should probably not need any)

- build/: Build.cs, README, csproj, nuget.config
- build.ps1: bootstrap for .NET NUKE runner
- .gitignore: .nuke/, build/bin/

No DLL or source changes. Remaining pyrevit.py commands to be ported in follow-up for full pipenv removal.

Co-authored-by: Cursor <cursoragent@cursor.com>
@OnePowerUser88
Copy link
Contributor Author

Also, can you please omit the not strictly needed files? This move to nuke should't change the DLLs.
Were the source code (and thus DLL) changes made by Cursor just to be able to finish its task? try to ask it to not touch them 😉

I'm not able to find a solution to build without editing mongo.go and ScriptConsole.cs without it failing. Anyone have any input?

@jmcouffin
Copy link
Contributor

find a solution to build without editing mongo.go and ScriptConsole.cs

What is the error

@OnePowerUser88
Copy link
Contributor Author

Summary of source file changes (this branch)

This comment describes the source code changes introduced alongside the NUKE build. These are product improvements and bug fixes that apply whether you use pipenv or NUKE. Verified in Revit 2024 and 2026 after build.


1. dev/pyRevitLabs.PyRevit.Runtime/ScriptConsole.cs — WPF theme loading (Script Console)

Problem

When pyRevit loads in Revit (especially 2026 / .NET Core), the Script Console window throws:

System.IO.IOException: Cannot locate resource 'styles/themes/light.blue.xaml'

The MahApps.Metro theme is loaded via a pack URI. In some hosts the resource is resolved with lowercase path (styles/themes/light.blue.xaml) instead of the canonical Styles/Themes/Light.Blue.xaml.
Additionally, Controls.xaml was merged into the window’s resources before the theme. Controls.xaml itself merges dictionaries that reference the theme, so WPF tries to resolve the theme during the load of Controls.xaml. If the theme is not yet in the window’s MergedDictionaries, that resolution fails and the exception is thrown.

Changes

  • TryAddThemeResource(string packUri)
    New helper that loads the Light.Blue theme with a fallback for path casing:

    • Tries the canonical pack URI: .../Styles/Themes/Light.Blue.xaml.
    • On any exception, tries the lowercase variant: .../styles/themes/light.blue.xaml.
    • Both attempts are wrapped in try/catch. If neither succeeds, no theme is added (window still opens; styling may be wrong but no crash).
  • Load order in SetupDynamicResources()
    The theme is now added first, before Controls.xaml and Fonts.xaml. When WPF then loads Controls.xaml and its merged dictionaries reference the theme, the theme is already in the window’s MergedDictionaries and the resource resolves correctly.

Result

Script Console loads without IOException in Revit 2024 and 2026. No change to behavior beyond fixing theme resolution and load order.


2. dev/pyRevitTelemetryServer/persistence/mongo.go — MongoDB Go driver v2

Problem

The telemetry server’s MongoDB code was written for the v1 driver API. The project already depended on go.mongodb.org/mongo-driver/v2 in go.mod, but the code still used v1-style calls and the deprecated connstring package (x/mongo/driver/connstring), which is not part of the v2 public API. As a result, go build failed with undefined symbols (mongo, options, readpref, bson, connstring, etc.).

Changes

  • Imports
    Switched to v2 packages:

    • go.mongodb.org/mongo-driver/v2/bson
    • go.mongodb.org/mongo-driver/v2/mongo
    • go.mongodb.org/mongo-driver/v2/mongo/options
    • go.mongodb.org/mongo-driver/v2/mongo/readpref
      Added net/url and strings for URI parsing.
  • mongo.Connect
    In v2, Connect takes only options (no context):
    mongo.Connect(options.Client().ApplyURI(uri)).
    All call sites were updated; context is used only for Ping, Disconnect, RunCommand, and InsertOne.

  • Connection string / database name
    Replaced connstring.ParseAndValidate(connStr) with a local helper mongoDatabaseFromURI(connStr) that:

    • Parses the URI with url.Parse.
    • Takes the path (e.g. /mydb), trims the leading slash and any query string.
    • Defaults to "admin" if the path is empty.
      commitMongo and any logic that used connStringInfo.Database now use this helper.
  • Error handling and defers

    • In GetVersion: check err after mongo.Connect and return early on failure; defer client.Disconnect(ctx) only when client is non-nil.
    • In commitMongo: defer client.Disconnect(ctx) and use a separate inner context for InsertOne to avoid variable shadowing (iCtx, iCancel).

Result

The Go telemetry server builds successfully with the v2 driver. Behavior is unchanged from a user perspective. Same binary works whether built via pipenv or NUKE.


3. dev/pyRevitTelemetryServer/go.mod and go.sum

  • go.mod
    Already declared go.mongodb.org/mongo-driver/v2; no functional change required for the mongo.go update.

  • go.sum
    Updated by running go mod tidy so that the v2 driver and its transitive dependencies have correct checksums. Needed for a reproducible Go build.


4. build/Build.cs — Full build includes telemetry

Change: BuildProducts again depends on BuildTelem. The default full build runs:
BuildDeps → BuildLabs → BuildLoaders → BuildRuntime → DeployLibsToEngines → BuildTelem → BuildAutocmp.

Reason: With mongo.go fixed, the telemetry server builds successfully; including it in the full build matches the pipenv “build products” behavior and produces bin/pyrevit-telemetryserver.exe in one shot.


5. build/README.md — Documentation

  • “Source code used by this build”
    Short section stating that ScriptConsole and mongo.go changes are product improvements (theme fix and telemetry v2), not NUKE-only workarounds, and that they benefit both pipenv and NUKE builds.

  • A reference to this summary (see below).


Quick reference

File What changed Why
ScriptConsole.cs Theme loaded via TryAddThemeResource (canonical + lowercase fallback); theme added before Controls.xaml Fix “Cannot locate resource 'styles/themes/light.blue.xaml'” in Revit 2024/2026
mongo.go v2 driver imports; mongo.Connect(opts); mongoDatabaseFromURI instead of connstring; error handling and defers Telemetry server Go build was broken; v2 API and no deprecated connstring
go.mod / go.sum go.sum updated via go mod tidy Reproducible build with v2 driver
Build.cs BuildProducts depends on BuildTelem again Full build produces telemetry exe like pipenv
build/README.md “Source code used by this build” section Clarify that changes are product improvements, not Nuke workarounds

@jmcouffin jmcouffin requested a review from Copilot February 26, 2026 20:17
@jmcouffin jmcouffin added Command Line Utility (CLI) Issues related to pyRevit CLI tool [subsystem] go Pull requests that update Go code CI/CD Issues and PR related to the CI/CD workflow in github github_actions Pull requests that update GitHub Actions code labels Feb 26, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a NUKE-based build pipeline intended to produce the same build artifacts as the existing pipenv run pyrevit build products, enabling building the repository without Python/pipenv while keeping the pipenv workflow available.

Changes:

  • Added a NUKE build project (build/) plus a root build.ps1 bootstrap script to build C# and Go products and perform release-related versioning tasks.
  • Updated the telemetry server MongoDB persistence code to use the go.mongodb.org/mongo-driver/v2 driver and adjusted connection-string database name parsing.
  • Adjusted ScriptConsole WPF resource loading to add a theme dictionary first and fall back to a lowercase theme URI.

Reviewed changes

Copilot reviewed 8 out of 10 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
dev/pyRevitTelemetryServer/persistence/mongo.go Switches MongoDB integration to mongo-driver v2 and adds URI DB-name parsing helper.
dev/pyRevitTelemetryServer/go.mod Updates Go module dependency list (removes/adjusts indirect deps).
dev/pyRevitTelemetryServer/go.sum Updates dependency checksums in line with the Go module changes.
dev/pyRevitLabs.PyRevit.Runtime/ScriptConsole.cs Adds theme resource loading fallback and changes merge order to prevent missing-resource errors.
build/nuget.config Adds NuGet configuration affecting signature validation behavior during restores.
build/build.csproj Adds a net8.0 NUKE build project referencing Nuke.Common.
build/README.md Documents NUKE build usage, targets, outputs, and troubleshooting.
build/Build.cs Implements NUKE targets for building deps/labs/loaders/runtime, deploying libs, building Go tools, and some release automation.
build.ps1 Adds a root PowerShell bootstrapper to compile and run the NUKE build.
.gitignore Ignores NUKE’s .nuke/ and build runner output under build/bin/.

Comment on lines +28 to +38
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

logger.Debug("opening mongodb session")
client, err := mongo.Connect(ctx, options.Client().ApplyURI(w.Config.ConnString))

client, err := mongo.Connect(options.Client().ApplyURI(w.Config.ConnString))
if err != nil {
return ""
}
defer func() {
if err = client.Disconnect(ctx); err != nil {
panic(err)
if dErr := client.Disconnect(ctx); dErr != nil {
panic(dErr)
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In GetVersion(), the deferred Disconnect uses the ctx variable, but ctx is reassigned later for Ping/RunCommand. Because the deferred closure captures ctx by reference, Disconnect will run with the second (2s) context (likely already canceled), which can cause Disconnect to fail and the code to panic. Use a dedicated context variable for Disconnect (or capture the original ctx in a local var inside the defer) and use separate contexts for Ping/RunCommand.

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +6
<config>
<!-- Skip NuGet signature verification if it fails (e.g. proxy/corporate SSL) -->
<add key="signatureValidationMode" value="accept" />
</config>
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This repo-level NuGet config disables package signature verification (signatureValidationMode=accept). That weakens supply-chain protections for everyone building the repo, not just users behind problematic proxies. Prefer removing this from source control and documenting a per-user workaround (e.g., local NuGet.Config), or limit the relaxation to a narrowly-scoped restore step that’s explicitly opt-in.

Suggested change
<config>
<!-- Skip NuGet signature verification if it fails (e.g. proxy/corporate SSL) -->
<add key="signatureValidationMode" value="accept" />
</config>
<!--
Note: Do not disable NuGet package signature verification at the repo level.
If you need to relax signature checks (e.g. due to corporate SSL interception),
configure that in a user-specific NuGet.Config outside of source control.
-->

Copilot uses AI. Check for mistakes.
Comment on lines +189 to +192
var outputExe = BinPath / "pyrevit-telemetryserver.exe";
BinPath.CreateDirectory();
RunProcess("go", "get ./...", (string)telemPath, captureOutput: true, unsetProxy: true);
RunProcess("go", $"build -o \"{outputExe}\" .", (string)telemPath, captureOutput: true, unsetProxy: true);
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using go get ./... as part of the build can modify go.mod/go.sum (and potentially pull newer dependency versions), making builds non-reproducible and leaving a dirty working tree. Prefer go mod download (or just go build, which will fetch modules as needed) so the build doesn’t change module files.

Copilot uses AI. Check for mistakes.
Comment on lines +202 to +206
var outputExe = BinPath / "pyrevit-autocomplete.exe";
BinPath.CreateDirectory();
RunProcess("go", "get ./...", (string)autocmpPath, captureOutput: true, unsetProxy: true);
RunProcess("go", $"build -o \"{outputExe}\" .", (string)autocmpPath, captureOutput: true, unsetProxy: true);
}
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as BuildTelem: running go get ./... during BuildAutocmp can update go.mod/go.sum and fetch newer dependency versions. Prefer go mod download / go build to keep the build reproducible and avoid modifying the repo during a build.

Copilot uses AI. Check for mistakes.
build/Build.cs Outdated
Comment on lines +279 to +280
var year = DateTime.Now.Year;
if (DateTime.Now.Month == 12) year++;
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SetYear bumps the year for the entire month of December (if (DateTime.Now.Month == 12) year++;). The existing pipenv implementation only bumps when within ~30 days of Jan 1, so this will update copyright too early in most of December. Consider porting the same threshold logic from dev/_props.py to keep behavior consistent.

Suggested change
var year = DateTime.Now.Year;
if (DateTime.Now.Month == 12) year++;
var now = DateTime.Now;
var year = now.Year;
var nextJan1 = new DateTime(year + 1, 1, 1);
var threshold = nextJan1.AddDays(-30);
if (now >= threshold)
year++;

Copilot uses AI. Check for mistakes.
@OnePowerUser88
Copy link
Contributor Author

I’ve pushed a follow‑up commit to address the review feedback and harden a couple of edge cases:

Mongo telemetry (dev/pyRevitTelemetryServer/persistence/mongo.go)

  • Fixed the Disconnect context in GetVersion:
    • mongo.Connect is still mongo.Connect(options.Client().ApplyURI(...)), but we no longer reuse the same ctx for Ping and RunCommand.
    • Disconnect now uses its own timeout context inside the defer, so it doesn’t run with a cancelled context.
  • Kept the v2 driver and URI‑based DB name parsing (mongoDatabaseFromURI using net/url + strings).

(If anyone can fully test the Telemetry changes it would be greate, I have built a separate AzureSQL telemetry service for the extension I maintain, so I don't have the setup for testing it properlty.)

NUKE build (build/Build.cs)

  • Go builds:
    • BuildTelemCore and BuildAutocmpCore now use only:
      • go build -o "<output>" .
    • The earlier go get ./... calls are removed, so NUKE builds no longer mutate go.mod / go.sum or pull in newer deps behind your back.
  • SetYear:
    • Ported the same 30‑day threshold logic as dev/_props.py:set_year:
      • Compute nextJan1 and threshold = nextJan1 - 30 days, bump the year only when now >= threshold.

NuGet config

  • Removed build/nuget.config, so there is no more repo‑level signatureValidationMode="accept".
    Anyone who needs to relax signature checks can do so in a user‑specific NuGet.Config outside this repo.

Tab coloring robustness (pyrevitlib/pyrevit/revit/tabs.py)

  • Hardened against legacy / C# config setup (PR refactor: Rewrite pyRevit configurations #2482) user configs:
    • tabstyle_index and family_tabstyle_index are now normalized to int with safe defaults (DefaultTabColoringStyleIndex / DefaultFamilyTabColoringStyleIndex), so "0", "1", etc. no longer cause TypeError: expected int, got str.
    • tab_filtercolors is normalized before use:
      • if it’s a list, we turn it into {color: ""} for each entry;
      • if it’s anything other than a dict, we fall back to {}.
    • hex_to_brush is now defensive: invalid color strings are caught and replaced with a default brush (first DefaultBrushes entry, with a final fallback to white) instead of throwing.
  • This fixes the startup errors I was seeing when the loaded user config contained old/bad tab coloring values.

Note: These tab‑coloring issues are very likely related to the ongoing work in “fix/configuration” in PR #2482 that ports config handling to C#. That branch was writing tabstyle_* and tab_filtercolors slightly differently (indices as strings, non‑dict filtercolors). The guards in tabs.py make the Python side tolerant of both the legacy Python writer and the new C# writer, so this PR should be compatible with both.

Merges & testing

  • Merged latest upstream/develop into NUKE-build.
  • NUKE:
    • ./build.ps1 Clean followed by ./build.ps1 BuildProducts succeeds from a clean tree.
  • Revit:
    • Basic testing in Revit 2024 and 2026:
      • pyRevit loads,
      • tab coloring works,
      • no loader errors on startup.
  • Telemetry:
    • Manually ran the built telemetry server:

      ./bin/pyrevit-telemetryserver.exe `
        "mongodb://pyrevit:pyrevit@localhost:27017/pyrevit" `
        --scripts=scripts `
        --events=events `
        --port=8090

      and got Server listening on 8090..., so the v2 driver wiring and build seems to be correct.

Let me know if you’d like any of these pieces split into separate PRs or see further tweaks to the NUKE targets.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI/CD Issues and PR related to the CI/CD workflow in github Command Line Utility (CLI) Issues related to pyRevit CLI tool [subsystem] github_actions Pull requests that update GitHub Actions code go Pull requests that update Go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants