onestop

OneStop is a data discovery system being built by CIRES researchers on a grant from the NOAA National Centers for Environmental Information. We welcome contributions from the community!

This project is maintained by cedardevs

Developer Documentation Home

Estimated Reading Time: 20 minutes

Publishing Tags and Releases

Table of Contents

Basics

The goals of our tag publishing conventions are to be seamless and consistent. In general, a developer or deployer should only need to do one of the following things to publish the right tag:

NOTE: Running locally, with or without the release flag, the DOCKER_USER and DOCKER_PASSWORD environment variables will need to be set just as they are in the CI environment to publish to Docker Hub.

Circle CI Configuration

For Circle CI to triggers builds from tags, it cannot be defined at the workflow level:

CircleCI does not run workflows for tags unless you explicitly specify tag filters. Additionally, if a job requires any other jobs (directly or indirectly), you must specify tag filters for those jobs.

The branches filter is not used because we want all branches to trigger a Circle CI Build, and we rely on gradle to set the version/tag appropriately based on environment.

The job tags filter is defined for every job, in accordance with the CircleCI reference above. For simplicity, any tag is allowed to trigger a build, but the publishing logic will prevent tags containing non-semantic versions from getting published as such.

jobFilters: &jobFilters
  filters:
    tags:
      only: /.*/

workflows:
  version: 2
  build:
    jobs:
      - checkout:
          <<: *jobFilters
      - client:
          requires:
            - checkout
          <<: *jobFilters
      - registry:
          requires:
            - checkout
          <<: *jobFilters
      ...

Continuous Integration Automation

Many CI environments, including Circle CI set an environment variable CI to facilitate detecting the environment of the build. In the case that we have detected CI=true:

Cleanup Container Registry

Cleanup of the container registry (Docker Hub) is automated without being destructive or confusing about what a published tag represents.

The container registry API for DockerHub can be used to delete tags with the token obtained from the credentials. The continuous integration environment should attempt to clean up the registry before publishing on every run.

Release Tags (retain always)

These tags are identified through regex pattern matching and without the -SNAPSHOT suffix:

"3.0.0"     [RETAINED] (semantic version and not snapshot)
"2.4.2"     [RETAINED] (semantic version and not snapshot)
"2.4.2-RC1" [RETAINED] (semantic version and not snapshot)

Branch Tags

Active Branch Tags (retain)

The prefix before -SNAPSHOT can be intuited as the branch name which produced the last published snapshot for this tag:

"master-SNAPSHOT"       [RETAINED] ("master" branch should always exist on remote origin)
"123-featureA-SNAPSHOT" [RETAINED] ("123-featureA" exists as branch on remote origin)

Inactive Branch Tags (purge)

Purge any tags associated with a branch name that does not exist in the remote origin (e.g. - [“master”, “123-featureA”])

"456-featureB-SNAPSHOT" [PURGED] ("456-featureB" does NOT exist as branch on remote origin and not prefixed w/"LOCAL-")

Local Tags (retain)

"LOCAL-${branch}-${whoAmI}" [RETAINED] (prefixed w/"LOCAL-")

Dangling Tags (purge)

Purge all tags remaining that do NOT meet the following criteria:

Local Automation

When the user is running the jib Gradle task from their development machine, the rules for publishing change so that custom published images can be distinguished and preserved in the CI cleanup process.

The rules to publish in a CI environment afford a certain amount of built-in safety to prevent overriding critical tagged releases. The only way for a local jib task to overwrite a published release would require the following conditions to be met:

If the above conditions are NOT all met, then we assume we are in a “local” environment and build docker images and publish accordingly:

The local user may not have a need for or regularly publish manually, so they may not have the DOCKER_USER and DOCKER_PASSWORD environment variables set at all times. These credentials are required by the Docker Hub container registry API to delete images. Because of this, non-CI environments, should never attempt to clean up old/obsolete images automatically.

Gradle Task Considerations

Utilizing the publishing build logic is a matter of calling the dynamicVersion function on the root gradle project and assigning its return value to the root level project version.

The first parameter is the user, organization, or vendor (terminology depends on the container registry being used). The second parameter prepares the appropriate checks depending on which CI environment the build runs in. The last parameter is the container registry published to and cleaned from.

The dynamicVersion call, alone, will set some defaults for publishing, but will miss some sub-project specific details that you will want to set on a per-project basis.

Below is an example of what you probably want to set at the subproject level. Any of the Publish object properties can be overwritten, but it is not recommended to set more than what’s shown below, unless you are a power user and want specific subprojects to publish to different repositories, have different naming conventions, etc.

version = rootProject.dynamicVersion("cedardevs", CI.CIRCLE, Registry.DOCKER_HUB)

subprojects {
        project.setPublish(Publish(
                description = description,
                documentation = docs,
                authors = formatAuthors(authors),
                url = url,
                licenses = License.GPL20,
                cleanBefore = "jib"
        ))
}

Verifying Image Contents

We use the Open Containers Spec to define image annotations.

docker inspect image ${imageID}

"Labels": {
    "org.opencontainers.image.authors": "Coalition for Earth Data Applications and Research <cedar.cires@colorado.edu> (https://github.com/cedardevs)",
    "org.opencontainers.image.created": "2020-02-22T00:05:37.561983Z",
    "org.opencontainers.image.description": "A browser UI for the OneStop system.",
    "org.opencontainers.image.documentation": "https://cedardevs.github.io/onestop",
    "org.opencontainers.image.licenses": "GPL-2.0",
    "org.opencontainers.image.revision": "7606250a",
    "org.opencontainers.image.title": "onestop-client",
    "org.opencontainers.image.url": "https://data.noaa.gov/onestop",
    "org.opencontainers.image.vendor": "cedardevs",
    "org.opencontainers.image.version": "unknown-SNAPSHOT"
}

The same image annotations can be seen via Kubernetes, using the following command:

kubectl describe pod ${podName}


Top of Page