Skip to content

About

Unity Editor package for managing platform-specific package manifests, build profiles, scripting defines, and custom build pipelines.

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Manifestor

Manifestor is a Unity Editor package for defining project package manifests as reusable ScriptableObject assets. A manifest profile combines one or more package lists with a Unity Build Profile, allowing package dependencies, scoped registries, testable packages, and scripting define symbols to change together for a target build.

Manifestor also provides a custom build pipeline and a migration window for keeping package-list assets synchronized with manual changes to Packages/manifest.json.

Build entry points

  • Manifestor Build / Unity Editor: ManifestorUnityEditorPipeline powers the Manifestor Build window and queued Editor API.
  • Terminal: ManifestorHeadlessBuild.BuildFromCommandLine runs the same Standard plan in batch mode.
  • Unity Build Automation: ManifestorUnityBuildAutomation.Apply, .PreBuild, and .PostBuild run the UBA-enabled phases around UBA's player build.

Note

Manifestor 0.2.0 is an early public release. Its public API may evolve before 1.0.0.

Requirements

  • Unity 6000.4 or newer
  • Git installed and available to the Unity Package Manager when installing from a Git URL

Manifestor is Editor-only and does not add runtime components to a player build.

Installation

The preferred installation is to embed Manifestor directly in the Unity project:

  1. Clone or download this repository.
  2. Copy SharedPackages/com.mirovsky.manifestor into the target project's Packages folder.

The resulting path should be Packages/com.mirovsky.manifestor. Unity discovers embedded packages in this folder automatically, so Manifestor remains available without a dependency entry in Packages/manifest.json.

Alternatively, install the package from its Git URL through the Unity Package Manager:

  1. Open Window > Package Management > Package Manager.

  2. Select the + menu and choose Install package from git URL....

  3. Enter:

    https://github.com/Mirovsky/manifestor.git?path=/SharedPackages/com.mirovsky.manifestor#v0.2.0
    
  4. Select Install.

To pin a release or commit, append a Git revision after the package path, using #<tag-or-commit>.

Usage

1. Create package lists

Create one or more assets with Assets > Create > Manifestor > Packages List. Package lists can be shared by several profiles and contain:

  • Packages: package identifiers and their manifest values, such as com.unity.inputsystem and 1.14.2.
  • Defines: scripting define symbols for the profile's build target.
  • Scoped Registries: registry names, URLs, and scopes.
  • Testables: package identifiers to add to the manifest's testables array.

A package identifier may only be declared once across the lists assigned to the same profile. Registries and entries must have non-empty values, and each scoped registry must contain at least one scope.

2. Create a manifest profile

Open Tools > Manifestor > Manifestor Build and select New Manifest, or create an asset with Assets > Create > Manifestor > Platform Profile. Configure:

  • Profile Name: the display name used to identify the profile.
  • Build Profile: a saved Unity Build Profile for the target platform.
  • Package Lists: the package-list assets that make up this manifest.

The Manifestor Build window discovers saved manifest profiles automatically. Use Refresh if assets were changed outside the window.

3. Apply a profile

Select a profile and choose Apply Manifest. Manifestor will:

  1. Set the profile's Unity Build Profile as active.
  2. Generate Packages/manifest.json from its package lists.
  3. Replace the target's scripting define symbols with the combined defines from those lists.
  4. Ask the Unity Package Manager to resolve the new manifest.

The last successfully applied profile is restored when the editor starts if its configuration has changed. If applying fails, Manifestor attempts to restore the previous manifest, active Build Profile, and define symbols.

Important

Applying a profile replaces the manifest dependency, scoped registry, testables, and Manifestor-managed settings with the selected profile's data. Commit or otherwise back up Packages/manifest.json before first use.

4. Build

In Tools > Manifestor > Manifestor Build, select a profile and choose:

  • Build to apply the manifest and build the player.
  • Clean Build from the Build dropdown to request a clean Unity build cache.

Choose an output folder when prompted. Manifestor supplies the exact player output path through Unity's BuildPlayerOptions.locationPathName, using PlayerSettings.productName and the platform extension where applicable.

Build progress and failures are reported in the Unity Console. Only one Manifestor build or apply operation can run at a time.

Manifest migration

When installed packages change outside Manifestor, the package watches for differences between Packages/manifest.json and the package-list assets referenced by the currently applied manifest profile. If actionable differences are found, the Manifest Migration window opens automatically. You can also open it from Tools > Manifestor > Manifest Migration.

The window shows packages that were added, removed, or changed in the manifest. Select the package-list assets that should receive each change, create and attach another package list to the applied profile if necessary, and choose Apply. Migration updates package-list assets; it does not apply a manifest profile.

Extending Manifestor

Manifestor's assembly is Editor-only and has Auto Referenced disabled. Put extensions in an Editor assembly definition and add an explicit assembly reference to com.mirovsky.manifestor.

Custom manifest profile

Subclass ManifestProfileSO to add project-specific serialized settings. Mark exactly one concrete, non-generic subclass with [CustomManifestProfile]; the Manifestor Build window will then create that type instead of the base profile.

using System.Collections.Generic;
using System.Linq;
using Manifestor;
using UnityEngine;

[CustomManifestProfile]
public sealed class GameManifestProfile : ManifestProfileSO
{
    [SerializeField] private string _distributionChannel;

    public string distributionChannel => _distributionChannel;

    public override IReadOnlyList<string> GetScriptingDefines()
    {
        return base.GetScriptingDefines()
            .Append("CUSTOM_DISTRIBUTION")
            .ToArray();
    }
}

If no custom type is marked, Manifestor creates ManifestProfileSO. If more than one type is marked, profile creation is rejected with an error. Override GetScriptingDefines to extend the package-list defines by calling the base implementation, or omit the base call to replace them entirely. Overrides must return a non-null, normalized list.

Custom build steps

Implement IManifestorBuildStep and mark the class with [ManifestorBuildStep]. Every step belongs to one of three categories:

  • Apply updates the selected manifest and Unity Build Profile.
  • PreBuild validates or prepares content before a player build.
  • PostBuild consumes, packages, or publishes the completed player build.

Steps must be concrete, non-generic classes with a public parameterless constructor.

Steps run in both Standard and UBA pipelines by default. Pass ManifestorBuildStepTargets.Standard or ManifestorBuildStepTargets.UnityBuildAutomation as the attribute's second argument to restrict participation.

using Manifestor.Build;

[ManifestorBuildStep(ManifestorBuildStepCategory.PreBuild)]
public sealed class ValidateContentStep : IManifestorBuildStep
{
    public ManifestorBuildStepResult Tick(ManifestorBuildContext context)
    {
        if (context.profile == null)
        {
            return ManifestorBuildStepResult.Failed("A manifest profile is required.");
        }

        // Validate or prepare project content here.
        return ManifestorBuildStepResult.Succeeded();
    }
}

Use one or more [ManifestorBuildStepOrder] attributes to order a step Before or After another step type. Constraints are combined across all discovered steps; dependency cycles and constraints that contradict category order cause the pipeline to reject the operation. Without a constraint, steps within a category are ordered deterministically by their assembly-qualified type names.

Category order is always Apply, PreBuild, then PostBuild. Full builds execute the Unity player build between PreBuild and PostBuild:

  • Apply runs Apply steps only.
  • Build runs every category and the player build.
  • Unity Build Automation runs UBA-enabled Apply, PreBuild, and PostBuild steps around its externally owned player build.

The built-in Apply step applies and resolves the selected profile. After custom PreBuild steps, a fixed shared preparation action finalizes the target, options, and scenes. Player building is a fixed core action rather than a discoverable step.

ManifestorBuildContext provides the selected profile and a mutable Unity BuildPlayerOptions value. A step can replace context.buildPlayerOptions to configure scenes, output location, target, subtarget, build flags, asset-bundle manifest, or extra scripting defines for later steps. Changes are retained when a step succeeds or waits. The core player builder fills unset target, target group, subtarget, scenes, and location from the active build profile and Unity's saved build settings.

Because BuildPlayerOptions is a struct, copy it, modify the copy, and assign it back:

var buildPlayerOptions = context.buildPlayerOptions;
buildPlayerOptions.options |= BuildOptions.Development;
context.buildPlayerOptions = buildPlayerOptions;

Steps can also exchange string values through build-scoped user data. Values survive package resolution and editor reloads while the pipeline is active, and are cleared when it succeeds, fails, or is cancelled. Use step ordering to place the writer before the player build and the reader after it:

private const string PreviousSettingKey = "example.previous-setting";

// In a PreBuild step:
context.SetUserData(PreviousSettingKey, ReadCurrentSetting());

// In a PostBuild step:
if (context.TryGetUserData(PreviousSettingKey, out var previousSetting))
{
    RestoreSetting(previousSetting);
    context.RemoveUserData(PreviousSettingKey);
}

Keys are shared across all steps in the current Apply or Build operation. Setting an existing key overwrites it, and a null value is stored as an empty string. Later steps do not run when an earlier step fails or is cancelled, so this ordering mechanism is intended for successful build paths rather than guaranteed cleanup.

Return one of:

  • ManifestorBuildStepResult.Succeeded() to continue.
  • ManifestorBuildStepResult.Failed(message) to stop with an error.
  • ManifestorBuildStepResult.Cancelled(message) to stop as cancelled.
  • ManifestorBuildStepResult.Waiting(message) to retry the same step after the editor becomes available again.

Starting the pipeline from code

You can start an apply or full local build from Editor code:

using Manifestor;
using Manifestor.Build;
using UnityEditor;

ManifestorResult applyResult = ManifestorUnityEditorPipeline.Apply(profile);
ManifestorResult buildResult = ManifestorUnityEditorPipeline.Build(
    profile,
    outputFolder,
    BuildOptions.CleanBuildCache);

if (!buildResult.success)
{
    UnityEngine.Debug.LogError(buildResult.message);
}

Starting the pipeline queues the work; a successful ManifestorResult means the operation started, not that every step has finished. Subscribe to ManifestorUnityEditorPipeline.completed to observe its final status.

Headless builds

Run the same Standard pipeline from a terminal with ManifestorHeadlessBuild.BuildFromCommandLine. Do not pass Unity's -quit option; Manifestor exits after the resumable build completes.

Unity \
    -batchmode \
    -nographics \
    -projectPath "$PROJECT_DIRECTORY" \
    -executeMethod Manifestor.Build.ManifestorHeadlessBuild.BuildFromCommandLine \
    -manifestorProfile Assets/Path/To/ManifestProfile.asset \
    -manifestorOutput Builds/Player \
    -manifestorBuildOptions CleanBuildCache \
    -logFile -

Exit code 0 means success, 1 means invalid input or failure, and 2 means cancellation.

Addressables

Manifestor does not build Addressables directly. Standard Editor and headless builds call Unity's BuildPipeline.BuildPlayer, so projects that use Addressables should set Build Addressables on Player Build to Build Addressables content on Player Build in the project-level Addressable Asset Settings. Do not leave this on the machine-local Preferences value for automated builds. Unity then runs the active Addressables player data builder as part of the fixed player-build action and fails the player build if the content build fails.

Keep project-specific preparation in a UBA-enabled PreBuild step rather than calling AddressableAssetSettings.BuildPlayerContent from the step. This lets the same preparation run before the native Addressables stage in both Standard and UBA builds without building content twice.

Unity Build Automation

Unity Build Automation's pre-export method runs after Unity has compiled scripts. Changing Packages/manifest.json there is too late for the current build, so Manifestor uses two Unity processes:

  1. A UBA pre-build shell script launches Unity in batch mode and calls ManifestorUnityBuildAutomation.Apply.
  2. Apply runs all UBA-enabled Apply steps through the resumable shared pipeline and records a receipt under Library/Manifestor.
  3. UBA starts its normal Unity process, which resolves and compiles against the selected profile.
  4. UBA calls project forwarding methods that invoke ManifestorUnityBuildAutomation.PreBuild from Pre-Export and PostBuild from Post-Export.
  5. Pre-Export runs the shared player-build preparation and temporarily publishes its finalized scene list to Unity Editor Build Settings for UBA. Post-Export restores the preceding scene settings.

Commit a pre-build script such as BuildAutomation/manifestor-pre-build.sh with Unix line endings:

#!/usr/bin/env bash
set -euo pipefail

: "${UNITY_EXE:?UNITY_EXE is required}"
: "${PROJECT_DIRECTORY:?PROJECT_DIRECTORY is required}"
: "${MANIFESTOR_PROFILE_PATH:?MANIFESTOR_PROFILE_PATH is required}"

unity_exe="$UNITY_EXE"
project_directory="$PROJECT_DIRECTORY"
if [[ "${BUILDER_OS:-}" == "WINDOWS" ]]; then
    unity_exe="$(cygpath -wa "$UNITY_EXE")"
    project_directory="$(cygpath -wa "$PROJECT_DIRECTORY")"
fi

"$unity_exe" \
    -batchmode \
    -nographics \
    -projectPath "$project_directory" \
    -executeMethod Manifestor.Build.ManifestorUnityBuildAutomation.Apply \
    -logFile -

Because Manifestor's assembly has Auto Referenced disabled, put the forwarding hook in an Editor assembly that explicitly references the package. For example, create Assets/Editor/Project.ManifestorUnityBuildAutomation.asmdef:

{
  "name": "Project.ManifestorUnityBuildAutomation",
  "references": ["com.mirovsky.manifestor"],
  "includePlatforms": ["Editor"]
}

Add Assets/Editor/ManifestorUnityBuildAutomationHook.cs:

namespace ProjectBuildAutomation
{
    using Manifestor.Build;

    public static class ManifestorUnityBuildAutomationHook
    {
        public static void PreExport()
        {
            ManifestorUnityBuildAutomation.PreBuild();
        }

        public static void PostExport(string exportPath)
        {
            ManifestorUnityBuildAutomation.PostBuild(exportPath);
        }
    }
}

Configure the UBA target's advanced settings as follows:

  • Environment variable: MANIFESTOR_PROFILE_PATH=Assets/Path/To/ManifestProfile.asset.
  • Pre-Build Script: the repository-relative path to manifestor-pre-build.sh.
  • Pre-Export Method: ProjectBuildAutomation.ManifestorUnityBuildAutomationHook.PreExport.
  • Post-Export Method: ProjectBuildAutomation.ManifestorUnityBuildAutomationHook.PostExport.
  • Addressables: select Yes, build Addressables. For full player builds, leave content-update and content-only options disabled.

The selected path must be a committed .asset under Assets, and its Unity Build Profile target must match the UBA target. Manifestor must be present in the checkout's initial Packages/manifest.json and remain in the generated profile manifest unless it is embedded under Packages/com.mirovsky.manifestor.

Steps default to both Standard and UBA execution. Pass ManifestorBuildStepTargets.Standard to [ManifestorBuildStep] to exclude a step from UBA. Waiting is resumable during Apply, but returning it from synchronous PreBuild or PostBuild hooks fails the UBA build. A PreBuild step can set context.buildPlayerOptions.scenes; when it leaves scenes null, Manifestor uses the enabled Editor Build Settings scenes. Configure UBA to use project build-settings scenes so it does not override Manifestor's finalized list after Pre-Export.

UBA owns its Addressables build and runs it after Manifestor's Pre-Export/PreBuild work and before the Post-Export/PostBuild hook. Do not invoke CleanPlayerContent or BuildPlayerContent from UBA-enabled Manifestor steps. UBA publishes the generated Addressables content under $OUTPUT_DIRECTORY/extra_data/addrs; content-update, content-only, CCD upload, and publishing workflows require separate UBA configuration.

Development and support

The distributable package lives in SharedPackages/com.mirovsky.manifestor; the surrounding Unity project is its development and test host. See CONTRIBUTING.md for setup and contribution guidance. Report vulnerabilities using SECURITY.md, not a public issue.

Release history is recorded in CHANGELOG.md. Manifestor is licensed under the MIT License.

About

Unity Editor package for managing platform-specific package manifests, build profiles, scripting defines, and custom build pipelines.

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages