release.md (15075B)
1 # libjxl release process 2 3 This guide documents the release process for the libjxl project. 4 5 libjxl follows the [semantic versioning](https://semver.org/spec/v2.0.0.html) 6 specification for released versions. Releases are distributed as tags in the git 7 repository with the semantic version prefixed by the letter "v". For example, 8 release version "0.3.7" will have a git tag "v0.3.7". 9 10 The public API is explicitly defined as C headers in the `lib/include` 11 directory, normally installed in your include path. All other headers are 12 internal API and are not covered by the versioning rules. 13 14 ## Development and release workflow 15 16 New code development is performed on the `main` branch of the git repository. 17 Pre-submit checks enforce minimum build and test requirements for new patches 18 that balance impact and test latency, but not all checks are performed before 19 pull requests are merged. Several slower checks only run *after* the code has 20 been merged to `main`, resulting in some errors being detected hours after the 21 code is merged or even days after in the case of fuzzer-detected bugs. 22 23 Release tags are cut from *release branches*. Each MAJOR.MINOR version has its 24 own release branch, for example releases `0.7.0`, `0.7.1`, `0.7.2`, ... would 25 have tags `v0.7.0`, `v0.7.1`, `v0.7.2`, ... on commits from the `v0.7.x` branch. 26 `v0.7.x` is a branch name, not a tag name, and doesn't represent a released 27 version since semantic versioning requires that the PATCH is a non-negative 28 number. Released tags don't each one have their own release branch, all releases 29 from the same MAJOR.MINOR version will share the same branch. The first commit 30 after the branch-off points between the main branch and the release branch 31 should be tagged with the suffix `-snapshot` and the name of the next 32 MAJOR.MINOR version, in order to get meaningful output for `git describe`. 33 34 The main purpose of the release branch is to stabilize the code before a 35 release. This involves including fixes to existing bugs but **not** including 36 new features. New features often come with new bugs which take time to fix, so 37 having a release branch allows us to cherry-pick *bug fixes* from the `main` 38 branch into the release branch without including the new *features* from `main`. 39 For this reason it is important to make small commits in `main` and separate bug 40 fixes from new features. 41 42 After the initial minor release (`MAJOR.MINOR.PATCH`, for example `0.5.0`) the 43 release branch is used to continue to cherry-pick fixes to be included in a 44 patch release, for example a version `0.5.1` release. Patch fixes are only meant 45 to fix security bugs or other critical bugs that can't wait until the next major 46 or minor release. 47 48 Release branches *may* continue to be maintained even after the next minor or 49 major version has been released to support users that can't update to a newer 50 minor release. In that case, the same process applies to all the maintained 51 release branches. 52 53 A release branch with specific cherry-picks from `main` means that the release 54 code is actually a version of the code that never existed in the `main` branch, 55 so it needs to be tested independently. Pre-submit and post-submit tests run on 56 release branches (branches matching `v*.*.x`) but extra manual checks should be 57 performed before a release, specially if multiple bug fixes interact with each 58 other. Take this into account when selecting which commits to include in a 59 release. The objective is to have a stable version that can be used without 60 problems for months. Having the latest improvements at the time the release tag 61 is created is a non-goal. 62 63 ## Creating a release branch 64 65 A new release branch is needed before creating a new major or minor release, 66 that is, a new release where the MAJOR or MINOR numbers are increased. Patch 67 releases, where only the PATCH number is increased, reuse the branch from the 68 previous release of the same MAJOR and MINOR numbers. 69 70 The following instructions assume that you followed the recommended [libjxl git 71 setup](developing_in_github.md) where `origin` points to the upstream 72 libjxl/libjxl project, otherwise use the name of your upstream remote repository 73 instead of `origin`. 74 75 The release branch is normally created from the latest work in `main` at the 76 time the branch is created, but it is possible to create the branch from an 77 older commit if the current `main` is particularly unstable or includes commits 78 that were not intended to be included in the release. The following example 79 creates the branch `v0.5.x` from the latest commit in main (`origin/main`), if a 80 different commit is to be used then replace `origin/main` with the SHA of that 81 commit. Change the `v0.5.x` branch name to the one you are creating. 82 83 ```bash 84 git fetch origin main 85 git push git@github.com:libjxl/libjxl.git origin/main:refs/heads/v0.5.x 86 ``` 87 88 Here we use the SSH URL explicitly since you are pushing to the `libjxl/libjxl` 89 project directly to a branch there. If you followed the guide `origin` will have 90 the HTTPS URL which wouldn't normally let you push since you wouldn't be 91 authenticated. The `v*.*.x` branches are [GitHub protected 92 branches](https://docs.github.com/en/github/administering-a-repository/defining-the-mergeability-of-pull-requests/about-protected-branches) 93 in our repository, however you can push to a protected branch when *creating* it 94 but you can't directly push to it after it is created. To include more changes 95 in the release branch see the "Cherry-picking fixes to a release" section below. 96 97 ## Creating a merge label 98 99 We use GitHub labels in Pull Requests to keep track of the changes that should 100 be merged into a given release branch. For this purpose create a new label for 101 each new MAJOR.MINOR release branch called `merge-MAJOR.MINOR`, for example, 102 `merge-0.5`. 103 104 In the [edit labels](https://github.com/libjxl/libjxl/issues/labels) page, click 105 on "New label" and create the label. Pick your favorite color. 106 107 Labels are a GitHub-only concept and are not represented in git. You can add the 108 label to a Pull Request even after it was merged, whenever it is decided that 109 the Pull Request should be included in the given release branch. Adding the 110 label doesn't automatically merge it to the release branch. 111 112 ## Update the versioning number 113 114 The version number (as returned by `JxlDecoderVersion`) in the source code in 115 `main` must match the semantic versioning of a release. After the release 116 branch is created the code in `main` will only be included in the next major 117 or minor release. Right after a release branch update the version targeting the 118 next release. Artifacts from `main` should include the new (unreleased) version, 119 so it is important to update it. For example, after the `v0.5.x` branch is 120 created from main, you should update the version on `main` to `0.6.0`. 121 122 To help update it, run this helper command (in a Debian-based system): 123 124 ```bash 125 ./ci.sh bump_version 0.6.0 126 ``` 127 128 This will update the version in the following files: 129 130 * `lib/CMakeLists.txt` 131 * `lib/lib.gni`, automatically updated with 132 `tools/scripts/build_cleaner.py --update`. 133 * `debian/changelog` to create the Debian package release with the new version. 134 Debian changelog shouldn't repeat the library changelog, instead it should 135 include changes to the packaging scripts. 136 * `.github/workflows/conformance.yml` 137 138 If there were incompatible API/ABI changes, make sure to also adapt the 139 corresponding section in 140 [CMakeLists.txt](https://github.com/libjxl/libjxl/blob/main/lib/CMakeLists.txt#L12). 141 142 ## Cherry-pick fixes to a release 143 144 After a Pull Request that should be included in a release branch has been merged 145 to `main` it can be cherry-picked to the release branch. Before cherry-picking a 146 change to a release branch it is important to check that it doesn't introduce 147 more problems, in particular it should run for some time in `main` to make sure 148 post-submit tests and the fuzzers run on it. Waiting for a day is a good idea. 149 150 Most of the testing is done on the `main` branch, so be careful with what 151 commits are cherry-picked to a branch. Refactoring code is often not a good 152 candidate to cherry-pick. 153 154 To cherry-pick a single commit to a release branch (in this example to `v0.5.x`) 155 you can run: 156 157 ```bash 158 git fetch origin 159 git checkout origin/v0.5.x -b merge_to_release 160 git cherry-pick -x SHA_OF_MAIN_COMMIT 161 # -x will annotate the cherry-pick with the original SHA_OF_MAIN_COMMIT value. 162 # If not already mentioned in the original commit, add the original PR number to 163 # the commit, for example add "(cherry picked from PR #NNNN)". 164 git commit --amend 165 ``` 166 167 The `SHA_OF_MAIN_COMMIT` is the hash of the commit as it landed in main. Use 168 `git log origin/main` to list the recent main commits and their hashes. 169 170 Making sure that the commit message on the cherry-picked commit contains a 171 reference to the original pull request (like `#NNNN`) is important. It creates 172 an automatic comment in the original pull request notifying that it was 173 mentioned in another commit, helping keep track of the merged pull requests. If 174 the original commit was merged with the "Squash and merge" policy it will 175 automatically contain the pull request number on the first line, if this is not 176 the case you can amend the commit message of the cherry-pick to include a 177 reference. 178 179 Multiple commits can be cherry-picked and tested at once to save time. Continue 180 running `git cherry-pick` and `git commit --amend` multiple times for all the 181 commits you need to cherry-pick, ideally in the same order they were merged on 182 the `main` branch. At the end you will have a local branch with multiple commits 183 on top of the release branch. 184 185 To update the version number, for example from v0.8.0 to v0.8.1 run this helper 186 command (in a Debian-based system): 187 188 ```bash 189 ./ci.sh bump_version 0.8.1 190 ``` 191 192 as described above and commit the changes. 193 194 Finally, upload your changes to *your fork* like normal, except that when 195 creating a pull request select the desired release branch as a target: 196 197 ```bash 198 git push myfork merge_to_release 199 ``` 200 201 If you used the [guide](developing_in_github.md) `myfork` would be `origin` in 202 that example. Click on the URL displayed, which will be something like 203 204 `https://github.com/mygithubusername/libjxl/pull/new/merge_to_release` 205 206 In the "Open a pull request" page, change the drop-down base branch from 207 "base: main" (the default) to the release branch you are targeting. 208 209 The pull request approval and pre-submit rules apply as with normal pull 210 requests to the `main` branch. 211 212 **Important:** When merging multiple cherry-picks use "Rebase and merge" policy, 213 not the squash one since otherwise you would discard the individual commit 214 message references from the git history in the release branch. 215 216 ## Publishing a release 217 218 Once a release tag is created it must not be modified, so you need to prepare 219 the changes before creating the release. Make sure you checked the following: 220 221 * The semantic version number in the release branch (see `lib/CMakeLists.txt`) 222 matches the number you intend to release, all three MAJOR, MINOR and PATCH 223 should match. Otherwise send a pull request to the release branch to 224 update them. 225 226 * The GitHub Actions checks pass on the release branch. Look for the green 227 tick next to the last commit on the release branch. This should be visible 228 on the branch page, for example: https://github.com/libjxl/libjxl/tree/v0.5.x 229 230 * There no open fuzzer-found bugs for the release branch. The most effective 231 way is to [run the fuzzer](fuzzing.md) on the release branch for a while. You 232 can seed the fuzzer with corpus generated by oss-fuzz by [downloading 233 it](https://google.github.io/oss-fuzz/advanced-topics/corpora/#downloading-the-corpus), 234 for example `djxl_fuzzer` with libFuzzer will use: 235 gs://libjxl-corpus.clusterfuzz-external.appspot.com/libFuzzer/libjxl_djxl_fuzzer 236 237 * Manually check that images encode/decode ok. 238 239 * Manually check that downstream projects compile with our code. Sometimes 240 bugs on build scripts are only detected when other projects try to use our 241 library. For example, test compiling 242 [imagemagick](https://github.com/ImageMagick/ImageMagick) and Chrome. 243 244 A [GitHub 245 "release"](https://docs.github.com/en/github/administering-a-repository/releasing-projects-on-github/about-releases) 246 consists of two different concepts: 247 248 * a git "tag": this is a name (`v` plus the semantic version number) with a 249 commit hash associated, defined in the git repository. Most external projects 250 will use git tags or HTTP URLs to these tags to fetch the code. 251 252 * a GitHub "release": this is a GitHub-only concept and is not represented in 253 git other than by having a git tag associated with the release. A GitHub 254 release has a given source code commit SHA associated (through the tag) but 255 it *also* contains release notes and optional binary files attached to the 256 release. 257 258 Releases from the older GitLab repository only have a git tag in GitHub, while 259 newer releases have both a git tag and a release entry in GitHub. 260 261 To publish a release open the [New Release 262 page](https://github.com/libjxl/libjxl/releases/new) and follow these 263 instructions: 264 265 * Set the "Tag version" as "v" plus the semantic version number. 266 267 * Select the "Target" as your release branch. For example for a "v0.7.1" 268 release tag you should use the "v0.7.x" branch. 269 270 * Use the version number as the release title. 271 272 * Copy-paste the relevant section of the [CHANGELOG.md](../CHANGELOG.md) to the 273 release notes into the release notes. Add any other information pertaining 274 the release itself that are not included in the CHANGELOG.md, although prefer 275 to include those in the CHANGELOG.md file. You can switch to the Preview tab 276 to see the results. 277 278 * Finally click "Publish release" and go celebrate with the team. 🎉 279 280 * The branch v0.7.x will be pushed to gitlab automatically, but make sure to 281 manually push the *tag* of the release also to 282 https://gitlab.com/wg1/jpeg-xl, by doing 283 284 ```bash 285 git push gitlab v0.7.1 286 ``` 287 where `gitlab` is the remote `git@gitlab.com:wg1/jpeg-xl.git`. 288 289 ### How to build downstream projects 290 291 ```bash 292 docker run -it debian:bookworm /bin/bash 293 294 apt update 295 apt install -y clang cmake git libbrotli-dev nasm pkg-config ninja-build 296 export CC=clang 297 export CXX=clang++ 298 299 mkdir -p /src 300 cd /src 301 302 git clone --recurse-submodules --depth 1 -b v0.9.x \ 303 https://github.com/libjxl/libjxl.git 304 git clone --recurse-submodules --depth 1 \ 305 https://github.com/ImageMagick/ImageMagick.git 306 git clone --recurse-submodules --depth 1 \ 307 https://github.com/FFmpeg/FFmpeg.git 308 309 cd /src/libjxl 310 cmake -B build -G Ninja . 311 cmake --build build -j`nproc` 312 cmake --install build --prefix="/usr" 313 314 cd /src/ImageMagick 315 ./configure --with-jxl=yes 316 # check for "JPEG XL --with-jxl=yes yes" 317 make -j `nproc` 318 ./utilities/magick -version 319 320 cd /src/FFmpeg 321 ./configure --disable-all --disable-debug --enable-avcodec --enable-avfilter \ 322 --enable-avformat --enable-libjxl --enable-encoder=libjxl \ 323 --enable-decoder=libjxl --enable-ffmpeg 324 # check for libjxl decoder/encoder support 325 make -j `nproc` 326 ldd ./ffmpeg 327 ./ffmpeg -version 328 ```