hgitaly 18.4.0a0__tar.gz → 18.4.2__tar.gz

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 (309) hide show
  1. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/PKG-INFO +2 -2
  2. hgitaly-18.4.2/hgitaly/VERSION +1 -0
  3. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/message.py +5 -0
  4. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/scripts.py +5 -1
  5. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/commit.py +1 -1
  6. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/mercurial_operations.py +156 -7
  7. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/operations.py +2 -2
  8. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/repository.py +6 -3
  9. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/tests/fixture.py +23 -2
  10. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/tests/test_commit.py +3 -2
  11. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/tests/test_mercurial_operations.py +132 -0
  12. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/tests/test_repository_service.py +4 -3
  13. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/servicer.py +3 -1
  14. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/mercurial_operations_pb2.py +29 -19
  15. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/mercurial_operations_pb2_grpc.py +45 -1
  16. hgitaly-18.4.2/hgitaly/testing/repo.py +26 -0
  17. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/testing/storage.py +17 -1
  18. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/common.py +1 -0
  19. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly.egg-info/PKG-INFO +2 -2
  20. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly.egg-info/SOURCES.txt +1 -138
  21. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly.egg-info/requires.txt +1 -1
  22. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/install-requirements.txt +1 -1
  23. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/test_mercurial_aux_git.py +3 -3
  24. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/test_repository_service.py +62 -9
  25. hgitaly-18.4.0a0/.coveragerc +0 -5
  26. hgitaly-18.4.0a0/.gitlab-ci.yml +0 -154
  27. hgitaly-18.4.0a0/.hgignore +0 -36
  28. hgitaly-18.4.0a0/.hgtags +0 -168
  29. hgitaly-18.4.0a0/ci/heptapod-sftp-push +0 -31
  30. hgitaly-18.4.0a0/ci/heptapod-sign-package +0 -34
  31. hgitaly-18.4.0a0/ci/heptapod_known_hosts.ssh +0 -4
  32. hgitaly-18.4.0a0/ci/upload-rhgitaly +0 -43
  33. hgitaly-18.4.0a0/conftest.py +0 -100
  34. hgitaly-18.4.0a0/dev-requirements.txt +0 -2
  35. hgitaly-18.4.0a0/examples/client.py +0 -48
  36. hgitaly-18.4.0a0/examples/client_list_lcft.py +0 -55
  37. hgitaly-18.4.0a0/generate-stubs +0 -34
  38. hgitaly-18.4.0a0/hgitaly/VERSION +0 -1
  39. hgitaly-18.4.0a0/hgitaly/testing/data/authorized_keys +0 -1
  40. hgitaly-18.4.0a0/hgitaly/testing/data/backup_additional_no_git.tar +0 -0
  41. hgitaly-18.4.0a0/hgitaly/testing/data/id_ecdsa_user +0 -38
  42. hgitaly-18.4.0a0/hgitaly/testing/data/known_hosts +0 -2
  43. hgitaly-18.4.0a0/hgitaly/testing/data/ssh_host_ecdsa_key +0 -9
  44. hgitaly-18.4.0a0/hgitaly/testing/data/ssh_host_ecdsa_key.pub +0 -1
  45. hgitaly-18.4.0a0/hgitaly/testing/data/ssh_host_ed25519 +0 -8
  46. hgitaly-18.4.0a0/hgitaly/testing/data/ssh_host_ed25519.pub +0 -1
  47. hgitaly-18.4.0a0/hgitaly/testing/data/sshd_config +0 -17
  48. hgitaly-18.4.0a0/lint +0 -7
  49. hgitaly-18.4.0a0/protos/analysis.proto +0 -62
  50. hgitaly-18.4.0a0/protos/blob.proto +0 -299
  51. hgitaly-18.4.0a0/protos/cleanup.proto +0 -88
  52. hgitaly-18.4.0a0/protos/cluster.proto +0 -134
  53. hgitaly-18.4.0a0/protos/commit.proto +0 -996
  54. hgitaly-18.4.0a0/protos/conflicts.proto +0 -137
  55. hgitaly-18.4.0a0/protos/diff.proto +0 -644
  56. hgitaly-18.4.0a0/protos/errors.proto +0 -234
  57. hgitaly-18.4.0a0/protos/hook.proto +0 -205
  58. hgitaly-18.4.0a0/protos/internal.proto +0 -37
  59. hgitaly-18.4.0a0/protos/lint.proto +0 -75
  60. hgitaly-18.4.0a0/protos/log.proto +0 -137
  61. hgitaly-18.4.0a0/protos/mercurial-aux-git.proto +0 -32
  62. hgitaly-18.4.0a0/protos/mercurial-changeset.proto +0 -96
  63. hgitaly-18.4.0a0/protos/mercurial-operations.proto +0 -230
  64. hgitaly-18.4.0a0/protos/mercurial-repository.proto +0 -364
  65. hgitaly-18.4.0a0/protos/namespace.proto +0 -98
  66. hgitaly-18.4.0a0/protos/objectpool.proto +0 -173
  67. hgitaly-18.4.0a0/protos/operations.proto +0 -1161
  68. hgitaly-18.4.0a0/protos/packfile.proto +0 -26
  69. hgitaly-18.4.0a0/protos/partition.proto +0 -70
  70. hgitaly-18.4.0a0/protos/praefect.proto +0 -222
  71. hgitaly-18.4.0a0/protos/ref.proto +0 -600
  72. hgitaly-18.4.0a0/protos/remote.proto +0 -153
  73. hgitaly-18.4.0a0/protos/repository.proto +0 -1458
  74. hgitaly-18.4.0a0/protos/server.proto +0 -123
  75. hgitaly-18.4.0a0/protos/service_config.proto +0 -86
  76. hgitaly-18.4.0a0/protos/shared.proto +0 -248
  77. hgitaly-18.4.0a0/protos/smarthttp.proto +0 -121
  78. hgitaly-18.4.0a0/protos/ssh.proto +0 -109
  79. hgitaly-18.4.0a0/protos/transaction.proto +0 -104
  80. hgitaly-18.4.0a0/protos/wiki.proto +0 -211
  81. hgitaly-18.4.0a0/ruby/.ruby-version +0 -1
  82. hgitaly-18.4.0a0/ruby/Gemfile +0 -5
  83. hgitaly-18.4.0a0/ruby/README.md +0 -48
  84. hgitaly-18.4.0a0/ruby/generate-grpc-lib +0 -63
  85. hgitaly-18.4.0a0/ruby/hgitaly.gemspec +0 -25
  86. hgitaly-18.4.0a0/ruby/lib/hgitaly/mercurial-aux-git_pb.rb +0 -14
  87. hgitaly-18.4.0a0/ruby/lib/hgitaly/mercurial-aux-git_services_pb.rb +0 -29
  88. hgitaly-18.4.0a0/ruby/lib/hgitaly/mercurial-changeset_pb.rb +0 -69
  89. hgitaly-18.4.0a0/ruby/lib/hgitaly/mercurial-changeset_services_pb.rb +0 -25
  90. hgitaly-18.4.0a0/ruby/lib/hgitaly/mercurial-operations_pb.rb +0 -133
  91. hgitaly-18.4.0a0/ruby/lib/hgitaly/mercurial-operations_services_pb.rb +0 -53
  92. hgitaly-18.4.0a0/ruby/lib/hgitaly/mercurial-repository_pb.rb +0 -163
  93. hgitaly-18.4.0a0/ruby/lib/hgitaly/mercurial-repository_services_pb.rb +0 -79
  94. hgitaly-18.4.0a0/ruby/lib/hgitaly/version.rb +0 -4
  95. hgitaly-18.4.0a0/ruby/lib/hgitaly.rb +0 -13
  96. hgitaly-18.4.0a0/ruby/run.rb +0 -39
  97. hgitaly-18.4.0a0/run-all-tests +0 -24
  98. hgitaly-18.4.0a0/rust/Cargo.lock +0 -3898
  99. hgitaly-18.4.0a0/rust/Cargo.toml +0 -4
  100. hgitaly-18.4.0a0/rust/Makefile +0 -77
  101. hgitaly-18.4.0a0/rust/build-from-tarball.sh +0 -30
  102. hgitaly-18.4.0a0/rust/check-line-width +0 -48
  103. hgitaly-18.4.0a0/rust/dependencies/README.md +0 -19
  104. hgitaly-18.4.0a0/rust/dependencies/mercurial.patch +0 -51
  105. hgitaly-18.4.0a0/rust/dependencies/proto/google/protobuf/any.proto +0 -158
  106. hgitaly-18.4.0a0/rust/dependencies/proto/google/protobuf/api.proto +0 -208
  107. hgitaly-18.4.0a0/rust/dependencies/proto/google/protobuf/compiler/plugin.proto +0 -183
  108. hgitaly-18.4.0a0/rust/dependencies/proto/google/protobuf/descriptor.proto +0 -911
  109. hgitaly-18.4.0a0/rust/dependencies/proto/google/protobuf/duration.proto +0 -116
  110. hgitaly-18.4.0a0/rust/dependencies/proto/google/protobuf/empty.proto +0 -52
  111. hgitaly-18.4.0a0/rust/dependencies/proto/google/protobuf/field_mask.proto +0 -245
  112. hgitaly-18.4.0a0/rust/dependencies/proto/google/protobuf/source_context.proto +0 -48
  113. hgitaly-18.4.0a0/rust/dependencies/proto/google/protobuf/struct.proto +0 -95
  114. hgitaly-18.4.0a0/rust/dependencies/proto/google/protobuf/timestamp.proto +0 -147
  115. hgitaly-18.4.0a0/rust/dependencies/proto/google/protobuf/type.proto +0 -187
  116. hgitaly-18.4.0a0/rust/dependencies/proto/google/protobuf/wrappers.proto +0 -123
  117. hgitaly-18.4.0a0/rust/go-enry.rev +0 -1
  118. hgitaly-18.4.0a0/rust/lint +0 -14
  119. hgitaly-18.4.0a0/rust/mercurial.rev +0 -1
  120. hgitaly-18.4.0a0/rust/rhgitaly/Cargo.toml +0 -56
  121. hgitaly-18.4.0a0/rust/rhgitaly/build.rs +0 -92
  122. hgitaly-18.4.0a0/rust/rhgitaly/clippy.toml +0 -6
  123. hgitaly-18.4.0a0/rust/rhgitaly/src/bundle.rs +0 -282
  124. hgitaly-18.4.0a0/rust/rhgitaly/src/config.rs +0 -172
  125. hgitaly-18.4.0a0/rust/rhgitaly/src/errors.rs +0 -141
  126. hgitaly-18.4.0a0/rust/rhgitaly/src/generated/README.md +0 -7
  127. hgitaly-18.4.0a0/rust/rhgitaly/src/git.rs +0 -293
  128. hgitaly-18.4.0a0/rust/rhgitaly/src/gitlab/mod.rs +0 -50
  129. hgitaly-18.4.0a0/rust/rhgitaly/src/gitlab/reference.rs +0 -83
  130. hgitaly-18.4.0a0/rust/rhgitaly/src/gitlab/revision.rs +0 -320
  131. hgitaly-18.4.0a0/rust/rhgitaly/src/gitlab/state.rs +0 -508
  132. hgitaly-18.4.0a0/rust/rhgitaly/src/glob.rs +0 -233
  133. hgitaly-18.4.0a0/rust/rhgitaly/src/lib.rs +0 -45
  134. hgitaly-18.4.0a0/rust/rhgitaly/src/main.rs +0 -147
  135. hgitaly-18.4.0a0/rust/rhgitaly/src/mercurial.rs +0 -1389
  136. hgitaly-18.4.0a0/rust/rhgitaly/src/message.rs +0 -468
  137. hgitaly-18.4.0a0/rust/rhgitaly/src/metadata.rs +0 -61
  138. hgitaly-18.4.0a0/rust/rhgitaly/src/oid.rs +0 -86
  139. hgitaly-18.4.0a0/rust/rhgitaly/src/process.rs +0 -39
  140. hgitaly-18.4.0a0/rust/rhgitaly/src/repository/spawner.rs +0 -576
  141. hgitaly-18.4.0a0/rust/rhgitaly/src/repository.rs +0 -605
  142. hgitaly-18.4.0a0/rust/rhgitaly/src/service/analysis.rs +0 -183
  143. hgitaly-18.4.0a0/rust/rhgitaly/src/service/blob.rs +0 -260
  144. hgitaly-18.4.0a0/rust/rhgitaly/src/service/commit/find_commits.rs +0 -206
  145. hgitaly-18.4.0a0/rust/rhgitaly/src/service/commit/get_tree_entries.rs +0 -291
  146. hgitaly-18.4.0a0/rust/rhgitaly/src/service/commit/last_commits.rs +0 -569
  147. hgitaly-18.4.0a0/rust/rhgitaly/src/service/commit/tree_entry.rs +0 -154
  148. hgitaly-18.4.0a0/rust/rhgitaly/src/service/commit.rs +0 -654
  149. hgitaly-18.4.0a0/rust/rhgitaly/src/service/diff.rs +0 -137
  150. hgitaly-18.4.0a0/rust/rhgitaly/src/service/mercurial_aux_git.rs +0 -180
  151. hgitaly-18.4.0a0/rust/rhgitaly/src/service/mercurial_repository.rs +0 -496
  152. hgitaly-18.4.0a0/rust/rhgitaly/src/service/mod.rs +0 -19
  153. hgitaly-18.4.0a0/rust/rhgitaly/src/service/ref.rs +0 -515
  154. hgitaly-18.4.0a0/rust/rhgitaly/src/service/remote.rs +0 -793
  155. hgitaly-18.4.0a0/rust/rhgitaly/src/service/repository.rs +0 -983
  156. hgitaly-18.4.0a0/rust/rhgitaly/src/service/server.rs +0 -60
  157. hgitaly-18.4.0a0/rust/rhgitaly/src/sidecar.rs +0 -234
  158. hgitaly-18.4.0a0/rust/rhgitaly/src/ssh.rs +0 -102
  159. hgitaly-18.4.0a0/rust/rhgitaly/src/streaming.rs +0 -402
  160. hgitaly-18.4.0a0/rust/rhgitaly/src/util.rs +0 -132
  161. hgitaly-18.4.0a0/rust/rs-enry.rev +0 -1
  162. hgitaly-18.4.0a0/rust/src-tarball.sh +0 -70
  163. hgitaly-18.4.0a0/test-requirements.txt +0 -8
  164. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/LICENSE +0 -0
  165. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/MANIFEST.in +0 -0
  166. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/README.md +0 -0
  167. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgext3rd/__init__.py +0 -0
  168. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgext3rd/hgitaly/__init__.py +0 -0
  169. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgext3rd/hgitaly/revset.py +0 -0
  170. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgext3rd/hgitaly/tests/__init__.py +0 -0
  171. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgext3rd/hgitaly/tests/test_revset.py +0 -0
  172. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgext3rd/hgitaly/tests/test_serve.py +0 -0
  173. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/__init__.py +0 -0
  174. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/branch.py +0 -0
  175. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/changelog.py +0 -0
  176. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/diff.py +0 -0
  177. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/errors.py +0 -0
  178. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/feature.py +0 -0
  179. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/file_content.py +0 -0
  180. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/file_context.py +0 -0
  181. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/git.py +0 -0
  182. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/gitlab_ref.py +0 -0
  183. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/identification.py +0 -0
  184. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/logging.py +0 -0
  185. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/manifest.py +0 -0
  186. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/oid.py +0 -0
  187. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/pagination.py +0 -0
  188. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/path.py +0 -0
  189. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/peer.py +0 -0
  190. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/procutil.py +0 -0
  191. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/repository.py +0 -0
  192. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/revision.py +0 -0
  193. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/revset.py +0 -0
  194. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/server/__init__.py +0 -0
  195. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/server/address.py +0 -0
  196. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/server/mono.py +0 -0
  197. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/server/prefork.py +0 -0
  198. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/server/tests/__init__.py +0 -0
  199. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/server/tests/test_address.py +0 -0
  200. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/server/tests/test_mono.py +0 -0
  201. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/server/tests/test_prefork.py +0 -0
  202. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/server/tests/test_worker.py +0 -0
  203. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/server/worker.py +0 -0
  204. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/__init__.py +0 -0
  205. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/analysis.py +0 -0
  206. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/blob.py +0 -0
  207. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/diff.py +0 -0
  208. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/interceptors.py +0 -0
  209. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/mercurial_changeset.py +0 -0
  210. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/mercurial_repository.py +0 -0
  211. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/ref.py +0 -0
  212. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/server.py +0 -0
  213. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/tests/__init__.py +0 -0
  214. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/tests/test_analysis.py +0 -0
  215. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/tests/test_blob.py +0 -0
  216. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/tests/test_default_branch.py +0 -0
  217. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/tests/test_diff.py +0 -0
  218. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/tests/test_mercurial_changeset.py +0 -0
  219. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/tests/test_mercurial_repository.py +0 -0
  220. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/tests/test_operations.py +0 -0
  221. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/tests/test_ref.py +0 -0
  222. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/service/tests/test_server.py +0 -0
  223. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/ssh.py +0 -0
  224. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stream.py +0 -0
  225. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/__init__.py +0 -0
  226. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/analysis_pb2.py +0 -0
  227. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/analysis_pb2_grpc.py +0 -0
  228. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/blob_pb2.py +0 -0
  229. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/blob_pb2_grpc.py +0 -0
  230. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/commit_pb2.py +0 -0
  231. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/commit_pb2_grpc.py +0 -0
  232. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/diff_pb2.py +0 -0
  233. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/diff_pb2_grpc.py +0 -0
  234. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/errors_pb2.py +0 -0
  235. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/errors_pb2_grpc.py +0 -0
  236. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/lint_pb2.py +0 -0
  237. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/lint_pb2_grpc.py +0 -0
  238. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/mercurial_aux_git_pb2.py +0 -0
  239. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/mercurial_aux_git_pb2_grpc.py +0 -0
  240. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/mercurial_changeset_pb2.py +0 -0
  241. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/mercurial_changeset_pb2_grpc.py +0 -0
  242. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/mercurial_repository_pb2.py +0 -0
  243. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/mercurial_repository_pb2_grpc.py +0 -0
  244. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/operations_pb2.py +0 -0
  245. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/operations_pb2_grpc.py +0 -0
  246. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/ref_pb2.py +0 -0
  247. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/ref_pb2_grpc.py +0 -0
  248. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/remote_pb2.py +0 -0
  249. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/remote_pb2_grpc.py +0 -0
  250. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/repository_pb2.py +0 -0
  251. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/repository_pb2_grpc.py +0 -0
  252. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/server_pb2.py +0 -0
  253. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/server_pb2_grpc.py +0 -0
  254. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/shared_pb2.py +0 -0
  255. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/stub/shared_pb2_grpc.py +0 -0
  256. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tag.py +0 -0
  257. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/testing/__init__.py +0 -0
  258. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/testing/bundle.py +0 -0
  259. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/testing/context.py +0 -0
  260. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/testing/grpc.py +0 -0
  261. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/testing/multiprocessing.py +0 -0
  262. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/testing/ssh.py +0 -0
  263. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/testing/sshd.py +0 -0
  264. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/testing/tests/__init__.py +0 -0
  265. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/testing/tests/test_sshd.py +0 -0
  266. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/__init__.py +0 -0
  267. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_branch.py +0 -0
  268. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_diff.py +0 -0
  269. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_errors.py +0 -0
  270. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_feature.py +0 -0
  271. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_file_context.py +0 -0
  272. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_gitlab_ref.py +0 -0
  273. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_identification.py +0 -0
  274. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_manifest.py +0 -0
  275. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_messages.py +0 -0
  276. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_oid.py +0 -0
  277. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_peer.py +0 -0
  278. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_repository.py +0 -0
  279. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_revision.py +0 -0
  280. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_revset.py +0 -0
  281. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_servicer.py +0 -0
  282. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_stream.py +0 -0
  283. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_tag.py +0 -0
  284. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/tests/test_workdir.py +0 -0
  285. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/util.py +0 -0
  286. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly/workdir.py +0 -0
  287. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly.egg-info/dependency_links.txt +0 -0
  288. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly.egg-info/entry_points.txt +0 -0
  289. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/hgitaly.egg-info/top_level.txt +0 -0
  290. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/setup.cfg +0 -0
  291. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/setup.py +0 -0
  292. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/__init__.py +0 -0
  293. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/comparison.py +0 -0
  294. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/conftest.py +0 -0
  295. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/gitaly.py +0 -0
  296. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/hgitaly_rhgitaly_comparison.py +0 -0
  297. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/rhgitaly.py +0 -0
  298. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/test_blob_tree.py +0 -0
  299. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/test_commit.py +0 -0
  300. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/test_comparison.py +0 -0
  301. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/test_diff.py +0 -0
  302. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/test_gitaly_server.py +0 -0
  303. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/test_mercurial_operations.py +0 -0
  304. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/test_mercurial_repository.py +0 -0
  305. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/test_operations.py +0 -0
  306. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/test_ref.py +0 -0
  307. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/test_remote.py +0 -0
  308. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/test_rhgitaly_server.py +0 -0
  309. {hgitaly-18.4.0a0 → hgitaly-18.4.2}/tests_with_gitaly/test_server.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hgitaly
3
- Version: 18.4.0a0
3
+ Version: 18.4.2
4
4
  Summary: Server-side implementation of Gitaly protocol for Mercurial
5
5
  Home-page: https://foss.heptapod.net/heptapod/hgitaly
6
6
  Author: Georges Racinet
@@ -10,7 +10,7 @@ Keywords: hg mercurial heptapod gitlab
10
10
  Requires-Python: >=3.8
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
- Requires-Dist: heptapod>=5.2.0dev0
13
+ Requires-Dist: heptapod>=5.4.0
14
14
  Requires-Dist: protobuf~=6.31.1
15
15
  Requires-Dist: grpcio~=1.74.0
16
16
  Requires-Dist: grpcio-status~=1.74.0
@@ -0,0 +1 @@
1
+ 18.4.2
@@ -19,6 +19,7 @@ from .stub.shared_pb2 import (
19
19
  GitCommit,
20
20
  SignatureType,
21
21
  Tag,
22
+ User,
22
23
  )
23
24
  from .stub.commit_pb2 import (
24
25
  ListLastCommitsForTreeResponse,
@@ -138,6 +139,10 @@ def commit_author(ctx):
138
139
  )
139
140
 
140
141
 
142
+ def user_for_hg(user: User) -> bytes:
143
+ return b'%s <%s>' % (user.name, user.email)
144
+
145
+
141
146
  def commit_stats(ctx):
142
147
  if len(ctx.parents()) > 1:
143
148
  # Gitaly does not provide the stats for merge commits
@@ -197,6 +197,7 @@ def stats(): # pragma no cover
197
197
  incomplete = total_requests - sum(len(succ) for succ in succeeded.values())
198
198
 
199
199
  stats = []
200
+ all_total_ms = 0
200
201
  for req, count in called.items():
201
202
  percent = round(count * 100 / total_requests)
202
203
  succ = succeeded[req]
@@ -208,10 +209,12 @@ def stats(): # pragma no cover
208
209
  )
209
210
  stats.append((req, req_stats))
210
211
  if nb_succ > 0:
212
+ req_total = sum(s for s in succ)
213
+ all_total_ms += req_total
211
214
  timing = req_stats['completion_stats_ms'] = dict(
212
215
  mean=statistics.mean(succ),
213
216
  median=statistics.median(succ),
214
- total=sum(s for s in succ),
217
+ total=req_total,
215
218
  )
216
219
  if nb_succ > 1:
217
220
  timing['standard_deviation'] = statistics.pstdev(succ)
@@ -246,6 +249,7 @@ def stats(): # pragma no cover
246
249
 
247
250
  print(f"TOTAL Requests since {first_timestamp}: {total_requests} \n"
248
251
  f" {incomplete} incomplete (cancelled or failed)")
252
+ print("Total wall time: %d seconds" % int(all_total_ms / 1000))
249
253
  print("Breakdown:")
250
254
  for req, details in stats.items():
251
255
  percent = '%4.1f' % details['percent']
@@ -925,7 +925,7 @@ class CommitServicer(CommitServiceServicer, HGitalyServicer):
925
925
  sort_key = b'-topo' if reverse else b'topo'
926
926
  elif request.order == Order.DATE:
927
927
  # See docstring about this approximative choice
928
- sort_key = b'-date' if reverse else b'date'
928
+ sort_key = b'date' if reverse else b'-date'
929
929
 
930
930
  revset = b'sort(%s, %s)' % (revset, sort_key)
931
931
 
@@ -15,11 +15,25 @@ from mercurial.node import nullhex as NULL_NODE_HEX
15
15
  from mercurial.phases import (
16
16
  public as PUBLIC,
17
17
  )
18
- from mercurial import util as hgutil
18
+ from mercurial import (
19
+ cmdutil,
20
+ commands,
21
+ error as hgerror,
22
+ util as hgutil,
23
+ )
24
+ from hgext.rebase import (
25
+ rebaseruntime,
26
+ sortsource as rebase_sort_source
27
+ )
19
28
 
20
29
  from heptapod.gitlab.branch import (
21
- NAMED_BRANCH_PREFIX,
30
+ branch_is_named_branch,
22
31
  gitlab_branch_ref,
32
+ parse_gitlab_branch,
33
+ )
34
+ from hgext3rd.heptapod.branch import (
35
+ gitlab_branches,
36
+ invalidate_gitlab_branches,
23
37
  )
24
38
 
25
39
  from .. import message
@@ -48,6 +62,8 @@ from ..workdir import (
48
62
  from ..stub.errors_pb2 import (
49
63
  MergeConflictError,
50
64
  ReferenceUpdateError,
65
+ ReferenceStateMismatchError,
66
+ ResolveRevisionError,
51
67
  )
52
68
  from ..stub.mercurial_operations_pb2 import (
53
69
  CensorRequest,
@@ -62,6 +78,9 @@ from ..stub.mercurial_operations_pb2 import (
62
78
  PublishChangesetError,
63
79
  PublishChangesetRequest,
64
80
  PublishChangesetResponse,
81
+ RebaseError,
82
+ RebaseRequest,
83
+ RebaseResponse,
65
84
  ReleaseWorkingDirectoryRequest,
66
85
  ReleaseWorkingDirectoryResponse,
67
86
  GetWorkingDirectoryRequest,
@@ -266,7 +285,7 @@ class MercurialOperationsServicer(MercurialOperationsServiceServicer,
266
285
  target_branch = request.branch
267
286
  if not target_branch:
268
287
  context.abort(StatusCode.INVALID_ARGUMENT, "empty branch name")
269
- if not target_branch.startswith(NAMED_BRANCH_PREFIX):
288
+ if not branch_is_named_branch(target_branch):
270
289
  context.abort(StatusCode.FAILED_PRECONDITION,
271
290
  "Heptapod merges are currently targeting "
272
291
  "named branches only (no topics nor bookmarks)")
@@ -384,7 +403,7 @@ class MercurialOperationsServicer(MercurialOperationsServiceServicer,
384
403
  new_changeset = self.merge(working_dir=wd,
385
404
  source_changeset=to_merge,
386
405
  user=request.user,
387
- message=request.message,
406
+ commit_message=request.message,
388
407
  unix_timestamp=unix_ts,
389
408
  context=context)
390
409
  except ConflictError as exc:
@@ -411,7 +430,7 @@ class MercurialOperationsServicer(MercurialOperationsServiceServicer,
411
430
  ))
412
431
 
413
432
  def merge(self, working_dir, context, source_changeset,
414
- user: User, message, unix_timestamp):
433
+ user: User, commit_message, unix_timestamp):
415
434
  """Merge changeset with given revno in working repository.
416
435
 
417
436
  The working repositoy is assumed to be already updated in a
@@ -424,11 +443,141 @@ class MercurialOperationsServicer(MercurialOperationsServiceServicer,
424
443
  raise ConflictError(unresolved)
425
444
  # TODO user timezone (symbolic or UTC offset?)
426
445
  self.repo_command(working_repo, context, 'commit',
427
- user=b'%s <%s>' % (user.name, user.email),
446
+ user=message.user_for_hg(user),
428
447
  date=b'%d 0' % unix_timestamp,
429
- message=message)
448
+ message=commit_message)
430
449
  return working_repo[b'.']
431
450
 
451
+ def Rebase(self, request: RebaseRequest, context) -> RebaseResponse:
452
+ logger = LoggerAdapter(base_logger, context)
453
+
454
+ repo = self.load_repo(request.repository, context,
455
+ for_mutation_by=request.user)
456
+
457
+ source = request.source
458
+ if not source:
459
+ context.abort(StatusCode.INVALID_ARGUMENT,
460
+ "empty source branch name")
461
+ dest = request.destination
462
+ if not dest:
463
+ context.abort(StatusCode.INVALID_ARGUMENT,
464
+ "empty destination branch name")
465
+
466
+ branch, topic = parse_gitlab_branch(source)
467
+ if topic is None:
468
+ structured_abort(
469
+ context,
470
+ StatusCode.INVALID_ARGUMENT,
471
+ "Not a topic",
472
+ RebaseError(pre_check=PreCheckUpdateError.NOT_A_TOPIC)
473
+ )
474
+ # todo check sha if given
475
+
476
+ dest_cs = gitlab_revision_changeset(repo, dest)
477
+ if dest_cs is None:
478
+ structured_abort(
479
+ context,
480
+ StatusCode.FAILED_PRECONDITION,
481
+ "Failed to resolve destination",
482
+ RebaseError(resolve_rev=ResolveRevisionError(revision=dest))
483
+ )
484
+ source_cs = gitlab_revision_changeset(repo, source)
485
+ if source_cs is None:
486
+ structured_abort(
487
+ context,
488
+ StatusCode.FAILED_PRECONDITION,
489
+ "Failed to resolve source",
490
+ RebaseError(resolve_rev=ResolveRevisionError(revision=source))
491
+ )
492
+ expected_sha = request.source_head_sha.encode('utf-8')
493
+ actual_sha = source_cs.hex()
494
+ if expected_sha and expected_sha != actual_sha:
495
+ structured_abort(
496
+ context,
497
+ StatusCode.FAILED_PRECONDITION,
498
+ "Source head sha mismatch",
499
+ RebaseError(ref_mismatch=ReferenceStateMismatchError(
500
+ reference_name=source,
501
+ expected_object_id=expected_sha,
502
+ actual_object_id=actual_sha))
503
+ )
504
+
505
+ # branch and topic naming rules make sure that we need no escaping
506
+ # using the head sha for reassurance
507
+ revset = b"branch('%s//%s') and ::%s" % (
508
+ branch, topic, source_cs.hex()
509
+ )
510
+ username = message.user_for_hg(request.user)
511
+ logger.info("Performing rebase, revset=%r, destination=%r",
512
+ revset, dest_cs.hex())
513
+ with self.working_dir(gl_repo=request.repository,
514
+ repo=repo,
515
+ changeset=source_cs,
516
+ context=context) as wd:
517
+ did_rebase = wd_rebase(wd, username, revset, dest_cs, context)
518
+
519
+ if not did_rebase:
520
+ return RebaseResponse()
521
+
522
+ invalidate_gitlab_branches(repo)
523
+ # do not use gitlab_revisions_changeset, as building the
524
+ # changectx would fail (`repo[new_head]` would end up in LookupError)
525
+ # we'd need to reload the repo, which is quite useless because we
526
+ # are happy with just the new Node ID
527
+ new_head = gitlab_branches(repo)[source]
528
+ return RebaseResponse(
529
+ branch_update=OperationBranchUpdate(
530
+ commit_id=new_head.decode('ascii')))
531
+
532
+
533
+ def wd_rebase(working_dir, username, revset, dest_cs, context):
534
+ """Perform the rebase in the working directory, handling errors
535
+
536
+ :returns: ``True`` if rebase actually happened
537
+ """
538
+ repo = working_dir.repo
539
+
540
+ # TODO would be nice to experiment with in-memory rebase (wouldn't
541
+ # need a working dir) but not sure what the good use cases are.
542
+ # For instance, is a small rebase on a big repo much more efficient
543
+ # in memory or should that precisely be avoided?
544
+ overrides = {
545
+ (b'experimental', b'evolution.allowunstable'): False,
546
+ (b'rebase', b'singletransaction'): True,
547
+ }
548
+ # overriding ui.username does not work, this does:
549
+ repo.ui.environ[b'HGUSER'] = username
550
+ with repo.ui.configoverride(overrides, b'rebase'):
551
+ rebase = cmdutil.findcmd(b'rebase', commands.table)[1][0]
552
+ try:
553
+ retcode = rebase(repo.ui, repo, rev=[revset], dest=dest_cs.hex())
554
+ except hgerror.ConflictResolutionRequired:
555
+ conflicts = list(mergestate.read(repo).unresolved())
556
+ runtime = rebaseruntime(repo, repo.ui)
557
+ runtime.restorestatus()
558
+ # rebase_sort_source is the generator used by rebase to
559
+ # know what to do in order. Not sure why each yielded element
560
+ # is a list though (it's a singleton in simple tested cases)
561
+ failed_rev = next(rebase_sort_source(runtime.destmap))[0]
562
+ failed_sha = repo[failed_rev].hex().decode('ascii')
563
+ current_sha = repo[None].p1().hex().decode('ascii')
564
+
565
+ # next use of this workdir should be able to recover. Still it
566
+ # is best to do it right away
567
+ rebase(repo.ui, repo, abort=True)
568
+ working_dir.purge()
569
+
570
+ structured_abort(
571
+ context,
572
+ StatusCode.FAILED_PRECONDITION,
573
+ "Rebase conflict",
574
+ RebaseError(conflict=MergeConflictError(
575
+ conflicting_files=conflicts,
576
+ conflicting_commit_ids=[current_sha, failed_sha]
577
+ ))
578
+ )
579
+ return retcode is None or retcode == 0
580
+
432
581
 
433
582
  def wd_merge(working_dir, source_cs):
434
583
  """Merge source_cs in the given a working directory (repo share).
@@ -23,7 +23,7 @@ from heptapod import (
23
23
  )
24
24
 
25
25
  from heptapod.gitlab.branch import (
26
- NAMED_BRANCH_PREFIX,
26
+ branch_is_named_branch,
27
27
  parse_gitlab_branch,
28
28
  )
29
29
 
@@ -252,7 +252,7 @@ class OperationServicer(OperationServiceServicer, HGitalyServicer):
252
252
  if not request.branch:
253
253
  context.abort(StatusCode.INVALID_ARGUMENT, "empty branch name")
254
254
 
255
- if not request.branch.startswith(NAMED_BRANCH_PREFIX):
255
+ if not branch_is_named_branch(request.branch):
256
256
  context.abort(StatusCode.FAILED_PRECONDITION,
257
257
  "Heptapod fast forwards are currently "
258
258
  "for named branches only (no topics nor bookmarks)")
@@ -36,6 +36,7 @@ from hgext3rd.heptapod.branch import set_default_gitlab_branch
36
36
  from hgext3rd.heptapod.special_ref import write_gitlab_special_ref
37
37
  from hgext3rd.heptapod.keep_around import (
38
38
  create_keep_around,
39
+ delete_keep_around,
39
40
  parse_keep_around_ref,
40
41
  )
41
42
 
@@ -337,7 +338,9 @@ class RepositoryServicer(RepositoryServiceServicer, HGitalyServicer):
337
338
 
338
339
  keep_around = parse_keep_around_ref(ref)
339
340
  if keep_around is not None:
340
- if (CHANGESET_HASH_BYTES_REGEXP.match(keep_around) is None
341
+ if target == ZERO_SHA:
342
+ delete_keep_around(repo, keep_around)
343
+ elif (CHANGESET_HASH_BYTES_REGEXP.match(keep_around) is None
341
344
  or target != keep_around):
342
345
  context.abort(
343
346
  StatusCode.INVALID_ARGUMENT,
@@ -346,8 +349,8 @@ class RepositoryServicer(RepositoryServiceServicer, HGitalyServicer):
346
349
  "target must "
347
350
  "match the ref name" % (target, ref)
348
351
  )
349
-
350
- create_keep_around(repo, target)
352
+ else:
353
+ create_keep_around(repo, target)
351
354
  return WriteRefResponse()
352
355
  except Exception:
353
356
  # TODO this is a stop-gap measure to prevent repository breakage
@@ -17,6 +17,7 @@ from hgitaly.servicer import (
17
17
  SKIP_HOOKS_MD_KEY,
18
18
  )
19
19
  from hgitaly.stub.shared_pb2 import Repository
20
+ from hgitaly.workdir import wd_path
20
21
 
21
22
  from heptapod.testhelpers import (
22
23
  LocalRepoWrapper,
@@ -37,6 +38,9 @@ from hgitaly.stub.shared_pb2 import (
37
38
  User,
38
39
  )
39
40
  from hgitaly.testing.storage import (
41
+ repo_workdirs_root,
42
+ storage_path,
43
+ storage_workdirs,
40
44
  stowed_away_git_repo_path,
41
45
  )
42
46
 
@@ -143,12 +147,12 @@ class ServiceFixture:
143
147
  self.repos_to_cleanup.append(repo_path)
144
148
  return repo_path, repo_msg
145
149
 
146
- def storage_path(self, storage_name='default'):
150
+ def storage_path(self, **storage_kw):
147
151
  """Utility method to avoid depending too much on actual disk layout.
148
152
 
149
153
  This repeats the actual implementation just once.
150
154
  """
151
- return self.server_repos_root / storage_name
155
+ return storage_path(self.server_repos_root, **storage_kw)
152
156
 
153
157
  def repo_path(self, rel_path, **kw):
154
158
  """Utility method to avoid depending too much on actual disk layout.
@@ -172,6 +176,23 @@ class ServiceFixture:
172
176
  """
173
177
  return LocalRepoWrapper.load(self.repo_path(rel_path, **kw))
174
178
 
179
+ def storage_workdirs(self, **storage_kw):
180
+ return storage_workdirs(self.server_repos_root, **storage_kw)
181
+
182
+ def repo_workdirs_root(self, grpc_repo=None):
183
+ if grpc_repo is None:
184
+ grpc_repo = self.grpc_repo
185
+ return repo_workdirs_root(self.server_repos_root, grpc_repo)
186
+
187
+ def workdir_repo_wrapper(self, wd_id, grpc_repo=None):
188
+ """Direct low level access to a workdir repo.
189
+
190
+ This doesn't go through the normal initialization procedure, hence
191
+ is suitable to check state after error recovery.
192
+ """
193
+ return LocalRepoWrapper.load(
194
+ wd_path(self.repo_workdirs_root(grpc_repo=grpc_repo), wd_id))
195
+
175
196
  def rpc(self, method_name, request):
176
197
  """Call a method, taking care of metadata."""
177
198
  return getattr(self.stub, method_name)(
@@ -1362,8 +1362,9 @@ def test_list_commits(commit_fixture_empty_repo):
1362
1362
  # orderings
1363
1363
  Order = ListCommitsRequest.Order
1364
1364
  assert list_commits(sha4, order=Order.TOPO) == [sha4, sha3, sha2, sha0]
1365
- # having no explicit date, ctx0 looks to be the most recent one.
1366
- assert list_commits(sha4, order=Order.DATE) == [sha2, sha3, sha4, sha0]
1365
+ # being the only one with no explicit date, ctx0 looks to be
1366
+ # the most recent one.
1367
+ assert list_commits(sha4, order=Order.DATE) == [sha0, sha4, sha3, sha2]
1367
1368
 
1368
1369
  # no result
1369
1370
  assert list_commits(sha4, caret(ctx4)) == []
@@ -15,6 +15,8 @@ from mercurial import (
15
15
  error as hg_error,
16
16
  phases,
17
17
  )
18
+ from mercurial.mergestate import mergestate
19
+ from mercurial.node import nullid as NULL_NODE
18
20
  from mercurial_testhelpers import RepoWrapper
19
21
 
20
22
  from google.protobuf.timestamp_pb2 import Timestamp
@@ -38,6 +40,9 @@ from hgitaly.stub.mercurial_operations_pb2 import (
38
40
  CensorRequest,
39
41
  MergeBranchError,
40
42
  MergeBranchRequest,
43
+ RebaseError,
44
+ RebaseRequest,
45
+ RebaseResponse,
41
46
  MercurialPermissions,
42
47
  PreCheckUpdateError,
43
48
  PublishChangesetRequest,
@@ -50,6 +55,7 @@ from hgitaly.stub.mercurial_operations_pb2_grpc import (
50
55
  MercurialOperationsServiceStub,
51
56
  )
52
57
  from hgitaly.tests.common import make_empty_repo_with_gitlab_state_maintainer
58
+ from hgitaly.testing.repo import assert_empty_repo_status
53
59
  from .fixture import MutationServiceFixture
54
60
 
55
61
  parametrize = pytest.mark.parametrize
@@ -86,6 +92,12 @@ class OperationsFixture(MutationServiceFixture):
86
92
  return self.stub.MergeBranch(MergeBranchRequest(**kw),
87
93
  metadata=self.grpc_metadata())
88
94
 
95
+ def rebase(self, **kw):
96
+ kw.setdefault('repository', self.grpc_repo)
97
+ kw.setdefault('user', self.user)
98
+ return self.stub.Rebase(RebaseRequest(**kw),
99
+ metadata=self.grpc_metadata())
100
+
89
101
  def get_workdir(self, **kw):
90
102
  kw.setdefault('client_id', self.client_id)
91
103
  kw.setdefault('incarnation_id', INCARNATION_ID)
@@ -596,6 +608,126 @@ def test_merge_branch_troubled_changesets(operations_fixture):
596
608
  assert merge_error.pre_check == PreCheckUpdateError.UNSTABLE_CHANGESET
597
609
 
598
610
 
611
+ @parametrize('project_mode', ('hg-git-project', 'native-project'))
612
+ def test_rebase_basic(operations_fixture, project_mode):
613
+ fixture = operations_fixture
614
+ rebase = fixture.rebase
615
+
616
+ fixture.hg_native = project_mode != 'hg-git-project'
617
+ wrapper = fixture.repo_wrapper
618
+
619
+ gl_branch = b'branch/default'
620
+ gl_topic = b'topic/default/zetop'
621
+
622
+ # because of the config set by fixture, this leads in all cases to
623
+ # creation of a Git repo and its `branch/default` Git branch
624
+ ctx0 = wrapper.commit_file('foo')
625
+ sha0 = ctx0.hex().decode()
626
+ default_head = wrapper.commit_file('foo')
627
+ ctx2 = wrapper.commit_file('bar', topic='zetop', parent=ctx0)
628
+ sha2 = ctx2.hex().decode()
629
+ # avoid keeping the rebased changesets visible
630
+ wrapper.update_bin(NULL_NODE)
631
+
632
+ # simple error cases
633
+ with pytest.raises(RpcError) as exc_info:
634
+ rebase(source=gl_topic)
635
+ assert exc_info.value.code() == StatusCode.INVALID_ARGUMENT
636
+ with pytest.raises(RpcError) as exc_info:
637
+ rebase(destination=gl_branch)
638
+ assert exc_info.value.code() == StatusCode.INVALID_ARGUMENT
639
+
640
+ # not a topic
641
+ with pytest.raises(RpcError) as exc_info:
642
+ rebase(source=gl_branch, destination=gl_branch)
643
+ details, rebase_error = parse_assert_structured_error(
644
+ exc_info.value, RebaseError, StatusCode.INVALID_ARGUMENT)
645
+ assert rebase_error.pre_check == PreCheckUpdateError.NOT_A_TOPIC
646
+
647
+ # unresolvable source or dest
648
+ with pytest.raises(RpcError) as exc_info:
649
+ rebase(destination=gl_branch, source=b'topic/default/unknown')
650
+ details, rebase_error = parse_assert_structured_error(
651
+ exc_info.value, RebaseError, StatusCode.FAILED_PRECONDITION)
652
+ assert rebase_error.resolve_rev.revision == b'topic/default/unknown'
653
+ with pytest.raises(RpcError) as exc_info:
654
+ rebase(source=gl_topic, destination=b'branch/unknown')
655
+ details, rebase_error = parse_assert_structured_error(
656
+ exc_info.value, RebaseError, StatusCode.FAILED_PRECONDITION)
657
+ assert rebase_error.resolve_rev.revision == b'branch/unknown'
658
+
659
+ # source_sha check failed
660
+ with pytest.raises(RpcError) as exc_info:
661
+ rebase(destination=gl_branch, source=gl_topic, source_head_sha=sha0)
662
+ details, rebase_error = parse_assert_structured_error(
663
+ exc_info.value, RebaseError, StatusCode.FAILED_PRECONDITION)
664
+ mismatch = rebase_error.ref_mismatch
665
+ assert mismatch.expected_object_id == ctx0.hex()
666
+ assert mismatch.actual_object_id == ctx2.hex()
667
+ assert mismatch.reference_name == gl_topic
668
+
669
+ # working simple case
670
+ resp = rebase(source=gl_topic, source_head_sha=sha2,
671
+ destination=gl_branch)
672
+ wrapper.reload()
673
+ new_hex = resp.branch_update.commit_id.encode('ascii')
674
+ assert new_hex
675
+ assert new_hex != ctx2.hex()
676
+ rebased = wrapper.repo[new_hex]
677
+ assert rebased.p1() == default_head
678
+ assert rebased.topic() == b'zetop'
679
+
680
+ # no-op gives empty response
681
+ wrapper.commit_file('fast-fwd', topic='ff', parent=default_head)
682
+ assert rebase(source=b'topic/default/ff',
683
+ destination=gl_branch) == RebaseResponse()
684
+
685
+
686
+ @parametrize('project_mode', ('hg-git-project', 'native-project'))
687
+ def test_rebase_conflict(operations_fixture, project_mode):
688
+ fixture = operations_fixture
689
+ rebase = fixture.rebase
690
+
691
+ fixture.hg_native = project_mode != 'hg-git-project'
692
+ wrapper = fixture.repo_wrapper
693
+
694
+ gl_branch = b'branch/default'
695
+ gl_topic = b'topic/default/zetop'
696
+
697
+ # because of the config set by fixture, this leads in all cases to
698
+ # creation of a Git repo and its `branch/default` Git branch
699
+ ctx0 = wrapper.commit_file('foo')
700
+ default_head = wrapper.commit_file('foo', content='foo')
701
+ default_sha = default_head.hex().decode()
702
+ ctx2 = wrapper.commit_file('foo', topic='zetop', parent=ctx0,
703
+ content='bar')
704
+ sha2 = ctx2.hex().decode()
705
+ # avoid keeping the rebased changesets visible
706
+ wrapper.update_bin(NULL_NODE)
707
+
708
+ initial_branches = gitlab_branches(wrapper.repo)
709
+
710
+ with pytest.raises(RpcError) as exc_info:
711
+ rebase(source=gl_topic, destination=gl_branch)
712
+ details, rebase_error = parse_assert_structured_error(
713
+ exc_info.value, RebaseError, StatusCode.FAILED_PRECONDITION)
714
+ conflict = rebase_error.conflict
715
+ assert conflict.conflicting_files == [b"foo"]
716
+ assert set(conflict.conflicting_commit_ids) == {default_sha, sha2}
717
+
718
+ # nothing changed and working dir is clean
719
+ wrapper.reload()
720
+ assert gitlab_branches(wrapper.repo) == initial_branches
721
+
722
+ wd_wrapper = fixture.workdir_repo_wrapper(0)
723
+ wd_repo = wd_wrapper.repo
724
+ ms = mergestate.read(wd_repo)
725
+ assert not list(ms.unresolved())
726
+ wctx = wd_repo[None]
727
+ assert wctx.p1() == ctx2
728
+ assert_empty_repo_status(wd_wrapper)
729
+
730
+
599
731
  @parametrize('project_mode', ('hg-git-project', 'native-project'))
600
732
  def test_censor(operations_fixture, project_mode):
601
733
  fixture = operations_fixture
@@ -456,6 +456,8 @@ def test_write_ref(fixture_with_repo):
456
456
  create_keep_around(repo, existing_ka)
457
457
  fixture.write_ref(b'refs/keep-around/' + sha, sha)
458
458
  assert set(iter_keep_arounds(repo)) == {sha, existing_ka}
459
+ fixture.write_ref(b'refs/keep-around/' + existing_ka, ZERO_SHA)
460
+ assert set(iter_keep_arounds(repo)) == {sha}
459
461
 
460
462
 
461
463
  def test_write_special_refs_exceptions(fixture_with_repo):
@@ -896,8 +898,7 @@ def test_remove_repository(fixture_with_repo, wds_success):
896
898
  os.makedirs(aux_git_dir, exist_ok=True)
897
899
  (aux_git_dir / 'anyfile').write_bytes(b'anything')
898
900
 
899
- tmp_dir = wrapper.path.parent / '+hgitaly/tmp'
900
- wds_root = tmp_dir / 'workdirs' / grpc_repo.relative_path
901
+ wds_root = fixture.repo_workdirs_root()
901
902
 
902
903
  if wds_success == 'error':
903
904
  # let's sabotage the roster file to trigger an inner exception
@@ -920,7 +921,7 @@ def test_remove_repository(fixture_with_repo, wds_success):
920
921
  assert not aux_git_dir.exists()
921
922
 
922
923
  # no leftover in the temporary directory either
923
- assert not os.listdir(tmp_dir / 'workdirs')
924
+ assert not os.listdir(fixture.storage_workdirs())
924
925
 
925
926
  # unknown storage and repo
926
927
  with pytest.raises(grpc.RpcError) as exc_info:
@@ -33,6 +33,8 @@ from .stub.shared_pb2 import (
33
33
  GARBAGE_COLLECTING_RATE_GEN2 = 250
34
34
  GARBAGE_COLLECTING_RATE_GEN1 = 20
35
35
  AUX_GIT_REPOS_RELATIVE_DIR = "+hgitaly/hg-git"
36
+ TMP_RELATIVE_DIR = "+hgitaly/tmp"
37
+ REPOS_WORKDIRS_RELATIVE_DIR = TMP_RELATIVE_DIR + '/workdirs'
36
38
  HG_GIT_MIRRORING_MD_KEY = 'x-heptapod-hg-git-mirroring'
37
39
  NATIVE_PROJECT_MD_KEY = 'x-heptapod-hg-native'
38
40
  # TODO check if there is a GitLab MD for this, it should:
@@ -357,7 +359,7 @@ class HGitalyServicer:
357
359
  :raises OSError: if creation fails.
358
360
  """
359
361
  temp_dir = os.path.join(self.storage_root_dir(storage_name, context),
360
- b'+hgitaly', b'tmp')
362
+ TMP_RELATIVE_DIR.encode('ascii'))
361
363
  if not ensure:
362
364
  return temp_dir
363
365