# frozen_string_literal: true module Groundskeeper # Wraps git executable and adds a few convenience methods on top. class Git COMMAND = "git" # git arguments STATUS = "status" FETCH_WITH_TAGS = "fetch --tags" VERSION = "--version" TAGS_ASC = "tag -l --sort=v:refname" LATEST_TAG_COMMIT = "#{COMMAND} rev-list --tags --max-count=1" LATEST_TAG_NAME = format("describe --tags $(%s)", LATEST_TAG_COMMIT) LATEST_TAG_BRANCHES = format("branch --contains $(%s)", LATEST_TAG_COMMIT) LATEST_CHANGES = "log %s..HEAD --oneline" CREATE_AND_CHECKOUT_BRANCH = "checkout -b %s" ADD_UPDATE = "add -u" COMMIT = "commit -m \"%s\"" ADD_TAG = "tag %s" PUSH_HEAD_WITH_TAGS = "push origin head --tags" attr_reader :git # Wraps the "git" shell command. class Executable def execute(arguments) `#{COMMAND} #{arguments}` end end def self.build new Executable.new end def initialize(git) @git = git end def status git.execute(STATUS) end def fetch git.execute(FETCH_WITH_TAGS) end def version semantic_version = /\d+.\d+.\d+/ git.execute(VERSION).match(semantic_version)[0] end def list_tags git.execute(TAGS_ASC) end def latest_tag_name_across_branches git.execute(LATEST_TAG_NAME).chop end def branches_containing_latest_tag git.execute(LATEST_TAG_BRANCHES).split("\n").map(&:strip) end def raw_changes_since_latest_tag latest_changes = format(LATEST_CHANGES, latest_tag_name_across_branches) git.execute(latest_changes).split("\n") end def create_and_checkout_branch(name) git.execute(format(CREATE_AND_CHECKOUT_BRANCH, name)) end def add_update git.execute(ADD_UPDATE) end def commit(message) git.execute(format(COMMIT, message)) end def add_tag(name) git.execute(format(ADD_TAG, name)) end def push_with_tags git.execute(PUSH_HEAD_WITH_TAGS) end end end