-
Notifications
You must be signed in to change notification settings - Fork 6
Description
- Summary
- What is the relevance of this feature?
- Feature design description
- Technical design description
- What are the advantages of this feature?
- What are the disadvantages of this feature?
- Are there any alternatives to this feature?
- How will users learn this feature?
- Are there any open questions?
- Examples
- CMake changes for finding engines
- project.json and user/project.json "engine_finder_cmake" and "engine_path" changes
- O3DE CLI --user and upgrade option changes
Summary:
A versioning scheme is needed to determine code compatibility between engines, projects and gems. Currently, only the engine has a version scheme tied to 6 month releases which is not granular enough.
Version and dependency information will be added inside engine.json, project.json and gem.json and relevant tools will be updated to use this information. Version information will be incremented to indicate API or other relevant changes.
What is the relevance of this feature?
Versioning and dependency information will allow users and tools to make informed decisions regarding compatibility. Given the distributed nature of O3DE, an established version and dependency scheme is the only scalable way to allow de-centralized control over compatibility.
Feature design description:
The following changes will be made
-
Semantic version fields in the format
<major>.<minor>.<patch>(e.g. 1.21.9) will be added inengine.json,project.jsonandgem.json<major>is for API-breaking changes<minor>is for non-API-breaking changes that add new APIs or change them in a non-breaking way<patch>is for all other non-API-breaking changes, usually important fixes
-
Dependency fields containing lists of dependencies in the format
<name><version specifier>(e.g. o3de >= 1.19.1) will be added inproject.jsonandgem.jsonwhere version specifiers are compatible with PEP 440 so we can use existing Python versioning functionality. If a version specifier is omitted for a gem dependency, the project's engine version will be used to determine the latest compatible gem version.*IMPORTANT* Version specifiers indicate "known compatibility". This means, there isn't a way with the proposed versioning system to specify "known incompatibility". We use the version specifiers to recommend the most compatible gem, but we warn users when they attempt to use a version that is not listed as compatible. -
CMake will make #defines available with version information for compile-time compatibility control. e.g.
EDITOR_VERSION_MAJOR,EDITOR_VERSION_MINOR, etc. -
The o3de.py CLI and Project Manager and CMake will take into account version and dependency specifications to display version information, determine compatibility and when a project needs to be re-compiled. The UX changes for these tools are not part of this RFC.
Workflows:
- During O3DE engine development in the
developmentbranch, thegem_version,engine_api_versionsandengine_versionwill be updated as important changes are made.- When developers make a change to an API version in the engine or gem that ships with the engine, they will also update the
engine_version. For example, if they change the minor version of a gem and zero out the patch version, they should also increase the minor version of theengine_versionand zero out the patch version. - In the future, when a GitHub action exists to update the
engine_version, developers will no longer need to manually update that field.
- When developers make a change to an API version in the engine or gem that ships with the engine, they will also update the
- When a
stabilizationbranch is created in preparation for a release it should reflect version information that themainbranch will have whenstabilizationis merged tomain.- The
engine_versionminor version should be immediately incremented in development after creating thestabilizationbranch so there is less time that the two branches share the sameengine_versionvalue. - The
engine_display_versionin engine.json should be set to the appropriateYY.MM.XXrelease version prior to merging tomain, preferably the last change submitted to thestabilizationbranch before merging tomainto avoid accidentally merging this value back to development. - When merging from
stabilizationtodevelopmentbranches, developers should be careful not to bring theengine_display_versionorengine_versionfromstabilizationintodevelopment. - When merging changes from
developmenttostabilizationbranches, developers should be careful to only include appropriate version changes. For example, if the major gem version was bumped indevelopmentbut you're only merging over a patch fix for that gem into stabilization - do not bump the major gem version, just the patch.
- The
- The major and minor engine versions in the
stabilizationbranch should not change because only bug fixes should be merged to the branch which should never result in more than the patch version changing. - When
stabilizationis merged tomainit should have the correctengine_display_version.
Technical design description:
The versioning system will be backward compatible and optional. If there is no versioning or dependency information available the system will fallback to not enforcing compatibility, but will warn the user.
JSON file changes
engine.json is modified so we have version fields for release and development and a new engine_api_versions field is added so gems can depend on specific versions of APIs inside the core engine.
{
"engine_display_version":"22.05.1", // rename O3DEVersion field, set to 0.0.0 in development
"engine_version":"1.0.1", // use engine_version for all compatibility checks
"engine_api_versions": { // versions of general APIs provided by the core engine (not gems)
"editor":"3.1.4",
"framework":"2.0.0",
"launcher":"1.0.0",
"tools":"4.0.0"
},
...
}project.json will now include a project and engine version and fields for engine and gem dependencies. Also, a compatible_engines field is added as a simple way for project maintainers to indicate known good versions of the engine (and gems) their project is compatible with.
{
"project_version":"1.0.0", // not needed for dependencies, but useful for users and added for consistency
"engine_finder_cmake":"cmake/EngineFinder.cmake", // path to cmake script used to find the engine
"engine":"o3de", // engine_name this project was registered with
"engine_version":"10.1.4", // engine version this project was registered with
"compatible_engines": [ // if empty (default) or missing, the project is assumed compatible with every engine
"o3de>=1.0.0", // project is compatible with any o3de engine greater than or equal to version 1.0.0
"o3de-install==1.2.3" // project is ALSO compatible with the o3de-install engine version 1.2.3
],
"engine_api_dependencies": [ // declaration of dependency on engine api versions, defaults to empty
"framework~=2.0.0"
],
"gem_dependencies": [ // rename "gem_names" to "gem dependencies" and support optional version specifiers
"example~=2.3", // project depends on example gem version 2.3.x
"other==1.2.3", // project ALSO depends on other gem version 1.2.3
"lmbrcentral", // if no version specifier, use latest version compatible with project's engine
...
],
...
}project.json and user/project.json
- A new optional local-only file
<project>/user/project.jsoncan be used to overrideproject.jsonsettings locally. These properties can be set usingo3de edit-project-properties --user. See O3DE CLI --user option changes for details. - A new field
engine_finder_cmakewill be contain the relative path to the appropriate.cmakefile that will be used to find the engine for the project. Currently this file is hardcoded to becmake/EngineFinder.cmakebut we need the flexibility to easily update and revert this logic for future engines and projects. - A new field
engine_pathcan be used to specify the path to the engine. The path may be local or relative if inuser/project.jsonbut may only be relative in the sharedproject.json. This field is provided for users to explicitly set the path to the engine, which is especially useful if they have multiple copies of an engine with the same name and version.
gem.json will now include a version field and fields for engine and gem dependencies. It will also have a compatible_engines field as a simple way for gem maintainers to indicate known good versions of the engine their gem is compatible with.
{
"gem_version":"0.0.0", // default gem version is 0.0.0
"compatible_engines": [ // if empty (default) or missing, the gem is assumed compatible with every engine
"o3de>=0.0.0" , // gem is compatible with any version of an engine named o3de
"o3de-sdk>=2.0.1, <=3.1.0" // gem is ALSO compatible with o3de-sdk engine versions from 2.0.1 up to 3.1.0
],
"engine_api_dependencies": [ // optional declaration of dependency on engine api versions, default is empty
"framework~=2.0.0"
],
"gem_dependencies": [ // rename "dependencies" to "gem_dependencies" and add version specifiers
"AWSCore>=1.0.0" // NEW version specifiers added
],
...
}CLI tool changes
The o3de.py CLI tool will have the following updates:
- Whenever the user attempts to make a change that violates the dependency rules, the action will fail. A
--forceparam can be used to force the action. - Edit functionality for projects and gems will be updated to allow manipulation of the new fields
- Gem and project registration will take into account dependencies and their versions
- Enable/Disable gem functionality will take into account dependencies
- Newly enabled gems will appear in the
project.jsongem_dependenciesfield using a version specifier of- no version specifier
- if the gem has no version information or
- is a gem that is shipped with the engine or
- the user selects the option to always use the latest gem that is compatible with their project's engine
== <gem version>if the gem has version information and the user selects the option to use a specific gem version
- no version specifier
- When gems are downloaded, the appropriate version will be downloaded and put in versioned folders.
o3de.py CLI changes
- A
--useroption will be added toregister,edit-project-propertiesandenable-gem/disable-gemto use theuser/project.jsonand manipulate it. If--userCLI operations fail the command does not fall back to just use theproject.json. - An
upgradecommand will be added that will be used to perform project upgrades. Initially this command will compare the project's engine version and the current engine version and execute Python commands to upgrade project files, outputting the list of files changed, where backups were stored, and letting the user know that, if they're using source control, they should check these files in.
Project Manager changes
The Project Manager tool will have the following updates:
- Version information will be shown. For engines with display version information, display the "engine_display_version" data, otherwise display the "engine_version".
- Project and Gem workflows will be updated to take into account version information and surface issues to the user.
- users will be able to select the version of a gem they want to use with their project, but the Project Manager will attempt to determine and recommend the most compatible gem
- appropriate UX (likely a warning) will be displayed when a user attempts to enable a gem or compile with a gem that may be incompatible with their engine or other gems
- When gems are downloaded, the appropriate version will be downloaded and put in versioned folders.
CMake changes
The following changes will be made to the CMake build scripts:
-
CMake scripts will be updated to surface the version information from each
.jsonfile as#definesthat can be used by code in one of the following formats:ENGINE_VERSION_<MAJOR/MINOR/PATCH>
ENGINE_<engine API>_API_VERSION_<MAJOR/MINOR/PATCH>
<PROJECT/GEM>_<project name/gem name>_VERSION_<MAJOR/MINOR/PATCH>- Example 1: a gem named
examplewith version1.2.3would have the following defines made available:
GEM_EXAMPLE_VERSION_MAJOR 1 GEM_EXAMPLE_VERSION_MINOR 2 GEM_EXAMPLE_VERSION_PATCH 3
- Example 2: a core engine API named
frameworkwith version2.3.0would have the following defines:
ENGINE_FRAMEWORK_API_VERSION_MAJOR 2 ENGINE_FRAMEWORK_API_VERSION_MINOR 3 ENGINE_FRAMEWORK_API_VERSION_PATCH 0
- Example 1: a gem named
-
CMake scripts will be updated to take into account gem versions as well as gem names when determining correct sub-directories
- The
CMakeList.txtin projects will be updated to read theproject.jsonand then theuser/project.jsonfor the "engine_finder_cmake" entry and theninclude()that path. - The
EngineFinder.cmakefile will be updated to check project <-> engine compatibility.
Content updates
- Gems provided with the engine will be updated with default versions
1.0.0 - AutomatedTesting and other sample projects will be updated with default versions
1.0.0 - Gem and project templates will be updated with the new fields.
- Gem providers will be notified so they can update their projects and gems.
- Documentation will be updated to reflect the version changes.
What are the advantages of the feature?
- Provides more granular versioning beyond individual releases
- Deters (but does not prevent) users from accidentally enabling incompatible gems in their projects, or incompatible projects in their engines.
- Allows gem creators to specify ranges of engine versions or engine library versions that gems are compatible with
- Allows projects to be incrementally upgraded in development branches instead of per engine release version
What are the disadvantages of the feature?
- Maintaining version numbers is now a developer burden. Developers must understand when to update engine and gem versions and dependency information.
- Old engines have the O3DEVersion field in engine.json that may cause confusion while those engines are in use.
How will this be implemented or integrated into the O3DE environment?
This does not require any new libraries. It will expand on both C++ source code and o3de python CLI code.
Are there any alternatives to this feature?
Two other similar approaches were considered but not selected due to their reliance on git and not all customers will use git as source control.
Storing the version information in .h (header) files does not satisfy the requirement of being able to determine version information when the source isn't available.
-
GitHub Tags
Utilize the git tag system to mark commits that increment version.Pros:
- Does not require editing a file
Cons:
- Requires access to git api from scripts or a minimal clone of the repo with the tags
- Per repo, so the tags must be configured when merging from a fork and will be different
- May require some form of approval to create new tags for a version
- This versioning only works for customers using git for source control
-
Version Per Commit
Each commit is considered a separate incremental version.Pros:
- Automatic versioning
- Does not require editing a file
Cons:
- Requires access to git API from scripts checking this
- Commits can be squashed or merged from other branches changing hashes so they are not stable until in development
- This versioning only works for customers using git for source control
- Customers will have to use a version specifier to depend on a commit hash which isn't numerical for readability or for discovering where the engine is at in development.
For example, a customer would need to depend oncommit >=<sha1 hash>buto3de>=23e38520e9fcould be after commit hasho3de>=a086bcbe0
How will users learn this feature?
- The version of the engine along with the current version of projects as well as the supported versions for a gem will all be displayed within the Project Manager for users to see.
- Upgrading projects will be added as a feature utilizing this system and automatically detecting potential upgrades and presenting them to the user.
- Engine, project and gem version fields will be visible in the Project Manager and in the o3de CLI.
- Documentation will be updated for developers to know more about how to use the versioning system.
Are there any open questions?
- What are the best defaults to use for project and gem versions, would something be better than
1.0.0? - What are the best version specifiers to use for
gem_dependencieswhen enabling a gem in a project? - What is the best way to update the
engine_version? - What are the best API groupings to use for the
engine_api_versionslist - are there better ones than those proposed?
Examples
Project using latest version of gems for an engine
When you intend to use the latest versions of gems that are compatible with whatever engine your project uses, you would leave the version specifier portion of the gem_depencencies blank and provide an engine_name and engine_version. This will likely be common for teams that use the pre-built SDK.
The following example project will attempt to use the latest version of PopcornFX and KytheraAI gems that are compatible with the o3de-sdk engine with version 1.2.3, and because the LmbrCentral gem is provided with the engine, no version specifier is necessary.
project.json
{
"project_name":"Example",
"engine_name":"o3de-sdk",
"engine_version":"1.2.3",
"gem_dependencies": [
"LmbrCentral",
"PopcornFX",
"KytheraAI",
],
}Project requiring specific gem versions
Game studios with engineers dedicated to engine integrations may prefer to download all the necessary gems for a project and check them into source control and specify the exact version to use to discourage non-engineers from using other versions that may not be approved.
In this example, the project specifies a custom internal engine and version, and the exact versions of the PopcornFX and KytheraAI gems to use. The LmbrCentral still does not need a version specifier because it is always provided with the engine, but the team could provide a version specifier if desired for consistency.
project.json
{
"project_name":"Example",
"engine_name":"o3de-internal",
"engine_version":"1.0.1",
"gem_dependencies": [
"LmbrCentral",
"PopcornFX==1.2.3",
"KytheraAI==2.3.4",
],
}Gem compatible with engine release versions
When you intend to provide a gem that only needs to be compatible with released engine versions you can specify those exact versions in the compatible_engines field. You will not be able to use a range because that would include development engine versions.
The following example declares this gem is compatible with engines version 1.2.3 and 2.3.4
Gems\Example\1.2.3\gem.json
{
"gem_name":"Example",
"compatible_engines": [
"o3de-sdk == 1.2.3",
"o3de-sdk == 2.3.4",
"o3de == 1.2.3",
"o3de == 2.3.4"
],
}Gem depending on specific APIs
When you intend to provide a gem that should be compatible with any future engine so long as a core API doesn't change you can use the engine_api_dependencies and gem_dependencies fields .
The following example shows a gem that should be compatible with all versions of the engine containing the framework API major version 2
Gems\Example\1.2.3\gem.json
{
"gem_name":"Example",
"engine_api_dependencies": [
"framework ~= 2.0.0"
],
}Metadata
Metadata
Assignees
Labels
Type
Projects
Status