Discover the new easier way to develop Kurento video applications

Release Procedures

Introduction

Kurento as a project spans across a multitude of different technologies and languages, each of them with their sets of conventions and best practices. This document aims to summarize all release procedures that apply to each one of the modules that compose the Kurento project. The main form of categorization is by technology type: C/C++ based modules, Java modules, JavaScript modules, and others.

General considerations

  • Lists of projects in this document are sorted according to the repository lists given in Code repositories.

  • Kurento projects to be released have supposedly been under development, and will have development version numbers:

    • In Java (Maven) projects, development versions are indicated by the suffix -SNAPSHOT after the version number. Example: 6.9.1-SNAPSHOT.
    • In C/C++ (CMake) projects, development versions are indicated by the suffix -dev after the version number. Example: 6.9.1-dev.

    These suffixes must be removed for release, and then recovered again to resume development.

  • All dependencies to development versions will be changed to a release version during the release procedure. Concerning people will be asked to choose an appropriate release version for each development dependency.

  • Tags are named with the version number of the release. Example: 6.9.0.

  • Contrary to the project version, the Debian package versions don’t contain development suffixes, and should always be of the form 1.2.3-0kurento1:

    • The first part (1.2.3) is the project’s base version number.
    • The second part (0kurento1) is the Debian package revision. The first number (0) means that the package only exists in Kurento (not in Debian or Ubuntu); this is typically the case for the projects owned or forked by Kurento. The rest (kurento1) means that this is the first package released by Kurento for the corresponding base version.

    Please check the Debian Policy Manual and this Ask Ubuntu answer for more information about the package versions.

    Note

    Most Kurento fork packages have a Debian package revision that starts with 1 instead of 0. This was due to a mistake, but changing it back to 0 would cause more problems than solutions so we’re maintaining those until the projects get updated to a newer base version.

  • Kurento uses Semantic Versioning. Whenever you need to decide what is going to be the final release version for a new release, try to follow the SemVer guidelines:

    Given a version number MAJOR.MINOR.PATCH, increment the:
    
    1. MAJOR version when you make incompatible API changes,
    2. MINOR version when you add functionality in a backwards-compatible manner, and
    3. PATCH version when you make backwards-compatible bug fixes.
    

    Please refer to https://semver.org/ for more information.

    Example

    If the last Kurento release was 6.8.2 (with e.g. Debian package version 6.8.2-0kurento3, because it had been repackaged 3 times) then after release the project versions should have been left as 6.8.3-dev (or 6.8.3-SNAPSHOT for Java components).

    If the next release of Kurento only includes patches, then the next version number 6.8.3 is already good. However, maybe our release includes new functionality, which according to Semantic Versioning should be accompanied with a bump in the minor version number, so the next release version number should be 6.9.0. The Debian package version is reset accordignly, so the full version is 6.9.0-0kurento1.

    If you are repackaging an already released version (for example, because maybe after release you found out that the packages fail to install) then just increment the Debian package version: 0kurento2.

Note

Made a mistake? Don’t panic!

Do not be afraid of applying some Git magic to solve mistakes during the release process. Here are some which can be useful:

  • How to remove a release tag?

    • Remove the local tag:

      git tag --delete <TagName>
      
    • Remove the remote tag:

      git push --delete origin <TagName>
      
  • How to push just a local tag?

    git push origin <TagName>
    
  • How to ammend a commit and push it again?

    See: https://www.atlassian.com/git/tutorials/rewriting-history#git-commit–amend

    # <Remove Tag>
    # <Amend>
    # <Create Tag>
    git push --force --follow-tags
    

Warning

As of this writing, there is a mix of methods in the CI scripts (adm-scripts) when it comes to handle the release versions. The instructions in this document favor creating and pushing git tags manually in the developer’s computer, however some projects also make use of the script kurento_check_version.sh, which tries to detect when a project’s version is not a development snapshot, then creates and pushes a git tag automatically. However if the tag alreeady exists (created manually by the developer), then the git tag command fails, and this script prints a warning message before continuing with its work.

We’ve been toying with different methodologies between handling the tags automatically in CI or handling them manually by the developer before releasing new versions; both of these methods have pros and cons. For example, if tags are handled manually by the developer, solving mistakes in the release process becomes simpler because there are no surprises from CI creating tags inadvertently; on the other hand, leaving them to be created by CI seems to simplify a bit the release process, but not really by a big margin.

Fork Repositories

This graph shows the dependencies between forked projects used by Kurento:

digraph dependencies_forks {
  bgcolor = "transparent";
  fontname = "Bitstream Vera Sans";
  fontsize = 8;
  size = "12,8";

  rankdir = "RL";

  // Kurento external libraries
  "jsoncpp";
  "libsrtp";
  "openh264";
  "usrsctp";
  "gstreamer";
  "gst-plugins-base" -> "gstreamer";
  "gst-plugins-good" -> "gst-plugins-base";
  "gst-plugins-bad" -> {"gst-plugins-base" "libsrtp" "openh264"};
  "gst-plugins-ugly" -> "gst-plugins-base";
  "gst-libav" -> "gst-plugins-base";
  "openwebrtc-gst-plugins" -> {"gstreamer" "gst-plugins-base" "usrsctp"};
  "libnice" -> "gstreamer";
}

Projects forked by Kurento

Release order:

  • jsoncpp
  • libsrtp
  • openh264
  • usrsctp
  • gstreamer
  • gst-plugins-base
  • gst-plugins-good
  • gst-plugins-bad
  • gst-plugins-ugly
  • gst-libav
  • openwebrtc-gst-plugins
  • libnice

For each project above:

  1. Prepare release.
  2. Push a new tag to Git.
  3. Move to next development version.

Release steps

  1. Decide what is going to be the final release version. For this, follow the upstream version and the SemVer guidelines, as explained above in General considerations.

  2. Set the final release version, commit the results, and create a tag.

    # Change these
    NEW_VERSION="<ReleaseVersion>"        # Eg.: 1.0.0
    NEW_DEBIAN="<DebianRevision>"         # Eg.: 0kurento1
    
    function do_release {
        local PACKAGE_VERSION="${NEW_VERSION}-${NEW_DEBIAN}"
        local COMMIT_MSG="Prepare release $PACKAGE_VERSION"
    
        local SNAPSHOT_ENTRY="* UNRELEASED"
        local RELEASE_ENTRY="* $COMMIT_MSG"
    
        gbp dch \
            --ignore-branch \
            --git-author \
            --spawn-editor=never \
            --new-version="$PACKAGE_VERSION" \
            \
            --release \
            --distribution="testing" \
            --force-distribution \
            \
            ./debian \
        || { echo "ERROR: Command failed: gbp dch"; return 1; }
    
        # First appearance of "UNRELEASED": Put our commit message
        sed -i "0,/${SNAPSHOT_ENTRY}/{s/${SNAPSHOT_ENTRY}/${RELEASE_ENTRY}/}" \
            ./debian/changelog \
        || { echo "ERROR: Command failed: sed"; return 2; }
    
        # Remaining appearances of "UNRELEASED" (if any): Delete line
        sed -i "/${SNAPSHOT_ENTRY}/d" \
            ./debian/changelog \
        || { echo "ERROR: Command failed: sed"; return 3; }
    
        git add debian/changelog \
        && git commit -m "$COMMIT_MSG" \
        && git tag -a -m "$COMMIT_MSG" "$PACKAGE_VERSION" \
        && git push --follow-tags \
        || { echo "ERROR: Command failed: git"; return 4; }
    }
    
    do_release
    
  3. Follow on with releasing Kurento Media Server.

  4. AFTER THE WHOLE RELEASE HAS BEEN COMPLETED: Set the next development version in all projects. To choose the next version number, increment the Debian revision number.

    The version number will only be changed when the fork gets updated from upstream code. When doing that, then change our version number so it matched the version number used in upstream.

    # Change these
    NEW_VERSION="<NextVersion>"           # Eg.: 1.0.0
    NEW_DEBIAN="<NextDebianRevision>"     # Eg.: 0kurento2
    
    function do_release {
        local PACKAGE_VERSION="${NEW_VERSION}-${NEW_DEBIAN}"
        local COMMIT_MSG="Bump development version to $PACKAGE_VERSION"
    
        gbp dch \
              --ignore-branch \
              --git-author \
              --spawn-editor=never \
              --new-version="$PACKAGE_VERSION" \
              ./debian \
        || { echo "ERROR: Command failed: gbp dch"; return 1; }
    
        git add debian/changelog \
        && git commit -m "$COMMIT_MSG" \
        && git push \
        || { echo "ERROR: Command failed: git"; return 2; }
    }
    
    do_release
    

Kurento Media Server

All KMS projects:

digraph dependencies_kms {
  bgcolor = "transparent";
  fontname = "Bitstream Vera Sans";
  fontsize = 8;
  size = "12,8";

  rankdir = "RL";

  // KMS main components
  {
    rank = "same";
    "kurento-module-creator";
    "kms-cmake-utils";
  }
  "kms-jsonrpc" -> "kms-cmake-utils";
  "kms-core" -> {"kurento-module-creator" "kms-cmake-utils" "kms-jsonrpc"};
  "kms-elements" -> "kms-core";
  "kms-filters" -> "kms-elements";
  "kurento-media-server" -> {"kms-core" "kms-elements" "kms-filters"};

  // KMS extra modules
  "kms-chroma" -> {"kms-core" "kms-elements" "kms-filters"};
  "kms-crowddetector" -> {"kms-core" "kms-elements" "kms-filters"};
  "kms-datachannelexample" -> {"kms-core" "kms-elements" "kms-filters"};
  "kms-platedetector" -> {"kms-core" "kms-elements" "kms-filters"};
  "kms-pointerdetector" -> {"kms-core" "kms-elements" "kms-filters"};
}

Projects that are part of Kurento Media Server

Release order:

  • kurento-module-creator
  • kms-cmake-utils
  • kms-jsonrpc
  • kms-core
  • kms-elements
  • kms-filters
  • kurento-media-server
  • kms-chroma
  • kms-crowddetector
  • kms-platedetector
  • kms-pointerdetector

For each project above:

  1. Prepare release.
  2. Push a new tag to Git.
  3. Move to next development version.

Preparation: kurento-module-creator

If kurento-maven-plugin is going to get also a new release, then edit the file kurento-module-creator/src/main/templates/maven/model_pom_xml.ftl to update the plugin version in the auto-generation template:

   <groupId>org.kurento</groupId>
   <artifactId>kurento-maven-plugin</artifactId>
-  <version>6.8.2</version>
+  <version>6.9.0</version>
   <executions>

Preparation: KMS API Java modules

Test the KMS API Java module generation (local check).

apt-get update && apt-get install --no-install-recommends --yes \
    kurento-module-creator \
    kms-cmake-utils \
    kms-jsonrpc-dev \
    kms-core-dev \
    kms-elements-dev \
    kms-filters-dev

cd kms-omni-build

function do_release {
    local PROJECTS=(
        kms-core
        kms-elements
        kms-filters
    )

    for PROJECT in "${PROJECTS[@]}"; do
        pushd "$PROJECT" || { echo "ERROR: Command failed: pushd"; return 1; }

        mkdir build \
        && cd build \
        && cmake .. -DGENERATE_JAVA_CLIENT_PROJECT=TRUE -DDISABLE_LIBRARIES_GENERATION=TRUE \
        && cd java \
        && mvn clean install -Dmaven.test.skip=false \
        || { echo "ERROR: Command failed"; return 1; }

        popd
    done
}

do_release

Release steps

  1. Review changes in all KMS sub-projects, and edit kurento-media-server/CHANGELOG.md to add them.

    You can use this command to get a list of commit messages since last release:

    git log "$(git describe --tags --abbrev=0)"..HEAD --oneline
    

    Then add the new CHANGELOG.md for the upcoming release commit:

    cd kurento-media-server
    git add CHANGELOG.md
    
  2. Decide what is going to be the final release version. For this, follow the SemVer guidelines, as explained above in General considerations.

  3. Set the final release version in all projects. Use the helper script kms-omni-build/bin/set-versions.sh to set version numbers, commit the results, and create a tag.

    # Change these
    NEW_VERSION="<ReleaseVersion>"        # Eg.: 1.0.0
    NEW_DEBIAN="<DebianRevision>"         # Eg.: 0kurento1
    
    cd kms-omni-build
    ./bin/set-versions.sh "$NEW_VERSION" --debian "$NEW_DEBIAN" \
        --release --commit --tag
    

    Now push changes:

    git submodule foreach 'git push --follow-tags'
    
  4. It’s also nice to update the git-submodule references of the all-in-one repo kms-omni-build, and create a tag just like in all the other repos.

    # Change this
    NEW_VERSION="<ReleaseVersion>"      # Eg.: 1.0.0
    
    COMMIT_MSG="Prepare release $NEW_VERSION"
    
    cd kms-omni-build
    git add . \
    && git commit -m "$COMMIT_MSG" \
    && git tag -a -m "$COMMIT_MSG" "$NEW_VERSION" \
    && git push --follow-tags
    
  5. Start the KMS CI job with the parameters JOB_RELEASE ENABLED and JOB_ONLY_KMS DISABLED.

  6. Wait until all packages get created and published correctly. Fix any issues that appear.

    The KMS CI job is a Jenkins MultiJob Project. If it fails at any stage, after fixing the cause of the error it’s not needed to start the job again from the beginning; instead, it is possible to resume the build from the point it was before the failure. For this, just open the latest build number that failed (with a red marker in the Build History panel at the left of the job page); in the description of the build, the action Resume build is available on the left side.

  7. Check that the Auto-Generated API Client JavaScript repos have been updated (which should happen as part of the CI jobs for all Kurento Media Server modules that contain API Definition files (.KMD).

    • kms-core -> kurento-client-core-js
    • kms-elements -> kurento-client-elements-js
    • kms-filters -> kurento-client-filters-js
    • kms-chroma -> kurento-module-chroma-js
    • kms-crowddetector -> kurento-module-crowddetector-js
    • kms-platedetector -> kurento-module-platedetector-js
    • kms-pointerdetector -> kurento-module-pointerdetector-js
  8. When all repos have been released, and CI jobs have finished successfully, publish the Java artifacts:

    • Open the Nexus Sonatype Staging Repositories section.
    • Select kurento repository.
    • Inspect Content to ensure they are as expected:
      • kurento-module-creator (if it was released)
      • kms-api-core
      • kms-api-elements
      • kms-api-filters
      • All of them must appear in the correct version, $NEW_VERSION.
    • Close repository.
    • Wait a bit.
    • Refresh.
    • Release repository.
    • Maven artifacts will be available after 10 minutes.
  9. Also, check that the JavaScript modules have been published by CI:

  10. AFTER THE WHOLE RELEASE HAS BEEN COMPLETED: Set the next development version in all projects. To choose the next version number, increment the patch number. Use the helper script kms-omni-build/bin/set-versions.sh to set version numbers and commit.

    # Change these
    NEW_VERSION="<NextVersion>"           # Eg.: 1.0.1
    NEW_DEBIAN="<NextDebianRevision>"     # Eg.: 0kurento1
    
    cd kms-omni-build
    ./bin/set-versions.sh "$NEW_VERSION" --debian "$NEW_DEBIAN" \
        --new-development --commit
    

    Now push changes:

    git submodule foreach 'git push'
    
  11. Start the KMS CI job with the parameters JOB_RELEASE DISABLED and JOB_ONLY_KMS DISABLED.

Kurento JavaScript client

Release order:

  • kurento-jsonrpc-js
  • kurento-utils-js
  • kurento-client-js
  • kurento-tutorial-js
  • kurento-tutorial-node

For each project above:

  1. Prepare release.
  2. Push a new tag to Git.
  3. Move to next development version.

Release steps

  1. Decide what is going to be the final release version. For this, follow the SemVer guidelines, as explained above in General considerations.

  2. Ensure there are no uncommited files.

    git diff-index --quiet HEAD \
    || echo "ERROR: Uncommited files not allowed!"
    
  3. Set the final release version in project and dependencies. This operation is done in different files, depending on the project:

    • kurento-jsonrpc-js/package.json
    • kurento-utils-js/package.json
    • kurento-client-js/package.json
    • Each one in kurento-tutorial-js/**/bower.json
    • Each one in kurento-tutorial-node/**/package.json
  4. Review all dependencies to remove development versions.

    This command can be used to search for all development versions:

    grep . --exclude-dir='*node_modules' -Fr -e '-dev"' -e '"git+' \
    && echo "ERROR: Development versions not allowed!"
    

    For example: All dependencies to Kurento packages that point directly to their Git repos should be changed to point to a pinned SemVer number (or version range). Later, the Git URL can be restored for the next development iteration.

  5. Test the build, to make sure the code is in a working state.

    npm install
    if [[ -x node_modules/.bin/grunt ]]; then
        node_modules/.bin/grunt jsbeautifier \
        && node_modules/.bin/grunt \
        && node_modules/.bin/grunt sync:bower \
        || echo "ERROR: Command failed: npm"
    fi
    

    To manually run the beautifier, do this:

    npm install
    
    # To run beautifier over all files, modifying in-place:
    node_modules/.bin/grunt jsbeautifier::default
    
    # To run beautifier over a specific file:
    node_modules/.bin/grunt jsbeautifier::file:<FilePath>.js
    

    Some times it happens that Grunt needs to be run a couple of times until it ends without errors.

  6. All-In-One script.

    Note

    You’ll need to install the jq command-line JSON processor.

    # Change this
    NEW_VERSION="<ReleaseVersion>"        # Eg.: 1.0.0
    
    function do_release {
        local COMMIT_MSG="Prepare release $NEW_VERSION"
    
        local PROJECTS=(
            kurento-jsonrpc-js
            kurento-utils-js
            kurento-client-js
            kurento-tutorial-js
            kurento-tutorial-node
        )
    
        for PROJECT in "${PROJECTS[@]}"; do
            pushd "$PROJECT" || { echo "ERROR: Command failed: pushd"; return 1; }
            git stash
    
            git pull --rebase \
            || { echo "ERROR: Command failed: git pull"; return 2; }
    
            # Ensure there are no uncommited files
            git diff-index --quiet HEAD \
            || { echo "ERROR: Uncommited files not allowed!"; return 3; }
    
            # Set the final release version in project and dependencies
            JQ_PROGRAM="$(mktemp)"
            tee "$JQ_PROGRAM" >/dev/null <<EOF
    # This is a program for the "jq" command-line JSON processor
    # The last 4 rules are specifically for kurento-client-js
    if .version? then
        .version = "$NEW_VERSION"
    else . end
    | if .dependencies."kurento-client-core"? then
        .dependencies."kurento-client-core" = "$NEW_VERSION"
    else . end
    | if .dependencies."kurento-client-elements"? then
        .dependencies."kurento-client-elements" = "$NEW_VERSION"
    else . end
    | if .dependencies."kurento-client-filters"? then
        .dependencies."kurento-client-filters" = "$NEW_VERSION"
    else . end
    | if .dependencies."kurento-jsonrpc"? then
        .dependencies."kurento-jsonrpc" = "$NEW_VERSION"
    else . end
    EOF
            find . -path '*node_modules' -prune , -name '*.json' | while read FILE; do
                echo "Process file: $(realpath "$FILE")"
    
                TEMP="$(mktemp)"
                jq --from-file "$JQ_PROGRAM" "$FILE" >"$TEMP" \
                && mv --update "$TEMP" "$FILE" \
                || { echo "ERROR: Command failed: jq"; return 4; }
    
                git add "$FILE"
            done
    
            # Review all dependencies to remove development versions
            grep . --exclude-dir='*node_modules' -Fr -e '-dev"' -e '"git+' \
            && { echo "ERROR: Development versions not allowed!"; return 5; }
    
            # Test the build
            npm install
            if [[ -x node_modules/.bin/grunt ]]; then
                node_modules/.bin/grunt jsbeautifier \
                && node_modules/.bin/grunt \
                && node_modules/.bin/grunt sync:bower \
                || { echo "ERROR: Command failed: npm"; return 6; }
            fi
    
            git stash pop
            popd
        done
    
        # Everything seems OK so proceed to commit and push
        for PROJECT in "${PROJECTS[@]}"; do
            pushd "$PROJECT" || { echo "ERROR: Command failed: pushd"; return 7; }
    
            git commit -m "$COMMIT_MSG" \
            && git tag -a -m "$COMMIT_MSG" "$NEW_VERSION" \
            && git push --follow-tags \
            || { echo "ERROR: Command failed: git"; return 8; }
    
            popd
        done
    }
    
    do_release
    
  7. When all repos have been released, and CI jobs have finished successfully,

    • Open the Nexus Sonatype Staging Repositories section.
    • Select kurento repository.
    • Inspect Content to ensure they are as expected:
      • kurento-jsonrpc-js
      • kurento-utils-js
      • kurento-client-js
      • All of them must appear in the correct version, $NEW_VERSION.
    • Close repository.
    • Wait a bit.
    • Refresh.
    • Release repository.
    • Maven artifacts will be available after 10 minutes.
  8. AFTER THE WHOLE RELEASE HAS BEEN COMPLETED: Set the next development version in all projects. To choose the next version number, increment the patch number and add “-dev”.

    All-In-One script.

    # Change this
    NEW_VERSION="<NextVersion>-dev"           # Eg.: 1.0.1-dev
    
    function do_release {
        local COMMIT_MSG="Prepare for next development iteration"
    
        local PROJECTS=(
            kurento-jsonrpc-js
            kurento-utils-js
            kurento-client-js
            kurento-tutorial-js
            kurento-tutorial-node
        )
    
        for PROJECT in "${PROJECTS[@]}"; do
            pushd "$PROJECT" || { echo "ERROR: Command failed: pushd"; return 1; }
            git stash
    
            git pull --rebase \
            || { echo "ERROR: Command failed: git pull"; return 2; }
    
            # Set the next development version in project and dependencies
            JQ_PROGRAM="$(mktemp)"
            tee "$JQ_PROGRAM" >/dev/null <<EOF
    # This is a program for the "jq" command-line JSON processor
    # The last 4 rules are specifically for kurento-client-js
    if .version? then
        .version = "$NEW_VERSION"
    else . end
    | if .dependencies."kurento-client-core"? then
        .dependencies."kurento-client-core" = "git+https://github.com/Kurento/kurento-client-core-js.git"
    else . end
    | if .dependencies."kurento-client-elements"? then
        .dependencies."kurento-client-elements" = "git+https://github.com/Kurento/kurento-client-elements-js.git"
    else . end
    | if .dependencies."kurento-client-filters"? then
        .dependencies."kurento-client-filters" = "git+https://github.com/Kurento/kurento-client-filters-js.git"
    else . end
    | if .dependencies."kurento-jsonrpc"? then
        .dependencies."kurento-jsonrpc" = "git+https://github.com/Kurento/kurento-jsonrpc-js.git"
    else . end
    EOF
            find . -path '*node_modules' -prune , -name '*.json' | while read FILE; do
                echo "Process file: $(realpath "$FILE")"
    
                TEMP="$(mktemp)"
                jq --from-file "$JQ_PROGRAM" "$FILE" >"$TEMP" \
                && mv --update "$TEMP" "$FILE" \
                || { echo "ERROR: Command failed: jq"; return 3; }
    
                git add "$FILE"
            done
    
            git stash pop
            popd
        done
    
        # Everything seems OK so proceed to commit and push
        for PROJECT in "${PROJECTS[@]}"; do
            pushd "$PROJECT" || { echo "ERROR: Command failed: pushd"; return 4; }
    
            git commit -m "$COMMIT_MSG" \
            && git push \
            || { echo "ERROR: Command failed: git"; return 5; }
    
            popd
        done
    }
    
    do_release
    

Kurento Maven plugin

  1. Review changes in all KMS sub-projects, and edit changelog to add them.

    You can use this command to get a list of commit messages since last release:

    git log "$(git describe --tags --abbrev=0)"..HEAD --oneline
    
  2. Decide what is going to be the final release version. For this, follow the SemVer guidelines, as explained above in General considerations.

  3. Set the final release version in pom.xml. Remove “-SNAPSHOT”.

       <groupId>org.kurento</groupId>
       <artifactId>kurento-maven-plugin</artifactId>
    -  <version>1.2.3-SNAPSHOT</version>
    +  <version>1.2.3</version>
       <packaging>maven-plugin</packaging>
    
  4. Git add, commit, tag, and push.

    # Change this
    NEW_VERSION="<ReleaseVersion>"        # Eg.: 1.0.0
    
    COMMIT_MSG="Prepare release $NEW_VERSION"
    
    cd kurento-maven-plugin
    git add pom.xml changelog \
    && git commit -m "$COMMIT_MSG" \
    && git tag -a -m "$COMMIT_MSG" "$NEW_VERSION" \
    && git push --follow-tags  \
    || echo "ERROR: Command failed: git"
    
  5. The CI jobs should start automatically; some tests are run as a result of this commit, so you should wait for their completion.

  6. AFTER THE WHOLE RELEASE HAS BEEN COMPLETED: Set the next development version in all projects. To choose the next version number, increment the patch number and add “-SNAPSHOT”.

       <groupId>org.kurento</groupId>
       <artifactId>kurento-maven-plugin</artifactId>
    -  <version>1.2.3</version>
    +  <version>1.2.4-SNAPSHOT</version>
       <packaging>maven-plugin</packaging>
    
  1. Git add, commit, and push.

    COMMIT_MSG="Prepare for next development iteration"
    
    cd kurento-maven-plugin
    git add pom.xml \
    && git commit -m "$COMMIT_MSG" \
    && git push \
    || echo "ERROR: Command failed: git"
    

Kurento Java client

Release order:

  • kurento-qa-pom
  • kurento-java
  • kurento-tutorial-java
  • kurento-tutorial-test

For each project above:

  1. Prepare release.
  2. Push a new tag to Git.
  3. Move to next development version.

Preparation: kurento-java

If there have been changes in the API of Kurento Media Server modules (in the .KMD JSON files), update the corresponding versions in kurento-parent-pom/pom.xml:

    <properties>
-   <version.kms-api-core>6.8.2</version.kms-api-core>
-   <version.kms-api-elements>6.8.2</version.kms-api-elements>
-   <version.kms-api-filters>6.8.2</version.kms-api-filters>
+   <version.kms-api-core>6.9.0</version.kms-api-core>
+   <version.kms-api-elements>6.9.0</version.kms-api-elements>
+   <version.kms-api-filters>6.9.0</version.kms-api-filters>

Doing this ensures that the Java client gets generated according to the latest versions of the API definitions.

Similarly, update the version numbers of any other Kurento project that has been updated:

<version.kurento-utils-js>6.7.0</version.kurento-utils-js>
<version.kurento-maven-plugin>6.7.0</version.kurento-maven-plugin>

<version.kurento-chroma>6.6.0</version.kurento-chroma>
<version.kurento-crowddetector>6.6.0</version.kurento-crowddetector>
<version.kurento-platedetector>6.6.0</version.kurento-platedetector>
<version.kurento-pointerdetector>6.6.0</version.kurento-pointerdetector>

Release steps

  1. Decide what is going to be the final release version. For this, follow the SemVer guidelines, as explained above in General considerations.

  2. Ensure there are no uncommited files.

    git diff-index --quiet HEAD \
    || echo "ERROR: Uncommited files not allowed!"
    
  3. Set the final release version in project and dependencies. This operation varies between projects.

    Note

    kurento-tutorial-java and kurento-tutorial-test require that kurento-java has been installed locally (with mvn install) before being able to change their version numbers programmatically with Maven.

  4. Review all dependencies to remove development versions.

    Note

    In kurento-java, all dependencies are defined as properties in the file kurento-parent-pom/pom.xml.

    This command can be used to search for all development versions:

    grep . --include='pom.xml' -Fr -e '-SNAPSHOT' \
    && echo "ERROR: Development versions not allowed!"
    
  5. Test the build, to make sure the code is in a working state.

    Note

    The profile ‘kurento-release’ is used to enforce no development versions are present.

    mvn -U clean install -Dmaven.test.skip=false -Pkurento-release \
    || echo "ERROR: Command failed: mvn clean install"
    
  6. All-In-One script:

    Note

    Use mvn --batch-mode if you copy this to an actual script.

    # Change this
    NEW_VERSION="<ReleaseVersion>"        # Eg.: 1.0.0
    
    function do_release {
        local COMMIT_MSG="Prepare release $NEW_VERSION"
    
        local PROJECTS=(
            kurento-qa-pom
            kurento-java
            kurento-tutorial-java
            kurento-tutorial-test
        )
    
        for PROJECT in "${PROJECTS[@]}"; do
            pushd "$PROJECT" || { echo "ERROR: Command failed: pushd"; return 1; }
            git stash
    
            git pull --rebase \
            || { echo "ERROR: Command failed: git pull"; return 2; }
    
            # Ensure there are no uncommited files
            git diff-index --quiet HEAD \
            || { echo "ERROR: Uncommited files not allowed!"; return 3; }
    
            # Set the final release version in project and dependencies
            if [[ "$PROJECT" == "kurento-qa-pom" ]]; then
                mvn \
                    versions:set \
                    -DgenerateBackupPoms=false \
                    -DnewVersion="$NEW_VERSION" \
                || { echo "ERROR: Command failed: mvn versions:set"; return 4; }
            elif [[ "$PROJECT" == "kurento-java" ]]; then
                mvn --file kurento-parent-pom/pom.xml \
                    versions:set \
                    -DgenerateBackupPoms=false \
                    -DnewVersion="$NEW_VERSION" \
                || { echo "ERROR: Command failed: mvn versions:set"; return 5; }
    
                mvn --file kurento-parent-pom/pom.xml \
                    versions:set-property \
                    -DgenerateBackupPoms=false \
                    -Dproperty=version.kms-api-core \
                    -DnewVersion="$NEW_VERSION"
                mvn --file kurento-parent-pom/pom.xml \
                    versions:set-property \
                    -DgenerateBackupPoms=false \
                    -Dproperty=version.kms-api-elements \
                    -DnewVersion="$NEW_VERSION"
                mvn --file kurento-parent-pom/pom.xml \
                    versions:set-property \
                    -DgenerateBackupPoms=false \
                    -Dproperty=kms-api-filters \
                    -DnewVersion="$NEW_VERSION"
            else # kurento-tutorial-java, kurento-tutorial-test
                mvn \
                    versions:update-parent \
                    -DgenerateBackupPoms=false \
                    -DparentVersion="[${NEW_VERSION}]" \
                || { echo "ERROR: Command failed: mvn versions:update-parent"; return 6; }
    
                mvn -N \
                    versions:update-child-modules \
                    -DgenerateBackupPoms=false \
                || { echo "ERROR: Command failed: mvn versions:update-child-modules"; return 7; }
            fi
    
            # Review all dependencies to remove development versions
            grep . --include='pom.xml' -Fr -e '-SNAPSHOT' \
            && echo "ERROR: Development versions not allowed!"
    
            # Test the build
            mvn -U clean install -Dmaven.test.skip=false -Pkurento-release \
            || { echo "ERROR: Command failed: mvn clean install"; return 8; }
    
            git stash pop
            popd
        done
    
        # Everything seems OK so proceed to commit and push
        for PROJECT in "${PROJECTS[@]}"; do
            pushd "$PROJECT" || { echo "ERROR: Command failed: pushd"; return 9; }
    
            ( git ls-files --modified | grep -E '/?pom.xml$' | xargs -r git add ) \
            && git commit -m "$COMMIT_MSG" \
            && git tag -a -m "$COMMIT_MSG" "$NEW_VERSION" \
            && git push --follow-tags \
            || { echo "ERROR: Command failed: git"; return 10; }
    
            popd
        done
    }
    
    do_release
    
  7. When all repos have been released, and CI jobs have finished successfully:

    • Open the Nexus Sonatype Staging Repositories section.
    • Select kurento repositories.
    • Inspect Content to ensure they are as expected: kurento-java, etc.
    • Close repositories.
    • Wait a bit.
    • Refresh.
    • Release repositories.
    • Maven artifacts will be available after 10 minutes.
    • Open the Nexus Sonatype Staging Repositories section.
    • Select kurento repository.
    • Inspect Content to ensure they are as expected:
      • kurento-client
      • kurento-commons
      • kurento-integration-tests
      • kurento-java
      • kurento-jsonrpc
      • kurento-jsonrpc-client
      • kurento-jsonrpc-client-jetty
      • kurento-jsonrpc-server
      • kurento-parent-pom
      • kurento-repository (ABANDONED PROJECT)
      • kurento-repository-client (ABANDONED)
      • kurento-repository-internal (ABANDONED)
      • kurento-test
      • All of them must appear in the correct version, $NEW_VERSION.
    • Close repository.
    • Wait a bit.
    • Refresh.
    • Release repository.
    • Maven artifacts will be available after 10 minutes.
  8. AFTER THE WHOLE RELEASE HAS BEEN COMPLETED: Set the next development version in all projects. To choose the next version number, increment the patch number and add “-SNAPSHOT”.

    Note

    Maven can do this automatically with the Maven Versions Plugin.

    Note

    You should wait for a full nightly run of the Kurento Media Server pipeline, so the next development packages become available from KMS API modules: kms-api-core, kms-api-elements, and kms-api-filters. This way, the properties in kurento-parent-pom/pom.xml will get updated to the latest SNAPSHOT version.

    All-In-One script:

    Note

    Use mvn --batch-mode if you copy this to an actual script.

    function do_release {
        local COMMIT_MSG="Prepare for next development iteration"
    
        local PROJECTS=(
            kurento-qa-pom
            kurento-java
            kurento-tutorial-java
            kurento-tutorial-test
        )
    
        for PROJECT in "${PROJECTS[@]}"; do
            pushd "$PROJECT" || { echo "ERROR: Command failed: pushd"; return 1; }
            git stash
    
            # Set the next development version in project and dependencies
            if [[ "$PROJECT" == "kurento-qa-pom" ]]; then
                mvn \
                    versions:set \
                    -DgenerateBackupPoms=false \
                    -DnextSnapshot=true \
                || { echo "ERROR: Command failed: mvn versions:set"; return 2; }
            elif [[ "$PROJECT" == "kurento-java" ]]; then
                mvn --file kurento-parent-pom/pom.xml \
                    versions:set \
                    -DgenerateBackupPoms=false \
                    -DnextSnapshot=true \
                || { echo "ERROR: Command failed: mvn versions:set"; return 3; }
    
                mvn --file kurento-parent-pom/pom.xml \
                    versions:update-property \
                    -DgenerateBackupPoms=false \
                    -DallowSnapshots=true \
                    -Dproperty=version.kms-api-core
                mvn --file kurento-parent-pom/pom.xml \
                    versions:update-property \
                    -DgenerateBackupPoms=false \
                    -DallowSnapshots=true \
                    -Dproperty=version.kms-api-elements
                mvn --file kurento-parent-pom/pom.xml \
                    versions:update-property \
                    -DgenerateBackupPoms=false \
                    -DallowSnapshots=true \
                    -Dproperty=version.kms-api-filters
            else # kurento-tutorial-java, kurento-tutorial-test
                mvn \
                    versions:update-parent \
                    -DgenerateBackupPoms=false \
                    -DallowSnapshots=true \
                || { echo "ERROR: Command failed: mvn versions:update-parent"; return 4; }
    
                mvn -N \
                    versions:update-child-modules \
                    -DgenerateBackupPoms=false \
                    -DallowSnapshots=true \
                || { echo "ERROR: Command failed: mvn versions:update-child-modules"; return 5; }
            fi
    
            # Test the build
            mvn -U clean install -Dmaven.test.skip=true \
            || { echo "ERROR: Command failed: mvn clean install"; return 6; }
    
            git stash pop
            popd
        done
    
        # Everything seems OK so proceed to commit and push
        for PROJECT in "${PROJECTS[@]}"; do
            pushd "$PROJECT" || { echo "ERROR: Command failed: pushd"; return 7; }
    
            ( git ls-files --modified | grep -E '/?pom.xml$' | xargs -r git add ) \
            && git commit -m "$COMMIT_MSG" \
            && git push \
            || { echo "ERROR: Command failed: git"; return 8; }
    
            popd
        done
    }
    
    do_release
    

Docker images

A new set of development images is deployed to Kurento Docker Hub on each nightly build. Besides, a release version will be published as part of the CI jobs chain when the KMS CI job is triggered.

The repository kurento-docker contains Dockerfile*s for all the Kurento Docker images, however this repo shouldn’t be tagged, because it is essentially a “multi-repo” and the tags would be meaningless (because *which one of the sub-dirs would the tag apply to?).

Kurento documentation

The documentation scripts will download both Java and JavaScript clients, generate HTML Javadoc / Jsdoc pages from them, and embed everything into a static section.

For this reason, the documentation must be built only after all the other modules have been released.

  1. Write the Release Notes in doc-kurento/source/project/relnotes/.

  2. Ensure that the whole nightly CI chain works:

    Job doc-kurento -> job doc-kurento-readthedocs -> New build at ReadTheDocs.

  3. Edit VERSIONS.conf.sh to set all relevant version numbers: version of the documentation itself, and all referred modules and client libraries.

    These numbers can be different because not all of the Kurento projects are necessarily released with the same frequency. Check each one of the Kurento repositories to verify what is the latest version of each one, and put it in the corresponding variable:

  4. In VERSIONS.conf.sh, set VERSION_RELEASE to true. Remember to set it again to false after the release, when starting a new development iteration.

  5. Test the build locally, check everything works.

    make html
    

    Note that the JavaDoc and JsDoc pages won’t be generated locally if you don’t have your system prepared to do so; also there are some Sphinx constructs or plugins that might fail if you don’t have them ready to use, but the ReadTheDocs servers have them so they should end up working fine.

    In any case, always check the final result of the intermediate documentation builds at https://doc-kurento.readthedocs.io/en/latest/, to have an idea of how the final release build will end up looking like.

  6. Git add, commit, tag, and push:

    # Change this
    NEW_VERSION="<ReleaseVersion>"        # Eg.: 1.0.0
    
    function do_release {
        local COMMIT_MSG="Prepare release $NEW_VERSION"
    
        # Set [VERSION_RELEASE]="true"
        sed -r -i 's/(VERSION_RELEASE.*)false/\1true/' VERSIONS.conf.sh \
        || { echo "ERROR: Command failed: sed"; return 1; }
    
        git add VERSIONS.conf.sh \
        && git add source/project/relnotes/v*.rst \
        && git commit -m "$COMMIT_MSG" \
        && git tag -a -m "$COMMIT_MSG" "$NEW_VERSION" \
        && git push --follow-tags \
        || { echo "ERROR: Command failed: git"; return 1; }
    }
    
    do_release
    

    Note

    If you made a mistake and want to re-create the git tag with a different commit, remember that the re-tagging must be done manually in both doc-kurento and doc-kurento-readthedocs repos. ReadTheDocs CI servers will read the later one to obtain the documentation sources and release tags.

  7. Run the doc-kurento CI job with the parameter JOB_RELEASE ENABLED.

  8. CI automatically tags Release versions in the ReadTheDocs source repo, doc-kurento-readthedocs, so the release will show up as “stable” in ReadTheDocs.

  9. Open ReadTheDocs Builds. If the new version hasn’t been detected and built, do it manually: use the Build Version button to force a build of the latest version.

    Doing this, ReadTheDocs will “realize” that there is a new tagged release version of the documentation, in the doc-kurento-readthedocs repo. After the build is finished, the new release version will be available for selection in the next step.

  10. Open ReadTheDocs Advanced Settings and select the new version in the Default Version combo box.

    Note

    We don’t set the Default Version field to “stable”, because we want that the actual version number gets shown in the upper part of the side panel (below the Kurento logo, above the search box) when users open the documentation. If “stable” was selected here, then users would just see the word “stable” in the mentioned panel.

  11. AFTER THE WHOLE RELEASE HAS BEEN COMPLETED: Set VERSION_RELEASE to false. Create Release Notes document for the next release:

    # Change this
    NEW_VERSION="<NextVersion>"           # Eg.: 1.0.1
    
    function do_release {
        local COMMIT_MSG="Prepare for next development iteration"
    
        # Set [VERSION_RELEASE]="false"
        sed -r -i 's/(VERSION_RELEASE.*)true/\1false/' VERSIONS.conf.sh \
        || { echo "ERROR: Command failed: sed"; return 1; }
    
        # Add a new Release Notes document
        local RELNOTES_NAME="v${NEW_VERSION//./_}"
        cp source/project/relnotes/v0_TEMPLATE.rst \
            "source/project/relnotes/${RELNOTES_NAME}.rst" \
        && sed -i 's/1.2.3/${NEW_VERSION}/' \
            "source/project/relnotes/${RELNOTES_NAME}.rst" \
        && sed -i "8i\   $RELNOTES_NAME" \
            source/project/relnotes/index.rst \
        || { echo "ERROR: Command failed: sed"; return 1; }
    
        git add VERSIONS.conf.sh \
        && git add source/project/relnotes/v*.rst \
        && git commit -m "$COMMIT_MSG" \
        && git push \
        || { echo "ERROR: Command failed: git"; return 1; }
    }
    
    do_release