class Maximus::GitControl
Git management @since 0.1.0
Public Class Methods
Set up instance variables
Inherits settings from {Config#initialize} @param opts [Hash] options passed directly to config @option opts [Config object] :config custom Maximus::Config
object @option opts [String] :commit accepts sha, “working”, “last”, or “master”.
# File lib/maximus/git_control.rb, line 18 def initialize(opts = {}) opts[:config] ||= Maximus::Config.new({ commit: opts[:commit] }) @config = opts[:config] @settings = @config.settings @psuedo_commit = ( !@settings[:commit].blank? && %w(working last master).include?(@settings[:commit]) ) @g = Git.open(@config.working_dir) end
Public Instance Methods
Define associations to linters based on file extension @return [Hash] linters and extension arrays
# File lib/maximus/git_control.rb, line 145 def associations { css: ['css'], scss: ['scss', 'sass'], js: ['js'], ruby: ['rb', 'Gemfile', 'lock', 'yml', 'Rakefile', 'ru', 'rdoc', 'rake', 'Capfile', 'jbuilder'], rails: ['slim', 'haml', 'jbuilder', 'erb'], images: ['png', 'jpg', 'jpeg', 'gif'], static: ['pdf', 'txt', 'doc', 'docx', 'csv', 'xls', 'xlsx'], markup: ['html', 'xml', 'xhtml'], markdown: ['md', 'markdown', 'mdown'], php: ['php', 'ini'] } end
30,000 foot view of a commit @param commit_sha [String] (head_sha) the sha of the commit @return [Hash] commit data
# File lib/maximus/git_control.rb, line 31 def commit_export(commit_sha = head_sha) commit_sha = commit_sha.to_s ce_commit = @g.gcommit(commit_sha) if first_commit == commit_sha ce_diff = diff_initial(first_commit) else last_commit = @g.gcommit(previous_commit(commit_sha)) ce_diff = diff(last_commit, ce_commit) end { commit_sha: commit_sha, branch: branch, message: ce_commit.message, remote_repo: remote, git_author: ce_commit.author.name, git_author_email: ce_commit.author.email, commit_date: ce_commit.author.date.to_s, diff: ce_diff } end
Compare two commits and get line number ranges of changed patches
@example output from the method
{ 'sha': { rb: { filename: 'file.rb', changes: { ['0..4'], ['10..20'] } } } }
@param sha1 [String] @param sha2 [String] @return [Hash] diff_return files changed grouped by file extension and line number
# File lib/maximus/git_control.rb, line 72 def compare(sha1 = master_commit_sha, sha2 = head_sha) diff_return = {} sha1 = define_psuedo_commit if @settings[:commit] # Reverse so that we go in chronological order git_spread = commit_range(sha1, sha2).reverse git_spread.each do |git_sha| # Grab all files in that commit and group them by extension # If working copy, just give the diff names of the files changed files = @psuedo_commit ? working_copy_files : files_by_sha(git_sha) diff_return[git_sha] = match_associations(git_sha, files) end diff_return end
Run appropriate lint for every sha in commit history. For each sha a new branch is created then deleted
@example sample output
{ 'sha': { lints: { scsslint: { files_inspec... }, }, statisti... }, 'sha'... }
@see compare @param lint_by_path [Boolean] only lint by files in git commit and
not the commit as a whole
@param git_shas [Hash] (compare
) a hash of gitcommit shas
and relevant file types in the commit
@param nuclear [Boolean] do everything regardless of what's in the commit @return [Hash] data all data grouped by task
# File lib/maximus/git_control.rb, line 114 def lints_and_stats(lint_by_path = false, git_shas = compare, nuclear = false) return false if git_shas.blank? base_branch = branch git_ouput = {} git_shas.each do |sha, exts| create_branch(sha) unless @psuedo_commit sha = sha.to_s puts sha.color(:blue) exts.each do |ext, files| # For relevant_lines data lint_opts = { git_files: files, config: @config, file_paths: (lint_file_paths(files, ext) if lint_by_path) } git_ouput[sha] = nuclear ? lints_and_stats_nuclear(lint_opts) : lints_and_stats_switch(ext, lint_opts) end destroy_branch(base_branch, sha) unless @psuedo_commit end git_ouput end
Protected Instance Methods
Retrieve shas of all commits to be evaluated @since 0.1.5
If working directory, just have a single item array.
The space here is important because git-lines checks for a second arg, and if one is present, it runs git diff without a commit or a comparison to a commit.
Include the first sha because rev-list is doing a traversal
So sha1 is never included
@param sha1 [String] @param sha2 [String] @return [Array] shas
# File lib/maximus/git_control.rb, line 177 def commit_range(sha1, sha2) git_spread = @psuedo_commit ? "git #{sha1}" : sha_range(sha1, sha2) git_spread = git_spread.nil? ? [] : git_spread.split("\n") git_spread << sha1 unless @psuedo_commit git_spread end
Get sha if words passed for :commit config option @since 0.1.5 @return [String] commit sha
# File lib/maximus/git_control.rb, line 188 def define_psuedo_commit case @settings[:commit] when 'master' then master_commit_sha when 'last' then previous_commit(head_sha) when 'working' then 'working' else @settings[:commit] end end
Get general stats of commit on HEAD versus last commit on master branch @modified 0.1.4 @param old_commit [Git::Object] @param new_commit [Git::Object] @return [Git::Diff] hash of abbreviated, useful stats with added lines
# File lib/maximus/git_control.rb, line 227 def diff(old_commit, new_commit) stats = @g.diff(old_commit, new_commit).stats lines = lines_added(new_commit.sha) return if !lines.is_a?(Hash) || stats.blank? lines.each do |filename, filelines| stats[:files][filename][:lines_added] = filelines if stats[:files].key?(filename) end stats end
Get diff stats on just the initial commit Ruby-git doesn't support this well @see diff @since 0.1.5 @param commit_sha [String] @return [Hash] stat data similar to Ruby-git's Diff.stats return
# File lib/maximus/git_control.rb, line 245 def diff_initial(commit_sha) data = commit_information(commit_sha) value = { total: { insertions: 0, deletions: 0, lines: 0, files: data.length }, files: {} } data.each do |d| item = d.split("\t") insertions = item[0].to_i value[:total][:insertions] += insertions value[:total][:lines] += insertions value[:files][item[2]] = { insertions: insertions, deletions: 0, lines_added: ["0..#{item[0]}"] } end value end
Determine which lines were added (where and how many) in a commit
@example output from method
{ 'filename': [ '0..10', '11..14' ] }
@param git_sha [String] sha of the commit @return [Hash] ranges by lines added in a commit by file name
# File lib/maximus/git_control.rb, line 207 def lines_added(commit_sha) new_lines = {} git_lines = lines_by_sha(commit_sha) git_lines.each do |filename| fsplit = filename.split(':') # if file isn't already part of the array new_lines[fsplit[0]] ||= [] new_lines[fsplit[0]] << fsplit[1] unless fsplit[1].nil? # no repeats new_lines[fsplit[0]].uniq! end new_lines.delete("/dev/null") new_lines end
All data retrieved from reports @since 0.1.6 @param lint_opts [Hash] @return [Hash]
# File lib/maximus/git_control.rb, line 302 def lints_and_stats_nuclear(lint_opts) { lints: { scsslint: Maximus::Scsslint.new(lint_opts).result, jshint: Maximus::Jshint.new(lint_opts).result, rubocop: Maximus::Rubocop.new(lint_opts).result, railsbp: Maximus::Railsbp.new(lint_opts).result, brakeman: Maximus::Brakeman.new(lint_opts).result }, statistics: { stylestat: Maximus::Stylestats.new({config: @config}).result, phantomas: Maximus::Phantomas.new({config: @config}).result, wraith: Maximus::Wraith.new({config: @config}).result } } end
Specific data retrieved by file extension @since 0.1.6 @param ext [String] @param lint_opts [Hash] @return [Hash]
# File lib/maximus/git_control.rb, line 324 def lints_and_stats_switch(ext, lint_opts) result = { lints: {}, statistics: {} } lints = result[:lints] statistics = result[:statistics] case ext when :scss lints[:scsslint] = Maximus::Scsslint.new(lint_opts).result # @todo stylestat is singular here because model name in Rails is singular. # But adding a .classify when it's converted to a model chops off the end s on 'phantomas', # which breaks the model name. statistics[:stylestat] = Maximus::Stylestats.new({config: @config}).result # @todo double pipe here is best way to say, if it's already run, don't run again, right? statistics[:phantomas] ||= Maximus::Phantomas.new({config: @config}).result statistics[:wraith] ||= Maximus::Wraith.new({config: @config}).result when :js lints[:jshint] = Maximus::Jshint.new(lint_opts).result statistics[:phantomas] ||= Maximus::Phantomas.new({config: @config}).result # @todo double pipe here is best way to say, if it's already run, don't run again, right? statistics[:wraith] ||= Maximus::Wraith.new({config: @config}).result when :ruby lints[:rubocop] = Maximus::Rubocop.new(lint_opts).result lints[:railsbp] ||= Maximus::Railsbp.new(lint_opts).result lints[:brakeman] = Maximus::Brakeman.new(lint_opts).result when :rails lints[:railsbp] ||= Maximus::Railsbp.new(lint_opts).result end result end
Associate files by extension and match their changes @since 0.1.5 @param commit_sha [String] @param files [String] list of files from git @return [Hash] files with matched extensions and changes
# File lib/maximus/git_control.rb, line 275 def match_associations(commit_sha, files) new_lines = lines_added(commit_sha) files = files.split("\n").group_by { |f| f.split('.').pop } associations.each do |ext, related| files[ext] ||= [] related.each do |child| next if files[child].blank? files[child].each do |c| # hack to ignore deleted files files[child] = new_lines[c].blank? ? [] : [ filename: File.join(@config.working_dir, c), changes: new_lines[c] ] end files[ext].concat(files[child]) files.delete(child) end end files.delete_if { |k,v| v.blank? || k.nil? } files end
Private Instance Methods
Create branch to run report on @since 0.1.5 @param sha [String]
# File lib/maximus/git_control.rb, line 369 def create_branch(sha) silence_stream(STDERR) { `git -C #{@config.working_dir} checkout #{sha} -b maximus_#{sha}` } end
Destroy created branch @since 0.1.5 @param base_branch [String] branch we started on @param sha [String] used to check against created branch name
# File lib/maximus/git_control.rb, line 377 def destroy_branch(base_branch, sha) if base_branch == "maximus_#{sha}" @g.branch('master').checkout else @g.branch(base_branch).checkout end @g.branch("maximus_#{sha}").delete end
Get list of file paths @param files [Hash] hash of files denoted by key 'filename' @param ext [String] file extension - different extensions are joined different ways @return [String] file paths delimited by comma or space
# File lib/maximus/git_control.rb, line 390 def lint_file_paths(files, ext) file_list = files.map { |f| f[:filename] }.compact # Lints accept files differently ext == :ruby ? file_list.join(' ') : file_list.join(',') end