class Nucleus::Adapters::GitDeployer

Public Class Methods

new(repo_name, repo_url, user_email, repo_branch = 'master') click to toggle source

Initialize a new instance of the GitDeployer @param [String] user_email email address of the user, used as author of commits @param [String] repo_url address where the repository can be retrieved @param [String] repo_name name of the directory for the repository that shall be created in the tmp dir @param [String] repo_branch branch to push to

# File lib/nucleus/core/file_handling/git_deployer.rb, line 11
def initialize(repo_name, repo_url, user_email, repo_branch = 'master')
  @repo_name = repo_name
  @repo_url = repo_url
  @repo_branch = repo_branch
  @user_email = user_email
end

Public Instance Methods

deploy(file, file_compression_format) click to toggle source

Deploys the contents of the archive file to the repository that resides at the repo_url.

@param [File] file archive file whose contents shall be deployed to the repository @param [String] file_compression_format compression format of the application archive, e.g. ‘zip’ or ‘tar.gz’ @return [void]

# File lib/nucleus/core/file_handling/git_deployer.rb, line 38
def deploy(file, file_compression_format)
  extractor = Nucleus::ArchiveExtractor.new
  raise Errors::AdapterRequestError,
        'Unsupported format of the application archive' unless extractor.supports? file_compression_format

  push_repository_changes do |repo_dir|
    # now remove all current files, except the git db
    Find.find(repo_dir) do |f|
      next if f.start_with?("#{repo_dir}/.git") || f == repo_dir
      FileUtils.rm_rf(f) if File.directory?(f)
      FileUtils.rm_f(f) if File.file?(f)
    end

    # uncompress and extract to
    extracted = extractor.extract(file, repo_dir, file_compression_format)
    raise Errors::AdapterRequestError, 'Invalid application: Archive did not contain any files' if extracted == 0

    # if the application was wrapped within a directory, move all 1st level files and dirs to the root
    sanitizer = Nucleus::ApplicationRepoSanitizer.new
    sanitizer.sanitize(repo_dir)
  end
  nil
end
download(format, exclude_git = true) click to toggle source

Download the contents of a git repository in the requested format. @param [String] format compression to be used for the download e.g. ‘zip’ or ‘tar.gz’ @return [StringIO] data requested to be downloaded

# File lib/nucleus/core/file_handling/git_deployer.rb, line 65
def download(format, exclude_git = true)
  with_repository do |repo_dir|
    # TODO: maybe we can do this directly via SSH and prevent the disk writes?
    # download files temporarily from the repo
    Nucleus::Archiver.new(exclude_git).compress(repo_dir, format)
  end
end
trigger_build() click to toggle source

Force a build using the latest git commit. To enforce the new build, a file ‘nucleus-rebuild-trigger’ gets created or updated in the repository and the changes will be pushed. @return [void]

# File lib/nucleus/core/file_handling/git_deployer.rb, line 22
def trigger_build
  push_repository_changes do |repo_dir|
    # add a custom file that always changes the data and triggers a new build
    build_trigger_file = File.join(repo_dir, 'nucleus-rebuild-trigger')
    current_md5 = File.exist?(build_trigger_file) ? Digest::MD5.file(build_trigger_file).hexdigest : nil
    data = StringIO.new("Nucleus rebuild, triggered at #{Time.now}")
    FileManager.save_file_from_data(build_trigger_file, data, false, current_md5)
  end
  nil
end

Private Instance Methods

push(repository) click to toggle source

Push all contents of the repository to the default remote ‘origin’. The repository will also be pushed if none of the files did change and no new commit was made. @param [Git::Lib] repository repository whose contents are to be pushed @return [void]

# File lib/nucleus/core/file_handling/git_deployer.rb, line 113
def push(repository)
  # add all files to the repository
  repository.add(all: true)

  # commit, but be aware: current version could be identical to previous version resulting in an error
  begin
    repository.commit('Application deployment via Nucleus')
  rescue Git::GitExecuteError => e
    # usually indicates that no files could be committed, repository is up to date
    log.debug("Git commit failed: #{e}")
  end

  # repack to enhance compression
  repository.repack

  # force push, so that the push is executed even when all files remain unchanged
  repository.push('origin', @repo_branch, force: true)
end
push_repository_changes() { |repo_dir| ... } click to toggle source
# File lib/nucleus/core/file_handling/git_deployer.rb, line 98
def push_repository_changes
  with_repository do |repo_dir, repository|
    repository.config('user.name', 'Nucleus')
    repository.config('user.email', @user_email)
    # update files
    yield repo_dir
    # push changes
    push(repository)
  end
end
with_repository() { |repo_dir, repository| ... } click to toggle source
# File lib/nucleus/core/file_handling/git_deployer.rb, line 75
def with_repository
  tmp_dir = Dir.tmpdir
  repo_dir = "#{tmp_dir}/#{@repo_name}"
  begin
    repository = Git.clone(@repo_url, @repo_name, path: tmp_dir)
    # checkout custom branch
    unless @repo_branch == 'master'
      begin
        repository.checkout(repository.branch(@repo_branch))
      rescue StandardError
        # catch errors, might occur if no commit has been made and we try to switch the branch
        repository.checkout(@repo_branch, new_branch: true)
      end
    end

    # now execute the actual actions on the repository
    yield repo_dir, repository
  ensure
    # now delete the tmp directory again
    FileUtils.rm_rf(repo_dir)
  end
end