Skip to content

Tooling Scripts

Isthimius edited this page Aug 12, 2026 · 2 revisions

Gondwana includes a small set of PowerShell scripts for repository maintenance, local development, changelog generation, and releases.

They live under:

Tooling/scripts/
├── Generate-Project-Changelogs.ps1
├── Reinstall-Gondwana-Cli.ps1
├── Reinstall-Gondwana-Templates.ps1
├── Setup-Gondwana-Dev.ps1
└── release.ps1

These are maintainer and contributor tools. They are not part of the Gondwana runtime and are not required by games that consume Gondwana through NuGet.

Their purpose is to make common repository operations repeatable instead of relying on somebody remembering the right sequence of dotnet, Git, NuGet, git-cliff, and other commands.


Contents


Which script should I use?

Goal Script
Set up a new Gondwana development machine Setup-Gondwana-Dev.ps1
Test changes to the gondwana CLI locally Reinstall-Gondwana-Cli.ps1
Test changes to Gondwana dotnet new templates locally Reinstall-Gondwana-Templates.ps1
Generate or preview project-specific changelogs Generate-Project-Changelogs.ps1
Prepare and start an official Gondwana release release.ps1

A useful distinction is:

Setup-Gondwana-Dev.ps1
        │
        └── prepares a machine

Reinstall-*.ps1
        │
        └── supports local development

Generate-Project-Changelogs.ps1
        │
        └── maintains release history

release.ps1
        │
        └── initiates an official release

Running the scripts

From the repository root, a script can be invoked with its repository-relative path:

.\Tooling\scripts\Setup-Gondwana-Dev.ps1

or:

.\Tooling\scripts\release.ps1 -PreviewOnly

The scripts resolve the Gondwana repository root from their own location, so they do not depend heavily on the shell's current working directory.

That is intentional.

A maintenance script should know where the repository is because of where the script lives, rather than assuming the user happened to open PowerShell in exactly the right directory.

Most of the scripts explicitly require PowerShell 5.1 or later.


Setup-Gondwana-Dev.ps1

This is the bootstrap script for a Gondwana development environment.

Its intended use is:

Clone Gondwana, run one script, and get the machine as close as possible to ready for development.

It is designed to be idempotent: running it again should update, restore, or verify existing tools rather than assuming the machine is empty.

Basic usage:

.\Tooling\scripts\Setup-Gondwana-Dev.ps1

What it sets up

The script performs thirteen numbered checks or setup operations.

1. Git

It first verifies that:

git

is available on PATH.

Git is a hard prerequisite. If it cannot be found, setup stops.


2. .NET 8 SDK

The script verifies that a .NET 8 SDK is installed.

On Windows, if it is missing and winget is available, the script attempts to install:

Microsoft.DotNet.SDK.8

automatically.

On other platforms, it reports that .NET 8 must be installed through the platform's normal package-management mechanism or the .NET installer.


3. Local .NET tools

Gondwana contains a .NET tool manifest.

The setup script restores those tools using:

dotnet tool restore

This includes tooling such as Nerdbank.GitVersioning (nbgv).


4. NuGet restore

The complete Gondwana solution is restored in Release configuration with:

EnableWindowsTargeting=true

This is important because the solution contains Windows-targeted projects even when some development or CI work occurs outside Windows.

The restore also forces dependency reevaluation rather than simply trusting a potentially stale local cache.


5. Build

Unless disabled, the script builds:

Gondwana.sln

in:

Release

configuration.

This turns setup into more than a dependency installer.

It also provides an immediate sanity check:

Can this machine actually build Gondwana?

To skip this step:

.\Tooling\scripts\Setup-Gondwana-Dev.ps1 -SkipBuild

6. Gondwana CLI

The script checks for the global:

Gondwana.Cli

.NET tool.

If it is missing, it installs it.

If it already exists, the script attempts to update it.

It also handles the case where the configured package source contains an older version than the version already installed. In that situation, setup keeps the newer installed version rather than treating the attempted downgrade as fatal.

The global command provided by the package is:

gondwana

7. Gondwana project templates

The script similarly checks for:

Gondwana.Templates

and installs or updates the template package.

These are the templates used by commands such as Gondwana's dotnet new project templates.

If a newer local template package is already installed than the configured source provides, setup is intended to preserve the current installation rather than blindly downgrade it.


Optional development dependencies

Steps 8 through 12 can be skipped with:

.\Tooling\scripts\Setup-Gondwana-Dev.ps1 -SkipOptional

This is useful when only the core repository dependencies are needed.


8. WebAssembly tools

The script checks for the .NET:

wasm-tools

workload.

If missing, it installs it.

If already present, installed workloads are updated.

This supports Gondwana's Blazor/WebAssembly development path.


9. SDL2

The script checks for SDL2 native binaries used by:

Gondwana.Input.SDL2

If SDL2 is not detected, setup prints guidance rather than treating it as a fatal error.

That is because SDL2 is only required when using the SDL2 input package.


10. LibVLC

The script checks for LibVLC, used by:

Gondwana.Video

On Windows, when LibVLC is missing and winget is available, setup attempts to install VLC:

VideoLAN.VLC

If automatic installation is unavailable or fails, the script reports manual installation guidance.

Again, this is an optional subsystem dependency rather than a requirement for the Gondwana core engine.


11. git-cliff

Gondwana uses:

git-cliff

for changelog generation.

Setup verifies that it exists.

On Windows, it can install or update it through:

winget

using the orhun.git-cliff package.

git-cliff is especially important to the release scripts described later on this page.


12. butler

butler is itch.io's command-line publishing tool.

If it is missing, the script attempts to download the appropriate current binary from itch.io's Broth CDN.

The script supports platform-specific packages for:

  • Windows
  • Linux
  • macOS

and installs Butler under a user-local itch directory.

Typical locations are:

%LOCALAPPDATA%\itch\butler

on Windows and:

~/.itch/butler

on Unix-like systems.

The installation directory is added to PATH for the current PowerShell session.

The script also reminds the developer that it should be added permanently if Butler is expected to be available in future shells.

Authentication is then performed separately with:

butler login

13. gondwana doctor

Finally, setup runs:

gondwana doctor

when the command is available.

This provides an end-of-setup health check rather than simply assuming that every preceding installation produced a usable environment.

Conceptually:

install / restore / verify
          ↓
      build Gondwana
          ↓
  check optional tools
          ↓
    gondwana doctor

Setup parameters

Parameter Purpose
-SkipBuild Skip the Release build
-SkipOptional Skip WASM, SDL2, LibVLC, git-cliff, and Butler setup

For a minimal bootstrap:

.\Tooling\scripts\Setup-Gondwana-Dev.ps1 -SkipBuild -SkipOptional

For a complete development environment:

.\Tooling\scripts\Setup-Gondwana-Dev.ps1

Reinstall-Gondwana-Cli.ps1

This script exists for local CLI development.

Normally, installing the Gondwana CLI looks something like:

dotnet tool install --global Gondwana.Cli

That obtains a package from a configured package source.

That is not what you want while actively editing:

Tooling/Gondwana.Cli

because your newest changes have not necessarily been published anywhere.

Reinstall-Gondwana-Cli.ps1 solves that problem.


What it does

The script:

  1. packs the local Gondwana.Cli project
  2. places the resulting package in a local package directory
  3. detects whether Gondwana.Cli is currently installed globally
  4. uninstalls the existing global tool if necessary
  5. clears the cached gondwana.cli package
  6. installs the newly packed local package globally
  7. attempts to display the installed gondwana --version

Conceptually:

flowchart LR
    SRC[Gondwana.Cli source] --> PACK[dotnet pack]
    PACK --> FEED[Local NuGet directory]
    OLD[Installed CLI] --> REMOVE[Uninstall]
    FEED --> INSTALL[Install global tool]
    REMOVE --> INSTALL
    INSTALL --> CMD[gondwana]
Loading

Why the cache is cleared

NuGet caching is normally a good thing.

During local package development, however, repeatedly producing packages with the same version number can cause an older cached package to be reused.

The CLI reinstall script explicitly removes the local cached:

gondwana.cli

package before installing.

That helps ensure:

"Install my local CLI" actually means the CLI that was just packed.


Basic usage

.\Tooling\scripts\Reinstall-Gondwana-Cli.ps1

The default configuration is:

Release

and the default local package directory is:

.local-nuget

at the repository root.


Parameters

-Configuration

Select the build configuration used by dotnet pack.

For example:

.\Tooling\scripts\Reinstall-Gondwana-Cli.ps1 -Configuration Debug

-PackageOutput

Select another local package directory:

.\Tooling\scripts\Reinstall-Gondwana-Cli.ps1 `
    -PackageOutput artifacts\local-tools

Relative paths are resolved from the Gondwana repository root.


When to use it

Use this script when changing things such as:

  • Gondwana CLI commands
  • gondwana doctor
  • CLI argument handling
  • CLI output
  • CLI project creation or utility behavior

It is a development loop:

edit CLI
   ↓
run Reinstall-Gondwana-Cli.ps1
   ↓
run gondwana ...
   ↓
inspect result
   ↓
edit again

No public NuGet release is required.


Reinstall-Gondwana-Templates.ps1

This is the template equivalent of the CLI reinstall script.

It exists for development of:

Tooling/Gondwana.Templates

without publishing a new template package first.


What it does

The script:

  1. packs Gondwana.Templates
  2. identifies the exact .nupkg it just produced
  3. determines that package's version
  4. detects and uninstalls any currently installed Gondwana.Templates
  5. creates an isolated temporary NuGet package cache
  6. installs the freshly packed package directly
  7. verifies the installed template package
  8. lists available Gondwana templates
  9. restores the caller's original NUGET_PACKAGES environment
  10. removes its temporary cache

The temporary cache is particularly important.

It isolates the reinstall operation from whatever versions NuGet may already have stored globally.


Basic usage

.\Tooling\scripts\Reinstall-Gondwana-Templates.ps1

After installation, the script runs the equivalent of:

dotnet new list gondwana

so the developer can immediately see the Gondwana templates currently registered with the .NET template system.


Parameters

The same two main development parameters are available as the CLI script.

Configuration

.\Tooling\scripts\Reinstall-Gondwana-Templates.ps1 `
    -Configuration Debug

Package output

.\Tooling\scripts\Reinstall-Gondwana-Templates.ps1 `
    -PackageOutput artifacts\local-templates

The default package directory is again:

.local-nuget

CLI reinstall vs template reinstall

They solve similar problems but target two different .NET mechanisms.

Script Installation mechanism
Reinstall-Gondwana-Cli.ps1 dotnet tool
Reinstall-Gondwana-Templates.ps1 dotnet new

The CLI becomes a command:

gondwana

The templates become entries available to:

dotnet new

Generate-Project-Changelogs.ps1

Gondwana is a repository containing many separately meaningful projects.

A root changelog answers:

What changed in Gondwana as a whole?

But somebody consuming only:

Gondwana.WinForms

may instead want to know:

What changed in Gondwana.WinForms?

Generate-Project-Changelogs.ps1 creates those project-specific histories.


git-cliff

The script uses:

git-cliff

with Gondwana's repository-level:

cliff.toml

configuration.

Each project is processed with an --include-path filter.

Conceptually:

all repository commits
          │
          ├── touched Gondwana/** ?
          │       └── Gondwana/CHANGELOG.md
          │
          ├── touched Gondwana.Widgets/** ?
          │       └── Gondwana.Widgets/CHANGELOG.md
          │
          └── touched Gondwana.WinForms/** ?
                  └── Gondwana.WinForms/CHANGELOG.md

One commit may appear more than once

This is intentional.

Suppose a commit changes both:

Gondwana/**

and:

Gondwana.WinForms/**

That commit may legitimately appear in both project changelogs.

This is not duplication in the bookkeeping sense.

Each changelog answers a different question:

Did this change affect this project?

For both projects, the answer is yes.


Default projects

The script contains a default project list covering Gondwana library and tooling projects.

Demos and the unit-test project are intentionally excluded from this per-project changelog generation.

The root CHANGELOG.md remains the canonical repository-wide release history.


New vs existing changelogs

When a project has no changelog yet, the script uses git-cliff in normal output mode so the initial changelog header is generated.

Conceptually:

no CHANGELOG.md
      ↓
create complete changelog

For an existing changelog, it uses prepend behavior:

existing CHANGELOG.md
      ↓
prepend newest release
      ↓
retain previous history

This keeps newest releases at the top.


Previewing changes

The safest way to inspect what the script would generate is:

.\Tooling\scripts\Generate-Project-Changelogs.ps1 `
    -Unreleased `
    -PreviewOnly

-PreviewOnly writes the generated result to the console and does not modify the changelog files.


Generating unreleased changelogs

To actually write the current unreleased changes:

.\Tooling\scripts\Generate-Project-Changelogs.ps1 -Unreleased

Generating for a release tag

A version can be supplied explicitly:

.\Tooling\scripts\Generate-Project-Changelogs.ps1 `
    -Tag v1.2.3 `
    -Unreleased

The release script uses this form when preparing an official Gondwana release.


Limiting the project set

For development or testing, a subset can be requested:

.\Tooling\scripts\Generate-Project-Changelogs.ps1 `
    -Projects @(
        "Gondwana",
        "Gondwana.WinForms"
    ) `
    -Unreleased

Parameters

Parameter Purpose
-Tag Version tag passed to git-cliff
-Unreleased Restrict output to changes since the previous release
-PreviewOnly Print output without changing files
-Projects Override the default project list
-CliffConfigPath Use a different cliff.toml configuration

If any git-cliff operations fail, the script collects the failed project names and reports them when processing finishes.


release.ps1

release.ps1 is the local release orchestrator.

It is deliberately more conservative than the development scripts because running it can lead to packages being published publicly.

The critical distinction is:

release.ps1 prepares and pushes the release tag.

It does not directly publish Gondwana to NuGet.

Pushing the version tag triggers Gondwana's GitHub Actions release.yml workflow, which performs the actual remote release build and publication.


Release architecture

flowchart TD
    DEV[release.ps1] --> CHECKS[Pre-flight checks]
    CHECKS --> TESTS[Gondwana.Tests]
    TESTS --> VERSION[NBGV version]
    VERSION --> NOTES[Generate changelogs]
    NOTES --> CONFIRM[Type DEPLOY]
    CONFIRM --> COMMIT[Commit changelog changes]
    COMMIT --> TAG[Create vX.Y.Z tag]
    TAG --> PUSH[Push tag to GitHub]

    PUSH --> ACTIONS[GitHub Actions release.yml]
    ACTIONS --> GH[GitHub Release]
    ACTIONS --> NUGET[NuGet.org]
    ACTIONS --> PACKAGES[GitHub Packages]
    ACTIONS --> DOCS[Published API docs]
Loading

The local script and the GitHub workflow therefore form two halves of one release system.


Pre-flight checks

Before allowing a normal release, the script verifies several conditions.

These include:

  • Git is installed
  • .NET is installed
  • nbgv is installed
  • git-cliff is installed
  • cliff.toml exists
  • the current directory belongs to a Git repository
  • the required release branch is checked out
  • local repository state has been refreshed from the remote
  • local master matches remote master
  • there are no unstaged changes
  • there are no staged-but-uncommitted changes

By default, the required branch is:

master

and the remote is:

origin

Tests happen before release preparation

Before creating the release, the script runs:

Testing/Gondwana.Tests/Gondwana.Tests.csproj

in Release configuration.

If the tests fail:

release stops

There is no "publish it anyway" path built into the normal script.

That is exactly where a release script should be stubborn.


Versioning with NBGV

The script asks Nerdbank.GitVersioning for:

NuGetPackageVersion

and constructs the Git tag from that version.

For example:

NuGetPackageVersion = 1.4.2
              ↓
          v1.4.2

The release version is therefore derived from the repository's versioning configuration rather than being manually typed into the release command.


Release changelogs

The release script creates a grouped root release section.

It organizes changes by project or repository area, including sections such as:

  • Gondwana
  • audio projects
  • Avalonia
  • Blazor
  • hosting
  • SDL2 input
  • video
  • widgets
  • WinForms
  • tooling projects
  • build/repository changes

Each group asks git-cliff for changes touching the paths assigned to that group.

Groups are deliberately allowed to overlap.

A commit affecting two components can belong under both component headings.


Heading adjustment

git-cliff generates category headings of its own.

Because release.ps1 places those beneath project headings, it demotes the generated Markdown headings by one level.

Conceptually:

## Gondwana.WinForms

### Added

### Fixed

rather than having the project's heading and the changelog category compete at the same Markdown level.


Full changelog link

When a previous release tag exists, the generated root section ends with a comparison link conceptually equivalent to:

previous tag ... new tag

on GitHub.

That provides a direct path from the human-readable changelog to the complete Git diff.


Preview mode

Before doing a real release, use:

.\Tooling\scripts\release.ps1 -PreviewOnly

Preview mode still performs meaningful validation and changelog generation so the proposed release can be inspected.

But it does not:

  • write the changelogs
  • create a changelog commit
  • create a Git tag
  • push anything
  • trigger deployment

This should normally be the first release command run.


Hard deployment confirmation

A real release requires an explicit confirmation.

The script asks the maintainer to type:

DEPLOY

exactly.

Anything else cancels the operation.

That is intentionally harder to trigger than a simple Y.

The command sits immediately before operations that can ultimately result in an immutable public NuGet release.


Root and project changelogs

After confirmation, the script updates the root:

CHANGELOG.md

and then invokes:

Generate-Project-Changelogs.ps1

to update individual project changelogs.

It stages all generated changelog changes and creates a commit with a message of the form:

docs: update changelog for vX.Y.Z

That commit is pushed to the required branch before the tag is created.


Version verification after the changelog commit

After committing the changelog, the script asks NBGV for the version again.

The value is expected to remain unchanged.

If the changelog commit unexpectedly changes the calculated version, the script aborts before tagging.

This protects against releasing:

version calculated before commit

while the actual tag points at a commit whose calculated version is something different.


Tag handling

The final local release operation is the version tag.

The tag follows:

v<version>

For example:

v1.4.2

The script checks both local and remote tag state.

If the same version tag already exists, the current script deliberately removes and replaces it before pushing the new tag.

That is powerful behavior and is one reason release.ps1 should be treated as release infrastructure rather than a casual utility script.

Once the tag is pushed:

GitHub receives vX.Y.Z
        ↓
.github/workflows/release.yml runs

At that point, publication is handed off to GitHub Actions.


Release parameters

Parameter Default Purpose
-Remote origin Git remote used for synchronization and push
-RequiredBranch master Branch required for a normal release
-ChangelogPath CHANGELOG.md Root changelog location
-CliffConfigPath cliff.toml git-cliff configuration
-PreviewOnly off Validate and preview without deployment

For almost all normal Gondwana releases, the intended sequence is simply:

.\Tooling\scripts\release.ps1 -PreviewOnly

inspect the result, then:

.\Tooling\scripts\release.ps1

and type:

DEPLOY

when satisfied.


How the release scripts fit together

There are three different pieces involved in Gondwana's changelog/release system:

Generate-Project-Changelogs.ps1
release.ps1
.github/workflows/release.yml

Their responsibilities are different.

Generate-Project-Changelogs.ps1

Answers:

What changed in each individual project?

and writes the corresponding project changelogs.

release.ps1

Answers:

Is the repository ready to release, what version is it, and what release tag should be pushed?

It performs local validation, writes changelogs, commits them, and creates the tag.

GitHub Actions release.yml

Answers:

A release tag now exists. How do we build and publish it?

It performs the remote release build and publication.

Together:

git history
    ↓
git-cliff
    ↓
release.ps1
    ├── root changelog
    ├── project changelogs
    ├── changelog commit
    └── vX.Y.Z tag
             ↓
        GitHub Actions
             ├── GitHub Release
             ├── NuGet
             ├── GitHub Packages
             └── API documentation

Local packages and caching

The two Reinstall-* scripts exist partly because package caches are designed for released packages, not rapid iteration.

Normally:

package ID + package version

should uniquely identify package contents.

During development, however, it is convenient to repeatedly build:

Gondwana.Cli 1.2.3

without incrementing the version after every edit.

That creates a problem:

same package ID
+ same version
+ different local contents

NuGet may reasonably assume it already has that package.

The development scripts therefore take explicit measures to avoid stale package reuse.

The CLI script clears the cached CLI package before reinstalling.

The template script goes further and temporarily points:

NUGET_PACKAGES

at an isolated temporary directory.

After installation, it restores the previous environment and deletes the temporary cache.

This behavior is development-specific.

Published package versions should remain immutable.


Safety and failure behavior

These scripts generally use:

$ErrorActionPreference = 'Stop'

and command wrappers that inspect:

$LASTEXITCODE

for external programs.

That means failures are intended to stop the operation rather than quietly allowing later steps to continue from an invalid state.

This is particularly important for:

  • builds
  • tests
  • Git operations
  • package installation
  • changelog generation
  • releases

Development scripts are relatively disposable

The reinstall scripts modify local developer state:

global .NET tool installation
template installation
local package caches

If something goes wrong, the operation can normally be repeated.


Release operations are not disposable

A release can ultimately create:

  • Git commits
  • remote Git tags
  • GitHub Releases
  • NuGet packages

A published NuGet package version cannot simply be overwritten with different contents later.

For that reason:

release.ps1

contains substantially more validation and confirmation than the local development scripts.

Use:

-PreviewOnly

before a real deployment.


Mental model

The scripts fall into three layers.

DEVELOPMENT ENVIRONMENT
└── Setup-Gondwana-Dev.ps1
        prepares the machine

LOCAL ITERATION
├── Reinstall-Gondwana-Cli.ps1
└── Reinstall-Gondwana-Templates.ps1
        test unpublished local packages

RELEASE MANAGEMENT
├── Generate-Project-Changelogs.ps1
└── release.ps1
        prepare repository history and start deployment

Or, even more simply:

Setup prepares the developer.
Reinstall scripts test local tooling.
Changelog records what changed.
Release turns that history into a versioned deployment.

None of these scripts are required to run a Gondwana game.

They exist to make development and release engineering around the engine predictable, repeatable, and considerably less dependent on somebody remembering seventeen shell commands in exactly the right order.

Clone this wiki locally