Developing with the Engine and Adapters: Branches, Releases, Versions, and Conventions

As the project expands, the need for coordinated effort between apps, service, and the engine/adapter teams becomes more critical. This document aims to answer the following questions:

  • How do apps determine which branch and changeset to use during the development process?
  • How are engine/adapter bug fixes and patches delivered to the app and service teams?
  • How are engine versions determined, what do they mean, and how do I deliver a version of the engine to service for release?
  • What do various branches of the engine mean?

Engine releases, branches, and versions

Branches and versions

In general, current development for the next major or minor release occurs in the default branch. This release contains the version information for the planned release in the form of <major>.<minor>.0 (e.g. 2.1.0).

When a major or minor release occurs, the changeset of the release is tagged with Release_<major>.<minor>.<patch>, and the repository is then branched for that release in a branch called Release_<major>.<minor>.1

This release branch is then patched with bug fixes when service needs them (which must then be released to the app/service by the engine team). These are released in the following steps:

  1. The engine team ensures the version preprocessor macros are correct for the next patch release
  2. The engine team tags the appropriate changeset as above with Release_<major>.<minor>.<patch>.
  3. The app is then free to forward it to the service team for testing and distribution.

No version of the engine from the default branch may be sent to service for release with a product unless released as, at the very least, a release candidate by the engine team. Also, no unreleased patch version of a release branch should be distributed to service without a patch release. (Please see the next section for more details.)

The release process

Major and minor versions are planned in advance by the engine team and the architect. In general, these are released for testing to the app devs as release candidates when they are feature complete and nearing release (these will be tagged as Release_<major>.<minor>-RC<release_candidate_number>). They are released as release versions at latest when an app is about to released with that RC. The engine team needs to be notified when this is about to happen; any app using a prior RC will need to release with the actual release version or a later patch version from that point.

Unless asked to by engine dev, apps should generally not do development against default without having an engine-RC. Any app or adapter doing development against raw versions of the default branch in general should not plan to be able to simply pin a changeset that works and release at any time with that changeset. (Again, this is discouraged unless necessary.)

If you’ve been working against such a changeset (or an unreleased default tip), you will need to ask the engine for a release candidate, and work with that candidate. The engine should drive the releases, not the apps.

What we aim to prevent is the inability to keep track of releases programmatically, and for other parties to be able to use the versioning macro symbols in their code (both for debugging - it will be useful in service logs! - and for preprocessor defines when needed). If three apps release with three different versions of the engine, as has happened in the past, and the engine devs are unaware of what’s been put out there, we have no idea what we are working with and cannot ensure the patch version macros are correct without branching if further development has occurred.

We also might end up with patches out-of-order if different, non-a-priori-tagged changesets are used at release at different times.

To that end, engine releases, from now on, will be engine-driven. That is, if you even think you might be developing with an engine version from default that may go out with a product, even an alpha or beta version, you request a release candidate.

Best practice is to work with an existing tagged RC or patchset from the last release unless you’ve got a reason to ask for a new one or Volker has shiny new functionality he wants you to try (in which case, it’s RC time!).

If there’s no RC yet and you’re on default, ask for one.

Patch versions will be created, upgraded and tagged as new patch releases as bugs and minor functionality are added or backported to a release branch. The engine team is responsible for doing this regularly (when in doubt, upgrade and tag), preferably when anything is fixed or added with the intent to go out to service/the public.

In general, we’re not going to run out of RC or patch numbers.

The former are internal, and don’t even really mean we’re planning to release it to the public - it means that there is a danger they might be. The latter will just continuously upgrade for as long as a release is supported. We would much prefer to upgrade the number right away so that we don’t have to branch and fix preprocessor macros for correct versioning all the time, so please ask for releases/RCs early and often.

Again, to be clear, neither apps nor service should just be grabbing a changeset of their choice from the repo, especially if they are near release or testing.

Ask for a release.

Versioning conventions - major, minor, and patch

Our releases are numbered according to the convention <major>.<minor>.<patch> - the following explains how we determine where a release falls in this scheme.

Major release

In EngineWorld (and by extention, AdapterWorld), major releases occur when incompatibilities occur between source versions (for example, API-breaking changes, introduction of major new protocols, significant functionality changes, etc).

For example, the release of sync functionality and key reset moves us from the 1.x.x release family to 2.0.x releases.

Minor release

The definition of minor release is a bit fuzzier in our process. We use it for non-API-breaking changes which are more substantial than a patch release, but still do not include API-breaking changes or undermine compatibility between other versions in this major release family.

Patch release

Patch releases are just what they sound like - bug fixes (or bug backports for previous minor and major releases, when necessary), maintenance changes that should have gone out with the last minor or major release, etc.

This is reserved for smaller changes that need to go out to update a major or minor release.

Adapter Release Versions

Adapters MUST use the same major/minor versions as the engine releases; however, they may be/remain older in the case of minor changes.

In general, there should be an adapter release when there is an engine release (unless the adapter version is to remain the same as the previous engine release); this, as mentioned above, may not apply when the changes to the engine were minor and don’t really impact the adapter.

Adapter versions should be pinned to the first engine version they release with.

Branches: which branch means what?

As mentioned above, current development for the next minor or major release occurs in default. Already released branches, including their patches, are in release branch Release_<major>.<minor> (except 2.0, which is still called sync).

If there is a major feature being developed which is not yet ready for prime time, it should be kept in some sort of descriptively-named feature branch. Care should be taken that this branch does not end up going so far from mainline development that it effectively becomes the default branch. Should this happen, a release branch should be branched for current default and the feature branch should be moved back into default. Engine devs, please try to avoid this.

Other branches exist; some are just temporary development or experiment branches, and some are bug branches (often, but not always, labelled with the JIRA ticket number). These should not be used by apps or service unless an engine dev has asked you to test with one2.

The briefly active postrelease branch is dead for now. We might revive it if we have two parallel tracks going for a feature after release and an upcoming release, but in this case, it would make more sense to branch off current release development and keep working on postrelease functionality as default. We can decide this when we hit this situatioon again, however.

  1. An exception to this is the 2.0.0 release, which is a branch called sync for historical reasons.↩︎

  2. And just an unrelated point of common courtesy - I know we’re all open here, but if someone has opened a branch they’re working on but hasn’t been talking about it, don’t pop in and comment on their code, or have expectations of the branch because of the name. It may never come to anything, and until it is either announced or merged in, it’s really not intended for you. Be happy they’re committing so they don’t lose what they’re working on, but we all deserve to get to the point we’re ready to share without comments from the peanut gallery. This is just a point of common courtesy.↩︎