github-release 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ pkg/
2
+ .bundle/
3
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org/'
2
+
3
+ gemspec
@@ -0,0 +1,80 @@
1
+ This very simple gem provides a `git release` command, which will
2
+ automatically fill out any and all "release tags" into fully-blown "Github
3
+ Releases", complete with release notes, a heading, and all the other good
4
+ things in life.
5
+
6
+ Using this gem, you can turn the following tag annotation:
7
+
8
+ First Release
9
+
10
+ It is with much fanfare and blowing of horns that I bequeath the
11
+ awesomeness of `git release` upon the world.
12
+
13
+ Features in this release include:
14
+
15
+ * Ability to create a release from a tag annotation or commit message;
16
+ * Automatically generates an OAuth token if needed;
17
+ * Feeds your cat while you're hacking(*)
18
+
19
+ You should install it now! `gem install github-release`
20
+
21
+ Into [this](https://github.com/mpalmer/github-release/releases/tag/v0.1.0)
22
+ simply by running
23
+
24
+ git release
25
+
26
+
27
+ # Installation
28
+
29
+ Simply install the gem:
30
+
31
+ gem install github-release
32
+
33
+
34
+ # Usage
35
+
36
+ Using `git release` is very simple. Just make sure that your `origin`
37
+ remote points to your Github repo, and then run `git release`. All tags
38
+ that look like a "version tag" (see "Configuration", below) will be created
39
+ as Github releases (if they don't already exist) and the message from the
40
+ tag will be used as the release notes.
41
+
42
+ The format of the release notes is quite straightforward -- the first line
43
+ of the message associated with the commit will be used as the "name" of the
44
+ release, with the rest of the message used as the "body" of the release.
45
+ The body will be interpreted as Github-flavoured markdown, so if you'd like
46
+ to get fancy, go for your life.
47
+
48
+ The message associated with the "release tag" is either the tag's annotation
49
+ message (if it is an annotated tag) or else the commit log of the commit on
50
+ which the tag is placed. I *strongly* recommend annotated tags (but then
51
+ again, [I'm biased...](http://theshed.hezmatt.org/git-version-bump))
52
+
53
+ The first time you use `git release`, it will ask you for your Github
54
+ username and password. This is used to request an OAuth token to talk to
55
+ the Github API, which is then stored in your global git config. Hence you
56
+ *shouldn't* be asked for your credentials every time you use `git release`.
57
+ If you need to use multiple github accounts for different repos, you can
58
+ override the `release.api-token` config parameter in your repo configuration
59
+ (but you'll have to get your own OAuth token).
60
+
61
+
62
+ # Configuration
63
+
64
+ There are a few things you can configure to make `git release` work slightly
65
+ differently. None of them should be required for normal, sane use.
66
+
67
+ * `release.remote` (default `origin`) -- The name of the remote which is
68
+ used to determine what github repository to send release notes to.
69
+
70
+ * `release.api-token` (default is runtime generated) -- The OAuth token
71
+ to use to authenticate access to the Github API. When you first run `git
72
+ release`, you'll be prompted for a username and password to use to
73
+ generate an initial token; if you need to override it on a per-repo
74
+ basis, this is the key you'll use.
75
+
76
+ * `release.tag-regex` (default `v\d+\.\d+(\.\d+)?$`) -- The regular
77
+ expression to filter which tags denote releases, as opposed to other tags
78
+ you might have decided to make. Only tags which match this regular
79
+ expression will be pushed up by `git release`, and only those tags will
80
+ be marked as releases.
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ begin
5
+ Bundler.setup(:default, :development)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+
12
+ Bundler::GemHelper.install_tasks
13
+
14
+ require 'rdoc/task'
15
+
16
+ Rake::RDocTask.new do |rd|
17
+ rd.main = "README.md"
18
+ rd.title = 'github-release'
19
+ rd.rdoc_files.include("README.md", "lib/**/*.rb")
20
+ end
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'github-release'
4
+
5
+ GithubRelease.new.run
@@ -0,0 +1,25 @@
1
+ require 'git-version-bump'
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "github-release"
5
+
6
+ s.version = GVB.version
7
+ s.date = GVB.date
8
+
9
+ s.platform = Gem::Platform::RUBY
10
+
11
+ s.homepage = "http://theshed.hezmatt.org/github-release"
12
+ s.summary = "Upload tag annotations to github"
13
+ s.authors = ["Matt Palmer"]
14
+
15
+ s.extra_rdoc_files = ["README.md"]
16
+ s.files = `git ls-files`.split("\n")
17
+ s.executables = ["git-release"]
18
+
19
+ s.add_dependency 'octokit'
20
+ s.add_dependency 'git-version-bump'
21
+
22
+ s.add_development_dependency 'rake'
23
+ s.add_development_dependency 'bundler'
24
+ s.add_development_dependency 'rdoc'
25
+ end
@@ -0,0 +1,135 @@
1
+ require 'octokit'
2
+ require 'io/console'
3
+
4
+ class GithubRelease
5
+ def run
6
+ new_releases = tagged_releases.select { |r| !github_releases.include?(r) }
7
+
8
+ if new_releases.empty?
9
+ puts "No new release tags to push."
10
+ end
11
+
12
+ new_releases.each { |t| create_release(t) }
13
+
14
+ puts "All done!"
15
+ end
16
+
17
+ private
18
+ def api
19
+ @api ||= Octokit::Client.new(:access_token => token)
20
+ end
21
+
22
+ def token
23
+ @token ||= begin
24
+ # We cannot use the 'defaults' functionality of git_config here,
25
+ # because get_new_token would be evaluated before git_config ran
26
+ git_config("release.api-token") || get_new_token
27
+ end
28
+
29
+ log_val(@token)
30
+ end
31
+
32
+ def get_new_token
33
+ puts "Requesting a new OAuth token from Github..."
34
+ print "Github username: "
35
+ user = $stdin.gets.chomp
36
+ print "Github password: "
37
+ pass = $stdin.noecho(&:gets).chomp
38
+ puts
39
+
40
+ api = Octokit::Client.new(:login => user, :password => pass)
41
+ begin
42
+ res = api.create_authorization(:scopes => [:repo], :note => "git release")
43
+ rescue Octokit::Unauthorized
44
+ puts "Username or password incorrect. Please try again."
45
+ return get_new_token
46
+ end
47
+
48
+ token = res[:token]
49
+
50
+ system("git config --global release.api-token '#{token}'")
51
+
52
+ log_val(token)
53
+ end
54
+
55
+ def tag_regex
56
+ @tag_regex ||= `git config --get release.tag-regex`.strip
57
+ @tag_regex = /^v\d+\.\d+(\.\d+)?$/ if @tag_regex.empty?
58
+ log_val(@tag_regex)
59
+ end
60
+
61
+ def tagged_releases
62
+ @tagged_releases ||= `git tag`.split("\n").map(&:strip).grep tag_regex
63
+ log_val(@tagged_releases)
64
+ end
65
+
66
+ def repo_name
67
+ @repo_name ||= begin
68
+ case repo_url
69
+ when %r{^https://github.com/([^/]+/[^/]+)}
70
+ return $1.gsub(/\.git$/, '')
71
+ when %r{^(?:git@)?github\.com:([^/]+/[^/]+)}
72
+ return $1.gsub(/\.git$/, '')
73
+ else
74
+ raise RuntimeError,
75
+ "I cannot recognise the format of the push URL for remote #{remote_name} (#{repo_url})"
76
+ end
77
+ end
78
+ log_val(@repo_name)
79
+ end
80
+
81
+ def repo_url
82
+ @repo_url ||= begin
83
+ git_config("remote.#{remote_name}.pushurl") || git_config("remote.#{remote_name}.url")
84
+ end
85
+ log_val(@repo_url)
86
+ end
87
+
88
+ def remote_name
89
+ @remote_name ||= git_config("release.remote", "origin")
90
+ log_val(@remote_name)
91
+ end
92
+
93
+ def github_releases
94
+ @github_releases ||= api.repo(repo_name).rels[:releases].get.data.map(&:tag_name)
95
+ log_val(@github_releases)
96
+ end
97
+
98
+ def git_config(item, default = nil)
99
+ @config_cache ||= {}
100
+
101
+ @config_cache[item] ||= begin
102
+ v = `git config #{item}`.strip
103
+ v.empty? ? default : v
104
+ end
105
+
106
+ log_val(@config_cache[item], item)
107
+ end
108
+
109
+ def create_release(tag)
110
+ print "Creating a release for #{tag}..."
111
+ system("git push #{remote_name} tag #{tag} >/dev/null")
112
+
113
+ msg = `git tag -l -n1000 '#{tag}'`
114
+
115
+ # Ye ghods is is a horrific format to parse
116
+ name, body = msg.split("\n", 2)
117
+ name = name.gsub(/^#{tag}/, '').strip
118
+ body = body.split("\n").map { |l| l.sub(/^ /, '') }.join("\n")
119
+
120
+ api.create_release(repo_name, tag, :name => name, :body => body)
121
+
122
+ puts " done!"
123
+ end
124
+
125
+ def log_val(v, note = nil)
126
+ return v unless $DEBUG
127
+
128
+ calling_func = caller[0].split("`")[-1].sub(/'$/, '')
129
+
130
+ print "#{note}: " if note
131
+ puts "#{calling_func} => #{v.inspect}"
132
+
133
+ v
134
+ end
135
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: github-release
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Matt Palmer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-05-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: octokit
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: git-version-bump
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: bundler
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rdoc
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ description:
95
+ email:
96
+ executables:
97
+ - git-release
98
+ extensions: []
99
+ extra_rdoc_files:
100
+ - README.md
101
+ files:
102
+ - .gitignore
103
+ - Gemfile
104
+ - README.md
105
+ - Rakefile
106
+ - bin/git-release
107
+ - github-release.gemspec
108
+ - lib/github-release.rb
109
+ homepage: http://theshed.hezmatt.org/github-release
110
+ licenses: []
111
+ post_install_message:
112
+ rdoc_options: []
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ segments:
122
+ - 0
123
+ hash: -1742702825423313202
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ segments:
131
+ - 0
132
+ hash: -1742702825423313202
133
+ requirements: []
134
+ rubyforge_project:
135
+ rubygems_version: 1.8.23
136
+ signing_key:
137
+ specification_version: 3
138
+ summary: Upload tag annotations to github
139
+ test_files: []