jbox-web/gitolite-rugged

View on GitHub
lib/gitolite/gitolite_admin.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
98%
# frozen_string_literal: true

module Gitolite
  class GitoliteAdmin

    # Default settings
    DEFAULTS = {
      # clone/push url settings
      git_user: 'git',
      hostname: 'localhost',

      # Commit settings
      author_name:  'gitolite-rugged gem',
      author_email: 'gitolite-rugged@localhost',
      commit_msg:   'Commited by the gitolite-rugged gem',

      # Gitolite-Admin settings
      config_dir:     'conf',
      key_dir:        'keydir',
      key_subdir:     '',
      config_file:    'gitolite.conf',
      lock_file_path: '.lock',
      local_branch:   'master',
      remote_branch:  'master',

      # Repo settings
      update_on_init:      true,
      reset_before_update: true
    }

    include GitoliteAdmin::Accessors
    include GitoliteAdmin::Config
    include GitoliteAdmin::SshKeys

    attr_reader :repo
    attr_reader :path

    # Intialize with the path to
    # the gitolite-admin repository
    #
    # Settings:
    # [Connection]
    # :private_key: The key file containing the private SSH key for :git_user
    # :public_key: The key file containing the public SSH key for :git_user
    # :git_user: The git user to SSH to (:git_user@localhost:gitolite-admin.git), defaults to 'git'
    # :hostname: Hostname for clone url. Defaults to 'localhost'
    #
    # [Gitolite-Admin]
    # :config_dir: Config directory within gitolite repository (defaults to 'conf')
    # :key_dir: Public key directory within gitolite repository (defaults to 'keydir')
    # :config_file: Config file to parse (default: 'gitolite.conf')
    # **use only when you use the 'include' directive of gitolite)**
    # :key_subdir: Where to store gitolite-rugged known keys, defaults to '' (i.e., directly in keydir)
    # :lock_file_path: location of the transaction lockfile, defaults to <gitolite-admin.git>/.lock
    #
    # The settings hash is forwarded to +GitoliteAdmin.new+ as options.
    #
    def initialize(path, settings = {})
      @path     = path
      @settings = DEFAULTS.merge(settings)

      # Ensure SSH key settings exist
      @settings.fetch(:public_key)
      @settings.fetch(:private_key)

      # Set repository instance variable
      @repo = set_repo

      # Update repository if asked
      update if @settings[:update_on_init]

      # Load Gitolite config
      reload!
    end


    class << self

      # Checks if the given path is a gitolite-admin repository.
      # A valid repository contains a conf folder, keydir folder,
      # and a configuration file within the conf folder.
      #
      def is_gitolite_admin_repo?(dir)
        # First check if it is a git repository
        begin
          repo = Rugged::Repository.new(dir)
          return false if repo.empty?
        rescue Rugged::RepositoryError, Rugged::OSError
          return false
        end

        # Check if config file, key directory exist
        [
          File.join(dir, DEFAULTS[:config_dir]),
          File.join(dir, DEFAULTS[:key_dir]),
          File.join(dir, DEFAULTS[:config_dir], DEFAULTS[:config_file])
        ].each { |f| return false unless File.exist?(f) }

        true
      end

    end


    def admin_url
      ['ssh://', @settings[:git_user], '@', @settings[:hostname], '/gitolite-admin.git'].join
    end


    def commit_author
      { email: @settings[:author_email], name: @settings[:author_name] }.clone
    end


    def exists?
      Dir.exist?(path)
    end


    def lock_file_path
      File.expand_path(@settings[:lock_file_path], path)
    end


    def local_branch
      get_references "refs/heads/#{@settings[:local_branch]}"
    end


    def remote_branch
      get_references "refs/remotes/origin/#{@settings[:remote_branch]}"
    end


    def update_ref
      "refs/heads/#{@settings[:local_branch]}"
    end


    def update_message
      "[gitolite-rugged] Merged `origin/#{@settings[:remote_branch]}` into `#{@settings[:local_branch]}`"
    end


    ######################
    #  Config accessors  #
    ######################

    # This method will destroy the in-memory data structures and reload everything
    # from the file system
    #
    def reload!
      @ssh_keys = load_keys
      @config   = load_config
    end


    def credentials
      @credentials ||=
        Rugged::Credentials::SshKey.new(
          username:   @settings[:git_user],
          publickey:  @settings[:public_key],
          privatekey: @settings[:private_key]
        )
    end


    def get_references(name)
      ref = repo.references[name]
      return nil if ref.nil?

      ref.target
    end


    private


      def set_repo
        if self.class.is_gitolite_admin_repo?(path)
          Rugged::Repository.new(path, credentials: credentials)
        else
          clone
        end
      end

  end
end