From 27657484a8e8891552d630c2e74b0948742ef0e8 Mon Sep 17 00:00:00 2001 From: Arnaud Levy <contact@arnaudlevy.com> Date: Tue, 4 Jan 2022 11:35:29 +0100 Subject: [PATCH] clean architecture --- app/models/communication/website/git_file.rb | 21 ++++- app/services/git/providers/github.rb | 84 ++++++++++---------- app/services/git/repository.rb | 17 ++-- docs/websites/export.md | 26 ++++-- 4 files changed, 93 insertions(+), 55 deletions(-) diff --git a/app/models/communication/website/git_file.rb b/app/models/communication/website/git_file.rb index d67ff35c1..5b420edc3 100644 --- a/app/models/communication/website/git_file.rb +++ b/app/models/communication/website/git_file.rb @@ -30,8 +30,21 @@ class Communication::Website::GitFile < ApplicationRecord website.git_repository.add_git_file git_file end - def synced? - previous_path == path && previous_sha == sha + def synchronized_with_git? + git_sha == previous_sha + end + + def should_create? + !synchronized_with_git? || previous_path.nil? || previous_sha.nil? + end + + def should_update? + !synchronized_with_git? || previous_path != path || previous_sha != sha + end + + def should_destroy? + # TODO + false end def path @@ -55,6 +68,10 @@ class Communication::Website::GitFile < ApplicationRecord protected + def git_sha + @git_sha ||= website.git_repository.git_sha previous_path + end + # def add_media_to_batch(github) # return unless manifest_data[:has_media] && about.respond_to?(:active_storage_blobs) # about.active_storage_blobs.each { |blob| add_blob_to_batch(github, blob) } diff --git a/app/services/git/providers/github.rb b/app/services/git/providers/github.rb index 78fea8cb2..b6daf07d2 100644 --- a/app/services/git/providers/github.rb +++ b/app/services/git/providers/github.rb @@ -6,32 +6,40 @@ class Git::Providers::Github @repository = repository end - def add_to_batch( path: nil, - previous_path: nil, - data:) + def create_file(path, content) + batch << { + path: path, + mode: '100644', # https://docs.github.com/en/rest/reference/git#create-a-tree + type: 'blob', + content: content + } + end + + def update_file(path, previous_path, content) 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 - } - end + batch << { + path: previous_path, + mode: file[:mode], + type: file[:type], + sha: nil + } + batch << { + path: path, + mode: file[:mode], + type: file[:type], + content: content + } + end + + def destroy_file(path) + file = find_in_tree path + return if file.nil? + batch << { + path: path, + mode: file[:mode], + type: file[:type], + sha: nil + } end def push(commit_message) @@ -43,6 +51,16 @@ class Git::Providers::Github true end + def git_sha(path) + begin + content = client.content repository, path: path + sha = content[:sha] + rescue + sha = nil + end + sha + end + protected def valid? @@ -69,22 +87,6 @@ class Git::Providers::Github @tree ||= client.tree repository, branch_sha, recursive: true 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] diff --git a/app/services/git/repository.rb b/app/services/git/repository.rb index 7cd2916b4..573c34c51 100644 --- a/app/services/git/repository.rb +++ b/app/services/git/repository.rb @@ -16,6 +16,10 @@ class Git::Repository mark_as_synced if provider.push(commit_message) end + def git_sha(path) + provider.git_sha path + end + protected def provider @@ -27,11 +31,14 @@ class Git::Repository end def sync_git_files - git_files.each do |git_file| - next if git_file.synced? - provider.add_to_batch path: git_file.path, - previous_path: git_file.previous_path, - data: git_file.to_s + git_files.each do |file| + if file.should_create? + provider.create_file file.path, file.to_s + elsif file.should_update? + provider.update_file file.path, file.previous_path, file.to_s + elsif file.should_destroy? + provider.destroy_file file.path + end end end diff --git a/docs/websites/export.md b/docs/websites/export.md index e7fdeb9fe..d5de3dadf 100644 --- a/docs/websites/export.md +++ b/docs/websites/export.md @@ -64,10 +64,15 @@ def update end def destroy - + @page.save_and_sync end ``` + +Pour les reorder : +``` +``` + TODO gérer la suppression correctement ## Code @@ -85,11 +90,12 @@ Tous les objets qui doivent être exportés vers Git : - peuvent présenter une méthode `static_files` qui liste les identifiants des git_files à générer, pour les objets qui créent plusieurs fichiers ### GitFile + La responsabilité de la synchronisation repose sur Communication::Website::GitFile, notamment : -- le fichier doit-il être synchronisé ? -- le fichier doit-il être créé ? -- le fichier doit-il être déplacé ? -- le fichier doit-il être supprimé ? +- l'information est-elle intègre, synchronisée avec le repo ? (previous_sha et previous_path cohérents avec le repo git) +- le fichier doit-il être créé ? (non intègre, ou pas de previous_sha/previous_path) +- le fichier doit-il être mis à jour ? (non intègre, ou previous_sha/previous_path différent du sha/path) +- le fichier doit-il être supprimé ? (TODO) Pour cela, le git_file dispose des propriétés suivantes : @@ -98,8 +104,14 @@ Pour cela, le git_file dispose des propriétés suivantes : - identifier (l'identifiant du fichier à créer, `static` par défaut, pour les objets créant plusieurs fichiers) -Et pour générer les fichiers, il dispose des méthodes : +Pour informer sur les actions à mener, il dispose des méthodes interrogatives suivantes : +- synchronized_with_git? (pour évaluer l'intégrité vs le repository) +- should_create? (pour savoir s'il faut regénérer ou pas) +- should_update? (pour savoir s'il faut regénérer ou pas) +- should_destroy? (pour savoir s'il faut supprimer) + + +Pour générer les fichiers, il dispose des méthodes : - to_s (pour générer le fichier statique à jour) - sha (pour calculer le hash du fichier à jour) - path (pour générer le chemin à jour) -- synced? (pour savoir s'il faut regénérer ou pas) -- GitLab