# frozen_string_literal: true class Site # Acciones para el repositorio Git de un sitio. Por ahora hacemos un # uso muy básico de Git, con lo que asumimos varias cosas, por ejemplo # que un sitio tiene un solo origen, que siempre se trabaja con la # rama master, etc. class Repository attr_reader :rugged, :changes, :path def initialize(path) @path = path @rugged = Rugged::Repository.new(path) @changes = 0 end def remote @remote ||= rugged.remotes.first end # Trae los cambios del repositorio de origen sin aplicarlos y # devuelve la cantidad de commits pendientes. # # XXX: Prestar atención a la velocidad de respuesta cuando tengamos # repositorios remotos. def fetch if remote.check_connection :fetch @changes = rugged.fetch(remote)[:received_objects] else 0 end end # Incorpora los cambios en el repositorio actual # def merge(usuarie) merge = rugged.merge_commits(master, origin_master) # No hacemos nada si hay conflictos # # TODO: Enviar un correo a administración para poder revisar # manualmente. Idealmente no deberíamos tener conflictos pero # quién sabe. return if merge.conflicts? commit = Rugged::Commit .create(rugged, update_ref: 'HEAD', parents: [master, origin_master], tree: merge.write_tree(rugged), message: I18n.t('sites.fetch.merge.message'), author: author(usuarie), committer: committer) # Forzamos el checkout para mover el HEAD al último commit y # escribir los cambios rugged.checkout 'HEAD', strategy: :force commit end def master rugged.branches['master'].target end def origin_master rugged.branches['origin/master'].target end # Compara los commits entre el repositorio remoto y el actual para # que luego los podamos mostrar. def commits walker = Rugged::Walker.new rugged # Obtenemos todos los commits que existen en origin/master que no # están en la rama master local # # XXX: monitorear esto por performance walker.push 'refs/remotes/origin/master' walker.hide 'refs/heads/master' walker.each.to_a end # Hay commits sin aplicar? def needs_pull? fetch !commits.empty? end # Guarda los cambios en git, de a un archivo por vez def commit(file:, usuarie:, message:, remove: false) remove ? rm(file) : add(file) # Escribir los cambios para que el repositorio se vea tal cual rugged.index.write Rugged::Commit.create(rugged, message: message, update_ref: 'HEAD', parents: [rugged.head.target], tree: rugged.index.write_tree, author: author(usuarie), committer: committer) end def author(author) { name: author.name, email: author.email, time: Time.now } end def committer { name: 'Sutty', email: "sutty@#{Site.domain}", time: Time.now } end def add(file) rugged.index.add(relativize(file)) end def rm(file) rugged.index.remove(relativize(file)) end private def relativize(file) Pathname.new(file).relative_path_from(Pathname.new(path)).to_s end end end