Class: OctofactsUpdater::Service::GitHub

Inherits:
Object
  • Object
show all
Defined in:
lib/octofacts_updater/service/github.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ GitHub

Constructor.

options - Hash with options



37
38
39
40
41
# File 'lib/octofacts_updater/service/github.rb', line 37

def initialize(options = {})
  @options = options
  @verbose = github_options.fetch("verbose", false)
  @changes = []
end

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



10
11
12
# File 'lib/octofacts_updater/service/github.rb', line 10

def options
  @options
end

Class Method Details

.run(root, paths, options = {}) ⇒ Object

Callable external method: Push all changes to the indicated paths to GitHub.

root - A String with the root directory, to which paths are relative. paths - An Array of Strings, which are relative to the repository root. options - A Hash with configuration options.

Returns true if there were any changes made, false otherwise.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/octofacts_updater/service/github.rb', line 19

def self.run(root, paths, options = {})
  root ||= options.fetch("github", {})["base_directory"]
  unless root && File.directory?(root)
    raise ArgumentError, "Base directory must be specified"
  end
  github = new(options)
  project_root = Pathname.new(root)
  paths.each do |path|
    absolute_path = Pathname.new(path)
    stripped_path = absolute_path.relative_path_from(project_root)
    github.commit_data(stripped_path.to_s, File.read(path))
  end
  github.finalize_commit
end

Instance Method Details

#commit_data(path, new_content) ⇒ Object

Commit a file to a location in the repository with the provided message. This will return true if there was an actual change, and false otherwise. This method does not actually do the commit, but rather it batches up all of the changes which must be realized later.

path - A String with the path at which to commit the file new_content - A String with the new contents

Returns true (and updates @changes) if there was actually a change, false otherwise.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/octofacts_updater/service/github.rb', line 51

def commit_data(path, new_content)
  ensure_branch_exists

  old_content = nil
  begin
    contents = octokit.contents(repository, path: path, ref: branch)
    old_content = Base64.decode64(contents.content)
  rescue Octokit::NotFound
    verbose("No old content found in #{repository.inspect} at #{path.inspect} in #{branch.inspect}")
    # Fine, we will add below.
  end

  if new_content == old_content
    verbose("Content of #{path} matches, no commit needed")
    return false
  else
    verbose("Content of #{path} does not match. A commit is needed.")
    verbose(Diffy::Diff.new(old_content, new_content))
  end

  @changes << Hash(
    path: path,
    mode: "100644",
    type: "blob",
    sha: octokit.create_blob(repository, new_content)
  )

  verbose("Batched update of #{path}")
  true
end

#delete_file(path, message = commit_message) ⇒ Object

Delete a file from the repository. Because of the way the GitHub API works, this will generate an immediate commit and push. It will NOT be batched for later application.

path - A String with the path at which to commit the file message - A String with a commit message, defaults to the overall configured commit message.

Returns true if the file existed before and was deleted. Returns false if the file didn’t exist anyway.



107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/octofacts_updater/service/github.rb', line 107

def delete_file(path, message = commit_message)
  ensure_branch_exists
  contents = octokit.contents(repository, path: path, ref: branch)
  blob_sha = contents.sha
  octokit.delete_contents(repository, path, message, blob_sha, branch: branch)
  verbose("Deleted #{path}")
  find_or_create_pull_request
  true
rescue Octokit::NotFound
  verbose("Deleted #{path} (already gone)")
  false
end

#finalize_commit(message = commit_message) ⇒ Object

Finalize the GitHub commit by actually pushing any of the changes. This will not do anything if there are not any changes batched via the ‘commit_data` method.

message - A String with a commit message, defaults to the overall configured commit message.



86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/octofacts_updater/service/github.rb', line 86

def finalize_commit(message = commit_message)
  return unless @changes.any?

  ensure_branch_exists
  branch_ref = octokit.branch(repository, branch)
  commit = octokit.git_commit(repository, branch_ref[:commit][:sha])
  tree = commit["tree"]
  new_tree = octokit.create_tree(repository, @changes, base_tree: tree["sha"])
  new_commit = octokit.create_commit(repository, message, new_tree["sha"], commit["sha"])
  octokit.update_ref(repository, "heads/#{branch}", new_commit["sha"])
  verbose("Committed #{@changes.size} change(s) to GitHub")
  find_or_create_pull_request
end