# Branding, Builds, and Releases This document describes how branded builds work in this repository, how to add or edit a brand, how to build the default and branded variants, and how to publish releases. ## Overview The project supports one default product and any number of branded variants from the same codebase. - The default product is defined by built-in defaults in `build/scripts/brand_config.py`. - The default product identifier is `webdrop_bridge`. - Additional brands are defined by JSON manifests in `build/brands/`. - Runtime behavior can also be branded through application config values such as `brand_id`, `config_dir_name`, `app_name`, and update settings. - Windows and macOS installers are built as separate artifacts per brand. - Releases are shared by version. A single Forgejo release can contain installers for the default product and multiple brands. ## Branding Model There are two layers to branding: 1. Packaging identity Controls installer name, executable/app bundle name, product display name, bundle identifier, MSI upgrade code, installer artwork, and related metadata. 2. Runtime configuration Controls app name shown in the UI, config directory name, update feed settings, URL mappings, allowed roots, and similar application behavior. Packaging identity lives in `build/brands/.json`. Runtime configuration lives in app config files loaded by the application. See `config.example.json` for the current branded example. ## Important Files - `build/scripts/brand_config.py`: central helper for brand metadata, artifact naming, and release manifest generation - `build/brands/agravity.json`: example branded manifest - `build/scripts/build_windows.py`: Windows build entrypoint - `build/scripts/build_macos.sh`: macOS build entrypoint - `build/scripts/create_release.ps1`: Windows release uploader - `build/scripts/create_release.sh`: macOS release uploader - `config.example.json`: example runtime branding config ## Create a New Brand To create a new brand, add a new manifest file under `build/brands/`. Example: 1. Copy `build/brands/template.jsonc` to `build/brands/.json`. 2. Update the values for the new brand. 3. Add any brand-specific assets if you do not want to reuse the default icons/license assets. Minimal example: ```json { "brand_id": "customerx", "display_name": "Customer X Bridge", "asset_prefix": "CustomerXBridge", "exe_name": "CustomerXBridge", "manufacturer": "Customer X", "install_dir_name": "Customer X Bridge", "shortcut_description": "Customer X drag-and-drop bridge", "bundle_identifier": "com.customerx.bridge", "config_dir_name": "customerx_bridge", "msi_upgrade_code": "PUT-A-NEW-GUID-HERE", "update_channel": "stable", "icon_ico": "resources/icons/app.ico", "icon_icns": "resources/icons/app.icns", "dialog_bmp": "resources/icons/background.bmp", "banner_bmp": "resources/icons/banner.bmp", "license_rtf": "resources/license.rtf" } ``` ### Required Fields - `brand_id`: internal identifier used for build output folders and release manifest entries - `display_name`: user-facing product name - `asset_prefix`: base name for installer artifacts and app bundle name - `exe_name`: executable name for Windows and app bundle name base for macOS - `manufacturer`: MSI manufacturer string - `install_dir_name`: installation directory name shown to the OS - `shortcut_description`: Windows shortcut description - `bundle_identifier`: macOS bundle identifier - `config_dir_name`: local app config/log/cache directory name - `msi_upgrade_code`: stable GUID for Windows upgrades - `update_channel`: currently typically `stable` Generate a new `msi_upgrade_code` for a new brand once and keep it stable afterwards. Examples: ```powershell New-Guid ``` ```bash uuidgen ``` ### Asset Fields These can point at brand-specific files or default shared files: - `icon_ico` - `icon_icns` - `dialog_bmp` - `banner_bmp` - `license_rtf` Optional toolbar icon overrides: - `toolbar_icon_home` - `toolbar_icon_reload` - `toolbar_icon_open` - `toolbar_icon_openwith` If a referenced asset path does not exist, the helper falls back to the default asset defined in `build/scripts/brand_config.py`. For toolbar icons, the runtime looks for the configured paths in packaged and development layouts. If an icon is missing: - Home falls back to a standard Qt home icon - Reload/Open/OpenWith keep their existing icon behavior ### Identity Rules Treat these values as long-lived product identity once a brand has shipped: - `brand_id` - `asset_prefix` - `exe_name` - `bundle_identifier` - `config_dir_name` - `msi_upgrade_code` Changing them later can break one or more of the following: - Windows upgrade behavior - macOS app identity - auto-update asset selection - local config/log/cache continuity - installer and artifact naming consistency If the product is already in use, only change these values deliberately and with migration planning. ## Edit an Existing Brand To edit a shipped or in-progress brand: 1. Update the brand manifest in `build/brands/.json`. 2. If needed, update brand-specific assets referenced by that manifest. 3. If runtime behavior should also change, update the relevant application config values. 4. Rebuild the affected platform artifacts. 5. Validate the result with a dry-run release before publishing. Safe edits after release usually include: - `display_name` - `shortcut_description` - artwork paths - license text - update channel, if release policy changes High-risk edits after release are the identity fields listed above. ## Runtime Branding Configuration Packaging branding alone is not enough if the app should also present a different name, use different local storage, or point to different update settings. Relevant runtime config keys include: - `brand_id` - `config_dir_name` - `app_name` - `update_base_url` - `update_repo` - `update_channel` - `update_manifest_name` Toolbar icon env overrides (useful for packaged branding): - `TOOLBAR_ICON_HOME` - `TOOLBAR_ICON_RELOAD` - `TOOLBAR_ICON_OPEN` - `TOOLBAR_ICON_OPENWITH` The current example in `config.example.json` shows the Agravity runtime setup. When adding a new brand, make sure the runtime config matches the packaging manifest at least for: - `brand_id` - `config_dir_name` - `app_name` ## Build the Default Product ### Windows Build the default executable only: ```powershell python .\build\scripts\build_windows.py ``` Build the default Windows MSI: ```powershell python .\build\scripts\build_windows.py --msi ``` Build with a specific `.env` file: ```powershell python .\build\scripts\build_windows.py --msi --env-file .\.env ``` ### macOS Build the default macOS app and DMG: ```bash bash build/scripts/build_macos.sh ``` Build with a specific `.env` file: ```bash bash build/scripts/build_macos.sh --env-file .env ``` ## Build a Brand ### Windows Build a branded executable only: ```powershell python .\build\scripts\build_windows.py --brand agravity ``` Build a branded MSI: ```powershell python .\build\scripts\build_windows.py --brand agravity --msi ``` ### macOS Build a branded macOS app and DMG: ```bash bash build/scripts/build_macos.sh --brand agravity ``` ## Build Output Locations Windows artifacts are written to: - `build/dist/windows/webdrop_bridge/` for the default product - `build/dist/windows//` for branded products macOS artifacts are written to: - `build/dist/macos/webdrop_bridge/` for the default product - `build/dist/macos//` for branded products Typical artifact names: - Windows MSI: `--win-x64.msi` - Windows checksum: `--win-x64.msi.sha256` - macOS DMG: `--macos-universal.dmg` - macOS checksum: `--macos-universal.dmg.sha256` ## Create a Release Releases are shared by version. The release scripts scan local build outputs on the current machine and upload every artifact they find for that platform. This means: - a Windows machine can upload all locally built MSIs for the current version - a macOS machine can later upload all locally built DMGs for the same version - both runs contribute to the same Forgejo release tag - `release-manifest.json` is merged so later runs do not wipe earlier platform entries ### Windows Release Dry run first: ```powershell .\build\scripts\create_release.ps1 -DryRun ``` Publish all locally built Windows variants for the current version: ```powershell .\build\scripts\create_release.ps1 ``` Publish only selected brands: ```powershell .\build\scripts\create_release.ps1 -Brands agravity ``` Publish only the default product: ```powershell .\build\scripts\create_release.ps1 -Brands webdrop_bridge ``` Publish a specific version: ```powershell .\build\scripts\create_release.ps1 -Version 0.8.4 ``` ### macOS Release Dry run first: ```bash bash build/scripts/create_release.sh --dry-run ``` Publish all locally built macOS variants for the current version: ```bash bash build/scripts/create_release.sh ``` Publish only selected brands: ```bash bash build/scripts/create_release.sh --brand agravity ``` Publish only the default product: ```bash bash build/scripts/create_release.sh --brand webdrop_bridge ``` Publish a specific version: ```bash bash build/scripts/create_release.sh --version 0.8.4 ``` ### Credentials Both release scripts use Forgejo credentials from environment variables when available: - `FORGEJO_USER` - `FORGEJO_PASS` If they are not set and you are not in dry-run mode, the script prompts for them. Both scripts also support clearing credentials from the current shell session: - Windows: `-ClearCredentials` - macOS: `--clear-credentials` ## Dry Run Behavior Dry-run mode is the preferred validation step before publishing. Dry-run mode: - discovers the local artifacts exactly like a real release run - prints the release tag and target release URL - prints the brands that were discovered locally - prints the artifact paths that would be uploaded - writes a local manifest preview to `build/dist/release-manifest.json` - does not prompt for credentials - does not perform network requests - does not delete or upload assets ## Release Manifest The release scripts generate and upload `release-manifest.json`. This file is used by the updater to select the correct installer and checksum for a given brand and platform. Current platform keys are: - `windows-x64` - `macos-universal` The manifest is built from local artifacts and merged with any existing manifest already attached to the release. ## First Manual Download (Before Auto-Update) After creating a release, a user can manually download the first installer directly from Forgejo. Once installed, auto-update handles later versions. Base repository URL: - `https://git.him-tools.de/HIM-public/webdrop-bridge` Release page pattern: - `https://git.him-tools.de/HIM-public/webdrop-bridge/releases/tag/v` Direct asset download pattern: - `https://git.him-tools.de/HIM-public/webdrop-bridge/releases/download/v/` Example asset names: - `WebDropBridge-0.8.4-win-x64.msi` - `WebDropBridge-0.8.4-macos-universal.dmg` - `AgravityBridge-0.8.4-win-x64.msi` - `AgravityBridge-0.8.4-macos-universal.dmg` ### wget Examples ```bash # Default Windows installer wget "https://git.him-tools.de/HIM-public/webdrop-bridge/releases/download/v0.8.4/WebDropBridge-0.8.4-win-x64.msi" # Agravity macOS installer wget "https://git.him-tools.de/HIM-public/webdrop-bridge/releases/download/v0.8.4/AgravityBridge-0.8.4-macos-universal.dmg" ``` ### curl Examples ```bash # Default macOS installer curl -L -o WebDropBridge-0.8.4-macos-universal.dmg \ "https://git.him-tools.de/HIM-public/webdrop-bridge/releases/download/v0.8.4/WebDropBridge-0.8.4-macos-universal.dmg" # Agravity Windows installer curl -L -o AgravityBridge-0.8.4-win-x64.msi \ "https://git.him-tools.de/HIM-public/webdrop-bridge/releases/download/v0.8.4/AgravityBridge-0.8.4-win-x64.msi" ``` ### PowerShell Example ```powershell Invoke-WebRequest ` -Uri "https://git.him-tools.de/HIM-public/webdrop-bridge/releases/download/v0.8.4/WebDropBridge-0.8.4-win-x64.msi" ` -OutFile "WebDropBridge-0.8.4-win-x64.msi" ``` You can inspect `release-manifest.json` on the release to see the exact file names for each brand and platform. ## Recommended Workflow for a New Brand 1. Create `build/brands/.json`. 2. Add or update brand-specific assets if needed. 3. Prepare matching runtime config values. 4. Build the brand on Windows and/or macOS. 5. Run the release script in dry-run mode. 6. Verify artifact names, discovered brands, and manifest contents. 7. Run the actual release script. 8. Validate update behavior against the shared release. ## Troubleshooting Notes ### Brand not discovered by release script Check that: - the build completed successfully - the artifact is under the expected platform folder - the artifact name matches the `asset_prefix` and current version - the version used by the release script matches the built artifact version ### Windows upgrade behavior is wrong Check that the brand has its own stable `msi_upgrade_code`. Reusing or changing it incorrectly will break expected MSI upgrade semantics. ### App uses the wrong local config folder Check that runtime config uses the intended `config_dir_name`, and that it matches the packaging brand you expect. ### Auto-update downloads the wrong installer Check that: - the release contains the correct installer files - `release-manifest.json` includes the correct brand and platform entry - runtime update settings point to the expected repo/channel/manifest ## Current Example Brand The first branded variant currently in the repository is: - `build/brands/agravity.json` Use it as the template for future branded variants.