Class: TestIds::Git

Inherits:
Object
  • Object
show all
Includes:
Origen::Utility::InputCapture
Defined in:
lib/test_ids/git.rb

Overview

The Git driver is responsible for committing and fetching the store from the central Git repository.

All operations are automatically pushed immediately to the central repository and a lock will be taken out whenever a program generation operation is done in production mode to prevent the need to merge with other users.

An instance of this class is instantiated as TestIds.git

Defined Under Namespace

Classes: PathToLocal

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Git

Returns a new instance of Git.



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/test_ids/git.rb', line 52

def initialize(options)
  unless File.exist?("#{options[:local]}/.git")
    FileUtils.rm_rf(options[:local]) if File.exist?(options[:local])
    FileUtils.mkdir_p(options[:local])
    Dir.chdir options[:local] do
      `git clone #{options[:remote]} .`
      unless File.exist?('lock.json')
        # Should really try to use the Git driver for this
        exec 'touch lock.json'
        exec 'git add lock.json'
        exec 'git commit -m "Initial commit"'
        exec 'git push'
      end
    end
  end
  @local = options[:local]
  @repo = ::Git.open(options[:local])
  # Get rid of any local edits coming in here, this is only called once at the start
  # of the program generation run.
  # No need to pull latest as that will be done when we obtain a lock.
  @repo.reset_hard
end

Instance Attribute Details

#localObject (readonly)

Returns the value of attribute local.



15
16
17
# File 'lib/test_ids/git.rb', line 15

def local
  @local
end

#repoObject (readonly)

Returns the value of attribute repo.



15
16
17
# File 'lib/test_ids/git.rb', line 15

def repo
  @repo
end

Class Method Details

.path_to_localObject

Returns a path to the local test IDs repo, if multiple are found the user will be prompted to choose one



47
48
49
50
# File 'lib/test_ids/git.rb', line 47

def self.path_to_local
  # Implemented as a class as a hack to get access to InputCapture
  PathToLocal.new.find
end

Instance Method Details

#available_to_lock?Boolean

Returns:

  • (Boolean)


154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/test_ids/git.rb', line 154

def available_to_lock?
  result = false
  Origen.profile 'Checking for lock' do
    repo.fetch
    repo.reset_hard('origin/master')
    if lock_content && lock_user && lock_user != User.current.name
      result = Time.now.to_f > lock_expires
    else
      result = true
    end
  end
  result
end

#exec(cmd) ⇒ Object



103
104
105
106
107
108
# File 'lib/test_ids/git.rb', line 103

def exec(cmd)
  r = system(cmd)
  unless r
    fail "Something went wrong running command: #{cmd}"
  end
end

#get_lockObject



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/test_ids/git.rb', line 126

def get_lock
  return if @lock_open
  Origen.profile 'Obtaining test IDs lock' do
    until available_to_lock?
      puts
      puts "Waiting for lock, currently locked by #{lock_user} (the lock will expire in less than #{lock_minutes_remaining} #{'minute'.pluralize(lock_minutes_remaining)} if not released before that)"
      puts
      sleep 5
    end
    data = {
      'user'    => User.current.name,
      'expires' => (Time.now + minutes(5)).to_f
    }
    write('lock.json', JSON.pretty_generate(data))
    repo.commit('Obtaining lock')
    repo.push('origin')
  end
  @lock_open = true
end

#lock_contentObject



180
181
182
183
# File 'lib/test_ids/git.rb', line 180

def lock_content
  f = File.join(local, 'lock.json')
  JSON.load(File.read(f)) if File.exist?(f)
end

#lock_expiresObject



172
173
174
# File 'lib/test_ids/git.rb', line 172

def lock_expires
  lock_content['expires']
end

#lock_minutes_remainingObject



168
169
170
# File 'lib/test_ids/git.rb', line 168

def lock_minutes_remaining
  ((lock_expires - Time.now.to_f) / 60).ceil
end

#lock_userObject



176
177
178
# File 'lib/test_ids/git.rb', line 176

def lock_user
  lock_content['user']
end

#minutes(number) ⇒ Object



185
186
187
# File 'lib/test_ids/git.rb', line 185

def minutes(number)
  number * 60
end

#publishObject



110
111
112
113
114
115
116
117
# File 'lib/test_ids/git.rb', line 110

def publish
  Origen.profile 'Publishing the test IDs store' do
    release_lock
    repo.add  # Checkin everything
    repo.commit('Publishing latest store')
    repo.push('origin', 'master', force: true)
  end
end

#release_lockObject



146
147
148
149
150
151
152
# File 'lib/test_ids/git.rb', line 146

def release_lock
  data = {
    'user'    => nil,
    'expires' => nil
  }
  write('lock.json', JSON.pretty_generate(data))
end

#rollback(id) ⇒ Object

Roll the repo back to the given commit ID



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/test_ids/git.rb', line 76

def rollback(id)
  name = Pathname.new(local).basename.to_s
  begin
    commit = repo.object(id)
  rescue ::Git::GitExecuteError
    puts 'The given commit ID cannot be found in that repository'
    exit
  end
  # day = 24 * 60 * 60
  # if commit.date < Time.now - (7 * day)
  #  puts "Sorry, that commit is more than a week old and I'm too scared to rollback that far."
  #  puts 'You will need to do that manually if you must.'
  #  exit
  # end
  puts
  puts "About to rollback the TestIds repository #{name} to commit #{id}."
  puts
  puts 'This will permanently delete any IDs assigned by anyone, anywhere, since that commit.'
  puts
  puts 'ARE YOU SURE YOU KNOW WHAT YOU ARE DOING?'
  puts
  get_text(confirm: true, default: 'no')
  repo.reset_hard(id)
  repo.push('origin', 'master', force: true)
  puts 'As you wish, rolled back successfully!'
end

#write(path, data = nil) ⇒ Object

Writes the data to the given file and pushes to the remote repo



120
121
122
123
124
# File 'lib/test_ids/git.rb', line 120

def write(path, data = nil)
  f = File.join(local, path)
  File.write(f, data) if data
  repo.add(f)
end