cesarferreira/lasertag

View on GitHub
lib/lasertag.rb

Summary

Maintainability
A
3 hrs
Test Coverage
require 'optparse'
require 'colorize'
require 'oga'
require 'lasertag/version'
require 'git'

module Lasertag
  class MainApp
    def initialize(arguments)

      # defaults
      @app_path = Dir.pwd
      @app_module = nil
      @app_flavor = nil
      @app_remote = 'origin'
      @allow_push = true

      @require_analyses = true

      # Parse Options
      arguments.push "-h" if arguments.length == 0
      create_options_parser(arguments)

      manage_opts

    end

    ### Options parser
    def create_options_parser(args)

      args.options do |opts|
        opts.banner = "Usage: lasertag [OPTIONS]"
        opts.separator  ''
        opts.separator  "Options"

        opts.on('-m', '--module MODULE', 'Specifies the app module') do |app_module|
          @app_module = app_module
        end

        opts.on('-f', '--flavor FLAVOR', 'Specifies the flavor (e.g. dev, qa, prod)') do |app_flavor|
          @app_flavor = app_flavor
        end

        opts.on('-p PATH', '--path PATH', 'Custom path to android project') do |app_path|
          @app_path = app_path if @app_path != '.'
        end

        opts.on('-r REMOTE', '--remote REMOTE', 'Custom remote to your project (default: "origin")') do |app_remote|
          @app_remote = app_remote
        end

        opts.on('-d', '--dont-push', 'Only tags the code, doesn\'t push it upstream') do |dont|
          @allow_push = false
        end

        opts.on('-h', '--help', 'Displays help') do
          @require_analyses = false
          puts opts.help
          exit
        end
        opts.on('-v', '--version', 'Displays version') do
          @require_analyses = false
          puts Lasertag::VERSION
          exit
        end
        opts.parse!

      end
    end

    ### Manage options
    def manage_opts

      unless @app_module
        puts "Please give me an app module name".yellow
        exit 1
      end

      Dir.chdir @app_path

      if has_uncommited_code
        puts "You have uncommited code, please commit it first".red
        exit 1
      end

      ### Assemble
      is_success = system assemble_command

      unless is_success
        puts "\n\nSomething went wrong so I stopped all the madness!!\n".red
        exit 1
      end

      ### Get project properties
      @hash = project_properties @app_module

      ### Find app info
      app_info = get_app_info

      puts "\nFor package #{app_info[:package].yellow}\n"

      ### git tag -a "versionNumber" -m "versionName"

      package = app_info[:package]
      name = @app_module # not quite correct
      version = app_info[:versionName]

      builded = "#{@app_module}/build/outputs/apk/#{@app_module}#{"-#{@app_flavor}" if @app_flavor}-release-unsigned.apk"

      puts "#{name} #{version} built to #{builded}.".green

      tag_code "v#{version}"
      puts "Tagged v#{version}.".green

      unless @allow_push
        exit 1
      end

      #$ git push origin v#{version}
      push_tag "v#{version}"

      puts "Pushed git commits and tags.".green
      puts "Pushed #{name} #{version} to remote.".green

    end


    ### HAS UNCOMMITED CODE?
    def has_uncommited_code
      g = Git.open(Dir.pwd)
      g.status.changed.size > 0
    end

    ### PUSH TAG
    def push_tag(tag)
      g = Git.open(Dir.pwd)
      begin
        g.push(g.remote(@app_remote), tag)
      rescue Exception => e
        puts "Can't push tag\n reason: #{e.to_s.red}"
        delete_tag tag
        exit 1
      end
    end

    ### DELETE TAG
    def delete_tag(tag)
      g = Git.open(Dir.pwd)
      g.delete_tag(tag)
    end

    ### TAG CODE
    def tag_code(version)
      g = Git.open(Dir.pwd)
      begin
        g.add_tag(version, {:message => "Version #{version.gsub(/^v/, "")}"})
      rescue Exception => e
        expected = "'#{version}' already exists"
        if e.to_s.include? expected
          puts "Error ocurred: #{expected.red}"
        else
          puts "Can't tag the code\n reason: #{e.to_s.red}"
        end

        exit 1
      end
    end

    ### IS THE ANDROID HOME DEFINED?
    def android_home_is_defined
      sdk = `echo $ANDROID_HOME`.gsub("\n",'')
      !sdk.empty?
    end

    def call
      unless android_home_is_defined
        puts "\nWARNING: your #{'$ANDROID_HOME'.yellow} is not defined\n"
        puts "\nhint: in your #{'~/.bashrc'.yellow} add:\n  #{"export ANDROID_HOME=\"/Users/cesarferreira/Library/Android/sdk/\"".yellow}"
        puts "\nNow type #{'source ~/.bashrc'.yellow}\n\n"
        exit 1
      end
    end


    ### Convert the app info to an hash
    def convert_values_to_hash (str)
      hash = Hash.new

      str.split(/\r?\n|\r/).each { |line|
        next unless line.include? ':'
        indexOf = line.index(':')
        next unless indexOf > 0

        key = line[0..indexOf-1].strip
        value = line[indexOf+1..line.length].strip

        hash[key] = value
      }

      hash
    end

    ### Get the project properties
    def project_properties(project=nil)

      project = "#{project}:" if project

      result = %x[gradle #{project}properties]
      convert_values_to_hash result
    end


    ### Get the app info
    def get_app_info
      path = get_path_to_merged_manifest
      handle = File.open(path)

      parser = Oga.parse_xml(handle)

      package     = parser.xpath("//manifest").attr('package').last.value
      versionCode = parser.xpath("//manifest").attr('android:versionCode').last.value
      versionName = parser.xpath("//manifest").attr('android:versionName').last.value

      {
        package: package,
        versionCode: versionCode,
        versionName: versionName,
      }
    end

    ### Path to the merged manifest
    def get_path_to_merged_manifest
      build_dir = @hash['buildDir']

      flavor = @app_flavor ? "/#{@app_flavor}/" : "/"

      path = "#{build_dir}/intermediates/manifests/full"
      path = "#{path}#{flavor}release/"

      full_path = File.join(path, 'AndroidManifest.xml')

      exists = File.exist?(full_path)

      unless exists
        puts "The merged manifest could not be found\n"
        puts "   Try specifying a Flavor\n".green
        system("lasertag -h")
        exit 1
      end


      full_path
    end

    ### Assemble command
    def assemble_command
      "gradle :#{@app_module}:assemble#{(@app_flavor or "").capitalize}Release"
    end

  end
end