Codeticket Service
The primary purpose of the codeticket service is to assign monotonically increasing integers mapping to changeset ids.
The service supports attaching arbitrary metadata to every ticket delivered. Through careful use of relations between metadata items, it is possible to track:
- Changes contributing to a build
- Dependencies between builds
- Deltas between builds
- Changes being merged into new repositories
- Jira references used in commit comments
- ... and a variety of other uses.
The shortest way to describe the codeticket service is as an "append only data store, where arbitrary metadata can be attached to primary data elements, including references to other primary data elements".
Data Elements
A typical software development project will use multiple repositories reflecting QA status and intended stability criteria. Most common is a model like this:
Builds
Depending on the configuration of your continuous build system, some changesets will trigger builds. The codeticket service assigns these builds integers.
Note that multiple builds may get the same build number if they are triggered by the same changeset. As changesets propagate to different repositories via the mercurial hg pull
or hg push
command, they may end up at the tip multiple times, thereby re-triggering a build from a different repository, but for the same content.
Another deliberate way to get multiple builds using the same changeset is platform builds. The Second Life Viewer, for example, is compiled on three different platforms, and all those builds will get the same build number.
Even though some builds will directly map changesets to build numbers, most builds now compute a hash that includes the changeset and all the build dependencies, so if any of those change, a new build number will be generated.
Context Changesets
Not all changesets will trigger builds. Those changesets which do not match up to a build are called context changesets within the codeticket service.
At every build, the Automated Build System is designed to traverse the revision graph, and to associate every context changeset which is not already associated to the build in progress.
The build is said to "include these changes".
Once the Automated Build System encounters a changeset that already is associated with a build, then that build will be associated with the current build.
The build is said to "include that build".
Traversal of the arc containing the changeset stops at that point, as the associated build will already have all the subsequent associations.
This is just one way the "build is included in build" relationship is used. The other way is to include your dependencies. Observe that the subsequent algorithms work exactly the same way and don't care whether an included build is from the same repository or from a different repository.
Note: there is a red arrow missing between build 202102 and 202104
Querying Codeticket
The codeticket service has a web UI which allows users to navigate the relationships created by the Automated Build System.
Note: the webUI is not publicly accessible.
To simplify the explanations, we will omit context changesets from the diagram, and use a real example from the viewer builds done by the Snowstorm Team:
Note that it isn't a perfect minimal graph, since builds happen concurrently, and the information at the time of the build will practically never include the whole revision graph.
The web UI allows easy drilldown through the inclusion chains:
- A build will display all builds directly included by that build;
- A build will also display all context changesets directly included in that build;
- A context changeset will allow a drilldown into all builds including that context changeset, either directly or indirectly.
Various entry points for traversal exist:
- Builds by repository owner
- Builds by repository name
- Builds by tag
- ...
Guided Tour of the Web UI
Computing the Delta between Two Builds
Computing the delta between two builds is accomplished by first traversing all the ancestors of the "old" build and marking them as "included in old build":
Then traversal resumes at the "new" build. Any unmarked build will be marked as "included by new build". If a marked build is encountered, or if maximum traversal depth is reached, traversal stops:
To avoid overwhelming the user with data, a check is made to see if a build tagged as "included in old build" has been reached at least once. If not, the diff is not shown, as it is unlikely that the two builds are related.
Computing Builds Not In a Given Build
This starts the same way as the delta computation, except that we also register the repositories used when marking the "included in old build" nodes.
Traversal then resumes from the most recent build in every repository traversed so far: