Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undercover fails with shallow repository + grafted commits #175

Open
kuahyeow opened this issue Jun 24, 2022 · 3 comments
Open

Undercover fails with shallow repository + grafted commits #175

kuahyeow opened this issue Jun 24, 2022 · 3 comments

Comments

@kuahyeow
Copy link

On GitLab CI, the default depth for the cloned git repository is 50 (for projects like https://gitlab.com/gitlab-org/gitlab/, we set it even lower to 20, for speed purposes).

This leads to errors like below

$ cat scripts/undercoverage
#!/usr/bin/env bash

bundle exec undercover -c "${1:-$(git merge-base origin/master HEAD)}"

$ UNDERCOVERAGE_COMPARE="${CI_MERGE_REQUEST_TARGET_BRANCH_SHA:-$CI_MERGE_REQUEST_DIFF_BASE_SHA}"
$ echo $UNDERCOVERAGE_COMPARE
b0238c51c69da80150745d92be243dc244d947b9

$ scripts/undercoverage ${UNDERCOVERAGE_COMPARE}
bundler: failed to load command: undercover (/builds/gitlab-org/gitlab/vendor/ruby/2.7.0/bin/undercover)
/builds/gitlab-org/gitlab/vendor/ruby/2.7.0/gems/undercover-0.4.4/lib/undercover/changeset.rb:77:in `merge_base': object not found - no match for id (a0036d11ff015325fe97e86aa0278b3e01e13bb3) (Rugged::OdbError)
	from /builds/gitlab-org/gitlab/vendor/ruby/2.7.0/gems/undercover-0.4.4/lib/undercover/changeset.rb:77:in `compare_base_obj'
	from /builds/gitlab-org/gitlab/vendor/ruby/2.7.0/gems/undercover-0.4.4/lib/undercover/changeset.rb:70:in `full_diff'
	from /builds/gitlab-org/gitlab/vendor/ruby/2.7.0/gems/undercover-0.4.4/lib/undercover/changeset.rb:27:in `update'
	from /builds/gitlab-org/gitlab/vendor/ruby/2.7.0/gems/undercover-0.4.4/lib/undercover.rb:34:in `initialize'
	from /builds/gitlab-org/gitlab/vendor/ruby/2.7.0/gems/undercover-0.4.4/lib/undercover/cli.rb:26:in `new'
	from /builds/gitlab-org/gitlab/vendor/ruby/2.7.0/gems/undercover-0.4.4/lib/undercover/cli.rb:26:in `run_report'
	from /builds/gitlab-org/gitlab/vendor/ruby/2.7.0/gems/undercover-0.4.4/lib/undercover/cli.rb:21:in `run'
	from /builds/gitlab-org/gitlab/vendor/ruby/2.7.0/gems/undercover-0.4.4/bin/undercover:12:in `block in <top (required)>'
	from /usr/local/lib/ruby/2.7.0/benchmark.rb:308:in `realtime'
	from /builds/gitlab-org/gitlab/vendor/ruby/2.7.0/gems/undercover-0.4.4/bin/undercover:11:in `<top (required)>'
	from /builds/gitlab-org/gitlab/vendor/ruby/2.7.0/bin/undercover:25:in `load'
	from /builds/gitlab-org/gitlab/vendor/ruby/2.7.0/bin/undercover:25:in `<top (required)>'
	from /usr/local/lib/ruby/gems/2.7.0/gems/bundler-2.3.15/lib/bundler/cli/exec.rb:58:in `load'
	from /usr/local/lib/ruby/gems/2.7.0/gems/bundler-2.3.15/lib/bundler/cli/exec.rb:58:in `kernel_load'
	from /usr/local/lib/ruby/gems/2.7.0/gems/bundler-2.3.15/lib/bundler/cli/exec.rb:23:in `run'
	from /usr/local/lib/ruby/gems/2.7.0/gems/bundler-2.3.15/lib/bundler/cli.rb:483:in `exec'
	from /usr/local/lib/ruby/gems/2.7.0/gems/bundler-2.3.15/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
	from /usr/local/lib/ruby/gems/2.7.0/gems/bundler-2.3.15/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
	from /usr/local/lib/ruby/gems/2.7.0/gems/bundler-2.3.15/lib/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
	from /usr/local/lib/ruby/gems/2.7.0/gems/bundler-2.3.15/lib/bundler/cli.rb:31:in `dispatch'
	from /usr/local/lib/ruby/gems/2.7.0/gems/bundler-2.3.15/lib/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
	from /usr/local/lib/ruby/gems/2.7.0/gems/bundler-2.3.15/lib/bundler/cli.rb:25:in `start'
	from /usr/local/lib/ruby/gems/2.7.0/gems/bundler-2.3.15/exe/bundle:48:in `block in <top (required)>'
	from /usr/local/lib/ruby/gems/2.7.0/gems/bundler-2.3.15/lib/bundler/friendly_errors.rb:117:in `with_friendly_errors'
	from /usr/local/lib/ruby/gems/2.7.0/gems/bundler-2.3.15/exe/bundle:36:in `<top (required)>'
	from /usr/local/bin/bundle:23:in `load'
	from /usr/local/bin/bundle:23:in `<main>'

From https://gitlab.com/gitlab-org/gitlab/-/jobs/2627986054

Steps to reproduce

  1. Setup merged result pipelines on a GitLab project (https://docs.gitlab.com/ee/ci/pipelines/merged_results_pipelines.html)
  2. Create a merge request
  3. In the CI, run undercover -c ${CI_MERGE_REQUEST_TARGET_BRANCH_SHA}
  4. If the merge request's branch is old enough, it should fail with the above error.

libgit2/rugged#846 (comment) seems related.

@kuahyeow
Copy link
Author

kuahyeow commented Jun 24, 2022

I did manage to reproduce this locally as well - will post these steps soon.

We worked around this with the following monkey-patch

#!/usr/bin/env ruby

# frozen_string_literal: true

require 'undercover'

module Undercover
  class Changeset
    # Rugged merge_base complains when graft/shallow
    # (https://github.com/libgit2/rugged/issues/846)
    #
    # So we assume we provide the merge-base ourself. Modified from
    # https://github.com/grodowski/undercover/blob/32e62f66682ee566032b5970437ed2934ef29701/lib/undercover/changeset.rb#L74-L78
    def compare_base_obj
      return unless compare_base

      repo.lookup(compare_base.to_s)
    end
  end
end

compare_base = ARGV[0]
compare_base ||= IO.popen(%w(git merge-base origin/master HEAD)) { |p| p.read.chomp }

result = Undercover::CLI.run(%W(-c #{compare_base}))
exit result

I'm happy to draft up some PR but unsure if this should be another configuration option, or something else.

@grodowski
Copy link
Owner

Thanks for reporting this @kuahyeow, I remember getting compare_base_obj to work wasn't so obvious and I am aware that merge_base may stop working for shallow clones.

I'm happy to draft up some PR but unsure if this should be another configuration option, or something else.

I appreciate it and would be happy to help too. My initial thought is that ideally this wouldn't require any extra configuration, given that it's possible to infer what has been passed to --compare? If it's a ref, just look it up like in your workaround and only otherwise scan for the merge_base. I don't know it's doable with the current rugged API and will be looking more into it

@kuahyeow
Copy link
Author

kuahyeow commented Jul 20, 2022

Thanks for reporting this @kuahyeow, I remember getting compare_base_obj to work wasn't so obvious and I am aware that merge_base may stop working for shallow clones.

I'm happy to draft up some PR but unsure if this should be another configuration option, or something else.

I appreciate it and would be happy to help too. My initial thought is that ideally this wouldn't require any extra configuration, given that it's possible to infer what has been passed to --compare? If it's a ref, just look it up like in your workaround and only otherwise scan for the merge_base. I don't know it's doable with the current rugged API and will be looking more into it

@grodowski In GitLab's case, we pass in a SHA to --compare and not a ref. So not sure that will work.

For example, GitLab CI provides a variable called CI_MERGE_REQUEST_TARGET_BRANCH_SHA which is already the merge-base of the feature branch, and the main branch. It's value looks like 91a9efed376560f1f4ce35f350bfc52520cbbc7b.

Possible ideas:

  1. Change --compare to never get merge-base itself, require user to do it themself (breaking change)
  2. Provide an option --[no-]compare-merge-base. If --no-compare-merge-base, undercover skips getting the merge base from --compare. If --compare-merge-base, undercover gets the merge base from --compare as per now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants