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 +7 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +40 -0
- data/Rakefile +1 -0
- data/bin/github-copywriter +51 -0
- data/github-copywriter.gemspec +26 -0
- data/lib/github-copywriter.rb +209 -0
- metadata +110 -0
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
data/Gemfile
ADDED
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: []
|