Files
cpp-core/RELEASE-PROCESS.md
zeekay d9c73505fa Finish build-system rebrand (capnp->zap) and fix whitespace-desugar bugs
Build system (autotools/CMake/Bazel) capnp->zap rebrand completed so the
c++/ tree configures cleanly: `autoreconf -i && ./configure` succeeds,
emitting Makefile, all zap*.pc / kj*.pc and the Zap CMake config. configure.ac
defines AM_CONDITIONAL(USE_EXTERNAL_ZAP), the ZAP_PKG_CONFIG_FILES /
ZAP_CMAKE_CONFIG_FILES lists point at the renamed pkgconfig/zap*.pc.in and
cmake/Zap*.cmake.in, and Makefile.am's `if USE_EXTERNAL_ZAP` matches. Bazel
loads @zap-cpp//src/zap:cc_zap_library.bzl. Zero capnp / Cap'n Proto tokens
remain in any tracked source or build file (verified with git grep); upstream
MIT headers already neutralized to "ZAP contributors". quick-test.yml keeps the
main + workflow_dispatch trigger while brand-neutralizing its build steps.

Whitespace-significant schema desugar (compiler/desugar.c++) — fix three HIGH
correctness bugs and make the preprocessor total:

  * Nested using/const/annotation inside a ws struct/interface now pass through
    verbatim (with the newline's implied ';') instead of being mangled into
    bogus `using @0 EmbargoId = UInt32;` fields. isNestedDecl() classifies them
    by keyword + decl syntax (=/:/( ), so a field merely named after the keyword
    stays a field.
  * Ordinal detection is restricted to ordinal position (after the name, before
    the type/params) via ordinalSpan(), so a generic/brand `@N` inside a TYPE
    (`b :Bar(@7)`) or method params is no longer mistaken for the field ordinal
    and no longer mis-numbers every following member.
  * Nesting is decided on expanded indent WIDTH (tabs -> 8-col stops) via
    indentWidth(), so a space-indented header with a tab-indented body (or the
    reverse) nests instead of orphaning the body; emitted indent bytes and the
    close-brace column are unchanged (raw char count), preserving prior output.
  * Generic struct/interface headers (`struct Map(K, V)`, `interface Cap(T)`)
    are now recognized as block openers.
  * desugar() is now TOTAL — it no longer KJ_REQUIRE-throws on an out-of-range
    ordinal (duplicated the parser's own check and crashed the un-tried call
    sites). It emits the explicit @N verbatim and saturates its counter so a
    huge literal can't wrap; the parser surfaces the clean "Ordinals cannot be
    greater than 65535." diagnostic at the right file:line:col. Removed the now
    redundant validateAutoOrdinal and the dead kj/debug.h include. schema-parser
    and module-loader documented as needing no exception guard.

desugar-test.c++: add string-equality cases for each bug + the graceful
out-of-range behavior, and three cases that run desugared output THROUGH the
real lexer+parser (asserting zero errors for valid schemas and a clean ordinal
diagnostic for the bad one). Brace back-compat proven byte-identical over the
18-file corpus; sample.ws.zap still desugars to sample.brace.zap exactly.
2026-06-20 00:02:20 -07:00

3.3 KiB

How to release

Developing

  • First, develop some new features to release! As you do, make sure to keep the documentation up-to-date.

Testing

  • Run super-test.sh on as many platforms as you have available. Remember that you can easily run on any machine available through ssh using ./super-test.sh remote [hostname]. Also run in Clang mode. (If you are Kenton and running from Kenton's home machine and network, use ./mega-test.py mega-test.cfg to run on all supported compilers and platforms.)

  • Manually test Windows/MSVC -- unfortunately this can't be automated by super-test.sh.

  • Manually run the pointer fuzz tests under Valgrind. This will take 40-80 minutes.

    valgrind ./zap-test -fzap/fuzz-test.c++
    
  • Manually run the AFL fuzz tests by running afl-fuzz.sh. There are three test cases, and ideally each should run for 24 hours or more.

Documenting

  • Write a blog post discussing what is new, placing it in doc/_posts.

  • Run jekyll locally and review the blog post and docs.

Releasing

  • Check out the master branch in a fresh directory. Do NOT use your regular repo, as the release script commits changes and if anything goes wrong you'll probably want to trash the whole thing without pushing. DO NOT git clone the repo from an existing local repo -- check it out directly from github. Otherwise, when it pushes its changes back, they'll only be pushed back to your local repo.

  • Run ./release.sh candidate. This creates a new release branch, updates the version number to -rc1, builds release tarballs, copies them to the current directory, then switches back to the master branch and bumps the version number there. After asking for final confirmation, it will upload the tarball to S3 and push all changes back to github.

  • Install your release candidates on your local machine, as if you were a user.

  • Go to c++/samples in the git repo and run ./test.sh. It will try to build against your installed copy.

  • Post the release candidates somewhere public and then send links to the mailing list for people to test. Wait a bit for bug reports.

  • If there are any problems, fix them in master and start a new release candidate by running ./release.sh candidate <commit>... from the release branch. This will cherry-pick the specified commits into the release branch and create a new candidate. Repeat until all problems are fixed. Be sure that any such fixes include tests or process changes so that they don't happen again.

  • You should now be ready for an official release. Run ./release.sh final. This will remove the "-rcN" suffix from the version number, update the version number shown on the downloads page, build the final release package, and -- after final confirmation -- upload the binary, push changes to git, and publish the new documentation.

  • Submit the newly-published blog post to news sites and social media as you see fit.

  • If problems are discovered in the release, fix them in master and run ./release.sh candidate <commit>... in the release branch to start a new micro release. The script automatically sees that the current branch's version no longer contains -rc, so it starts a new branch. Repeat the rest of the process above. If you decide to write a blog post (not always necessary), do it in the master branch and cherry-pick it.