Skip to content
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 104 additions & 37 deletions app/jobs/generate_sponsors_yaml_file_job.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
class GenerateSponsorsYamlFileJob < ApplicationJob
delegate :octokit, :base_branch, to: :github_installation

def perform(conference, push: true)
@conference = conference

Expand Down Expand Up @@ -128,50 +126,119 @@ def json_data

def push_to_github
return unless repo
return if yaml_data.nil? # to generate
return if yaml_data.nil?

push_id = @last_id || "event-#{@last_event_editing_history_id}"
@branch_name = "sponsor-app/#{push_id}"
@filepath = repo.path
GitHubPusher.new(
conference: @conference,
filepath: repo.path,
content: yaml_data,
last_editing_history_id: @last_id,
push_id:,
).push
end

# For debugging
def self.get_octokit(repo)
GithubInstallation.new(repo).octokit
end

class GitHubPusher
MAX_RETRIES = 3

begin
octokit.delete_branch(repo.name, @branch_name)
rescue Octokit::UnprocessableEntity
delegate :octokit, :base_branch, to: :github_installation

def initialize(conference:, filepath:, content:, last_editing_history_id:, push_id:)
@conference = conference
@repo = conference.github_repo
@filepath = filepath
@content = content
@last_id = last_editing_history_id
@branch_name = "sponsor-app/#{conference.slug}"
@pr_title = "Update sponsors.yml for #{conference.slug} (#{push_id})"
end

head = octokit.branch(repo.name, base_branch)
octokit.create_ref(repo.name, "refs/heads/#{@branch_name}", head[:commit][:sha])
def push
return unless @repo

begin
blob_sha = octokit.contents(repo.name, path: @filepath)[:sha]
rescue Octokit::NotFound
blob_sha = nil
if branch_has_newer_data?
Rails.logger.info "GenerateSponsorsYamlFileJob: branch has newer data, skipping"
return
end

reset_branch
commit_content
create_or_update_pull_request
end

octokit.update_contents(
repo.name,
@filepath,
"Update sponsors.yml for #{@conference.slug} (#{push_id})",
blob_sha,
yaml_data,
branch: @branch_name,
)
octokit.create_pull_request(
repo.name,
base_branch,
@branch_name,
"Update sponsors.yml for #{@conference.slug} (#{push_id})",
nil,
)
end
private

# For debugging
def self.get_octokit(repo)
GithubInstallation.new(repo).octokit
end
def reset_branch
begin
octokit.delete_branch(@repo.name, @branch_name)
rescue Octokit::UnprocessableEntity
end

head = octokit.branch(@repo.name, base_branch)
octokit.create_ref(@repo.name, "refs/heads/#{@branch_name}", head[:commit][:sha])
end

def commit_content
begin
blob_sha = octokit.contents(@repo.name, path: @filepath)[:sha]

This comment was marked as outdated.

rescue Octokit::NotFound
blob_sha = nil
end

retries = 0
begin
octokit.update_contents(@repo.name, @filepath, @pr_title, blob_sha, @content, branch: @branch_name)
rescue Octokit::Conflict, Octokit::UnprocessableEntity => e
if retries < MAX_RETRIES && !branch_has_newer_data?
retries += 1
begin
blob_sha = octokit.contents(@repo.name, path: @filepath, ref: @branch_name)[:sha]
rescue Octokit::NotFound
blob_sha = nil
end
Rails.logger.info "GenerateSponsorsYamlFileJob: commit conflict, retrying (#{retries}/#{MAX_RETRIES})"
retry
else
Rails.logger.info "GenerateSponsorsYamlFileJob: commit conflict and branch has newer data (or max retries), skipping"
return
end
end
end

def branch_has_newer_data?
existing = octokit.contents(@repo.name, path: @filepath, ref: @branch_name)
existing_content = Base64.decode64(existing[:content])
if existing_content =~ /last_editing_history: (\d+)/
return @last_id && $1.to_i > @last_id
end
false
rescue Octokit::NotFound
false # Branch or file doesn't exist
end

private
def create_or_update_pull_request
owner = @repo.name.split('/')[0]
existing_prs = octokit.pull_requests(@repo.name, state: 'open', head: "#{owner}:#{@branch_name}")
if existing_prs.any?
octokit.update_pull_request(@repo.name, existing_prs[0][:number], title: @pr_title)
else
begin
octokit.create_pull_request(@repo.name, base_branch, @branch_name, @pr_title, nil)
rescue Octokit::UnprocessableEntity
# Concurrent job already created PR
existing_prs = octokit.pull_requests(@repo.name, state: 'open', head: "#{owner}:#{@branch_name}")
octokit.update_pull_request(@repo.name, existing_prs[0][:number], title: @pr_title) if existing_prs.any?
Comment on lines +238 to +241

This comment was marked as outdated.

end
end
end

def github_installation
@github_installation ||= GithubInstallation.new(repo.name, branch: repo.branch)
def github_installation
@github_installation ||= GithubInstallation.new(@repo.name, branch: @repo.branch)
end
end
end