1. 14 Oct, 2020 1 commit
    • Georges Racinet's avatar
      Repository archives: dispatching to HGitaly for Mercurial repos · 2e2da0334c73
      Georges Racinet authored
      For archive production, the Rails app duty is to return
      direct connection information to Workhorse, so that it can call
      Gitaly directly.
      We're reusing the dispatching logic for our existing (yet unplugged)
      HGitaly integration: by prefixing the storage (shard) with `hg:` for
      Mercurial repositories, we have the `GitalyClient.address` return
      connection information for the HGitaly server.
      For this to work, we need `archive_metadata` method of the
      Mercurial Repository classes to provide the Mercurial SHA, which we do
      by intoducing the dedicated `archive_sha` method.
      branch : heptapod
  2. 09 Oct, 2020 1 commit
    • Georges Racinet's avatar
      HgGitRepository: low level hg_tag method · 74b64d425d85
      Georges Racinet authored
      This is for now mostly intended as a helper for tests.
      We're using one of the HGitaly tags test to make sure it works,
      and in turn that test gets simplified.
      There's a catch: `hg_git_repository.hg_tag` would not
      work before `subject` has been used at least once, so that the
      repository is indeed initialized on disk.
      If we were in need to use `hg_git_repository` here, we'd have
      to switch to `subject!` instead of just `subject`.
      branch : heptapod
  3. 24 Sep, 2020 2 commits
  4. 10 Sep, 2020 1 commit
    • Georges Racinet's avatar
      Markdown renderings: lookup for Mercurial short nodes · 31146d7c450d
      Georges Racinet authored
      The `CommitReferenceFilter` class is the one responsible for
      the rendering.
      We're *adding* resolution of truncated Mercurial Node ids for
      the case of the `hg_git` VCS type, relying on the existing
      map of full Mercurial SHA (Node id) to Git SHA.
      This is very inefficient, and proper calls with low startup
      overhead to a persistent Mercurial nodemap would do much better
      above a certain repository size (persistent nodemap is provided
      by Rust native extensions, and low overhead would be achieved only
      by a fastpath without Python or a long-running process, such as
      While the `Git::Commit.batch_by_oid` method
      doesn't seem to be called except from the `#commits_by` method of the
      `Repository` model, the latter is used in several places
      of the application, with risks of breakage and/or severe performance
      degradation. For `hg_git` VCS type, most callers don't need the Mercurial
      resolution. That's why we're executing the new lookup only if
      the new `hg_full_resolution` argument is set to `true`.
      Preliminary performance analysis (non scientific, on my workstation)
      shows that in the 100k changesets range (pypy repo) this naive lookup takes
      about 30ms, whereas `hg log -T` is in the 100-200ms ballpark.
      Around 500k changesets (mozilla-central repo), times have the same order
      of magnitude (around 100-200ms again). To insist, this is with the hg startup
      overhead and without the Rust persistent nodemap (would take less than 1ms).
      We fully expect the current hg<->git maps to be an unbereable performance
      problem in Heptapod anyway around 500k to 1M changesets anyway, only solved
      by HGitaly.
      All in all, the performance question seems to be acceptable in the current
      inefficient context *for Note rendering*.
      HGitaly would provide an efficient RPC call anyway.
      branch : heptapod-stable
  5. 27 Aug, 2020 3 commits
    • Georges Racinet's avatar
      Forwarding actual permissions to Mercurial processes · 4c45dfe84231
      Georges Racinet authored
      Closes #334
      Normally, the abstraction layers in GitLab mean that the Project
      should not be accessible from the low level repository. However,
      we need it to pass it down to the `hg` processes. Doing it in
      `hg_env_for_write` is the way to make it really robust, since all
      write operations basically have to use it.
      To mitigate somewhat this breach of abstraction, we make the
      attribute writable only, and we give it a more specific name than
      just '@project'. Aesthetically, it would be better to store only
      a factory for the `UserAccess` instance that we really need, but
      that could be done separately.
      This required running some of `HgAccess` RSpec tests with empty
      repositories, because in them, the project owner does not have enough
      rights to create a first commit any more, and there's not even
      an admin user around for that.
      branch : heptapod
    • Georges Racinet's avatar
      HgGitRepository: removed duplication · 4fb9222b604b
      Georges Racinet authored
      We still have a deprecated compatibility alias, and the
      rebase tests prove that it works.
      branch : heptapod
    • Georges Racinet on mutations.racinet.fr's avatar
      HgGitRepository: attribute to skip Git hooks for tests · db821ec4ea3f
      This new attribute is not meant to be used in any other context
      than RSpec tests, whence the name. It allows us to use higher
      level methods such as `multi_action` in tests setups and will be
      necessary to test them.
      Upstream does something similar with no need to involve the tested code:
      they launch Gitaly server with the `GITALY_TESTING_NO_GIT_HOOKS` environment
      branch : heptapod
  6. 26 Aug, 2020 2 commits
  7. 24 Aug, 2020 2 commits
    • Georges Racinet's avatar
      Repository files (multi_action): check publisher permission · e029134a44f0
      Georges Racinet authored
      This is a variant of #332 for multi_action.
      As with the case of merge requests, the check should also be
      performed at low level by Mercurial, but doing it at the model
      level makes for early failure, avoiding atomicity issues.
      A difference with MRs is that we don't have a simple way *not* to
      propose the action to the user yet, because higher layers are more
      complicated and don't involve checks, since they are meant to produce
      forks for users without write permission.
      This currently provides 500 errors, but at least it closes the
      security problem, and we can later on add the necessary catching.
      We didn't want to affect Wikis, because for them, allowing publication
      for Developers is pretty normal.
      branch : heptapod-stable
    • Georges Racinet's avatar
      HgGitRepository: split out hg_config_item_bool? method · ff5823e89d14
      Georges Racinet authored
      This is just cleaner and prone to reuse.
      branch : heptapod-stable
  8. 03 Aug, 2020 1 commit
    • Georges Racinet's avatar
      Operations: port over HGRC files from main repo to share · db7ee4fbacad
      Georges Racinet authored
      Closes #324
      The specific repo configuration was ignored in all Mercurial
      operations initiated by the Rails app.
      I've considered making links instead of copying the file, but
      it could give rise to funny situations if the original HGRC
      files get changed in concurrency with some operation.
      Edition of the HGRC files is by no means atomic in itself,
      but that's a separate issue. On the other hand, operations can be
      arbitrary long, involving several calls to the `hg` executable.
      One would not want the rules to change in the middle of that.
      branch : heptapod
  9. 17 Jul, 2020 1 commit
  10. 16 Jul, 2020 4 commits
    • Georges Racinet's avatar
      HgGitRepository#get_hg_heptapod_config can ignore global conf · 05ed90b0af75
      Georges Racinet authored
      This will be useful for an incremental approach of configuration
      setting, and spares us INI format parsing in Ruby (GitLab does not
      come with a gem for this).
      branch : heptapod-stable
    • Georges Racinet's avatar
      HgGitRepository: make get_hg_heptapod_config work if empty · e70d3a5eb8d7
      Georges Racinet authored
      Because `hg config SECTION` exits with code 1 if no matching
      setting have been found, we previously had an error if this
      method (and the corresponding API endpoint) was called before
      any local setting is set in the `[heptapod]` section.
      This can be considered part of #299, too
      Also fixed the exception raising, Ruby has its quirks, not the
      same as Python's.
      branch : heptapod-stable
    • Georges Racinet's avatar
      HgGitRepository: don't crash if no managed hgrc exists yet · c23adf095138
      Georges Racinet authored
      Closes #299
      We'll return content to be `nil` in that case, which will be
      conveyed as `null` in the JSON API.
      branch : heptapod-stable
    • Georges Racinet's avatar
      HgGitRepository: taking Mercurial repo size into account · 2d5d3aff9555
      Georges Racinet authored
      Closes #314
      Previously only the Git repository was considered.
      Note that this is cached in the `projects_statistics` table,
      and can be invalidated by doing
      This seems in turn to be triggered by `UpdateProjectStatisticsWorker`,
      iself called by `ProjectCacheWorker`, from the likes of `PostReceiveWorker`
      branch : heptapod-stable
  11. 14 Jun, 2020 2 commits
    • Georges Racinet's avatar
      Post-receives for repository files and merges with changeset · 376d59c06826
      Georges Racinet authored
      Post-receive notificiations are necessary to trigger pipelines and
      other post branch update actions that must be taken on the GitLab
      Previously, we enabled them in merges with changeset performed by the
      Rails app itself, but we had only the publication step send them
      to avoid unnecessary consequences like redundant pipelines, but that
      was wrong: if there's already an added commit on `branch/default`
      a publication doesn't trigger any change on `branch/default`. The
      only post-receive it can send is a topic branch prune.
      branch : heptapod-stable
    • Georges Racinet's avatar
      Passing vcs_type to GitlabShellWorker and fixing repo removal · 1f9e56d13b01
      Georges Racinet authored
      Because sidekiq workers don't seem to take named arguments, we
      pass it as the last required positional one and convert it to
      named argument in the actual call to `Gitlab::Shell`.
      Then it was simpler just to let `Gitlab::Shell#rm_namespace`, the
      only method not taking a `vcs_type` named arg to accept it for
      All call sites for GitlabShellWorker are updated. There aren't so
      many, due to the general deprecation of `Gitlab::Shell`, also a
      reason not to worry about new callers appearing in future versions.
      Finally, the `remove` method wasn't even implemented in
      branch : heptapod
  12. 08 Jun, 2020 1 commit
  13. 05 Jun, 2020 1 commit
    • Georges Racinet's avatar
      Imports: adapted for GitLab 12.10 · 38a64ea242b6
      Georges Racinet authored
      The main code path for imports is no longer in `Gitlab::Shell`.
      Instead, that functionality is provided by the `Repository` objects,
      themselves called rather directly from `Projects::ImportService`.
      We're adopting our existing code in `HgGitRepository`. Because that
      is a repository creation, it means we have to passover the Mercurial
      specific arguments as well, and hence make the pure Git version from
      `Git::Repository` accept them.
      Finally, this allows us to remove our band-aid executable and its
      underlying lib (`gitlab_project_hg.rb`).
      Of course `ImportService` is itself always called from a Worker.
      branch : heptapod
  14. 04 Jun, 2020 3 commits
    • Georges Racinet's avatar
      Rebase: accepting new argument · 529df5c54809
      Georges Racinet authored
      At some point we'll have to investigate these push options and
      what Mercurial can do with them. Ignoring them is good enough
      for our immediate purpose: making our existing Heptapod work
      on GitLab 12.10
      branch : heptapod
    • Georges Racinet's avatar
      Squash: adapted for API break · 318ead425ecd
      Georges Racinet authored
      The `branch` argument does not exist any more. Not so surprising:
      we weren't using it.
      branch : heptapod
    • Georges Racinet's avatar
      HgGitRepository: fixed hg username generation · 027c191d4027
      Georges Racinet authored
      This hg username is used notably as commit author.
      Between GitLab 12.3 and 12.10, `committer_hash` was simply
      removed. That seems to be because Gitaly accepts separate
      name and email anyway.
      There was one calling site not using the `hg_prepare_user_encoding`.
      In that case, just using it is the solution.
      branch : heptapod
  15. 02 Jun, 2020 1 commit
    • Georges Racinet's avatar
      Adapted rename/transfer for GitLab 12.10 · 95a24b052d2a
      Georges Racinet authored
      We're following the trend of letting the Repository
      object take care of most of the logic, instead of calling
      separate methods for Git and Hg from the services or
      from `Gitlab::Shell`.
      For renames, including migration to hashed storage,
      this works because the fixup for the HGRC namespace inclusion
      can find the path to the namespace from the include line, or
      there's nothing to be fixed. This is what the new
      `rpath_to_namespace_if_hgrc_included` method does.
      The end result is certainly suboptimal: the repo HGRC will be
      scanned several times, and the transfers now fixup the inclusion,
      only to change it afterwards. But none of these is a real
      concern for now, the important thing is the concentration of
      the hg/git dispatching in less places than before.
      branch : heptapod
  16. 29 May, 2020 1 commit
  17. 28 May, 2020 2 commits
    • Georges Racinet's avatar
      Squash: honouring squash_in_progress? · cfd7b187b509
      Georges Racinet authored
      This works with the same principle as rebase_in_progress?,
      see parent commit.
      branch : heptapod
    • Georges Racinet's avatar
      Rebase: honouring rebase_in_progress? · d7a0e368784b
      Georges Racinet authored
      We name the temporary working directory according to the given
      rebase_id and the question whether it's in progress boils down
      to the workdir being there.
      Ideally, some other kind of persistent storage should be used
      immediately, but we can use this as a better approximation for
      the time being. In upstream GitLab, this is handled by Gitaly,
      whose rebase RPC call receives the `rebase_id` and then answers
      the question. Later on HGitaly will do the same.
      branch : heptapod
  18. 27 May, 2020 1 commit
    • Georges Racinet's avatar
      Mercurial rebase for topics · 5f6de060df79
      Georges Racinet authored
      Closes #280
      This is enough for merge requests based on topics, which
      currently would display a 'rebase' button if the method is
      For now we add a hard check that the branch being rebased is
      related to a topic, that makes for a simple revset.
      As in the case of squashs, the protection against concurrent
      rebases seems at first sight to be unneeded (the rebase itself
      is atomic enough, and a subsequent would fail because it'd create
      instabilities) but because of #277 we have to be cautious
      with concurrency and avoid potential thundering herds of shares.
      This will be done for both squash and rebase in a follow-up that
      would simply test for presence of a share.
      branch : heptapod
  19. 28 May, 2020 2 commits
  20. 23 May, 2020 2 commits
    • Georges Racinet's avatar
      Temporary workdirs: switching to the closure style · 8211911f4bca
      Georges Racinet authored
      This is better style and it makes sense for the method that
      create the temporary working directory to take care of its
      cleanup. Overall, we lower the risk to forget an `ensure`
      We change the name of the method in the same move because
      - it's consistent with what the method does
      - it helps us being sure there isn't a leftover call to
        the old `hg_new_workdir` method.
      branch : heptapod
    • Georges Racinet's avatar
      Cleaning up temporary workdirs (shares) if creation fails · ac2102a384f3
      Georges Racinet authored
      Severe leaks of temporary workdirs are reported in #277.
      This change removes a potential source, not claiming to be a
      complete solution: if the update to revision failed, it would
      leave a directory behind, that maybe could be large already.
      That is because the begin … ensure clauses typically happen
      after the return from `hg_new_workdir`
      branch : heptapod
  21. 12 May, 2020 1 commit
    • Georges Racinet's avatar
      Mercurial::Repository.multi_action normalize exception raise · 6fc21d2a7dcb
      Georges Racinet authored
      Higher level methods in GitLab expect Git::Index::IndexError,
      so we have to give them some. For instance, the API will catch
      these and provide appropriate 400 errors from the message.
      We decided to settle for the same messages as provided by Gitlab
      (actually by Gitaly through the `user_commit_files` request of
      the OperationService), even though some are a bit ambiguous,
      especially in the case of renames.
      This doesn't change the fact that the hg calls could still fail,
      even though many cases are covered by the a priori checks. We'll
      still raise HgError for unexpected failures.
      branch : heptapod
  22. 11 May, 2020 5 commits
    • Georges Racinet's avatar
      Mercurial::Repository.multi_action distinction create/update · 52e78e85ca23
      Georges Racinet authored
      What they are supposed to do is written in comment, and
      actually obtained by looking at the Git implementation.
      Notably, subdirectory creation is implicit in create, etc.
      branch : heptapod
    • Georges Racinet's avatar
      Mercurial::Repository.multi_action start_branch_name defaulting · 6a19a5f00cd0
      Georges Racinet authored
      Up to now, our implementation behaved as if it were actually
      required, but some callers (e.g., Wikis::CreateAttachmentService)
      don't pass it, and defaulting to `branch_name` is the right way
      to go.
      branch : heptapod
    • Georges Racinet's avatar
      Mercurial::Repository.multi_action create_dir · 701a767a9316
      Georges Racinet authored
      It had previously not been implemented
      branch : heptapod
    • Georges Racinet's avatar
      Mercurial::Repository.multi_action logging tweaks · e7f932486f0e
      Georges Racinet authored
      Since the content is part of the action Hash, it's important
      to avoid it. Name and path will be enough.
      Also, logging `share_path` is useful to debug (before it
      is destroyed, obviously)
      branch : heptapod
    • Georges Racinet's avatar
      Mercurial::Repository multi_action refactor for FS independence · 52136082f11a
      Georges Racinet authored
      The contract for multi_action is that incoming path are specified
      the "web" way (as obvious e.g., in Wiki operations), meaning with
      forward slash as separator.
      In the Git case for GitLab 12 they are passed over as-is to Gitaly.
      In our local Hg implementation, we should now convert with `File.join`
      The odds of using Heptapod on Windows are low, but it's good hygiene.
      Also, factorizing in the `file_path` and `abspath` variables for
      further developments (separation of `create` and `update`, notably).
      branch : heptapod