ignorance 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +151 -0
- data/Rakefile +1 -0
- data/ignorance.gemspec +25 -0
- data/lib/ignorance.rb +85 -0
- data/lib/ignorance/git_ignore_file.rb +33 -0
- data/lib/ignorance/hg_ignore_file.rb +16 -0
- data/lib/ignorance/ignore_file.rb +96 -0
- data/lib/ignorance/project_oriented_vcs.rb +14 -0
- data/lib/ignorance/svn_ignore_file.rb +13 -0
- data/lib/ignorance/version.rb +3 -0
- data/spec/ignorefile_helpers.rb +25 -0
- data/spec/io_helpers.rb +32 -0
- data/spec/lib/ignorance/git_ignore_file_spec.rb +31 -0
- data/spec/lib/ignorance/hg_ignore_file_spec.rb +14 -0
- data/spec/lib/ignorance/ignore_file_spec.rb +11 -0
- data/spec/lib/ignorance/svn_ignore_file_spec.rb +14 -0
- data/spec/lib/ignorance_spec.rb +49 -0
- data/spec/shared_examples/for_ignorance.rb +93 -0
- data/spec/shared_examples/for_ignore_files.rb +147 -0
- data/spec/shared_examples/for_project_oriented_vcs.rb +26 -0
- data/spec/spec_helper.rb +16 -0
- metadata +145 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Joel Helbling
|
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,151 @@
|
|
1
|
+
# Ignorance
|
2
|
+
|
3
|
+
Ensures specified files are ignored by Git, Mercurial or SVN.
|
4
|
+
|
5
|
+
## Use Case
|
6
|
+
|
7
|
+
You've created a utility to be used by others' projects which generates
|
8
|
+
or uses files and directories which ought not be committed/pushed/shared
|
9
|
+
with the world.
|
10
|
+
|
11
|
+
Ignorance helps your code be considerate of its users by protecting
|
12
|
+
their sensitive information.
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
gem 'ignorance'
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
|
26
|
+
$ gem install ignorance
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
If you'd like to warn users and fellow developers to add certain artifacts
|
31
|
+
to the project's ignore file, you can include this somewhere in your runtime:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
include Ignorance
|
35
|
+
|
36
|
+
advise_ignorance '.myfile'
|
37
|
+
```
|
38
|
+
|
39
|
+
Assuming those files are not in the project's .gitignore file, when
|
40
|
+
the code is run, your program will output the following to STDERR
|
41
|
+
(but not halt):
|
42
|
+
|
43
|
+
```
|
44
|
+
WARNING: please add ".myfile" to this project's .gitignore file!
|
45
|
+
```
|
46
|
+
|
47
|
+
If ignoring those files is really critical, you can halt with an exception:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
guard_ignorance 'mydir/'
|
51
|
+
```
|
52
|
+
|
53
|
+
You can even prompt the user, offering to automatically add the pertinent
|
54
|
+
files to the ignore file:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
negotiate_ignorance 'some_file.md'
|
58
|
+
```
|
59
|
+
|
60
|
+
And finally, if ignorance is absolutely critical, you can silently add
|
61
|
+
tokens to the project's ignore file:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
guarantee_ignorance! 'mydir/'
|
65
|
+
```
|
66
|
+
|
67
|
+
You can also use Ignorance directly (with out including the module).
|
68
|
+
Shorter method names are provided for that purpose:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
Ignorance.advise '.myfile'
|
72
|
+
Ignorance.guard 'some_other_file.txt'
|
73
|
+
Ignorance.negotiate 'family_phone_numbers.yaml'
|
74
|
+
Ignorance.guarantee! 'bank_login.cfg'
|
75
|
+
```
|
76
|
+
|
77
|
+
## When Ignorance Works
|
78
|
+
|
79
|
+
Ignorance works on the ignore files of any and all detected repository types.
|
80
|
+
If .git is present, .gitignore is managed. If .hg then .hgignore,
|
81
|
+
if .svn, .svnignore. For Git and Mercurial, parent directories will also
|
82
|
+
be searched for a repository root.
|
83
|
+
|
84
|
+
Ignorance does nothing when one of two conditions exist:
|
85
|
+
|
86
|
+
1. All specified tokens are already ignored
|
87
|
+
2. The current directory is not within a repository
|
88
|
+
|
89
|
+
Ignorance's repo detection is based on the current working directory (e.g.
|
90
|
+
Dir.getwd, usually the directory where the code was launched). It presumes
|
91
|
+
the common dev-time situation wherein a program is launched from within its
|
92
|
+
project dir.
|
93
|
+
|
94
|
+
This means that if your code uses Ignorance, and others use your code, repo
|
95
|
+
and ignore file detection will happen relative to their project directory.
|
96
|
+
|
97
|
+
## Adding a Comment
|
98
|
+
|
99
|
+
The #negotiate and #guarantee! methods (and their longer counterparts)
|
100
|
+
accept an optional comment parameter:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
negotiate_ignorance 'api_token.yml', 'added by HandyBankUtil'
|
104
|
+
```
|
105
|
+
|
106
|
+
This will add the following to the ignore file (assuming 'api_token.yml'
|
107
|
+
wasn't already ignored):
|
108
|
+
|
109
|
+
```
|
110
|
+
# added by HandyBankUtil
|
111
|
+
api_token.yml
|
112
|
+
|
113
|
+
```
|
114
|
+
|
115
|
+
If the supplied comment was already in the ignore file (suppose you
|
116
|
+
negotiated several tokens with the same comment), the new token will be
|
117
|
+
added to the bottom of that section. So if the ignore file already had
|
118
|
+
this:
|
119
|
+
|
120
|
+
```
|
121
|
+
# added by HandyBankUtil
|
122
|
+
secret_info.txt
|
123
|
+
|
124
|
+
```
|
125
|
+
|
126
|
+
The above example would result in this in the ignore file:
|
127
|
+
|
128
|
+
```
|
129
|
+
# added by HandyBankUtil
|
130
|
+
secret_info.txt
|
131
|
+
api_token.yml
|
132
|
+
|
133
|
+
```
|
134
|
+
|
135
|
+
## Contributing
|
136
|
+
|
137
|
+
1. Fork it
|
138
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
139
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
140
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
141
|
+
5. Create new Pull Request
|
142
|
+
|
143
|
+
## Do you love Ignorance, and want to make it even better?
|
144
|
+
|
145
|
+
Here's some stuff I ain't figured out yet:
|
146
|
+
|
147
|
+
- *Support for globs & regexes*: If you `gaurd_ignorance 'myfile.private'` and
|
148
|
+
the ignore file contains a glob or regex which would cause that to be ignored,
|
149
|
+
Ignorance will raise an error anyway.
|
150
|
+
- *Support for other version control systems.* Visual SourceSafe can't use
|
151
|
+
Ignorance. Does that seem right to you?
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/ignorance.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ignorance/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "ignorance"
|
8
|
+
gem.version = Ignorance::VERSION
|
9
|
+
gem.authors = ["Joel Helbling"]
|
10
|
+
gem.email = ["joel@joelhelbling.com"]
|
11
|
+
gem.description = %q{Ensures specified files are ignored by Git, Mercurial or SVN.}
|
12
|
+
gem.summary = %q{Ignorance helps your code be considerate of its users by protecting sensitive information from version control.}
|
13
|
+
gem.homepage = "http://github.com/joelhelbling/ignorance"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency 'highline', '~> 1.6.15'
|
21
|
+
|
22
|
+
gem.add_development_dependency 'rspec', '~> 2.12.0'
|
23
|
+
gem.add_development_dependency 'fakefs', '~> 0.4.2'
|
24
|
+
gem.add_development_dependency 'pry', '~> 0.9.11.4'
|
25
|
+
end
|
data/lib/ignorance.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'highline'
|
2
|
+
require 'ignorance/version'
|
3
|
+
|
4
|
+
require 'ignorance/git_ignore_file'
|
5
|
+
require 'ignorance/hg_ignore_file'
|
6
|
+
require 'ignorance/svn_ignore_file'
|
7
|
+
|
8
|
+
module Ignorance
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def advise(token)
|
12
|
+
active_ignore_files.each do |ignore_file|
|
13
|
+
warning token, ignore_file unless ignore_file.ignored?(token)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def guard(token)
|
18
|
+
active_ignore_files.each do |ignore_file|
|
19
|
+
unless ignore_file.ignored?(token)
|
20
|
+
raise IgnorefileError.new "Please add \"#{token}\" to this project's #{ignore_file.name} file!"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def negotiate(token, comment=nil)
|
26
|
+
active_ignore_files.each do |ignore_file|
|
27
|
+
unless ignore_file.ignored?(token)
|
28
|
+
msg = "would you like me to add #{token} to this project's #{ignore_file.name} file automatically?"
|
29
|
+
if agree? msg
|
30
|
+
guarantee! token, comment
|
31
|
+
puts "Added \"#{token}\" to this project's #{ignore_file.name} file."
|
32
|
+
else
|
33
|
+
warning token, ignore_file
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def guarantee!(token, comment=nil)
|
40
|
+
active_ignore_files.each do |ignore_file|
|
41
|
+
unless ignore_file.ignored?(token)
|
42
|
+
ignore_file.ignore! token, comment
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def warning(token, ignore_file)
|
50
|
+
warn "WARNING: please add \"#{token}\" to this project's #{ignore_file.name} file!"
|
51
|
+
end
|
52
|
+
|
53
|
+
def active_ignore_files
|
54
|
+
ignore_files.select(&:its_a_repo?)
|
55
|
+
end
|
56
|
+
|
57
|
+
def ignore_files
|
58
|
+
[GitIgnoreFile.new, HgIgnoreFile.new, SvnIgnoreFile.new]
|
59
|
+
end
|
60
|
+
|
61
|
+
def agree?(msg)
|
62
|
+
HighLine.new.agree("#{msg} [Y]es/[n]o? ")
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
def advise_ignorance(token)
|
68
|
+
Ignorance.advise token, comment
|
69
|
+
end
|
70
|
+
|
71
|
+
def guard_ignorance(token)
|
72
|
+
Ignorance.guard token, comment
|
73
|
+
end
|
74
|
+
|
75
|
+
def negotiate_ignorance(token, comment=nil)
|
76
|
+
Ignorance.negotiate token, comment
|
77
|
+
end
|
78
|
+
|
79
|
+
def guarantee_ignorance!(token, comment=nil)
|
80
|
+
Ignorance.guarantee! token, comment
|
81
|
+
end
|
82
|
+
|
83
|
+
class IgnorefileError < IOError; end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'ignorance/ignore_file'
|
2
|
+
require 'ignorance/project_oriented_vcs'
|
3
|
+
|
4
|
+
module Ignorance
|
5
|
+
class GitIgnoreFile < IgnoreFile
|
6
|
+
attr_reader :ignore_file, :repo_dir
|
7
|
+
|
8
|
+
include ProjectOrientedVCS
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@ignore_file = '.gitignore'
|
12
|
+
@repo_dir = '.git'
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def ignored
|
18
|
+
(file_contents + user_ignore_file_contents).reject do |t|
|
19
|
+
t.match /^\#/
|
20
|
+
end.map(&:chomp)
|
21
|
+
end
|
22
|
+
|
23
|
+
def user_ignore_file_contents
|
24
|
+
File.exists?(user_ignore_file) ? File.readlines(user_ignore_file) : []
|
25
|
+
end
|
26
|
+
|
27
|
+
def user_ignore_file
|
28
|
+
@user_ignore_file ||= `git config --global --get core.excludesfile`.chomp
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'ignorance/ignore_file'
|
2
|
+
require 'ignorance/project_oriented_vcs'
|
3
|
+
|
4
|
+
module Ignorance
|
5
|
+
class HgIgnoreFile < IgnoreFile
|
6
|
+
attr_reader :ignore_file, :repo_dir
|
7
|
+
|
8
|
+
include ProjectOrientedVCS
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@ignore_file = '.hgignore'
|
12
|
+
@repo_dir = '.hg'
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Ignorance
|
2
|
+
class IgnoreFile
|
3
|
+
|
4
|
+
def name
|
5
|
+
ignore_file
|
6
|
+
end
|
7
|
+
|
8
|
+
def exists?
|
9
|
+
File.exists? ignore_file
|
10
|
+
end
|
11
|
+
|
12
|
+
def its_a_repo?
|
13
|
+
Dir.exists? repo_dir
|
14
|
+
end
|
15
|
+
|
16
|
+
def ignored?(token)
|
17
|
+
ignored.include? token
|
18
|
+
end
|
19
|
+
|
20
|
+
def included?(token)
|
21
|
+
file_contents.include? token
|
22
|
+
end
|
23
|
+
|
24
|
+
def ignore!(token, comment=nil)
|
25
|
+
return true if ignored?(token)
|
26
|
+
if comment
|
27
|
+
anchor = commentified comment
|
28
|
+
if included? anchor
|
29
|
+
insert_after anchor, token
|
30
|
+
else
|
31
|
+
append "\n"
|
32
|
+
append anchor
|
33
|
+
append token
|
34
|
+
end
|
35
|
+
else # There's no comment
|
36
|
+
append token
|
37
|
+
end
|
38
|
+
|
39
|
+
write_ignore_file
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def ignored
|
45
|
+
file_contents.reject{ |t| t.match /^\#/ }.map(&:chomp)
|
46
|
+
end
|
47
|
+
|
48
|
+
def file_contents
|
49
|
+
@file_contents ||= exists? ? File.readlines(ignore_file) : []
|
50
|
+
end
|
51
|
+
|
52
|
+
def insert_at(index, token)
|
53
|
+
file_contents.insert(index, token)
|
54
|
+
end
|
55
|
+
|
56
|
+
def append(token)
|
57
|
+
insert_at(file_contents.size, token)
|
58
|
+
end
|
59
|
+
|
60
|
+
def insert_after(anchor, token)
|
61
|
+
insert_index = file_contents.find_index(anchor) + 1
|
62
|
+
insert_index += 1 until here_is_good?(insert_index)
|
63
|
+
insert_at insert_index, token
|
64
|
+
end
|
65
|
+
|
66
|
+
def here_is_good?(insert_index)
|
67
|
+
at_maximum?(insert_index) || blank_line_at?(insert_index)
|
68
|
+
end
|
69
|
+
|
70
|
+
def at_maximum?(insert_index)
|
71
|
+
insert_index >= file_contents.size
|
72
|
+
end
|
73
|
+
|
74
|
+
def blank_line_at?(insert_index)
|
75
|
+
file_contents[insert_index].match(/^[\s\n]*$/)
|
76
|
+
end
|
77
|
+
|
78
|
+
def commentified(comment)
|
79
|
+
"# " + comment.gsub(/^\s*\#\s*/, '')
|
80
|
+
end
|
81
|
+
|
82
|
+
def printified(line)
|
83
|
+
line.chomp + "\n"
|
84
|
+
end
|
85
|
+
|
86
|
+
def write_ignore_file
|
87
|
+
File.open(ignore_file, 'w') do |fh|
|
88
|
+
file_contents.each do |line|
|
89
|
+
fh.write printified line
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Ignorance
|
2
|
+
module ProjectOrientedVCS
|
3
|
+
|
4
|
+
def its_a_repo?
|
5
|
+
path = Dir.getwd.scan(/\/[^\/]+/).map{|p| p[1..-1]}
|
6
|
+
repo_found = false
|
7
|
+
until (repo_found = Dir.exists?(File.join("/", path, @repo_dir))) || path.empty?
|
8
|
+
path.pop
|
9
|
+
end
|
10
|
+
repo_found
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module IgnorefileHelpers
|
2
|
+
|
3
|
+
def ignorefile_write(contents)
|
4
|
+
File.open(ignore_file, 'w') do |fh|
|
5
|
+
fh.write contents
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def ignorefile_lines
|
10
|
+
File.readlines(ignore_file)
|
11
|
+
end
|
12
|
+
|
13
|
+
def ignored_tokens
|
14
|
+
ignorefile_lines.map(&:chomp)
|
15
|
+
end
|
16
|
+
|
17
|
+
def ignorefile_contents
|
18
|
+
File.read(ignore_file)
|
19
|
+
end
|
20
|
+
|
21
|
+
def mk_repo_dir
|
22
|
+
Dir.mkdir repo_dir
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/spec/io_helpers.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
module IOHelpers
|
4
|
+
|
5
|
+
def output_from
|
6
|
+
$stdout = $stderr = fake_io
|
7
|
+
yield
|
8
|
+
fake_io.string
|
9
|
+
ensure
|
10
|
+
$stdout = STDOUT; $stderr = STDERR
|
11
|
+
end
|
12
|
+
|
13
|
+
def user_types(input, &block)
|
14
|
+
$stdin = StringIO.new input
|
15
|
+
output_from &block
|
16
|
+
ensure
|
17
|
+
$stdin = STDIN
|
18
|
+
end
|
19
|
+
|
20
|
+
def stdout_from(&block)
|
21
|
+
output_from &block
|
22
|
+
end
|
23
|
+
|
24
|
+
def stderr_from(&block)
|
25
|
+
output_from &block
|
26
|
+
end
|
27
|
+
|
28
|
+
def fake_io
|
29
|
+
@fake_io ||= StringIO.new
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ignorance/git_ignore_file'
|
3
|
+
|
4
|
+
module Ignorance
|
5
|
+
describe GitIgnoreFile, :fakefs do
|
6
|
+
|
7
|
+
let(:ignore_file) { '.gitignore' }
|
8
|
+
let(:repo_dir) { '.git' }
|
9
|
+
|
10
|
+
it_should_behave_like "an ignore file"
|
11
|
+
it_should_behave_like "a project-oriented VCS"
|
12
|
+
|
13
|
+
context "when the user's gitignore file includes the token" do
|
14
|
+
let(:token) { "foofile.md" }
|
15
|
+
let(:user_ignore_file) { '~/.gitignore' }
|
16
|
+
before do
|
17
|
+
ignorefile_write %w[other stuff here].join("\n")
|
18
|
+
File.open(user_ignore_file, 'w') do |fh|
|
19
|
+
fh.write "#{token}\n"
|
20
|
+
end
|
21
|
+
subject.stub(:user_ignore_file).and_return(user_ignore_file)
|
22
|
+
end
|
23
|
+
|
24
|
+
specify "then the file is ignored" do
|
25
|
+
File.read('~/.gitignore').should match /#{token}/
|
26
|
+
subject.ignored?(token).should be_true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ignorance/hg_ignore_file'
|
3
|
+
|
4
|
+
module Ignorance
|
5
|
+
describe HgIgnoreFile, :fakefs do
|
6
|
+
|
7
|
+
let(:ignore_file) { '.hgignore' }
|
8
|
+
let(:repo_dir) { '.hg' }
|
9
|
+
|
10
|
+
it_should_behave_like "an ignore file"
|
11
|
+
it_should_behave_like "a project-oriented VCS"
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ignorance'
|
3
|
+
|
4
|
+
describe Ignorance do
|
5
|
+
|
6
|
+
describe "class methods (e.g. Ingorance.guard...)" do
|
7
|
+
subject { Ignorance }
|
8
|
+
it { should respond_to :advise, :guard, :negotiate, :guarantee! }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "when included" do
|
12
|
+
before do
|
13
|
+
class TestIncluder
|
14
|
+
include Ignorance
|
15
|
+
end
|
16
|
+
end
|
17
|
+
subject { TestIncluder.new }
|
18
|
+
|
19
|
+
it do
|
20
|
+
should respond_to :advise_ignorance,
|
21
|
+
:guard_ignorance,
|
22
|
+
:negotiate_ignorance,
|
23
|
+
:guarantee_ignorance!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "with Git" do
|
28
|
+
let(:ignore_file) { '.gitignore' }
|
29
|
+
let(:repo_dir) { '.git' }
|
30
|
+
|
31
|
+
it_should_behave_like Ignorance
|
32
|
+
end
|
33
|
+
|
34
|
+
context "with Mercurial" do
|
35
|
+
let(:ignore_file) { '.hgignore' }
|
36
|
+
let(:repo_dir) { '.hg' }
|
37
|
+
|
38
|
+
it_should_behave_like Ignorance
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
context "with SVN" do
|
43
|
+
let(:ignore_file) { '.svnignore' }
|
44
|
+
let(:repo_dir) { '.svn' }
|
45
|
+
|
46
|
+
it_should_behave_like Ignorance
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
shared_examples Ignorance do
|
2
|
+
|
3
|
+
context "So anyway...", :fakefs do
|
4
|
+
before { mk_repo_dir }
|
5
|
+
let(:token) { "foo.rb" }
|
6
|
+
|
7
|
+
describe "::advise", :capture_io do
|
8
|
+
|
9
|
+
context "token is already in ignore file" do
|
10
|
+
before { ignorefile_write "#{token}\n" }
|
11
|
+
|
12
|
+
it "does not warn" do
|
13
|
+
expect( stderr_from { Ignorance.advise token } ).to be_empty
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "token is NOT in ignore file" do
|
18
|
+
before { ignorefile_write "something-else.txt\n" }
|
19
|
+
|
20
|
+
it "prints warn (STDERR)" do
|
21
|
+
expect( stderr_from { Ignorance.advise token } ).to match /WARNING:.*add "#{token}" to .*#{ignore_file}/
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "::guard" do
|
27
|
+
context "token is already in ignore file" do
|
28
|
+
before { ignorefile_write "#{token}\n" }
|
29
|
+
|
30
|
+
specify "no error is raised" do
|
31
|
+
expect { Ignorance.guard token }.to_not raise_error
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "token is NOT in ignore file" do
|
36
|
+
before { ignorefile_write "something-else.txt\n" }
|
37
|
+
|
38
|
+
it "raises an error" do
|
39
|
+
expect { Ignorance.guard token }.to raise_error Ignorance::IgnorefileError, /add "#{token}" to .*#{ignore_file}/
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "::negotiate", :capture_io do
|
45
|
+
|
46
|
+
context "token is already in ignore file" do
|
47
|
+
before { ignorefile_write "#{token}\n" }
|
48
|
+
|
49
|
+
it "does nothing" do
|
50
|
+
expect( stdout_from { Ignorance.negotiate token } ).to be_empty
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "token is NOT in ignore file" do
|
55
|
+
before { ignorefile_write "stuff.txt\n" }
|
56
|
+
|
57
|
+
context "user agrees (y)" do
|
58
|
+
specify do
|
59
|
+
expect( user_types("y") { Ignorance.negotiate token } ).to match /added "#{token}"/i
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "user disagrees (n)" do
|
64
|
+
specify do
|
65
|
+
expect( user_types("n") { Ignorance.negotiate token } ).to match /WARNING:.*add "#{token}" to .*#{ignore_file}/
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "::guarantee!" do
|
72
|
+
context "token is already in ignore file" do
|
73
|
+
before { ignorefile_write "#{token}\n" }
|
74
|
+
|
75
|
+
it "does not change the ignore file" do
|
76
|
+
Ignorance.guarantee! token, "a comment"
|
77
|
+
ignorefile_contents.should == "#{token}\n"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "token is NOT in ignore file" do
|
82
|
+
before { ignorefile_write "stuff.txt\n" }
|
83
|
+
|
84
|
+
it "adds to the ignore file" do
|
85
|
+
Ignorance.guarantee! token, "a comment"
|
86
|
+
ignorefile_contents.should == "stuff.txt\n\n# a comment\n#{token}\n"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module Ignorance
|
2
|
+
shared_examples "an ignore file" do
|
3
|
+
|
4
|
+
it { should respond_to :name, :exists?, :its_a_repo?, :ignored?, :ignore! }
|
5
|
+
its(:name) { should == ignore_file }
|
6
|
+
|
7
|
+
describe "#exists?" do
|
8
|
+
|
9
|
+
context "when the ignore file does NOT exist" do
|
10
|
+
it { should_not exist }
|
11
|
+
end
|
12
|
+
|
13
|
+
context "when the ignore file DOES exist" do
|
14
|
+
before { ignorefile_write "" }
|
15
|
+
it { should exist }
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
describe "#its_a_repo?" do
|
22
|
+
|
23
|
+
context "when the repo subdirectory does NOT exist" do
|
24
|
+
it { should_not be_its_a_repo }
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when the repo subdirectory DOES exist" do
|
28
|
+
before { Dir.mkdir repo_dir }
|
29
|
+
it { should be_its_a_repo }
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#ignored?" do
|
35
|
+
let(:token) { "foofile.txt" }
|
36
|
+
|
37
|
+
context "when the ignore file doesn't exist" do
|
38
|
+
specify "then the file is not ignored, duh" do
|
39
|
+
subject.should_not exist
|
40
|
+
subject.ignored?(token).should == false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when the ignore file does exist" do
|
45
|
+
|
46
|
+
context "when the ignore file doesn't include the token" do
|
47
|
+
before { ignorefile_write %w[other stuff here].join("\n") }
|
48
|
+
it { should_not be_ignored(token) }
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when the ignore file DOES include the token" do
|
52
|
+
before { ignorefile_write ["other", token+"", "stuff"].join("\n") }
|
53
|
+
it { should be_ignored(token) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
describe "#ignore!" do
|
61
|
+
let(:token) { "foofile.txt" }
|
62
|
+
|
63
|
+
context "there is no ignore file" do
|
64
|
+
it "writes to the ignore file" do
|
65
|
+
subject.should_not exist
|
66
|
+
subject.ignore! token
|
67
|
+
ignored_tokens.should include token
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "there is already an ignore file" do
|
72
|
+
before { ignorefile_write "*.swp\n" }
|
73
|
+
specify do
|
74
|
+
ignored_tokens.should include '*.swp'
|
75
|
+
subject.ignore! token
|
76
|
+
ignored_tokens.should include '*.swp'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "the token is already in the ignore file" do
|
81
|
+
let(:content) { "other\n#{token}\nstuff\n" }
|
82
|
+
before { ignorefile_write content }
|
83
|
+
|
84
|
+
it "doesn't write to the ignore file" do
|
85
|
+
File.any_instance.should_not_receive(:write)
|
86
|
+
subject.ignore!(token)
|
87
|
+
ignored_tokens.should include token
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "with a comment" do
|
92
|
+
context "when the comment wasn't already in the file" do
|
93
|
+
specify do
|
94
|
+
subject.ignore! token, "# hide these files!"
|
95
|
+
ignorefile_contents.should match /# hide these files!\n#{token}\n/
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "when the comment was already in the file" do
|
100
|
+
let(:comment) { "hide these files!" }
|
101
|
+
|
102
|
+
context "comment is the last line of the file" do
|
103
|
+
before { ignorefile_write "\n# #{comment}\n" }
|
104
|
+
|
105
|
+
specify do
|
106
|
+
subject.ignore! token, comment
|
107
|
+
ignorefile_contents.should match /# #{comment}\n#{token}\n/
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context "when the comment has other tokens after it" do
|
112
|
+
before do
|
113
|
+
ignorefile_write <<-IGNORE
|
114
|
+
# #{comment}
|
115
|
+
barfile.md
|
116
|
+
|
117
|
+
other-things
|
118
|
+
IGNORE
|
119
|
+
end
|
120
|
+
let(:expected) { Regexp.new /# #{comment}\nbarfile\.md\n#{token}\n\nother-things/ }
|
121
|
+
|
122
|
+
specify do
|
123
|
+
subject.ignore! token, comment
|
124
|
+
ignorefile_contents.should match expected
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "when comment has other tokens at end of file" do
|
129
|
+
before do
|
130
|
+
ignorefile_write <<-IGNORE
|
131
|
+
# #{comment}
|
132
|
+
barfile.md
|
133
|
+
IGNORE
|
134
|
+
end
|
135
|
+
let(:expected) { Regexp.new /# #{comment}\nbarfile\.md\n#{token}\n/ }
|
136
|
+
|
137
|
+
specify do
|
138
|
+
subject.ignore! token, comment
|
139
|
+
ignorefile_contents.should match expected
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
shared_examples "a project-oriented VCS" do
|
2
|
+
|
3
|
+
describe "#its_a_repo?", :fakefs do
|
4
|
+
context "pwd is a subdirectory of the repo root" do
|
5
|
+
before do
|
6
|
+
mk_repo_dir
|
7
|
+
Dir.mkdir 'lib'
|
8
|
+
Dir.mkdir 'lib/other'
|
9
|
+
Dir.chdir 'lib/other'
|
10
|
+
end
|
11
|
+
|
12
|
+
it { should be_its_a_repo }
|
13
|
+
end
|
14
|
+
|
15
|
+
context "pwd is not the subdirectory of any repo" do
|
16
|
+
before do
|
17
|
+
Dir.mkdir 'lib'
|
18
|
+
Dir.mkdir 'lib/other'
|
19
|
+
Dir.chdir 'lib/other'
|
20
|
+
end
|
21
|
+
|
22
|
+
it { should_not be_its_a_repo }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'fakefs/spec_helpers'
|
2
|
+
require File.join(File.dirname(__FILE__), 'ignorefile_helpers')
|
3
|
+
require File.join(File.dirname(__FILE__), 'io_helpers')
|
4
|
+
|
5
|
+
here = File.dirname(__FILE__)
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift(File.expand_path(File.join(here, '..', '..', 'lib')))
|
8
|
+
|
9
|
+
Dir[File.join(here, "shared_examples") + "/**/*.rb"].sort.map{|f| File.basename f }.map{|f| "shared_examples/#{f}"}.each {|f| require f}
|
10
|
+
|
11
|
+
RSpec.configure do |cfg|
|
12
|
+
cfg.treat_symbols_as_metadata_keys_with_true_values = true
|
13
|
+
cfg.include FakeFS::SpecHelpers, fakefs: true
|
14
|
+
cfg.include IgnorefileHelpers, fakefs: true
|
15
|
+
cfg.include IOHelpers, capture_io: true
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ignorance
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joel Helbling
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: highline
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.6.15
|
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: 1.6.15
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 2.12.0
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.12.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: fakefs
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.4.2
|
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.4.2
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: pry
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 0.9.11.4
|
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.9.11.4
|
78
|
+
description: Ensures specified files are ignored by Git, Mercurial or SVN.
|
79
|
+
email:
|
80
|
+
- joel@joelhelbling.com
|
81
|
+
executables: []
|
82
|
+
extensions: []
|
83
|
+
extra_rdoc_files: []
|
84
|
+
files:
|
85
|
+
- .gitignore
|
86
|
+
- Gemfile
|
87
|
+
- LICENSE.txt
|
88
|
+
- README.md
|
89
|
+
- Rakefile
|
90
|
+
- ignorance.gemspec
|
91
|
+
- lib/ignorance.rb
|
92
|
+
- lib/ignorance/git_ignore_file.rb
|
93
|
+
- lib/ignorance/hg_ignore_file.rb
|
94
|
+
- lib/ignorance/ignore_file.rb
|
95
|
+
- lib/ignorance/project_oriented_vcs.rb
|
96
|
+
- lib/ignorance/svn_ignore_file.rb
|
97
|
+
- lib/ignorance/version.rb
|
98
|
+
- spec/ignorefile_helpers.rb
|
99
|
+
- spec/io_helpers.rb
|
100
|
+
- spec/lib/ignorance/git_ignore_file_spec.rb
|
101
|
+
- spec/lib/ignorance/hg_ignore_file_spec.rb
|
102
|
+
- spec/lib/ignorance/ignore_file_spec.rb
|
103
|
+
- spec/lib/ignorance/svn_ignore_file_spec.rb
|
104
|
+
- spec/lib/ignorance_spec.rb
|
105
|
+
- spec/shared_examples/for_ignorance.rb
|
106
|
+
- spec/shared_examples/for_ignore_files.rb
|
107
|
+
- spec/shared_examples/for_project_oriented_vcs.rb
|
108
|
+
- spec/spec_helper.rb
|
109
|
+
homepage: http://github.com/joelhelbling/ignorance
|
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
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ! '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
requirements: []
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 1.8.24
|
130
|
+
signing_key:
|
131
|
+
specification_version: 3
|
132
|
+
summary: Ignorance helps your code be considerate of its users by protecting sensitive
|
133
|
+
information from version control.
|
134
|
+
test_files:
|
135
|
+
- spec/ignorefile_helpers.rb
|
136
|
+
- spec/io_helpers.rb
|
137
|
+
- spec/lib/ignorance/git_ignore_file_spec.rb
|
138
|
+
- spec/lib/ignorance/hg_ignore_file_spec.rb
|
139
|
+
- spec/lib/ignorance/ignore_file_spec.rb
|
140
|
+
- spec/lib/ignorance/svn_ignore_file_spec.rb
|
141
|
+
- spec/lib/ignorance_spec.rb
|
142
|
+
- spec/shared_examples/for_ignorance.rb
|
143
|
+
- spec/shared_examples/for_ignore_files.rb
|
144
|
+
- spec/shared_examples/for_project_oriented_vcs.rb
|
145
|
+
- spec/spec_helper.rb
|