Testing the libraries

Before starting, if you don’t know Braden, you should check out his newsletter. He shares insightful articles on computational development in the AEC space. As with the previous article, Braden continues to collaborate on this series, contributing his sharp insights and experience throughout.

AEC teams frequently face change requests that require structured version control to prevent version drift across enterprise environments. When Dynamo (DYN) or Grasshopper (GH) components spread throughout organisations, ensuring everyone has compatible versions becomes critical for project success.
Version control is a crucial component of any development environment, as it helps manage changes made to code and how it is deployed. This is especially important for GH or DYN components because they spread like wildfire, making it challenging to ensure that everyone is working with the latest version.

Foundation: Git & build integration

Version control for code should be the foundation of any development workflow. The most popular option is Git, using GitHub to host code. There are alternatives like Gitlab, Bitbucket or Azure Repos, but the choice of platform matters less than having systematic version control.
Git becomes the trigger for our automated build system. From first article, our build.props handles version propagation through conditional logic:

<Choose>
    <!-- When no version is provided, default to development version -->
    <When Condition="'$(AssemblyInformationalVersion)' == '' ">
        <PropertyGroup>
            <Version>0.0.0.0</Version>
            <AssemblyInformationalVersion>0.0.0.0</AssemblyInformationalVersion>
        </PropertyGroup>
    </When>
    <!-- When version is provided by CI/CD pipeline, use it across all builds -->
    <When Condition="'$(AssemblyInformationalVersion)' != '' ">
        <PropertyGroup>
            <AssemblyCompany>AECOM</AssemblyCompany>
            <AssemblyProduct>Toolbox</AssemblyProduct>
            <!-- Ensure consistent versioning across all platform configurations -->
            <Version>$(AssemblyVersion)</Version>
        </PropertyGroup>
    </When>
</Choose>

This configuration enables version information to flow directly from CI/CD pipelines into our build process, ensuring consistent version numbers across all platform combinations. Once the AssemblyInformationalVersion is set, every configuration (Revit, Civil3D, Grasshopper) receives the same version tag, preventing deployment mismatches.

Branching strategies

With version information now automated across builds, the next challenge becomes managing how changes flow through branches before release. Two strategies dominate the landscape, each with distinct advantages for AEC workflows.

Git flow

Before CI/CD systems became prevalent, this was the strategy used by most software companies. It maintained clean handling of changes made by different people to the same repository.

For each change (hotfix, bug, feature), there is a new branch. This makes any changes to the core codebase localised. When things are tested and ready, they can be committed back into the main branch (core codebase). Having a branch for releases helps ensure that what’s being released is stable and maintains a copy of the deployed code for potential hotfixes.

The key to successful GitFlow implementation is intentional branches and commits. Avoid putting multiple features onto the same feature branch, although what constitutes a “feature” can be subjective.

Trunk-Based Development (TBD)

Since improved CI/CD systems emerged, GitFlow has fallen out of favour for this strategy. The main driver is rapid deployment capability – potentially daily releases. This approach originated from web application development, where deploying desktop applications remains more challenging.

The central difference is eliminating “long-lived” branches – everything must return to the main codebase within a promised timeframe (daily or weekly, depending on team practices). This increases the likelihood of production failures but enables faster fixes through CI/CD with automated testing on a single branch, making maintenance quicker and easier.

GitFlow vs TBD for GH/DYN

Experience with both strategies across different component sets reveals that, unless deploying regularly or working with 1-2 developers, GitFlow proves to be the better strategy.

This recommendation stems from the reality that development of these components is rarely a full-time activity. Teams have other projects and products to manage. Component development typically isn’t managed on a full-time basis. Budgets remain tight for development work, and there’s always a long list of features and bugs to address.

For this reason, long-lived branches make sense. Feature implementation can start on a branch and be paused when team members become busy with other priorities. When a fix needs implementation, branching off the currently deployed code, making the fix, and re-deploying becomes possible without affecting current feature development. When time permits, the bug fix can be incorporated into the feature branch to continue working on it. Trunk-based development makes this workflow very difficult to execute.

Automated version management with Release Drafter

Manual version numbering becomes impractical when managing releases across six software versions and multiple frameworks. Release Drafter automates semantic versioning based on pull request labels, integrating seamlessly with our build infrastructure:

# Configure release naming and tagging based on semantic versioning
name-template: '$RESOLVED_VERSION'
tag-template: '$RESOLVED_VERSION'

# Automatically determine version increments based on PR labels
version-resolver:
  major:
    labels: ['major']        # Breaking changes
  minor:
    labels: ['minor']        # New features, backward compatible
  patch:
    labels: ['patch']        # Bug fixes, patches

Developers apply semantic labels to pull requests. Release Drafter calculates version increments automatically and generates structured release notes. This integrates seamlessly with our build infrastructure, ensuring consistent versioning across all platform configurations.

Multi-module version management

The monolithic project structure we established in the first article creates multiple interdependent modules within a single repository:

  • LibraryCore: Shared functionality used by all platforms
  • LibraryDynamo: Dynamo-specific components (Extensions, Functions, UI)
  • LibraryGrasshopper: Grasshopper-specific components and utilities

Rather than versioning the entire repository for every change, enterprise workflows require selective versioning based on which modules actually changed. This prevents unnecessary builds and maintains clear change tracking.

The four pathways to automated integration testing

When it comes to automating tests that touch Rhino + Grasshopper (and by extension, similar challenges exist for Dynamo), there are four mainstream approaches. Each bootstraps the host application in a different place, so their trade-offs revolve around where the application lives, how licenses are consumed, and how portable the workflow is to CI.

Path-based change detection

GitHub Actions path filtering enables selective module versioning:

name: Detect Changes
jobs:
  changes:
    runs-on: ubuntu-latest
    steps:
      - name: Filter changed projects
	uses: dorny/paths-filter@v2
	with:
	  filters: |
	    core: 'Core/**'           # Core library changes
	    dynamo: 'DYN/**'          # Dynamo components
	    grasshopper: 'GH/**'      # Grasshopper components
            
      # Additional workflow steps for processing changes
      - name: 📘 Create release
        if: steps.changes.outputs.code == 'true'  # Only run if code changed
        uses: release-drafter/release-drafter@v6
        id: release
        with:
          config-name: release-drafter.yml
          # Generate alpha versions for non-main branch builds
          prerelease: ${{ boolean switch }}
          prerelease-identifier: 'alpha'
          publish: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

This workflow only triggers versioning for modules with actual changes, reducing build overhead while the conditional compilation system handles platform-specific references and dependencies.

Recommended GitFlow workflow for GH/DYN

  • Create two primary branches: Main and Develop
  • Feature development: Create feature branches from Develop
  • Testing and integration: Merge completed features back into Develop
    • Send alpha versions to testers for validation across platform configurations
  • Production release: Merge from Develop to Main and deploy to users
    • Tag commits as releases for easier visualisation and tracking
  • Hotfix management: Create hotfix branches from Main for critical production issues
    • Fix bugs and commit back to Main, then deploy immediately
    • Integrate hotfixes into active development branches to maintain consistency

This approach integrates with Release Drafter automation: each merged pull request updates draft releases with appropriate version increments, enabling coordinated releases across the entire platform matrix.

AI-enhanced version control workflows

The development landscape is evolving toward intelligent automation, where AI agents handle routine tasks while humans focus on strategic decisions. Current AI capabilities and near-future potential are transforming version control from manual oversight to intelligent collaboration.

Current AI capabilities

Modern AI agents can already automate several version control tasks:

  • Pull Request Analysis: AI reviews code changes and suggests appropriate semantic version labels based on actual impact across platforms
  • Dependency Detection: Automated analysis identifies when changes affect module dependencies or create conflicts in multi-platform builds
  • Test Coverage Validation: AI ensures new changes include appropriate tests for supported platforms before allowing merges

Near-future agentic systems

Emerging agentic workflows represent a fundamental shift toward autonomous, multi-step processes. These AI systems operate through iterative loops – analysing data, making decisions, and executing actions without constant human intervention. Applied to version control, agentic workflows could:

  • Predictive Impact Analysis: Multi-agent systems that analyse code changes, cross-reference internal repositories, and predict deployment impacts across the entire configuration matrix
  • Automated Release Coordination: AI agents specialising in different aspects (dependency mapping, change impact prediction, release coordination) collaborate to reduce errors in multi-platform deployments
  • Adaptive Version Management: Intelligent systems that understand project context, adapt to changing requirements, and make autonomous decisions about version increments based on semantic rules and historical patterns

Practical implementation

Early implementations already show promise. AI agents can analyse vast amounts of code changes in minutes instead of hours, cross-reference module dependencies, and produce customised impact reports. This mirrors successful applications in other fields where AI agents handle due diligence tasks that previously required days of manual work.

The competitive landscape suggests that the first organisations to integrate AI deeply into version control tools will achieve significant efficiency advantages. However, successful implementation requires addressing the stop-start reality of AEC development, where AI agents must adapt to irregular development cycles and maintain consistency across long-lived branches.

These agentic workflows complement rather than replace the sophisticated infrastructure we’ve built, enabling development teams to maintain multi-platform consistency while reducing manual overhead and improving decision quality in complex deployment scenarios.