Class: ShopifyCLI::Git
- Inherits:
-
Object
- Object
- ShopifyCLI::Git
- Defined in:
- lib/shopify_cli/git.rb
Overview
ShopifyCLI::Git wraps git functionality to make it easier to integrate will git.
Class Method Summary collapse
-
.available?(ctx) ⇒ Boolean
Check if the current working directory is a Git repository.
-
.branches(ctx) ⇒ Object
will fetch the repos list of branches.
-
.clone(repo_with_branch, dest, ctx: Context.new) ⇒ Object
calls git to clone a new repo into a supplied destination, it will also output progress of the cloning process into a new progress bar.
-
.clone_progress(stderr, bar: nil) ⇒ Object
handles showing the progress of the git clone command.
-
.exists?(ctx) ⇒ Boolean
Check if Git exists in the environment.
-
.git_clone_command(repo, dest, branch) ⇒ Object
returns array with components of git clone command.
-
.init(ctx) ⇒ Object
will initialize a new repo in the current directory.
-
.merge_file(current_file, base_file, other_file, opts = [], ctx: Context.new) ⇒ Object
Run git three-way file merge (it doesn’t require an initialized git repository).
-
.raw_clone(repo_with_branch, dest, ctx: Context.new) ⇒ Object
calls git to clone a new repo into a supplied destination, it will also call a supplied block with the percentage of clone completion.
-
.sha(dir: Dir.pwd, ctx: Context.new) ⇒ Object
will return the current sha of the cli repo.
- .sparse_checkout(repo, set, branch, ctx) ⇒ Object
Class Method Details
.available?(ctx) ⇒ Boolean
Check if the current working directory is a Git repository
16 17 18 19 20 21 |
# File 'lib/shopify_cli/git.rb', line 16 def available?(ctx) _output, status = ctx.capture2e("git", "status") status.success? rescue Errno::ENOENT # git is not installed false end |
.branches(ctx) ⇒ Object
will fetch the repos list of branches.
#### Parameters
-
‘ctx` - the current running context of your command, defaults to a new context.
#### Returns
-
‘branches` - [String] an array of strings that are branch names
#### Example
branches = ShopifyCLI::Git.branches(@ctx)
175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/shopify_cli/git.rb', line 175 def branches(ctx) output, status = ctx.capture2e("git", "branch", "--list", "--format=%(refname:short)") ctx.abort(ctx.("core.git.error.no_branches_found")) unless status.success? branches = if output == "" ["master"] else output.split("\n") end branches end |
.clone(repo_with_branch, dest, ctx: Context.new) ⇒ Object
calls git to clone a new repo into a supplied destination, it will also output progress of the cloning process into a new progress bar
#### Parameters
-
‘repo_with_branch` - a git url for git to clone the repo from
-
‘dest` - a filepath to where the repo should be cloned to
-
‘ctx` - the current running context of your command, defaults to a new context.
#### Returns
-
‘sha_string` - string of the sha of the most recent commit to the repo
#### Example
ShopifyCLI::Git.clone('[email protected]:shopify/test.git', 'test-app')
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/shopify_cli/git.rb', line 131 def clone(repo_with_branch, dest, ctx: Context.new) if Dir.exist?(dest) && !Dir.empty?(dest) ctx.abort(ctx.("core.git.error.directory_exists")) else msg = [] # require at usage point to not slow down CLI startup # https://github.com/Shopify/shopify-cli/pull/698#discussion_r444342445 require "open3" repo, branch = repo_with_branch.split("#") git_cmd = git_clone_command(repo, dest, branch) = ctx.("core.git.cloned", dest) CLI::UI::Frame.open(ctx.("core.git.cloning", repo, dest), success_text: ) do CLI::UI::Progress.progress do || success = Open3.popen3("git", *git_cmd, "--progress") do |_stdin, _stdout, stderr, thread| msg = clone_progress(stderr, bar: ) thread.value end.success? ctx.abort((msg.join("\n"))) unless success .tick(set_percent: 1.0) end end end end |
.clone_progress(stderr, bar: nil) ⇒ Object
handles showing the progress of the git clone command. if block given, assumes passing percent to block, otherwise increments bar for progress bar
#### Parameters
-
‘stderr` - Open3.popen3 output stream
-
‘bar` - progress bar object to set percent
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
# File 'lib/shopify_cli/git.rb', line 288 def clone_progress(stderr, bar: nil) msg = [] while (line = stderr.gets) msg << line.chomp next unless line.strip.start_with?("Receiving objects:") percent = (line.match(/Receiving objects:\s+(\d+)/)[1].to_f / 100).round(2) if block_given? yield percent elsif !.nil? .tick(set_percent: percent) end end msg end |
.exists?(ctx) ⇒ Boolean
Check if Git exists in the environment
8 9 10 11 12 13 |
# File 'lib/shopify_cli/git.rb', line 8 def exists?(ctx) _output, status = ctx.capture2e("git", "version") status.success? rescue Errno::ENOENT # git is not installed false end |
.git_clone_command(repo, dest, branch) ⇒ Object
returns array with components of git clone command
#### Parameters
-
‘repo` - repo url without branch name
-
‘dest` - a filepath to where the repo should be cloned to
-
‘branch` - branch name when cloning
#### Returns
-
array of strings
#### Example
["clone", "--single-branch", "--branch", "test-branch", "test-app"]
65 66 67 68 69 70 71 |
# File 'lib/shopify_cli/git.rb', line 65 def git_clone_command(repo, dest, branch) if branch ["clone", "--single-branch", "--branch", branch, repo, dest] else ["clone", "--single-branch", repo, dest] end end |
.init(ctx) ⇒ Object
will initialize a new repo in the current directory. This will output if it was successful or not.
#### Parameters
-
‘ctx` - the current running context of your command, defaults to a new context.
#### Example
ShopifyCLI::Git.init(@ctx)
236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/shopify_cli/git.rb', line 236 def init(ctx) output, status = ctx.capture2e("git", "status") unless status.success? ctx.abort(ctx.("core.git.error.repo_not_initiated")) end if output.include?("No commits yet") ctx.abort(ctx.("core.git.error.no_commits_made")) end end |
.merge_file(current_file, base_file, other_file, opts = [], ctx: Context.new) ⇒ Object
Run git three-way file merge (it doesn’t require an initialized git repository)
#### Parameters
-
‘current_file - string path of the current file
-
‘base_file` - string path of the base file
-
‘other_file` - string path of the other file
-
‘opts` - list of “git merge-file” options. Valid values:
- "-q" - do not warn about conflicts - "--diff3" - show conflicts - "--ours" - resolve conflicts favoring lines from `current_file` - "--theirs" - resolve conflicts favoring lines from `other_file` - "--union" - resolve conflicts favoring lines from both files - "-p" - send results to standard output instead of overwriting the `current_file`
-
‘ctx` - the current running context of your command, defaults to a new context
#### Returns
-
standard output from git
#### Example
output = ShopifyCLI::Git.merge_file(current_file, base_file, other_file, opts, ctx: ctx)
214 215 216 217 218 219 220 221 222 |
# File 'lib/shopify_cli/git.rb', line 214 def merge_file(current_file, base_file, other_file, opts = [], ctx: Context.new) output, status = ctx.capture2e("git", "merge-file", current_file, base_file, other_file, *opts) unless status.success? ctx.abort(ctx.("core.git.error.merge_failed")) end output end |
.raw_clone(repo_with_branch, dest, ctx: Context.new) ⇒ Object
calls git to clone a new repo into a supplied destination, it will also call a supplied block with the percentage of clone completion
#### Parameters
-
‘repo_with_branch` - a git url for git to clone the repo from
-
‘dest` - a filepath to where the repo should be cloned to
-
‘ctx` - the current running context of your command, defaults to a new context.
#### Returns
-
‘sha_string` - string of the sha of the most recent commit to the repo
#### Example
ShopifyCLI::Git.raw_clone('[email protected]:shopify/test.git', 'test-app')
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/shopify_cli/git.rb', line 91 def raw_clone(repo_with_branch, dest, ctx: Context.new) if Dir.exist?(dest) && !Dir.empty?(dest) ctx.abort(ctx.("core.git.error.directory_exists")) else msg = [] # require at usage point to not slow down CLI startup # https://github.com/Shopify/shopify-cli/pull/698#discussion_r444342445 require "open3" repo, branch = repo_with_branch.split("#") git_cmd = git_clone_command(repo, dest, branch) success = Open3.popen3("git", *git_cmd, "--progress") do |_stdin, _stdout, stderr, thread| msg = clone_progress(stderr, bar: nil) thread.value end.success? ctx.abort((msg.join("\n"))) unless success end end |
.sha(dir: Dir.pwd, ctx: Context.new) ⇒ Object
will return the current sha of the cli repo
#### Parameters
-
‘dir` - the directory of the git repo. This defaults to the cli repo
-
‘ctx` - the current running context of your command
#### Returns
-
‘sha_string` - string of the sha of the most recent commit to the repo
#### Example
ShopifyCLI::Git.sha
Some environments don’t have git in PATH and this prevents the execution from raising an error app.bugsnag.com/shopify/shopify-cli/errors/615dd36365ce57000889d4c5
42 43 44 45 46 |
# File 'lib/shopify_cli/git.rb', line 42 def sha(dir: Dir.pwd, ctx: Context.new) if available?(ctx) rev_parse("HEAD", dir: dir, ctx: ctx) end end |
.sparse_checkout(repo, set, branch, ctx) ⇒ Object
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/shopify_cli/git.rb', line 248 def sparse_checkout(repo, set, branch, ctx) _, status = ctx.capture2e("git init") unless status.success? ctx.abort(ctx.("core.git.error.repo_not_initiated")) end _, status = ctx.capture2e("git remote add -f origin #{repo}") unless status.success? ctx.abort(ctx.("core.git.error.remote_not_added")) end _, status = ctx.capture2e("git config core.sparsecheckout true") unless status.success? ctx.abort(ctx.("core.git.error.sparse_checkout_not_enabled")) end _, status = ctx.capture2e("git sparse-checkout set #{set}") unless status.success? ctx.abort(ctx.("core.git.error.sparse_checkout_not_set")) end resp, status = ctx.capture2e("git pull origin #{branch}") unless status.success? if resp.include?("fatal: couldn't find remote ref") ctx.abort(ctx.("core.git.error.pull_failed_bad_branch", branch)) end ctx.abort(ctx.("core.git.error.pull_failed")) end end |