tigerbeetle 0.0.34 → 0.0.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/ext/tb_client/extconf.rb +13 -13
  4. data/ext/tb_client/tigerbeetle/LICENSE +177 -0
  5. data/ext/tb_client/tigerbeetle/build.zig +2327 -0
  6. data/ext/tb_client/tigerbeetle/src/aof.zig +1000 -0
  7. data/ext/tb_client/tigerbeetle/src/build_multiversion.zig +808 -0
  8. data/ext/tb_client/tigerbeetle/src/cdc/amqp/protocol.zig +1283 -0
  9. data/ext/tb_client/tigerbeetle/src/cdc/amqp/spec.zig +1704 -0
  10. data/ext/tb_client/tigerbeetle/src/cdc/amqp/types.zig +341 -0
  11. data/ext/tb_client/tigerbeetle/src/cdc/amqp.zig +1450 -0
  12. data/ext/tb_client/tigerbeetle/src/cdc/runner.zig +1659 -0
  13. data/ext/tb_client/tigerbeetle/src/clients/c/samples/main.c +406 -0
  14. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/context.zig +1084 -0
  15. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/echo_client.zig +286 -0
  16. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/packet.zig +158 -0
  17. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal.zig +229 -0
  18. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal_fuzz.zig +110 -0
  19. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.h +386 -0
  20. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.zig +34 -0
  21. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_exports.zig +281 -0
  22. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header.zig +312 -0
  23. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header_test.zig +138 -0
  24. data/ext/tb_client/tigerbeetle/src/clients/c/test.zig +466 -0
  25. data/ext/tb_client/tigerbeetle/src/clients/docs_samples.zig +157 -0
  26. data/ext/tb_client/tigerbeetle/src/clients/docs_types.zig +90 -0
  27. data/ext/tb_client/tigerbeetle/src/clients/dotnet/ci.zig +203 -0
  28. data/ext/tb_client/tigerbeetle/src/clients/dotnet/docs.zig +79 -0
  29. data/ext/tb_client/tigerbeetle/src/clients/dotnet/dotnet_bindings.zig +542 -0
  30. data/ext/tb_client/tigerbeetle/src/clients/go/ci.zig +109 -0
  31. data/ext/tb_client/tigerbeetle/src/clients/go/docs.zig +86 -0
  32. data/ext/tb_client/tigerbeetle/src/clients/go/go_bindings.zig +370 -0
  33. data/ext/tb_client/tigerbeetle/src/clients/go/pkg/native/tb_client.h +386 -0
  34. data/ext/tb_client/tigerbeetle/src/clients/java/ci.zig +167 -0
  35. data/ext/tb_client/tigerbeetle/src/clients/java/docs.zig +126 -0
  36. data/ext/tb_client/tigerbeetle/src/clients/java/java_bindings.zig +996 -0
  37. data/ext/tb_client/tigerbeetle/src/clients/java/src/client.zig +748 -0
  38. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni.zig +3238 -0
  39. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_tests.zig +1718 -0
  40. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_thread_cleaner.zig +190 -0
  41. data/ext/tb_client/tigerbeetle/src/clients/node/ci.zig +104 -0
  42. data/ext/tb_client/tigerbeetle/src/clients/node/docs.zig +75 -0
  43. data/ext/tb_client/tigerbeetle/src/clients/node/node.zig +522 -0
  44. data/ext/tb_client/tigerbeetle/src/clients/node/node_bindings.zig +267 -0
  45. data/ext/tb_client/tigerbeetle/src/clients/node/src/c.zig +3 -0
  46. data/ext/tb_client/tigerbeetle/src/clients/node/src/translate.zig +379 -0
  47. data/ext/tb_client/tigerbeetle/src/clients/python/ci.zig +131 -0
  48. data/ext/tb_client/tigerbeetle/src/clients/python/docs.zig +63 -0
  49. data/ext/tb_client/tigerbeetle/src/clients/python/python_bindings.zig +588 -0
  50. data/ext/tb_client/tigerbeetle/src/clients/rust/assets/tb_client.h +386 -0
  51. data/ext/tb_client/tigerbeetle/src/clients/rust/ci.zig +73 -0
  52. data/ext/tb_client/tigerbeetle/src/clients/rust/docs.zig +106 -0
  53. data/ext/tb_client/tigerbeetle/src/clients/rust/rust_bindings.zig +305 -0
  54. data/ext/tb_client/tigerbeetle/src/config.zig +296 -0
  55. data/ext/tb_client/tigerbeetle/src/constants.zig +790 -0
  56. data/ext/tb_client/tigerbeetle/src/copyhound.zig +202 -0
  57. data/ext/tb_client/tigerbeetle/src/counting_allocator.zig +72 -0
  58. data/ext/tb_client/tigerbeetle/src/direction.zig +11 -0
  59. data/ext/tb_client/tigerbeetle/src/docs_website/build.zig +158 -0
  60. data/ext/tb_client/tigerbeetle/src/docs_website/src/content.zig +156 -0
  61. data/ext/tb_client/tigerbeetle/src/docs_website/src/docs.zig +252 -0
  62. data/ext/tb_client/tigerbeetle/src/docs_website/src/file_checker.zig +313 -0
  63. data/ext/tb_client/tigerbeetle/src/docs_website/src/html.zig +87 -0
  64. data/ext/tb_client/tigerbeetle/src/docs_website/src/page_writer.zig +63 -0
  65. data/ext/tb_client/tigerbeetle/src/docs_website/src/redirects.zig +47 -0
  66. data/ext/tb_client/tigerbeetle/src/docs_website/src/search_index_writer.zig +28 -0
  67. data/ext/tb_client/tigerbeetle/src/docs_website/src/service_worker_writer.zig +61 -0
  68. data/ext/tb_client/tigerbeetle/src/docs_website/src/single_page_writer.zig +169 -0
  69. data/ext/tb_client/tigerbeetle/src/docs_website/src/website.zig +46 -0
  70. data/ext/tb_client/tigerbeetle/src/ewah.zig +445 -0
  71. data/ext/tb_client/tigerbeetle/src/ewah_benchmark.zig +128 -0
  72. data/ext/tb_client/tigerbeetle/src/ewah_fuzz.zig +171 -0
  73. data/ext/tb_client/tigerbeetle/src/fuzz_tests.zig +179 -0
  74. data/ext/tb_client/tigerbeetle/src/integration_tests.zig +662 -0
  75. data/ext/tb_client/tigerbeetle/src/io/common.zig +155 -0
  76. data/ext/tb_client/tigerbeetle/src/io/darwin.zig +1093 -0
  77. data/ext/tb_client/tigerbeetle/src/io/linux.zig +1880 -0
  78. data/ext/tb_client/tigerbeetle/src/io/test.zig +1005 -0
  79. data/ext/tb_client/tigerbeetle/src/io/windows.zig +1598 -0
  80. data/ext/tb_client/tigerbeetle/src/io.zig +34 -0
  81. data/ext/tb_client/tigerbeetle/src/iops.zig +134 -0
  82. data/ext/tb_client/tigerbeetle/src/list.zig +236 -0
  83. data/ext/tb_client/tigerbeetle/src/lsm/binary_search.zig +848 -0
  84. data/ext/tb_client/tigerbeetle/src/lsm/binary_search_benchmark.zig +179 -0
  85. data/ext/tb_client/tigerbeetle/src/lsm/cache_map.zig +424 -0
  86. data/ext/tb_client/tigerbeetle/src/lsm/cache_map_fuzz.zig +420 -0
  87. data/ext/tb_client/tigerbeetle/src/lsm/compaction.zig +2117 -0
  88. data/ext/tb_client/tigerbeetle/src/lsm/composite_key.zig +182 -0
  89. data/ext/tb_client/tigerbeetle/src/lsm/forest.zig +1119 -0
  90. data/ext/tb_client/tigerbeetle/src/lsm/forest_fuzz.zig +1102 -0
  91. data/ext/tb_client/tigerbeetle/src/lsm/forest_table_iterator.zig +200 -0
  92. data/ext/tb_client/tigerbeetle/src/lsm/groove.zig +1495 -0
  93. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge.zig +739 -0
  94. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge_benchmark.zig +166 -0
  95. data/ext/tb_client/tigerbeetle/src/lsm/manifest.zig +754 -0
  96. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level.zig +1294 -0
  97. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level_fuzz.zig +510 -0
  98. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log.zig +1263 -0
  99. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log_fuzz.zig +628 -0
  100. data/ext/tb_client/tigerbeetle/src/lsm/node_pool.zig +247 -0
  101. data/ext/tb_client/tigerbeetle/src/lsm/scan_buffer.zig +116 -0
  102. data/ext/tb_client/tigerbeetle/src/lsm/scan_builder.zig +543 -0
  103. data/ext/tb_client/tigerbeetle/src/lsm/scan_fuzz.zig +938 -0
  104. data/ext/tb_client/tigerbeetle/src/lsm/scan_lookup.zig +293 -0
  105. data/ext/tb_client/tigerbeetle/src/lsm/scan_merge.zig +362 -0
  106. data/ext/tb_client/tigerbeetle/src/lsm/scan_range.zig +99 -0
  107. data/ext/tb_client/tigerbeetle/src/lsm/scan_state.zig +17 -0
  108. data/ext/tb_client/tigerbeetle/src/lsm/scan_tree.zig +1036 -0
  109. data/ext/tb_client/tigerbeetle/src/lsm/schema.zig +617 -0
  110. data/ext/tb_client/tigerbeetle/src/lsm/scratch_memory.zig +84 -0
  111. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array.zig +1500 -0
  112. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_benchmark.zig +149 -0
  113. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_fuzz.zig +7 -0
  114. data/ext/tb_client/tigerbeetle/src/lsm/set_associative_cache.zig +865 -0
  115. data/ext/tb_client/tigerbeetle/src/lsm/table.zig +607 -0
  116. data/ext/tb_client/tigerbeetle/src/lsm/table_memory.zig +843 -0
  117. data/ext/tb_client/tigerbeetle/src/lsm/table_value_iterator.zig +105 -0
  118. data/ext/tb_client/tigerbeetle/src/lsm/timestamp_range.zig +40 -0
  119. data/ext/tb_client/tigerbeetle/src/lsm/tree.zig +630 -0
  120. data/ext/tb_client/tigerbeetle/src/lsm/tree_fuzz.zig +933 -0
  121. data/ext/tb_client/tigerbeetle/src/lsm/zig_zag_merge.zig +557 -0
  122. data/ext/tb_client/tigerbeetle/src/message_buffer.zig +469 -0
  123. data/ext/tb_client/tigerbeetle/src/message_bus.zig +1214 -0
  124. data/ext/tb_client/tigerbeetle/src/message_bus_fuzz.zig +936 -0
  125. data/ext/tb_client/tigerbeetle/src/message_pool.zig +343 -0
  126. data/ext/tb_client/tigerbeetle/src/multiversion.zig +2195 -0
  127. data/ext/tb_client/tigerbeetle/src/queue.zig +390 -0
  128. data/ext/tb_client/tigerbeetle/src/repl/completion.zig +201 -0
  129. data/ext/tb_client/tigerbeetle/src/repl/parser.zig +1356 -0
  130. data/ext/tb_client/tigerbeetle/src/repl/terminal.zig +496 -0
  131. data/ext/tb_client/tigerbeetle/src/repl.zig +1034 -0
  132. data/ext/tb_client/tigerbeetle/src/scripts/amqp.zig +973 -0
  133. data/ext/tb_client/tigerbeetle/src/scripts/cfo.zig +1866 -0
  134. data/ext/tb_client/tigerbeetle/src/scripts/changelog.zig +304 -0
  135. data/ext/tb_client/tigerbeetle/src/scripts/ci.zig +227 -0
  136. data/ext/tb_client/tigerbeetle/src/scripts/client_readmes.zig +658 -0
  137. data/ext/tb_client/tigerbeetle/src/scripts/devhub.zig +466 -0
  138. data/ext/tb_client/tigerbeetle/src/scripts/release.zig +1058 -0
  139. data/ext/tb_client/tigerbeetle/src/scripts.zig +105 -0
  140. data/ext/tb_client/tigerbeetle/src/shell.zig +1195 -0
  141. data/ext/tb_client/tigerbeetle/src/stack.zig +260 -0
  142. data/ext/tb_client/tigerbeetle/src/state_machine/auditor.zig +911 -0
  143. data/ext/tb_client/tigerbeetle/src/state_machine/workload.zig +2079 -0
  144. data/ext/tb_client/tigerbeetle/src/state_machine.zig +4872 -0
  145. data/ext/tb_client/tigerbeetle/src/state_machine_fuzz.zig +288 -0
  146. data/ext/tb_client/tigerbeetle/src/state_machine_tests.zig +3128 -0
  147. data/ext/tb_client/tigerbeetle/src/static_allocator.zig +82 -0
  148. data/ext/tb_client/tigerbeetle/src/stdx/bit_set.zig +157 -0
  149. data/ext/tb_client/tigerbeetle/src/stdx/bounded_array.zig +292 -0
  150. data/ext/tb_client/tigerbeetle/src/stdx/debug.zig +65 -0
  151. data/ext/tb_client/tigerbeetle/src/stdx/flags.zig +1414 -0
  152. data/ext/tb_client/tigerbeetle/src/stdx/mlock.zig +92 -0
  153. data/ext/tb_client/tigerbeetle/src/stdx/prng.zig +677 -0
  154. data/ext/tb_client/tigerbeetle/src/stdx/radix.zig +336 -0
  155. data/ext/tb_client/tigerbeetle/src/stdx/ring_buffer.zig +511 -0
  156. data/ext/tb_client/tigerbeetle/src/stdx/sort_test.zig +112 -0
  157. data/ext/tb_client/tigerbeetle/src/stdx/stdx.zig +1160 -0
  158. data/ext/tb_client/tigerbeetle/src/stdx/testing/low_level_hash_vectors.zig +142 -0
  159. data/ext/tb_client/tigerbeetle/src/stdx/testing/snaptest.zig +361 -0
  160. data/ext/tb_client/tigerbeetle/src/stdx/time_units.zig +275 -0
  161. data/ext/tb_client/tigerbeetle/src/stdx/unshare.zig +295 -0
  162. data/ext/tb_client/tigerbeetle/src/stdx/vendored/aegis.zig +436 -0
  163. data/ext/tb_client/tigerbeetle/src/stdx/windows.zig +48 -0
  164. data/ext/tb_client/tigerbeetle/src/stdx/zipfian.zig +402 -0
  165. data/ext/tb_client/tigerbeetle/src/storage.zig +489 -0
  166. data/ext/tb_client/tigerbeetle/src/storage_fuzz.zig +180 -0
  167. data/ext/tb_client/tigerbeetle/src/testing/bench.zig +146 -0
  168. data/ext/tb_client/tigerbeetle/src/testing/cluster/grid_checker.zig +53 -0
  169. data/ext/tb_client/tigerbeetle/src/testing/cluster/journal_checker.zig +61 -0
  170. data/ext/tb_client/tigerbeetle/src/testing/cluster/manifest_checker.zig +76 -0
  171. data/ext/tb_client/tigerbeetle/src/testing/cluster/message_bus.zig +110 -0
  172. data/ext/tb_client/tigerbeetle/src/testing/cluster/network.zig +412 -0
  173. data/ext/tb_client/tigerbeetle/src/testing/cluster/state_checker.zig +331 -0
  174. data/ext/tb_client/tigerbeetle/src/testing/cluster/storage_checker.zig +458 -0
  175. data/ext/tb_client/tigerbeetle/src/testing/cluster.zig +1198 -0
  176. data/ext/tb_client/tigerbeetle/src/testing/exhaustigen.zig +128 -0
  177. data/ext/tb_client/tigerbeetle/src/testing/fixtures.zig +181 -0
  178. data/ext/tb_client/tigerbeetle/src/testing/fuzz.zig +144 -0
  179. data/ext/tb_client/tigerbeetle/src/testing/id.zig +97 -0
  180. data/ext/tb_client/tigerbeetle/src/testing/io.zig +317 -0
  181. data/ext/tb_client/tigerbeetle/src/testing/marks.zig +126 -0
  182. data/ext/tb_client/tigerbeetle/src/testing/packet_simulator.zig +533 -0
  183. data/ext/tb_client/tigerbeetle/src/testing/reply_sequence.zig +154 -0
  184. data/ext/tb_client/tigerbeetle/src/testing/state_machine.zig +389 -0
  185. data/ext/tb_client/tigerbeetle/src/testing/storage.zig +1247 -0
  186. data/ext/tb_client/tigerbeetle/src/testing/table.zig +249 -0
  187. data/ext/tb_client/tigerbeetle/src/testing/time.zig +98 -0
  188. data/ext/tb_client/tigerbeetle/src/testing/tmp_tigerbeetle.zig +212 -0
  189. data/ext/tb_client/tigerbeetle/src/testing/vortex/constants.zig +26 -0
  190. data/ext/tb_client/tigerbeetle/src/testing/vortex/faulty_network.zig +580 -0
  191. data/ext/tb_client/tigerbeetle/src/testing/vortex/java_driver/ci.zig +39 -0
  192. data/ext/tb_client/tigerbeetle/src/testing/vortex/logged_process.zig +214 -0
  193. data/ext/tb_client/tigerbeetle/src/testing/vortex/rust_driver/ci.zig +34 -0
  194. data/ext/tb_client/tigerbeetle/src/testing/vortex/supervisor.zig +766 -0
  195. data/ext/tb_client/tigerbeetle/src/testing/vortex/workload.zig +543 -0
  196. data/ext/tb_client/tigerbeetle/src/testing/vortex/zig_driver.zig +181 -0
  197. data/ext/tb_client/tigerbeetle/src/tidy.zig +1448 -0
  198. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_driver.zig +227 -0
  199. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_load.zig +1069 -0
  200. data/ext/tb_client/tigerbeetle/src/tigerbeetle/cli.zig +1422 -0
  201. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect.zig +1658 -0
  202. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect_integrity.zig +518 -0
  203. data/ext/tb_client/tigerbeetle/src/tigerbeetle/libtb_client.zig +36 -0
  204. data/ext/tb_client/tigerbeetle/src/tigerbeetle/main.zig +646 -0
  205. data/ext/tb_client/tigerbeetle/src/tigerbeetle.zig +958 -0
  206. data/ext/tb_client/tigerbeetle/src/time.zig +236 -0
  207. data/ext/tb_client/tigerbeetle/src/trace/event.zig +745 -0
  208. data/ext/tb_client/tigerbeetle/src/trace/statsd.zig +462 -0
  209. data/ext/tb_client/tigerbeetle/src/trace.zig +556 -0
  210. data/ext/tb_client/tigerbeetle/src/unit_tests.zig +321 -0
  211. data/ext/tb_client/tigerbeetle/src/vopr.zig +1785 -0
  212. data/ext/tb_client/tigerbeetle/src/vortex.zig +101 -0
  213. data/ext/tb_client/tigerbeetle/src/vsr/checkpoint_trailer.zig +473 -0
  214. data/ext/tb_client/tigerbeetle/src/vsr/checksum.zig +208 -0
  215. data/ext/tb_client/tigerbeetle/src/vsr/checksum_benchmark.zig +43 -0
  216. data/ext/tb_client/tigerbeetle/src/vsr/client.zig +768 -0
  217. data/ext/tb_client/tigerbeetle/src/vsr/client_replies.zig +532 -0
  218. data/ext/tb_client/tigerbeetle/src/vsr/client_sessions.zig +338 -0
  219. data/ext/tb_client/tigerbeetle/src/vsr/clock.zig +1019 -0
  220. data/ext/tb_client/tigerbeetle/src/vsr/fault_detector.zig +279 -0
  221. data/ext/tb_client/tigerbeetle/src/vsr/free_set.zig +1381 -0
  222. data/ext/tb_client/tigerbeetle/src/vsr/free_set_fuzz.zig +315 -0
  223. data/ext/tb_client/tigerbeetle/src/vsr/grid.zig +1460 -0
  224. data/ext/tb_client/tigerbeetle/src/vsr/grid_blocks_missing.zig +757 -0
  225. data/ext/tb_client/tigerbeetle/src/vsr/grid_scrubber.zig +797 -0
  226. data/ext/tb_client/tigerbeetle/src/vsr/journal.zig +2586 -0
  227. data/ext/tb_client/tigerbeetle/src/vsr/marzullo.zig +308 -0
  228. data/ext/tb_client/tigerbeetle/src/vsr/message_header.zig +1777 -0
  229. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch.zig +715 -0
  230. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch_fuzz.zig +185 -0
  231. data/ext/tb_client/tigerbeetle/src/vsr/repair_budget.zig +333 -0
  232. data/ext/tb_client/tigerbeetle/src/vsr/replica.zig +12355 -0
  233. data/ext/tb_client/tigerbeetle/src/vsr/replica_format.zig +416 -0
  234. data/ext/tb_client/tigerbeetle/src/vsr/replica_reformat.zig +165 -0
  235. data/ext/tb_client/tigerbeetle/src/vsr/replica_test.zig +2910 -0
  236. data/ext/tb_client/tigerbeetle/src/vsr/routing.zig +1075 -0
  237. data/ext/tb_client/tigerbeetle/src/vsr/superblock.zig +1603 -0
  238. data/ext/tb_client/tigerbeetle/src/vsr/superblock_fuzz.zig +484 -0
  239. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums.zig +405 -0
  240. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +355 -0
  241. data/ext/tb_client/tigerbeetle/src/vsr/sync.zig +29 -0
  242. data/ext/tb_client/tigerbeetle/src/vsr.zig +1727 -0
  243. data/lib/tb_client/shared_lib.rb +12 -5
  244. data/lib/tigerbeetle/client.rb +1 -1
  245. data/lib/tigerbeetle/platforms.rb +9 -0
  246. data/lib/tigerbeetle/version.rb +2 -2
  247. data/tigerbeetle.gemspec +22 -5
  248. metadata +242 -3
  249. data/ext/tb_client/pkg.tar.gz +0 -0
@@ -0,0 +1,1058 @@
1
+ //! Orchestrates building and publishing a distribution of tigerbeetle --- a collection of (source
2
+ //! and binary) artifacts which constitutes a release and which we upload to various registries.
3
+ //!
4
+ //! Concretely, the artifacts are:
5
+ //!
6
+ //! - TigerBeetle binary build for all supported architectures
7
+ //! - TigerBeetle clients build for all supported languages
8
+ //!
9
+ //! This is implemented as a standalone zig script, rather as a step in build.zig, because this is
10
+ //! a "meta" build system --- we need to orchestrate `zig build`, `go build`, `npm publish` and
11
+ //! friends, and treat them as peers.
12
+ //!
13
+ //! Note on verbosity: to ease debugging, try to keep the output to O(1) lines per command. The idea
14
+ //! here is that, if something goes wrong, you can see _what_ goes wrong and easily copy-paste
15
+ //! specific commands to your local terminal, but, at the same time, you don't want to sift through
16
+ //! megabytes of info-level noise first.
17
+
18
+ const builtin = @import("builtin");
19
+ const std = @import("std");
20
+ const stdx = @import("stdx");
21
+ const log = std.log;
22
+ const assert = std.debug.assert;
23
+
24
+ const Shell = @import("../shell.zig");
25
+ const multiversion = @import("../multiversion.zig");
26
+ const changelog = @import("./changelog.zig");
27
+
28
+ const MiB = stdx.MiB;
29
+
30
+ const multiversion_binary_size_max = multiversion.multiversion_binary_size_max;
31
+
32
+ const Language = enum { dotnet, go, java, node, python, rust, zig, docker };
33
+ const LanguageSet = std.enums.EnumSet(Language);
34
+ pub const CLIArgs = struct {
35
+ sha: []const u8,
36
+ language: ?Language = null,
37
+ build: bool = false,
38
+ publish: bool = false,
39
+ // Set if there's no changelog entry for the current code. That is, if the top changelog
40
+ // entry describes a past release, and not the release we are creating here.
41
+ //
42
+ // This flag is used to test the release process on the main branch.
43
+ no_changelog: bool = false,
44
+ // Allow targeting only production x86_64 Linux, to speed up when invoked via devhub.
45
+ devhub: bool = false,
46
+ };
47
+
48
+ const VersionInfo = struct {
49
+ // release_triple is a comptime parameter of the VSR used for the upgrade protocol.
50
+ release_triple: []const u8,
51
+ release_triple_client_min: []const u8,
52
+ // tag is the symbolic name of the release used as a git tag and a version for client libraries.
53
+ // Normally, the tag and the release_triple match, but it is possible to have different tags
54
+ // with matching release_triples, for hot-fixes.
55
+ tag: []const u8,
56
+ // The git tag/GitHub release to download to include in a multiversion binary.
57
+ tag_multiversion: []const u8,
58
+ commit_sha: []const u8,
59
+ commit_timestamp: stdx.InstantUnix,
60
+ };
61
+
62
+ pub fn main(shell: *Shell, gpa: std.mem.Allocator, cli_args: CLIArgs) !void {
63
+ _ = gpa;
64
+
65
+ const languages = if (cli_args.language) |language|
66
+ LanguageSet.initOne(language)
67
+ else
68
+ LanguageSet.initFull();
69
+
70
+ if (cli_args.devhub) {
71
+ if (cli_args.language == null or cli_args.language.? != .zig) {
72
+ @panic("--devhub is only supported with --languages=zig.");
73
+ }
74
+ }
75
+
76
+ const changelog_text = try shell.project_root.readFileAlloc(
77
+ shell.arena.allocator(),
78
+ "CHANGELOG.md",
79
+ 1 * MiB,
80
+ );
81
+ var changelog_iteratator = changelog.ChangelogIterator.init(changelog_text);
82
+ const release, const release_multiversion, const changelog_body = blk: {
83
+ if (cli_args.no_changelog) {
84
+ var last_release = changelog_iteratator.next_changelog().?;
85
+ while (last_release.release == null) {
86
+ last_release = changelog_iteratator.next_changelog().?;
87
+ }
88
+
89
+ break :blk .{
90
+ multiversion.Release.from(.{
91
+ .major = last_release.release.?.triple().major,
92
+ .minor = last_release.release.?.triple().minor,
93
+ .patch = last_release.release.?.triple().patch + 1,
94
+ }),
95
+ last_release.release.?,
96
+ "",
97
+ };
98
+ } else {
99
+ const changelog_current = changelog_iteratator.next_changelog().?;
100
+ if (changelog_current.release == null) {
101
+ @panic("The last changelog entry must have a release version.");
102
+ }
103
+ const changelog_previous = while (changelog_iteratator.next_changelog()) |entry| {
104
+ // The release number can be null if it was tagged as "unreleased".
105
+ if (entry.release == null) continue;
106
+ break entry;
107
+ } else unreachable;
108
+ break :blk .{
109
+ changelog_current.release.?,
110
+ changelog_previous.release.?,
111
+ changelog_current.text_body,
112
+ };
113
+ }
114
+ };
115
+ assert(multiversion.Release.less_than({}, release_multiversion, release));
116
+
117
+ // Ensure we're building a version newer than the first multiversion release. That was
118
+ // bootstrapped with code to do a custom build of the release before that (see git history)
119
+ // whereas now past binaries are downloaded and the multiversion parts extracted.
120
+ const first_multiversion_release = "0.15.4";
121
+ assert(release.value >
122
+ (try multiversion.Release.parse(first_multiversion_release)).value);
123
+
124
+ // The minimum client version allowed to connect. This has implications for backwards
125
+ // compatibility and the upgrade path for replicas and clients. If there's no overlap
126
+ // between a replica version and minimum client version - eg, replica 0.15.4 requires
127
+ // client 0.15.4 - it means that upgrading requires coordination with clients, which
128
+ // will be very inconvenient for operators.
129
+ const release_triple_client_min = .{
130
+ .major = 0,
131
+ .minor = 16,
132
+ .patch = 4,
133
+ }; // NB: grep for 'TODO(client_release)' after changing!
134
+
135
+ const version_info = VersionInfo{
136
+ .release_triple = try shell.fmt(
137
+ "{[major]}.{[minor]}.{[patch]}",
138
+ release.triple(),
139
+ ),
140
+ .release_triple_client_min = try shell.fmt(
141
+ "{[major]}.{[minor]}.{[patch]}",
142
+ release_triple_client_min,
143
+ ),
144
+ .tag = try shell.fmt(
145
+ "{[major]}.{[minor]}.{[patch]}",
146
+ release.triple(),
147
+ ),
148
+ .tag_multiversion = try shell.fmt(
149
+ "{[major]}.{[minor]}.{[patch]}",
150
+ release_multiversion.triple(),
151
+ ),
152
+ .commit_sha = cli_args.sha,
153
+ .commit_timestamp = try shell.git_commit_timestamp(cli_args.sha),
154
+ };
155
+
156
+ // Typically GitHub tag matches the release triple in the binary exactly. For exceptional
157
+ // hot-fix releases, the tag can be different. To make a hot-fix release, set the tag manually
158
+ // here and remove the assert.
159
+ assert(std.mem.eql(u8, version_info.release_triple, version_info.tag));
160
+
161
+ log.info("release={s} sha={s}", .{ version_info.release_triple, version_info.commit_sha });
162
+ if (!std.mem.eql(u8, version_info.release_triple, version_info.tag)) {
163
+ log.warn("tag != release, tag={s}", .{version_info.tag});
164
+ }
165
+
166
+ if (cli_args.build) {
167
+ try build(shell, languages, version_info, cli_args.devhub);
168
+ }
169
+
170
+ if (cli_args.publish) {
171
+ assert(!cli_args.no_changelog);
172
+ assert(!cli_args.devhub);
173
+ try publish(shell, languages, changelog_body, version_info);
174
+ }
175
+ }
176
+
177
+ fn build(shell: *Shell, languages: LanguageSet, info: VersionInfo, devhub: bool) !void {
178
+ var section = try shell.open_section("build all");
179
+ defer section.close();
180
+
181
+ try shell.project_root.deleteTree("zig-out/dist");
182
+ var dist_dir = try shell.project_root.makeOpenPath("zig-out/dist", .{});
183
+ defer dist_dir.close();
184
+
185
+ log.info("building TigerBeetle distribution into {s}", .{
186
+ try dist_dir.realpathAlloc(shell.arena.allocator(), "."),
187
+ });
188
+
189
+ if (languages.contains(.zig)) {
190
+ var dist_dir_tigerbeetle = try dist_dir.makeOpenPath("tigerbeetle", .{});
191
+ defer dist_dir_tigerbeetle.close();
192
+
193
+ if (devhub) {
194
+ try build_tigerbeetle_target(shell, info, dist_dir_tigerbeetle, false, "x86_64-linux");
195
+ } else {
196
+ try build_tigerbeetle(shell, info, dist_dir_tigerbeetle);
197
+ }
198
+
199
+ var dist_dir_vortex = try dist_dir.makeOpenPath("vortex", .{});
200
+ defer dist_dir_vortex.close();
201
+
202
+ const vortex_targets = .{
203
+ "x86_64-linux",
204
+ "aarch64-linux",
205
+ };
206
+ inline for (vortex_targets) |target| {
207
+ try build_vortex_driver_target(shell, info, dist_dir_vortex, target);
208
+ }
209
+ }
210
+
211
+ if (languages.contains(.dotnet)) {
212
+ var dist_dir_dotnet = try dist_dir.makeOpenPath("dotnet", .{});
213
+ defer dist_dir_dotnet.close();
214
+
215
+ try build_dotnet(shell, info, dist_dir_dotnet);
216
+ }
217
+
218
+ if (languages.contains(.go)) {
219
+ var dist_dir_go = try dist_dir.makeOpenPath("go", .{});
220
+ defer dist_dir_go.close();
221
+
222
+ try build_go(shell, info, dist_dir_go);
223
+ }
224
+
225
+ if (languages.contains(.java)) {
226
+ var dist_dir_java = try dist_dir.makeOpenPath("java", .{});
227
+ defer dist_dir_java.close();
228
+
229
+ try build_java(shell, info, dist_dir_java);
230
+ }
231
+
232
+ if (languages.contains(.node)) {
233
+ var dist_dir_node = try dist_dir.makeOpenPath("node", .{});
234
+ defer dist_dir_node.close();
235
+
236
+ try build_node(shell, info, dist_dir_node);
237
+ }
238
+
239
+ if (languages.contains(.python)) {
240
+ var dist_dir_python = try dist_dir.makeOpenPath("python", .{});
241
+ defer dist_dir_python.close();
242
+
243
+ try build_python(shell, info, dist_dir_python);
244
+ }
245
+
246
+ if (languages.contains(.rust)) {
247
+ // Currently disabled.
248
+ }
249
+ }
250
+
251
+ fn build_tigerbeetle(shell: *Shell, info: VersionInfo, dist_dir: std.fs.Dir) !void {
252
+ const targets = .{
253
+ "x86_64-linux",
254
+ "x86_64-windows",
255
+ "aarch64-linux",
256
+ "aarch64-macos", // Will build a universal binary.
257
+ };
258
+
259
+ inline for (.{ true, false }) |debug| {
260
+ inline for (targets) |target| {
261
+ try build_tigerbeetle_target(shell, info, dist_dir, debug, target);
262
+ }
263
+ }
264
+ }
265
+
266
+ fn build_tigerbeetle_target(
267
+ shell: *Shell,
268
+ info: VersionInfo,
269
+ dist_dir: std.fs.Dir,
270
+ comptime debug: bool,
271
+ comptime target: []const u8,
272
+ ) !void {
273
+ var section = try shell.open_section(
274
+ "build tigerbeetle - " ++ target ++ " debug=" ++ if (debug) "true" else "false",
275
+ );
276
+ defer section.close();
277
+
278
+ // Build tigerbeetle binary for all OS/CPU combinations we support and copy the result to
279
+ // `dist`.
280
+ try shell.exec_zig(
281
+ \\build
282
+ \\ -Dtarget={target}
283
+ \\ -Drelease={release}
284
+ \\ -Dgit-commit={commit}
285
+ \\ -Dconfig-release={release_triple}
286
+ \\ -Dconfig-release-client-min={release_triple_client_min}
287
+ \\ -Dmultiversion={tag_multiversion}
288
+ , .{
289
+ .target = target,
290
+ .release = if (debug) "false" else "true",
291
+ .commit = info.commit_sha,
292
+ .release_triple = info.release_triple,
293
+ .release_triple_client_min = info.release_triple_client_min,
294
+ .tag_multiversion = info.tag_multiversion,
295
+ });
296
+
297
+ const windows = comptime std.mem.eql(u8, target, "x86_64-windows");
298
+ const macos = comptime std.mem.eql(u8, target, "aarch64-macos");
299
+
300
+ const exe_name = "tigerbeetle" ++ if (windows) ".exe" else "";
301
+ const zip_name = "tigerbeetle-" ++
302
+ (if (macos) "universal-macos" else target) ++
303
+ (if (debug) "-debug" else "") ++
304
+ ".zip";
305
+
306
+ if ((std.mem.eql(u8, target, "x86_64-linux") and builtin.target.os.tag == .linux) or
307
+ (macos and builtin.target.os.tag == .macos) or
308
+ (windows and builtin.target.os.tag == .windows))
309
+ {
310
+ const output = try shell.exec_stdout("./{exe_name} version --verbose", .{
311
+ .exe_name = exe_name,
312
+ });
313
+ assert(debug == (std.mem.indexOf(u8, output, "process.verify=true") != null));
314
+ const build_mode = if (debug)
315
+ "build.mode=builtin.OptimizeMode.Debug"
316
+ else
317
+ "build.mode=builtin.OptimizeMode.ReleaseSafe";
318
+ assert(std.mem.indexOf(u8, output, build_mode) != null);
319
+ }
320
+
321
+ const zip_file = try dist_dir.createFile(zip_name, .{ .truncate = false, .exclusive = true });
322
+ defer zip_file.close();
323
+
324
+ try shell.zip_executable(
325
+ zip_file,
326
+ .{
327
+ .executable_name = exe_name,
328
+ .executable_mtime = info.commit_timestamp,
329
+ .max_size = multiversion.multiversion_binary_size_max,
330
+ },
331
+ );
332
+ }
333
+
334
+ fn build_vortex_driver_target(
335
+ shell: *Shell,
336
+ info: VersionInfo,
337
+ dist_dir: std.fs.Dir,
338
+ comptime target: []const u8,
339
+ ) !void {
340
+ var section = try shell.open_section("build vortex:driver:zig - " ++ target);
341
+ defer section.close();
342
+
343
+ try shell.exec_zig(
344
+ \\build vortex:driver:zig
345
+ \\ -Dtarget={target}
346
+ \\ -Dconfig-release={release_triple}
347
+ \\ -Dconfig-release-client-min={release_triple_client_min}
348
+ , .{
349
+ .target = target,
350
+ .release_triple = info.release_triple,
351
+ .release_triple_client_min = info.release_triple_client_min,
352
+ });
353
+
354
+ const zip_name = try shell.fmt("vortex-driver-zig-{s}.zip", .{target});
355
+ const zip_file = try dist_dir.createFile(zip_name, .{ .truncate = false, .exclusive = true });
356
+ defer zip_file.close();
357
+
358
+ try shell.pushd("./zig-out/bin");
359
+ defer shell.popd();
360
+
361
+ try shell.zip_executable(
362
+ zip_file,
363
+ .{
364
+ .executable_name = "vortex-driver-zig",
365
+ .executable_mtime = info.commit_timestamp,
366
+ .max_size = 16 * MiB,
367
+ },
368
+ );
369
+ }
370
+
371
+ fn build_dotnet(shell: *Shell, info: VersionInfo, dist_dir: std.fs.Dir) !void {
372
+ var section = try shell.open_section("build dotnet");
373
+ defer section.close();
374
+
375
+ try shell.pushd("./src/clients/dotnet");
376
+ defer shell.popd();
377
+
378
+ const dotnet_version = shell.exec_stdout("dotnet --version", .{}) catch {
379
+ return error.NoDotnet;
380
+ };
381
+ log.info("dotnet version {s}", .{dotnet_version});
382
+
383
+ try shell.exec_zig(
384
+ \\build clients:dotnet -Drelease -Dconfig-release={release_triple}
385
+ \\ -Dconfig-release-client-min={release_triple_client_min}
386
+ , .{
387
+ .release_triple = info.release_triple,
388
+ .release_triple_client_min = info.release_triple_client_min,
389
+ });
390
+ try shell.exec(
391
+ \\dotnet pack TigerBeetle --configuration Release
392
+ \\/p:AssemblyVersion={tag} /p:Version={tag}
393
+ , .{ .tag = info.tag });
394
+
395
+ try Shell.copy_path(
396
+ shell.cwd,
397
+ try shell.fmt("TigerBeetle/bin/Release/tigerbeetle.{s}.nupkg", .{info.tag}),
398
+ dist_dir,
399
+ try shell.fmt("tigerbeetle.{s}.nupkg", .{info.tag}),
400
+ );
401
+ }
402
+
403
+ fn build_go(shell: *Shell, info: VersionInfo, dist_dir: std.fs.Dir) !void {
404
+ var section = try shell.open_section("build go");
405
+ defer section.close();
406
+
407
+ try shell.pushd("./src/clients/go");
408
+ defer shell.popd();
409
+
410
+ try shell.exec_zig(
411
+ \\build clients:go -Drelease -Dconfig-release={release_triple}
412
+ \\ -Dconfig-release-client-min={release_triple_client_min}
413
+ , .{
414
+ .release_triple = info.release_triple,
415
+ .release_triple_client_min = info.release_triple_client_min,
416
+ });
417
+
418
+ const files = try shell.exec_stdout("git ls-files", .{});
419
+ var files_lines = std.mem.tokenizeScalar(u8, files, '\n');
420
+ var copied_count: u32 = 0;
421
+ while (files_lines.next()) |file| {
422
+ assert(file.len > 3);
423
+ try Shell.copy_path(shell.cwd, file, dist_dir, file);
424
+ copied_count += 1;
425
+ }
426
+ assert(copied_count >= 10);
427
+
428
+ const native_files = try shell.find(.{ .where = &.{"."}, .extensions = &.{ ".a", ".lib" } });
429
+ copied_count = 0;
430
+ for (native_files) |native_file| {
431
+ try Shell.copy_path(shell.cwd, native_file, dist_dir, native_file);
432
+ copied_count += 1;
433
+ }
434
+ // 5 = 3 + 2
435
+ // 3 = x86_64 for mac, windows and linux
436
+ // 2 = aarch64 for mac and linux
437
+ assert(copied_count == 5);
438
+
439
+ const readme = try shell.fmt(
440
+ \\# tigerbeetle-go
441
+ \\This repo has been automatically generated from
442
+ \\[tigerbeetle/tigerbeetle@{[sha]s}](https://github.com/tigerbeetle/tigerbeetle/commit/{[sha]s})
443
+ \\to keep binary blobs out of the monorepo.
444
+ \\
445
+ \\Please see
446
+ \\<https://github.com/tigerbeetle/tigerbeetle/tree/main/src/clients/go>
447
+ \\for documentation and contributions.
448
+ , .{ .sha = info.commit_sha });
449
+ try dist_dir.writeFile(.{ .sub_path = "README.md", .data = readme });
450
+ }
451
+
452
+ fn build_java(shell: *Shell, info: VersionInfo, dist_dir: std.fs.Dir) !void {
453
+ var section = try shell.open_section("build java");
454
+ defer section.close();
455
+
456
+ try shell.pushd("./src/clients/java");
457
+ defer shell.popd();
458
+
459
+ const java_version = shell.exec_stdout("java --version", .{}) catch {
460
+ return error.NoJava;
461
+ };
462
+ log.info("java version {s}", .{java_version});
463
+
464
+ try shell.exec_zig(
465
+ \\build clients:java -Drelease -Dconfig-release={release_triple}
466
+ \\ -Dconfig-release-client-min={release_triple_client_min}
467
+ , .{
468
+ .release_triple = info.release_triple,
469
+ .release_triple_client_min = info.release_triple_client_min,
470
+ });
471
+
472
+ try backup_create(shell.cwd, "pom.xml");
473
+ defer backup_restore(shell.cwd, "pom.xml");
474
+
475
+ try shell.exec(
476
+ \\mvn --batch-mode --quiet --file pom.xml
477
+ \\versions:set -DnewVersion={tag}
478
+ , .{ .tag = info.tag });
479
+
480
+ try shell.exec(
481
+ \\mvn --batch-mode --quiet --file pom.xml
482
+ \\ -Dmaven.test.skip -Djacoco.skip
483
+ \\ package
484
+ , .{});
485
+
486
+ try Shell.copy_path(
487
+ shell.cwd,
488
+ try shell.fmt("target/tigerbeetle-java-{s}.jar", .{info.tag}),
489
+ dist_dir,
490
+ try shell.fmt("tigerbeetle-java-{s}.jar", .{info.tag}),
491
+ );
492
+ }
493
+
494
+ fn build_node(shell: *Shell, info: VersionInfo, dist_dir: std.fs.Dir) !void {
495
+ var section = try shell.open_section("build node");
496
+ defer section.close();
497
+
498
+ try shell.pushd("./src/clients/node");
499
+ defer shell.popd();
500
+
501
+ const node_version = shell.exec_stdout("node --version", .{}) catch {
502
+ return error.NoNode;
503
+ };
504
+ log.info("node version {s}", .{node_version});
505
+
506
+ try shell.exec_zig(
507
+ \\build clients:node -Drelease -Dconfig-release={release_triple}
508
+ \\ -Dconfig-release-client-min={release_triple_client_min}
509
+ , .{
510
+ .release_triple = info.release_triple,
511
+ .release_triple_client_min = info.release_triple_client_min,
512
+ });
513
+
514
+ try backup_create(shell.cwd, "package.json");
515
+ defer backup_restore(shell.cwd, "package.json");
516
+
517
+ try backup_create(shell.cwd, "package-lock.json");
518
+ defer backup_restore(shell.cwd, "package-lock.json");
519
+
520
+ try shell.exec(
521
+ "npm version --no-git-tag-version {tag}",
522
+ .{ .tag = info.tag },
523
+ );
524
+ try shell.exec("npm ci", .{});
525
+ try shell.exec("npm pack --quiet", .{});
526
+
527
+ try Shell.copy_path(
528
+ shell.cwd,
529
+ try shell.fmt("tigerbeetle-node-{s}.tgz", .{info.tag}),
530
+ dist_dir,
531
+ try shell.fmt("tigerbeetle-node-{s}.tgz", .{info.tag}),
532
+ );
533
+ }
534
+
535
+ fn build_python(shell: *Shell, info: VersionInfo, dist_dir: std.fs.Dir) !void {
536
+ var section = try shell.open_section("build python");
537
+ defer section.close();
538
+
539
+ try shell.pushd("./src/clients/python");
540
+ defer shell.popd();
541
+
542
+ const python_version = shell.exec_stdout("python3 --version", .{}) catch {
543
+ return error.NoPython;
544
+ };
545
+ log.info("{s}", .{python_version});
546
+
547
+ try shell.exec_zig(
548
+ \\build clients:python -Drelease -Dconfig-release={release_triple}
549
+ \\ -Dconfig-release-client-min={release_triple_client_min}
550
+ , .{
551
+ .release_triple = info.release_triple,
552
+ .release_triple_client_min = info.release_triple_client_min,
553
+ });
554
+
555
+ try backup_create(shell.cwd, "pyproject.toml");
556
+ defer backup_restore(shell.cwd, "pyproject.toml");
557
+
558
+ const pyproject = try shell.cwd.readFileAlloc(
559
+ shell.arena.allocator(),
560
+ "pyproject.toml",
561
+ 1 * MiB,
562
+ );
563
+ const version_line = try shell.fmt(
564
+ "version = \"{s}\"",
565
+ .{info.tag},
566
+ );
567
+ const pyproject_updated = try std.mem.replaceOwned(
568
+ u8,
569
+ shell.arena.allocator(),
570
+ pyproject,
571
+ "version = \"0.0.1\"",
572
+ version_line,
573
+ );
574
+ assert(std.mem.indexOf(u8, pyproject_updated, version_line) != null);
575
+
576
+ try shell.cwd.writeFile(.{
577
+ .sub_path = "pyproject.toml",
578
+ .data = pyproject_updated,
579
+ });
580
+
581
+ try shell.exec("python3 -m build .", .{});
582
+
583
+ try Shell.copy_path(
584
+ shell.cwd,
585
+ try shell.fmt("dist/tigerbeetle-{s}-py3-none-any.whl", .{info.tag}),
586
+ dist_dir,
587
+ try shell.fmt("tigerbeetle-{s}-py3-none-any.whl", .{info.tag}),
588
+ );
589
+ }
590
+
591
+ fn publish(
592
+ shell: *Shell,
593
+ languages: LanguageSet,
594
+ changelog_body: []const u8,
595
+ info: VersionInfo,
596
+ ) !void {
597
+ var section = try shell.open_section("publish all");
598
+ defer section.close();
599
+
600
+ { // Sanity check that the new release doesn't exist but the multiversion does.
601
+ var tag_multiversion_exists = false;
602
+ var tag_exists = false;
603
+ const tags_exiting = try shell.exec_stdout(
604
+ "gh release list --json tagName --jq {query}",
605
+ .{ .query = ".[].tagName" },
606
+ );
607
+ var it = std.mem.splitScalar(u8, tags_exiting, '\n');
608
+ while (it.next()) |tag_existing| {
609
+ assert(std.mem.trim(u8, tag_existing, " \t\n\r").len == tag_existing.len);
610
+ if (std.mem.eql(u8, tag_existing, info.release_triple)) {
611
+ tag_exists = true;
612
+ }
613
+ if (std.mem.eql(u8, tag_existing, info.tag_multiversion)) {
614
+ tag_multiversion_exists = true;
615
+ }
616
+ }
617
+ assert(!tag_exists);
618
+ assert(tag_multiversion_exists);
619
+ }
620
+
621
+ assert(try shell.dir_exists("zig-out/dist"));
622
+
623
+ if (languages.contains(.zig)) {
624
+ _ = try shell.env_get("GITHUB_TOKEN");
625
+ const gh_version = shell.exec_stdout("gh --version", .{}) catch {
626
+ return error.NoGh;
627
+ };
628
+ log.info("gh version {s}", .{gh_version});
629
+
630
+ const release_included_min = blk: {
631
+ shell.project_root.deleteFile("tigerbeetle") catch {};
632
+ defer shell.project_root.deleteFile("tigerbeetle") catch {};
633
+
634
+ try shell.unzip_executable(
635
+ "zig-out/dist/tigerbeetle/tigerbeetle-x86_64-linux.zip",
636
+ "tigerbeetle",
637
+ );
638
+
639
+ const past_binary_contents = try shell.cwd.readFileAllocOptions(
640
+ shell.arena.allocator(),
641
+ "tigerbeetle",
642
+ multiversion_binary_size_max,
643
+ null,
644
+ 8,
645
+ null,
646
+ );
647
+
648
+ const parsed_offsets = try multiversion.parse_elf(past_binary_contents);
649
+ const header_bytes =
650
+ past_binary_contents[parsed_offsets.x86_64.?.header_offset..][0..@sizeOf(
651
+ multiversion.MultiversionHeader,
652
+ )];
653
+
654
+ const header = try multiversion.MultiversionHeader.init_from_bytes(header_bytes);
655
+ const release_min = header.past.releases[0];
656
+ const release_max = header.past.releases[header.past.count - 1];
657
+ assert(release_min < release_max);
658
+
659
+ break :blk multiversion.Release{ .value = release_min };
660
+ };
661
+
662
+ const notes = try shell.fmt(
663
+ \\# {[tag]s}
664
+ \\
665
+ \\### Supported upgrade versions
666
+ \\
667
+ \\Oldest supported client version: {[release_triple_client_min]s}
668
+ \\Oldest upgradable replica version: {[release_included_min]s}
669
+ \\
670
+ \\## Server
671
+ \\
672
+ \\* Binary: Download the zip for your OS and architecture from this page and unzip.
673
+ \\* Docker: `docker pull ghcr.io/tigerbeetle/tigerbeetle:{[tag]s}`
674
+ \\* Docker (debug image): `docker pull ghcr.io/tigerbeetle/tigerbeetle:{[tag]s}-debug`
675
+ \\
676
+ \\## Clients
677
+ \\
678
+ \\**NOTE**: Because of package manager caching, it may take a few
679
+ \\minutes after the release for this version to appear in the package
680
+ \\manager.
681
+ \\
682
+ \\You cannot run a newer client against an older cluster: clients are only compatible
683
+ \\with replicas from their own release *or newer*, subject to the newer release's
684
+ \\`Oldest supported client version`.
685
+ \\
686
+ \\* .NET: `dotnet add package tigerbeetle --version {[tag]s}`
687
+ \\* Go: `go mod edit -require github.com/tigerbeetle/tigerbeetle-go@v{[tag]s}`
688
+ \\* Java: Update the version of `com.tigerbeetle.tigerbeetle-java` in `pom.xml`
689
+ \\ to `{[tag]s}`.
690
+ \\* Node.js: `npm install --save-exact tigerbeetle-node@{[tag]s}`
691
+ \\* Python: `pip install tigerbeetle=={[tag]s}`
692
+ \\
693
+ \\## Changelog
694
+ \\
695
+ \\{[changelog]s}
696
+ , .{
697
+ .tag = info.tag,
698
+ .release_triple_client_min = info.release_triple_client_min,
699
+ .release_included_min = release_included_min,
700
+ .changelog = changelog_body,
701
+ });
702
+
703
+ try shell.exec(
704
+ \\gh release create --draft
705
+ \\ --target {sha}
706
+ \\ --notes {notes}
707
+ \\ {tag}
708
+ , .{
709
+ .sha = info.commit_sha,
710
+ .notes = notes,
711
+ .tag = info.tag,
712
+ });
713
+
714
+ // Here and elsewhere for publishing we explicitly spell out the files we are uploading
715
+ // instead of using a for loop to double-check the logic in `build`.
716
+ const artifacts: []const []const u8 = &.{
717
+ "zig-out/dist/tigerbeetle/tigerbeetle-aarch64-linux-debug.zip",
718
+ "zig-out/dist/tigerbeetle/tigerbeetle-aarch64-linux.zip",
719
+ "zig-out/dist/tigerbeetle/tigerbeetle-universal-macos-debug.zip",
720
+ "zig-out/dist/tigerbeetle/tigerbeetle-universal-macos.zip",
721
+ "zig-out/dist/tigerbeetle/tigerbeetle-x86_64-linux-debug.zip",
722
+ "zig-out/dist/tigerbeetle/tigerbeetle-x86_64-linux.zip",
723
+ "zig-out/dist/tigerbeetle/tigerbeetle-x86_64-windows-debug.zip",
724
+ "zig-out/dist/tigerbeetle/tigerbeetle-x86_64-windows.zip",
725
+ "zig-out/dist/vortex/vortex-driver-zig-aarch64-linux.zip",
726
+ "zig-out/dist/vortex/vortex-driver-zig-x86_64-linux.zip",
727
+ };
728
+ try shell.exec("gh release upload {tag} {artifacts}", .{
729
+ .tag = info.tag,
730
+ .artifacts = artifacts,
731
+ });
732
+ }
733
+
734
+ if (languages.contains(.docker)) try publish_docker(shell, info);
735
+ if (languages.contains(.dotnet)) try publish_dotnet(shell, info);
736
+ if (languages.contains(.go)) try publish_go(shell, info);
737
+ if (languages.contains(.java)) try publish_java(shell, info);
738
+ if (languages.contains(.node)) try publish_node(shell, info);
739
+ if (languages.contains(.python)) try publish_python(shell, info);
740
+
741
+ if (languages.contains(.zig)) {
742
+ try shell.exec(
743
+ \\gh release edit --draft=false --latest=true
744
+ \\ {tag}
745
+ , .{ .tag = info.tag });
746
+
747
+ // Build our docs last so that if it fails everything else is still released.
748
+ try publish_docs(shell, info);
749
+ }
750
+ }
751
+
752
+ fn publish_dotnet(shell: *Shell, info: VersionInfo) !void {
753
+ var section = try shell.open_section("publish dotnet");
754
+ defer section.close();
755
+
756
+ assert(try shell.dir_exists("zig-out/dist/dotnet"));
757
+
758
+ const nuget_key = try shell.env_get("NUGET_KEY");
759
+ try shell.exec(
760
+ \\dotnet nuget push
761
+ \\ --api-key {nuget_key}
762
+ \\ --source https://api.nuget.org/v3/index.json
763
+ \\ {package}
764
+ , .{
765
+ .nuget_key = nuget_key,
766
+ .package = try shell.fmt("zig-out/dist/dotnet/tigerbeetle.{s}.nupkg", .{
767
+ info.tag,
768
+ }),
769
+ });
770
+ }
771
+
772
+ fn publish_go(shell: *Shell, info: VersionInfo) !void {
773
+ var section = try shell.open_section("publish go");
774
+ defer section.close();
775
+
776
+ assert(try shell.dir_exists("zig-out/dist/go"));
777
+
778
+ const token = try shell.env_get("TIGERBEETLE_GO_PAT");
779
+ try shell.exec(
780
+ \\git clone --no-checkout --depth 1
781
+ \\ https://oauth2:{token}@github.com/tigerbeetle/tigerbeetle-go.git tigerbeetle-go
782
+ , .{ .token = token });
783
+ defer {
784
+ shell.project_root.deleteTree("tigerbeetle-go") catch {};
785
+ }
786
+
787
+ const dist_files = try shell.find(.{ .where = &.{"zig-out/dist/go"} });
788
+ assert(dist_files.len > 10);
789
+ for (dist_files) |file| {
790
+ try Shell.copy_path(
791
+ shell.project_root,
792
+ file,
793
+ shell.project_root,
794
+ try std.mem.replaceOwned(
795
+ u8,
796
+ shell.arena.allocator(),
797
+ file,
798
+ "zig-out/dist/go",
799
+ "tigerbeetle-go",
800
+ ),
801
+ );
802
+ }
803
+
804
+ try shell.pushd("./tigerbeetle-go");
805
+ defer shell.popd();
806
+
807
+ try shell.exec("git add .", .{});
808
+ // Native libraries are ignored in this repository, but we want to push them to the
809
+ // tigerbeetle-go one!
810
+ try shell.exec("git add --force pkg/native", .{});
811
+
812
+ try shell.git_env_setup(.{ .use_hostname = false });
813
+ try shell.exec("git commit --message {message}", .{
814
+ .message = try shell.fmt(
815
+ "Autogenerated commit from tigerbeetle/tigerbeetle@{s}",
816
+ .{info.commit_sha},
817
+ ),
818
+ });
819
+
820
+ try shell.exec("git tag tigerbeetle-{sha}", .{ .sha = info.commit_sha });
821
+ try shell.exec("git tag v{tag}", .{ .tag = info.tag });
822
+
823
+ try shell.exec("git push origin main", .{});
824
+ try shell.exec("git push origin tigerbeetle-{sha}", .{ .sha = info.commit_sha });
825
+ try shell.exec("git push origin v{tag}", .{ .tag = info.tag });
826
+ }
827
+
828
+ fn publish_java(shell: *Shell, info: VersionInfo) !void {
829
+ var section = try shell.open_section("publish java");
830
+ defer section.close();
831
+
832
+ assert(try shell.dir_exists("zig-out/dist/java"));
833
+
834
+ // These variables don't have a special meaning in maven, and instead are a part of
835
+ // settings.xml generated by GitHub actions.
836
+ _ = try shell.env_get("MAVEN_USERNAME");
837
+ _ = try shell.env_get("MAVEN_CENTRAL_TOKEN");
838
+ _ = try shell.env_get("MAVEN_GPG_PASSPHRASE");
839
+
840
+ // TODO: Maven uniquely doesn't support uploading pre-build package, so here we just rebuild
841
+ // from source and upload a _different_ artifact. This is wrong.
842
+ //
843
+ // As far as I can tell, there isn't a great solution here. See, for example:
844
+ //
845
+ // <https://users.maven.apache.narkive.com/jQ3WocgT/mvn-deploy-without-rebuilding>
846
+ //
847
+ // I think what we should do here is for `build` to deploy to the local repo, and then use
848
+ //
849
+ // <https://gist.github.com/rishabh9/183cc0c4c3ada4f8df94d65fcd73a502>
850
+ //
851
+ // to move the contents of that local repo to maven central. But this is todo, just rebuild now.
852
+ try backup_create(shell.project_root, "src/clients/java/pom.xml");
853
+ defer backup_restore(shell.project_root, "src/clients/java/pom.xml");
854
+
855
+ try shell.exec(
856
+ \\mvn --batch-mode --quiet --file src/clients/java/pom.xml
857
+ \\ versions:set -DnewVersion={tag}
858
+ , .{ .tag = info.tag });
859
+
860
+ // Retrying in case of timeout:
861
+ const attempts_max = 5;
862
+ for (0..attempts_max) |index| {
863
+ return shell.exec_options(.{ .timeout = .minutes(5) },
864
+ \\mvn --batch-mode --quiet --file src/clients/java/pom.xml
865
+ \\ -Dmaven.test.skip -Djacoco.skip
866
+ \\ deploy
867
+ , .{}) catch |err| switch (err) {
868
+ error.ExecTimeout => {
869
+ const attempt = index + 1;
870
+ log.warn("java deploy timed out. Attempt={}", .{attempt});
871
+ if (attempt == attempts_max) return err;
872
+ continue;
873
+ },
874
+ else => err,
875
+ };
876
+ } else unreachable;
877
+ }
878
+
879
+ fn publish_node(shell: *Shell, info: VersionInfo) !void {
880
+ var section = try shell.open_section("publish node");
881
+ defer section.close();
882
+
883
+ assert(try shell.dir_exists("zig-out/dist/node"));
884
+
885
+ try shell.exec("npm publish {package}", .{
886
+ .package = try shell.fmt("zig-out/dist/node/tigerbeetle-node-{s}.tgz", .{
887
+ info.tag,
888
+ }),
889
+ });
890
+ }
891
+
892
+ fn publish_python(shell: *Shell, info: VersionInfo) !void {
893
+ var section = try shell.open_section("publish python");
894
+ defer section.close();
895
+
896
+ assert(try shell.dir_exists("zig-out/dist/python"));
897
+
898
+ _ = try shell.env_get("TWINE_USERNAME");
899
+ _ = try shell.env_get("TWINE_PASSWORD");
900
+
901
+ try shell.exec("python3 -m twine upload {package}", .{
902
+ .package = try shell.fmt("zig-out/dist/python/tigerbeetle-{s}-py3-none-any.whl", .{
903
+ info.tag,
904
+ }),
905
+ });
906
+ }
907
+
908
+ // Docker is not required and not recommended for running TigerBeetle. A container is published
909
+ // just for convenience of consumers expecting one!
910
+ fn publish_docker(shell: *Shell, info: VersionInfo) !void {
911
+ var section = try shell.open_section("publish docker");
912
+ defer section.close();
913
+
914
+ assert(try shell.dir_exists("zig-out/dist/tigerbeetle"));
915
+
916
+ try shell.exec(
917
+ \\docker login --username tigerbeetle --password {password} ghcr.io
918
+ , .{
919
+ .password = try shell.env_get("GITHUB_TOKEN"),
920
+ });
921
+
922
+ try shell.exec(
923
+ \\docker buildx create --use
924
+ , .{});
925
+
926
+ for ([_]bool{ true, false }) |debug| {
927
+ const triples = [_][]const u8{ "aarch64-linux", "x86_64-linux" };
928
+ const docker_arches = [_][]const u8{ "arm64", "amd64" };
929
+ for (triples, docker_arches) |triple, docker_arch| {
930
+ // We need to unzip binaries from dist. For simplicity, don't bother with a temporary
931
+ // directory.
932
+ shell.project_root.deleteFile("tigerbeetle") catch {};
933
+
934
+ const zip_path = try shell.fmt(
935
+ "./zig-out/dist/tigerbeetle/tigerbeetle-{s}{s}.zip",
936
+ .{ triple, if (debug) "-debug" else "" },
937
+ );
938
+ try shell.unzip_executable(zip_path, "tigerbeetle");
939
+
940
+ try shell.project_root.rename(
941
+ "tigerbeetle",
942
+ try shell.fmt("tigerbeetle-{s}", .{docker_arch}),
943
+ );
944
+ }
945
+ // Build docker container by copying pre-build executable inside.
946
+ //
947
+ // TigerBeetle doesn't install its own signal handlers, and PID 1 doesn't have a default
948
+ // SIGTERM signal handler. (See https://github.com/krallin/tini#why-tini). Using "tini" as
949
+ // PID 1 ensures that signals work as expected, so e.g. "docker stop" will not hang.
950
+ try shell.exec_options(
951
+ .{
952
+ .stdin_slice =
953
+ \\FROM alpine:latest
954
+ \\RUN apk add --no-cache tini
955
+ \\ARG TARGETARCH
956
+ \\COPY tigerbeetle-${TARGETARCH} /tigerbeetle
957
+ \\ENTRYPOINT ["tini", "--", "/tigerbeetle"]
958
+ ,
959
+ },
960
+ \\docker buildx build
961
+ \\ --file - .
962
+ \\ --platform linux/amd64,linux/arm64
963
+ \\ --tag ghcr.io/tigerbeetle/tigerbeetle:{tag}{debug}
964
+ \\ {tag_latest}
965
+ \\ --push
966
+ ,
967
+ .{
968
+ .tag = info.tag,
969
+ .debug = if (debug) "-debug" else "",
970
+ .tag_latest = @as(
971
+ []const []const u8,
972
+ if (debug) &.{} else &.{ "--tag", "ghcr.io/tigerbeetle/tigerbeetle:latest" },
973
+ ),
974
+ },
975
+ );
976
+
977
+ // Sadly, there isn't an easy way to locally build & test a multiplatform image without
978
+ // pushing it out to the registry first. As docker testing isn't covered under not rocket
979
+ // science rule, let's do a best effort after-the-fact testing here.
980
+ const version_verbose = try shell.exec_stdout(
981
+ \\docker run ghcr.io/tigerbeetle/tigerbeetle:{tag}{debug} version --verbose
982
+ , .{
983
+ .tag = info.tag,
984
+ .debug = if (debug) "-debug" else "",
985
+ });
986
+ const mode = if (debug) "Debug" else "ReleaseSafe";
987
+ assert(std.mem.indexOf(u8, version_verbose, mode) != null);
988
+ assert(std.mem.indexOf(u8, version_verbose, info.release_triple) != null);
989
+ }
990
+ }
991
+
992
+ fn publish_docs(shell: *Shell, info: VersionInfo) !void {
993
+ var section = try shell.open_section("publish docs");
994
+ defer section.close();
995
+
996
+ {
997
+ try shell.pushd("./src/docs_website");
998
+ defer shell.popd();
999
+
1000
+ try shell.exec_zig("build", .{});
1001
+ }
1002
+
1003
+ const token = try shell.env_get("TIGERBEETLE_DOCS_PAT");
1004
+ try shell.exec(
1005
+ \\git clone --no-checkout --depth 1
1006
+ \\ https://oauth2:{token}@github.com/tigerbeetle/docs.git tigerbeetle-docs
1007
+ , .{ .token = token });
1008
+ defer {
1009
+ shell.project_root.deleteTree("tigerbeetle-docs") catch {};
1010
+ }
1011
+
1012
+ const docs_files = try shell.find(.{ .where = &.{"src/docs_website/zig-out"} });
1013
+ assert(docs_files.len > 10);
1014
+ for (docs_files) |file| {
1015
+ try Shell.copy_path(
1016
+ shell.project_root,
1017
+ file,
1018
+ shell.project_root,
1019
+ try std.mem.replaceOwned(
1020
+ u8,
1021
+ shell.arena.allocator(),
1022
+ file,
1023
+ "src/docs_website/zig-out",
1024
+ "tigerbeetle-docs/",
1025
+ ),
1026
+ );
1027
+ }
1028
+
1029
+ try shell.pushd("./tigerbeetle-docs");
1030
+ defer shell.popd();
1031
+
1032
+ try shell.exec("git add .", .{});
1033
+ try shell.env.put("GIT_AUTHOR_NAME", "TigerBeetle Bot");
1034
+ try shell.env.put("GIT_AUTHOR_EMAIL", "bot@tigerbeetle.com");
1035
+ try shell.env.put("GIT_COMMITTER_NAME", "TigerBeetle Bot");
1036
+ try shell.env.put("GIT_COMMITTER_EMAIL", "bot@tigerbeetle.com");
1037
+ // We want to push a commit even if there are no changes to the docs, to make sure
1038
+ // that the latest commit message on the docs repo points to the latest tigerbeetle
1039
+ // release.
1040
+ try shell.exec("git commit --allow-empty --message {message}", .{
1041
+ .message = try shell.fmt(
1042
+ "Autogenerated commit from tigerbeetle/tigerbeetle@{s}",
1043
+ .{info.commit_sha},
1044
+ ),
1045
+ });
1046
+
1047
+ try shell.exec("git push origin main", .{});
1048
+ }
1049
+
1050
+ fn backup_create(dir: std.fs.Dir, comptime file: []const u8) !void {
1051
+ try Shell.copy_path(dir, file, dir, file ++ ".backup");
1052
+ }
1053
+
1054
+ fn backup_restore(dir: std.fs.Dir, comptime file: []const u8) void {
1055
+ dir.deleteFile(file) catch {};
1056
+ Shell.copy_path(dir, file ++ ".backup", dir, file) catch {};
1057
+ dir.deleteFile(file ++ ".backup") catch {};
1058
+ }