From 8b4795056897f9db5f664ca122a7f4de09e1b960 Mon Sep 17 00:00:00 2001 From: Arnaud Levy <contact@arnaudlevy.com> Date: Mon, 3 Jan 2022 22:24:32 +0100 Subject: [PATCH] clean architecture --- app/models/concerns/with_git.rb | 1 - app/services/git/providers/github.rb | 85 +++++++++++----------- app/services/git/repository.rb | 102 ++------------------------- docs/websites/export.md | 2 + 4 files changed, 51 insertions(+), 139 deletions(-) diff --git a/app/models/concerns/with_git.rb b/app/models/concerns/with_git.rb index d749a1403..6de6df853 100644 --- a/app/models/concerns/with_git.rb +++ b/app/models/concerns/with_git.rb @@ -21,7 +21,6 @@ module WithGit end handle_asynchronously :sync_with_git - def git_path_static '' end diff --git a/app/services/git/providers/github.rb b/app/services/git/providers/github.rb index dc67bcbf2..714e65953 100644 --- a/app/services/git/providers/github.rb +++ b/app/services/git/providers/github.rb @@ -1,26 +1,31 @@ class Git::Providers::Github + attr_reader :access_token, :repository + + def initialize(access_token, repository) + @access_token = access_token + @repository = repository + end def add_to_batch( path: nil, previous_path: nil, data:) - @batch ||= [] file = find_in_tree previous_path if file.nil? # New file - @batch << { + batch << { path: path, mode: '100644', # https://docs.github.com/en/rest/reference/git#create-a-tree type: 'blob', content: data } - elsif previous_path != path || file_sha(previous_path) != local_file_sha(data) + elsif previous_path != path || git_sha(previous_path) != sha(data) # Different path or content - @batch << { + batch << { path: previous_path, mode: file[:mode], type: file[:type], sha: nil } - @batch << { + batch << { path: path, mode: file[:mode], type: file[:type], @@ -29,50 +34,32 @@ class Git::Providers::Github end end - def commit_batch(commit_message) - unless @batch.empty? - new_tree = client.create_tree repository, @batch, base_tree: tree[:sha] - commit = client.create_commit repository, commit_message, new_tree[:sha], branch_sha - client.update_branch repository, default_branch, commit[:sha] - end - @tree = nil + def push(commit_message) + return unless valid? + return if batch.empty? + new_tree = client.create_tree repository, batch, base_tree: tree[:sha] + commit = client.create_commit repository, commit_message, new_tree[:sha], branch_sha + client.update_branch repository, default_branch, commit[:sha] true end - def remove(path, commit_message) - client.delete_contents repository, path, commit_message, file_sha(path) - true - rescue - false - end + protected - def read_file_at(path) - data = client.content repository, path: path - Base64.decode64 data.content - rescue - '' + def valid? + repository.present? && access_token.present? end - protected - def client @client ||= Octokit::Client.new access_token: access_token end - def file_sha(path) - begin - content = client.content repository, path: path - sha = content[:sha] - rescue - sha = nil - end - sha + def access_token + @access_token ||= website&.access_token end - def local_file_sha(data) - # Git SHA-1 is calculated from the String "blob <length>\x00<contents>" - # Source: https://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html - OpenSSL::Digest::SHA1.hexdigest "blob #{data.bytesize}\x00#{data}" + # Path of the repo + def repository + @repository ||= website&.repository end def default_branch @@ -87,14 +74,30 @@ class Git::Providers::Github @tree ||= client.tree repository, branch_sha, recursive: true end + def batch + @batch ||= [] + end + + def git_sha(path) + begin + content = client.content repository, path: path + sha = content[:sha] + rescue + sha = nil + end + sha + end + + def sha(data) + # Git SHA-1 is calculated from the String "blob <length>\x00<contents>" + # Source: https://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html + OpenSSL::Digest::SHA1.hexdigest "blob #{data.bytesize}\x00#{data}" + end + def find_in_tree(path) tree[:tree].each do |file| return file if path == file[:path] end nil end - - def tmp_directory - "tmp/github/#{repository}" - end end diff --git a/app/services/git/repository.rb b/app/services/git/repository.rb index 2c48cb8ff..7cd2916b4 100644 --- a/app/services/git/repository.rb +++ b/app/services/git/repository.rb @@ -11,125 +11,33 @@ class Git::Repository end def sync! - return unless valid? return if git_files.empty? sync_git_files - mark_as_synced if commit_batch + mark_as_synced if provider.push(commit_message) end protected - def client - @client ||= Octokit::Client.new access_token: access_token - end - - def access_token - @access_token ||= website&.access_token - end - - def repository - @repository ||= website&.repository - end - def provider - @provider ||= Git::Providers::Github.new + @provider ||= Git::Providers::Github.new(website&.access_token, website&.repository) end def git_files @git_files ||= [] end - def batch - @batch ||= [] - end - - def default_branch - @default_branch ||= client.repo(repository)[:default_branch] - end - - def branch_sha - @branch_sha ||= client.branch(repository, default_branch)[:commit][:sha] - end - - def tree - @tree ||= client.tree repository, branch_sha, recursive: true - end - - def valid? - repository.present? && access_token.present? - end - def sync_git_files git_files.each do |git_file| next if git_file.synced? - add_to_batch path: git_file.path, - previous_path: git_file.previous_path, - data: git_file.to_s - end - end - - def add_to_batch( path: nil, - previous_path: nil, - data:) - file = find_in_tree previous_path - if file.nil? # New file - batch << { - path: path, - mode: '100644', # https://docs.github.com/en/rest/reference/git#create-a-tree - type: 'blob', - content: data - } - elsif previous_path != path || git_sha(previous_path) != sha(data) - # Different path or content - batch << { - path: previous_path, - mode: file[:mode], - type: file[:type], - sha: nil - } - batch << { - path: path, - mode: file[:mode], - type: file[:type], - content: data - } + provider.add_to_batch path: git_file.path, + previous_path: git_file.previous_path, + data: git_file.to_s end end - def commit_batch - return if batch.empty? - new_tree = client.create_tree repository, batch, base_tree: tree[:sha] - commit = client.create_commit repository, commit_message, new_tree[:sha], branch_sha - client.update_branch repository, default_branch, commit[:sha] - true - end - def mark_as_synced git_files.each do |git_file| git_file.update_columns previous_path: git_file.path, previous_sha: git_file.sha end end - - def git_sha(path) - begin - content = client.content repository, path: path - sha = content[:sha] - rescue - sha = nil - end - sha - end - - def sha(data) - # Git SHA-1 is calculated from the String "blob <length>\x00<contents>" - # Source: https://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html - OpenSSL::Digest::SHA1.hexdigest "blob #{data.bytesize}\x00#{data}" - end - - def find_in_tree(path) - tree[:tree].each do |file| - return file if path == file[:path] - end - nil - end end diff --git a/docs/websites/export.md b/docs/websites/export.md index a4c71a4ac..bf9c2e88a 100644 --- a/docs/websites/export.md +++ b/docs/websites/export.md @@ -67,6 +67,8 @@ def update end ``` +TODO gérer la suppression correctement + ## Code ### Website::WithRepository -- GitLab