github-copywriter 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 042abefd4aaf029250ac23d3e3c2922ff1226830
4
+ data.tar.gz: 91effc0c7e326866d4b5b1bfcd3adc19a42edb0e
5
+ SHA512:
6
+ metadata.gz: 0c20d89f92d42dcbfb72770e2d7d05956440f79f4799cd3b4057dba93cf691524ed346319a65ef95f46a1d66e27bcaf931f24de786694058b4db2ec3c787413e
7
+ data.tar.gz: 399848ed05d2e4d63277a31426fb334cdd267292ae503254c7bfc8db6ab68235748a404c489532942ad802f3b84152fae282909c7ae3f29fa85ddc697986747c
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ # Added by bundler
2
+ /.bundle/
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
11
+ *.bundle
12
+ *.so
13
+ *.o
14
+ *.a
15
+ mkmf.log
16
+
17
+ # Jekyll build
18
+ _site
19
+
20
+ # Vim
21
+ .*.swp
22
+ .*.swo
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in copywriter.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Ryan Jacobs
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # github-copywriter
2
+
3
+ Updates your copyrights... so you don't have to!
4
+
5
+ `$ gem install github-copywriter`
6
+
7
+ ---
8
+
9
+ ### Update specific repos
10
+ `$ github-copywriter MyCoolRepo MyOtherCoolRepo`
11
+
12
+ ### Update all repos
13
+ `$ github-copywriter --all`
14
+
15
+ ### Update all repos, excluding forks
16
+ `$ github-copywriter --all --skip-forks`
17
+
18
+ ---
19
+
20
+ ## Contributing
21
+ Please submit issues or feature requests [here](//github.com/ryanmjacobs/github-copywriter/issues).
22
+ Questions and comments are fine too :)
23
+
24
+ Feel free to [fork](//github.com/ryanmjacobs/github-copywriter) this project, and:
25
+
26
+ * fix bugs
27
+ * add some sweet features
28
+ * implement feature requests
29
+ * improve the docs and/or this site
30
+
31
+ ---
32
+
33
+ ## Under the hood
34
+ All GitHub API calls are made with [Octokit](//github.com/octokit/octokit.rb).
35
+
36
+ ####Basic breakdown of the program's logic:
37
+ 1. Authenticate to GitHub.
38
+ 2. Loop through each user repo given, and:
39
+ * Update copyrights on files: `README.md`, `LICENSE`, etc.
40
+ * Create a local commit and push to GitHub.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+ ################################################################################
3
+ # github-copywriter
4
+ #
5
+ # Author: Ryan Jacobs <ryan.mjacobs@gmail.com
6
+ ################################################################################
7
+
8
+ require "github-copywriter"
9
+ require "optparse"
10
+
11
+ options = {}
12
+
13
+ ARGV << "-h" if ARGV.empty?
14
+ OptionParser.new do |opts|
15
+ executable_name = File.split($0)[1]
16
+ opts.banner = <<-EOS
17
+ Updates your copyrights... so you don't have to!
18
+
19
+ Usage: #{executable_name} [repos...]
20
+ #{executable_name} --all
21
+
22
+ EOS
23
+
24
+ opts.on("--all", "Update copyrights on ALL repositories.") do
25
+ options[:all] = true
26
+ end
27
+
28
+ opts.on("-s", "--skip-forks", "Don't update forked repositories.") do
29
+ options[:skip_forks] = true
30
+ end
31
+
32
+ opts.on_tail("-h","--help", "Show this message.") do
33
+ puts opts
34
+ exit
35
+ end
36
+
37
+ opts.on_tail("-v", "--version", "Print the version.") do
38
+ puts "github-copywriter v#{Copywriter::VERSION}"
39
+ exit
40
+ end
41
+ end.parse!
42
+
43
+ if ARGV.empty? and not options[:all]
44
+ puts "error: No repositories supplied!"
45
+ exit
46
+ end
47
+
48
+ options[:repos] = ARGV
49
+
50
+ Copywriter.login!
51
+ Copywriter.run!(options)
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "github-copywriter"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "github-copywriter"
8
+ spec.version = Copywriter::VERSION
9
+ spec.authors = ["Ryan Jacobs"]
10
+ spec.email = ["ryan.mjacobs@gmail.com"]
11
+ spec.summary = %q{github-copywriter updates your copyrights... so you don't have to!}
12
+ spec.description = %q{github-copywriter scans through your repositories and updates any copyrights it finds.}
13
+ spec.homepage = "http://ryanmjacobs.github.io/github-copywriter"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+
24
+ spec.add_runtime_dependency "octokit" # GitHub API
25
+ spec.add_runtime_dependency "colorize" # Colorize text
26
+ end
@@ -0,0 +1,209 @@
1
+ ################################################################################
2
+ # github-copywriter
3
+ #
4
+ # Author: Ryan Jacobs <ryan.mjacobs@gmail.com
5
+ ################################################################################
6
+
7
+ require "highline/import"
8
+ require "octokit"
9
+ require "base64"
10
+ require "colorize"
11
+ require "pp" # debug tool
12
+
13
+ module Copywriter
14
+ extend self
15
+
16
+ VERSION = "0.0.1"
17
+ COMMIT_MSG = "Update copyright. ♥ github-copywriter\nFor more info, visit http://ryanmjacobs.github.io/github-copywriter"
18
+
19
+ # Get time/date
20
+ time = Time.now
21
+ CUR_YEAR = time.year
22
+
23
+ def login!
24
+ # Grab username and pass
25
+ puts "Obtaining OAuth2 access_token from github."
26
+ username = ask("GitHub username: ") { |q| q.echo = true }
27
+ password = ask("GitHub password: ") { |q| q.echo = "*" }
28
+
29
+ # Auth to GitHub
30
+ @client = Octokit::Client.new(:login => username, :password => password)
31
+
32
+ # Check if the basic_auth worked; TODO: Find a better way to do this
33
+ begin
34
+ @client.authorizations
35
+ rescue Octokit::Unauthorized
36
+ puts "error: Bad credentials".red
37
+ exit
38
+ end
39
+ end
40
+
41
+ ##
42
+ # Returns true if this is a file that we will update.
43
+ def accepted_name?(filename)
44
+ filename = File.basename(filename)
45
+
46
+ names = ["readme", "license"]
47
+ extensions = [".md", ".txt", ".html"]
48
+
49
+ if names.include? filename.downcase then return true end
50
+ if extensions.include? File.extname(filename.downcase) then return true end
51
+ end
52
+
53
+ ##
54
+ # Updates copyright using regex, then commits it.
55
+ #
56
+ # repo = Repo to commit to, e.g. "user/repo_name"
57
+ # ref = Branch to commit to, e.g. "heads/master"
58
+ # file_path = File path on repo, e.g. "readme", "src/file.rb", etc.
59
+ #
60
+ def update_copyright(repo, ref, file_path)
61
+
62
+ # Grab file from repo
63
+ file = @client.contents(repo, :path => file_path)
64
+ if file[:type] != "file" then raise "error: #{file_path} on #{repo} is not a file!" end
65
+
66
+ # Have to do separate assignments b/c ruby shares strings,
67
+ # TODO: find a way around this
68
+ content = Base64.decode64(file[:content])
69
+ old_content = Base64.decode64(file[:content])
70
+
71
+ # Do the substitution
72
+ #
73
+ # Matches:
74
+ # Copyright 2014
75
+ # copyright 2014
76
+ #
77
+ # Copyright (C) 2014
78
+ # copyright (c) 2014
79
+ # Copyright © 2014
80
+ # copyright © 2014
81
+ #
82
+ # (c) 2014
83
+ # (C) 2014
84
+ # © 2014
85
+ begin
86
+ content.gsub!(/([Cc]opyright( \([Cc]\)| ©)|\([Cc]\)|©) \d{4}/, "\\1 #{CUR_YEAR}")
87
+ rescue
88
+ # try w/o "©" symbol if we had errors
89
+ content.gsub!(/([Cc]opyright( \([Cc]\))|\([Cc]\)) \d{4}/, "\\1 #{CUR_YEAR}")
90
+ end
91
+
92
+ # Only commit if we need to
93
+ if content != old_content then
94
+ @modified_files << {:path => file_path, :content => content}
95
+ puts " #{file_path} is now up-to-date.".green
96
+ else
97
+ puts " #{file_path} was already up-to-date."
98
+ end
99
+ end
100
+
101
+ ##
102
+ # Commits files to a GitHub repo.
103
+ #
104
+ # repo = Repo to commit to, e.g. "user/repo_name"
105
+ # ref = Branch to commit to, e.g. "heads/master"
106
+ # file_mode = Filemode on repo, e.g. "100644"
107
+ # files = Array of {:path, :content}
108
+ # commit_msg = Commit message, e.g. "Update file.rb"
109
+ #
110
+ def commit_files(repo, ref, file_mode, files, commit_msg)
111
+
112
+ # Return if we don't have any files to commit
113
+ if files.size == 0 then return end
114
+
115
+ # Force file_mode to be either 100644 or 100775
116
+ if file_mode != "100644" or file_mode != "100775" then
117
+ file_mode = "100644"
118
+ end
119
+
120
+ # Construct temp. tree of files to commit
121
+ trees = Array.new
122
+ files.each do |file|
123
+ blob_sha = @client.create_blob(repo, Base64.encode64(file[:content]), "base64")
124
+
125
+ trees << {
126
+ :path => file[:path],
127
+ :mode => file_mode,
128
+ :type => "blob",
129
+ :sha => blob_sha
130
+ }
131
+ end
132
+
133
+ # Contruct the commit
134
+ latest_commit = @client.ref(repo, ref).object
135
+ base_tree = @client.commit(repo, latest_commit.sha).commit.tree
136
+ new_tree = @client.create_tree(repo, trees, :base_tree => base_tree.sha)
137
+ new_commit = @client.create_commit(repo, commit_msg, new_tree.sha, latest_commit.sha)
138
+
139
+ # Commit it!
140
+ @client.update_ref(repo, ref, new_commit.sha)
141
+ end
142
+
143
+ def run!(options={})
144
+ # Default options
145
+ options = {all: false, skip_forks: false}.merge(options)
146
+
147
+ if options[:all] then
148
+ repos = @client.repositories()
149
+ else
150
+ repos = Array.new
151
+ options[:repos].each do |r|
152
+ name = @client.login+"/"+File.basename(r)
153
+ if @client.repository?(name) then
154
+ repos << @client.repository(name)
155
+ else
156
+ puts "error: repo \"#{name}\" does not exist!".red
157
+ exit
158
+ end
159
+ end
160
+ end
161
+
162
+ # Loop through each repo
163
+ repos.each do |repo|
164
+
165
+ next if options[:skip_forks] and repo[:fork]
166
+
167
+ # Get repo info
168
+ repo_name = repo[:full_name]
169
+ ref = "heads/#{repo[:default_branch]}"
170
+ latest_commit = @client.ref(repo_name, ref).object
171
+ root_tree = @client.commit(repo_name, latest_commit.sha).commit.tree
172
+ puts "\n"+repo_name+":"
173
+
174
+ # Grab the *whole* tree
175
+ tree = @client.tree(repo_name, root_tree.sha, :recursive => true)
176
+
177
+ # warn user about truncation
178
+ if tree[:truncated] then
179
+ puts " warning: tree truncated because number of items exceeded limit.".yellow
180
+ puts " If you feel like fixing this, see issue #xx".yellow
181
+ puts " http://github.com/ryanmjacobs/github-copywriter/xx".yellow
182
+ end
183
+
184
+ # Stores updated files until we commit
185
+ # @modified_files is a hash {:path, :content}
186
+ @modified_files = Array.new
187
+
188
+ # Loop through all of the tree's blobs
189
+ tree[:tree].each do |file|
190
+ next if file[:type] != "blob"
191
+
192
+ if accepted_name?(file[:path]) then
193
+ update_copyright(repo_name, ref, file[:path])
194
+ end
195
+ end
196
+
197
+ # Commit stored up files
198
+ if @modified_files.size > 0 then
199
+ print " Committing #{@modified_files.size} files..."
200
+ commit_files(repo_name, ref, "100644", @modified_files, COMMIT_MSG)
201
+ puts " done"
202
+ else
203
+ puts " No files needed to be commited."
204
+ end
205
+ end
206
+ end
207
+
208
+ private :update_copyright, :accepted_name?, :commit_files
209
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: github-copywriter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Jacobs
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: octokit
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: colorize
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: github-copywriter scans through your repositories and updates any copyrights
70
+ it finds.
71
+ email:
72
+ - ryan.mjacobs@gmail.com
73
+ executables:
74
+ - github-copywriter
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - ".gitignore"
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - bin/github-copywriter
84
+ - github-copywriter.gemspec
85
+ - lib/github-copywriter.rb
86
+ homepage: http://ryanmjacobs.github.io/github-copywriter
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.2.2
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: github-copywriter updates your copyrights... so you don't have to!
110
+ test_files: []