Module: ReleaseTagger

Defined in:
lib/release_tagger.rb,
lib/release_tagger/repo.rb,
lib/release_tagger/version.rb

Defined Under Namespace

Classes: Repo, Version

Constant Summary collapse

TAG_PRODUCTION =
'-prod'
TAG_QA =
'-qa'
VERSION =
File.read(
  File.join(File.dirname(__FILE__), "..", "..", "VERSION")
).strip

Class Method Summary collapse

Class Method Details

.behind_origin?Boolean

Returns:

  • (Boolean)


72
73
74
# File 'lib/release_tagger.rb', line 72

def behind_origin?
  %x{git fetch origin >/dev/null 2>&1; git diff --stat HEAD...@{u}}.strip != ""
end

.changelogObject



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/release_tagger.rb', line 92

def changelog
  # Get commits since latest tag if any (in this branch or from the original branched one)
  commits = ''
  previous_tag = %x{git describe --abbrev=0 --tags --match *.*.*}.strip
  unless $?.success?
    raise RuntimeError, "Error getting previous tag!"
  end
  unless previous_tag == ''
    commits = %x{git log --pretty="format:* %s" #{previous_tag}..HEAD}
    unless $?.success?
      raise RuntimeError, "Error getting changelog!"
    end
  end
  commits
end

.color_terminal?Boolean

Returns:

  • (Boolean)


32
33
34
# File 'lib/release_tagger.rb', line 32

def color_terminal?
  ENV["TERM"] =~ /color/
end

.dirty_working_tree?Boolean

Returns:

  • (Boolean)


76
77
78
# File 'lib/release_tagger.rb', line 76

def dirty_working_tree?
  %x{git status --porcelain 2>/dev/null | egrep "^(M| M)"}.strip != ""
end

.err(message) ⇒ Object



56
57
58
# File 'lib/release_tagger.rb', line 56

def err(message)
  $stderr.puts(red(message))
end

.get_repo_nameObject



108
109
110
111
112
113
114
# File 'lib/release_tagger.rb', line 108

def get_repo_name
  repo_name = %x{basename `git rev-parse --show-toplevel`}.strip
  unless $?.success?
    raise RuntimeError, "Error getting repo name!"
  end
  repo_name
end

.green(string) ⇒ Object



36
37
38
39
40
41
42
# File 'lib/release_tagger.rb', line 36

def green(string)
  if color_terminal?
    "\x1b[0;32m#{string}\x1b[0m"
  else
    string
  end
end

.log(message) ⇒ Object



52
53
54
# File 'lib/release_tagger.rb', line 52

def log(message)
  $stdout.puts(green(message))
end

.on_master_branch?Boolean

Returns:

  • (Boolean)


68
69
70
# File 'lib/release_tagger.rb', line 68

def on_master_branch?
  `git rev-parse --abbrev-ref HEAD`.strip == "master"
end

.red(string) ⇒ Object



44
45
46
47
48
49
50
# File 'lib/release_tagger.rb', line 44

def red(string)
  if color_terminal?
    "\x1b[0;31m#{string}\x1b[0m"
  else
    string
  end
end

.release_message(version) ⇒ Object



88
89
90
# File 'lib/release_tagger.rb', line 88

def release_message(version)
  "Release #{version}#{release_tag}"
end

.release_tagObject



80
81
82
83
84
85
86
# File 'lib/release_tagger.rb', line 80

def release_tag
  if on_master_branch?
    TAG_PRODUCTION
  else
    TAG_QA
  end
end

.run!Object



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/release_tagger.rb', line 116

def run!
  if ARGV.length != 1
    usage
    exit 1
  end

  release_type = ARGV.first

  unless valid_release_type?(release_type)
    usage
    exit 1
  end

  if behind_origin?
    err "You are behind the origin/master branch - please pull before releasing."
    exit 1
  end

  if dirty_working_tree?
    err "There are uncommitted changes in the working directory."
    err "Please commit or stash all changes before making a release."
    exit 1
  end

  package_name       = 'lmn-' + get_repo_name
  old_version_string = Repo.new().get_max_package_version(package_name)
  old_version_parts  = old_version_string.split(".").map(&:to_i)
  old_version        = Version.new(*old_version_parts)
  new_version        = old_version.bump(release_type)

  $stderr.write "This will release version #{new_version}. Are you sure? [y/N]: "
  unless STDIN.gets.strip == "y"
    err "Exiting."
    exit 1
  end

  commits = changelog

  log "Creating release commit"
  commit_output = %x{git commit --allow-empty -m "#{release_message(new_version)}\n\n#{commits}" 2>&1}
  unless $?.success?
    err "Error committing release"
    err commit_output
    exit 1
  end

  log "Adding release tag"
  tag_output = %x{git tag -a #{new_version}#{release_tag} -m "#{release_message(new_version)}\n\n#{commits}" 2>&1}
  unless $?.success?
    err "Error adding version tag #{new_version}#{release_tag}:"
    err tag_output
    exit 1
  end

  log "Pushing release to origin"
  # Separate `push` and `push --tags` here, because only relatively recent
  # versions of git push both refs and tags with the single command.
  push_output = %x{git push && git push --tags 2>&1}
  unless $?.success?
    err "Error pushing release tag to origin:"
    err push_output
    exit 1
  end
  log "Pushed version #{new_version}"
end

.usageObject



60
61
62
# File 'lib/release_tagger.rb', line 60

def usage
  puts "Usage: #{File.basename($0)} (major|minor|patch)"
end

.valid_release_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


64
65
66
# File 'lib/release_tagger.rb', line 64

def valid_release_type?(type)
  %w{ major minor patch }.include?(type)
end