braid 1.0.22 → 1.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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -2
  3. data/README.md +48 -0
  4. data/_config.yml +1 -0
  5. data/bin/braid +44 -7
  6. data/braid.gemspec +4 -0
  7. data/config_versions.md +58 -0
  8. data/lib/braid.rb +7 -0
  9. data/lib/braid/command.rb +7 -7
  10. data/lib/braid/commands/add.rb +3 -3
  11. data/lib/braid/commands/diff.rb +7 -14
  12. data/lib/braid/commands/push.rb +10 -4
  13. data/lib/braid/commands/setup.rb +5 -1
  14. data/lib/braid/commands/status.rb +5 -1
  15. data/lib/braid/commands/update.rb +6 -15
  16. data/lib/braid/commands/upgrade_config.rb +56 -0
  17. data/lib/braid/config.rb +166 -27
  18. data/lib/braid/mirror.rb +111 -11
  19. data/lib/braid/operations.rb +51 -35
  20. data/lib/braid/version.rb +1 -1
  21. data/spec/config_spec.rb +2 -2
  22. data/spec/fixtures/shiny-conf-1.0.9-lock/.braids.json +10 -0
  23. data/spec/fixtures/shiny-conf-1.0.9-lock/expected.braids.json +9 -0
  24. data/spec/fixtures/shiny-conf-1.0.9-lock/skit1/layouts/layout.liquid +219 -0
  25. data/spec/fixtures/shiny-conf-1.0.9-lock/skit1/preview.png +0 -0
  26. data/spec/fixtures/shiny-conf-breaking-changes/.braids +14 -0
  27. data/spec/fixtures/shiny-conf-breaking-changes/Spoon-Knife/README.md +9 -0
  28. data/spec/fixtures/shiny-conf-breaking-changes/Spoon-Knife/index.html +20 -0
  29. data/spec/fixtures/shiny-conf-breaking-changes/Spoon-Knife/styles.css +17 -0
  30. data/spec/fixtures/shiny-conf-breaking-changes/expected.braids.json +10 -0
  31. data/spec/fixtures/shiny-conf-breaking-changes/skit1/layouts/layout.liquid +219 -0
  32. data/spec/fixtures/shiny-conf-breaking-changes/skit1/preview.png +0 -0
  33. data/spec/fixtures/shiny-conf-future/.braids.json +10 -0
  34. data/spec/fixtures/shiny-conf-future/skit1/layouts/layout.liquid +219 -0
  35. data/spec/fixtures/shiny-conf-future/skit1/preview.png +0 -0
  36. data/spec/fixtures/shiny-conf-json-old-name/.braids +9 -0
  37. data/spec/fixtures/shiny-conf-json-old-name/expected.braids.json +10 -0
  38. data/spec/fixtures/shiny-conf-json-old-name/skit1/layouts/layout.liquid +219 -0
  39. data/spec/fixtures/shiny-conf-json-old-name/skit1/preview.png +0 -0
  40. data/spec/fixtures/shiny-conf-yaml/.braids +8 -0
  41. data/spec/fixtures/shiny-conf-yaml/expected.braids.json +10 -0
  42. data/spec/fixtures/shiny-conf-yaml/skit1/layouts/layout.liquid +219 -0
  43. data/spec/fixtures/shiny-conf-yaml/skit1/preview.png +0 -0
  44. data/spec/fixtures/shiny/skit-layout.liquid.test +2 -0
  45. data/spec/fixtures/shiny/skit1.test +2 -0
  46. data/spec/fixtures/skit1.1x/layouts/layout.liquid +219 -0
  47. data/spec/integration/adding_spec.rb +82 -34
  48. data/spec/integration/config_versioning_spec.rb +222 -0
  49. data/spec/integration/diff_spec.rb +173 -9
  50. data/spec/integration/integration_helper.rb +23 -5
  51. data/spec/integration/push_spec.rb +57 -4
  52. data/spec/integration/remove_spec.rb +27 -5
  53. data/spec/integration/updating_spec.rb +104 -19
  54. metadata +73 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ab9eeee697a55d6b0126b0b7fc83f1ef5bcd72ce
4
- data.tar.gz: 592d7f2a02f89a1afa3accb32c3e8ab910982ba8
3
+ metadata.gz: aac9e65e786b934873c38a987ca055e3decb4fec
4
+ data.tar.gz: 0b653e5049e2961bfef4f4d0fa3ad7b9a35ac91a
5
5
  SHA512:
6
- metadata.gz: e0e1aab9e20c6be6b449c14e9c8c9b768e71b58bc81634e737b83358172a39b62044f92cc0dc8e7fb2eb48045ea4b3dfed67b19ac22faae335619040265a2869
7
- data.tar.gz: 644e0aced9a33f47309f1bf6df77c31e7098b9292e3133a1e44e7f5852b7f2d749f02147425b73f949f9e39d444cc1aa156897613450953906f073ff062d3231
6
+ metadata.gz: afe093d29c687ecedae3f8442cd8b2a309b1d3a8066d9c9f14fdb3b74b1c001040e5aa2f301d14a266fe02071b2728a8791cde094d68007380eaea9f8c4b6a3e
7
+ data.tar.gz: f8340b68dcb924a2af19da115eda4ae1b9eea2e8756159e9ffb6092c5625605c83da6df13cd561db47db760c4c5cec9f984ecce1d511a5d2b271563d57036e2e
data/Gemfile CHANGED
@@ -1,5 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
-
5
- gem 'rake'
data/README.md CHANGED
@@ -144,6 +144,54 @@ Go back to tracking a particular branch.
144
144
 
145
145
  braid diff vendor/rails
146
146
 
147
+ ## Braid version compatibility
148
+
149
+ Since Braid has been regularly changing the configuration format and adding new
150
+ features that some projects may choose to rely on, and somewhat less often
151
+ making breaking changes in how the configuration is handled, problems can arise
152
+ if different developers work on the same project using different versions of
153
+ Braid. Since version 1.1.0, Braid refuses to operate if it detects potentially
154
+ problematic version skew. If this happens, Braid will tell you what you can do.
155
+ If you'd like an overview of what to expect, read on.
156
+
157
+ Roughly speaking, the `.braids.json` configuration file contains a configuration
158
+ version number that corresponds to a range of compatible Braid minor versions
159
+ (`x.y`). "Patch" upgrades to Braid (i.e., `x.y.z` -> `x.y.(z+1)`) will never
160
+ (intentionally!) have configuration compatibility implications and are always
161
+ recommended as they may fix critical bugs.
162
+
163
+ If you use a Braid version too old for your configuration file, Braid will
164
+ direct you to the [configuration version history page](config_versions.md) with
165
+ instructions to upgrade Braid. If you use a Braid version too new, Braid will
166
+ tell you how you can upgrade your configuration file or find a compatible older
167
+ Braid version to use. (As an exception, a newer version of Braid can run
168
+ read-only commands on an older configuration file without upgrading it if there
169
+ are no breaking changes.) If you upgrade your configuration file, then other
170
+ developers on the project may need to upgrade Braid. Braid does not support
171
+ downgrading a configuration file, though you can revert the commit that upgraded
172
+ it if you haven't made any subsequent changes to the configuration.
173
+
174
+ If you work on multiple projects, you may need to install multiple versions of
175
+ Braid and manually run the correct version for each project. Fortunately, the
176
+ RubyGems system makes this reasonably straightforward.
177
+
178
+ Another approach is to standardize the Braid version for a project by listing
179
+ Braid in a `Gemfile` (either checking in `Gemfile.lock` or using a version
180
+ constraint in the `Gemfile`) and run the project's version of Braid via
181
+ [Bundler](http://bundler.io/) with `bundle exec braid`. Even non-Ruby projects
182
+ can do this if it's acceptable to have a `Gemfile` and `Gemfile.lock`. Ruby
183
+ projects that don't want Braid to interact with their other gems can potentially
184
+ put the `Gemfile` in a subdirectory and provide a wrapper script for `bundle`
185
+ that sets the `BUNDLE_GEMFILE` environment variable. We do not yet have enough
186
+ experience with this approach to make a firm recommendation for or against it.
187
+
188
+ This is the best design we could find to prevent surprises and adequately
189
+ support normal development processes while minimizing the additional maintenance
190
+ cost of the version compatibility mechanism. We want to have a scheme in place
191
+ that is robust enough to make it reasonable to encourage serious adoption of
192
+ Braid, yet we don't want to spend extra work adding conveniences until there's
193
+ evidence of sufficient demand for them.
194
+
147
195
  ## Contributing
148
196
 
149
197
  We appreciate any patches, error reports and usage ideas you may have. Please
@@ -0,0 +1 @@
1
+ theme: jekyll-theme-tactile
data/bin/braid CHANGED
@@ -64,7 +64,7 @@ Main {
64
64
  run {
65
65
  check_no_extra_args!
66
66
  Braid.verbose = verbose
67
- Braid::Command.run(:add, url, {'path' => local_path, 'branch' => branch, 'tag' => tag, 'revision' => revision, 'remote_path' => path})
67
+ Braid::Command.run(:Add, url, {'path' => local_path, 'branch' => branch, 'tag' => tag, 'revision' => revision, 'remote_path' => path})
68
68
  }
69
69
  }
70
70
 
@@ -97,7 +97,7 @@ Main {
97
97
  'keep' => keep
98
98
  }
99
99
  Braid.verbose = verbose
100
- Braid::Command.run(:update, local_path, options)
100
+ Braid::Command.run(:Update, local_path, options)
101
101
  }
102
102
  }
103
103
 
@@ -122,7 +122,7 @@ Main {
122
122
  :keep => keep
123
123
  }
124
124
  Braid.verbose = verbose
125
- Braid::Command.run(:remove, local_path, options)
125
+ Braid::Command.run(:Remove, local_path, options)
126
126
  }
127
127
  }
128
128
 
@@ -149,7 +149,7 @@ Main {
149
149
  'git_diff_args' => @argv
150
150
  }
151
151
  Braid.verbose = verbose
152
- Braid::Command.run(:diff, local_path, options)
152
+ Braid::Command.run(:Diff, local_path, options)
153
153
  }
154
154
  }
155
155
 
@@ -167,7 +167,7 @@ Main {
167
167
  'branch' => branch
168
168
  }
169
169
  Braid.verbose = verbose
170
- Braid::Command.run(:push, local_path, options)
170
+ Braid::Command.run(:Push, local_path, options)
171
171
  }
172
172
  }
173
173
 
@@ -182,7 +182,7 @@ Main {
182
182
  check_no_extra_args!
183
183
  Braid.verbose = verbose
184
184
  Braid.force = force
185
- Braid::Command.run(:setup, local_path)
185
+ Braid::Command.run(:Setup, local_path)
186
186
  }
187
187
  }
188
188
 
@@ -203,7 +203,44 @@ Main {
203
203
  run {
204
204
  check_no_extra_args!
205
205
  Braid.verbose = verbose
206
- Braid::Command.run(:status, local_path)
206
+ Braid::Command.run(:Status, local_path)
207
+ }
208
+ }
209
+
210
+ mode('upgrade-config') {
211
+ description <<-DESC
212
+ Upgrade your project's Braid configuration to the latest configuration version.
213
+ Other commands will notify you when you need to do this. This may make older
214
+ versions of Braid unable to read the configuration and may introduce breaking
215
+ changes in how the configuration is handled by Braid. An upgrade that
216
+ introduces breaking changes will not be performed without the
217
+ --allow-breaking-changes option.
218
+ DESC
219
+
220
+ mixin :option_verbose
221
+
222
+ option('dry-run') {
223
+ optional
224
+ desc 'Explain the consequences of the upgrade without performing it.'
225
+ attr :dry_run
226
+ }
227
+
228
+ option('allow-breaking-changes') {
229
+ optional
230
+ desc <<-DESC
231
+ Perform the upgrade even if it involves breaking changes.
232
+ DESC
233
+ attr :allow_breaking_changes
234
+ }
235
+
236
+ run {
237
+ check_no_extra_args!
238
+ options = {
239
+ 'dry_run' => dry_run,
240
+ 'allow_breaking_changes' => allow_breaking_changes
241
+ }
242
+ Braid.verbose = verbose
243
+ Braid::Command.run(:UpgradeConfig, options)
207
244
  }
208
245
  }
209
246
 
@@ -27,7 +27,11 @@ Gem::Specification.new do |s|
27
27
 
28
28
  s.required_ruby_version = '>= 2.2.0'
29
29
  s.add_dependency(%q<main>, ['>= 4.7.3'])
30
+ # XXX: Minimum version?
31
+ s.add_dependency(%q<json>)
30
32
 
31
33
  s.add_development_dependency(%q<rspec>, ['>= 3.4.4'])
32
34
  s.add_development_dependency(%q<mocha>, ['>= 0.9.11'])
35
+ s.add_development_dependency(%q<rake>)
36
+ s.add_development_dependency(%q<bundler>)
33
37
  end
@@ -0,0 +1,58 @@
1
+ # Braid configuration version history
2
+
3
+ The Braid configuration file (`.braids.json`) contains a configuration version
4
+ number that indicates the format of the configuration file and the Braid
5
+ features required by the project. You'll be directed to this page if you use a
6
+ version of Braid that does not support the project's configuration version; see
7
+ [the readme](README.md#braid-version-compatibility) for more information about
8
+ the versioning scheme.
9
+
10
+ To get a compatible version of Braid:
11
+
12
+ 1. First check if the project has its own instructions to install and run Braid,
13
+ and if so, follow them instead.
14
+ 2. Look up the Braid versions corresponding to your current configuration
15
+ version in the table below.
16
+ 3. Run `gem query --remote --all --exact braid` to get a list of all existing
17
+ versions of Braid, and choose one that is compatible with your configuration
18
+ version (you probably want the newest such version); call it `x.y.z`.
19
+ 4. Run `gem install braid --version x.y.z` to install the chosen version of
20
+ Braid.
21
+ 5. Run Braid as `braid _x.y.z_` (that's the chosen version surrounded by literal
22
+ underscores) followed by your desired arguments.
23
+
24
+ <table border="border">
25
+ <tr>
26
+ <th>Config. version</th>
27
+ <th>Braid versions</th>
28
+ <th>Changes since previous</th>
29
+ </tr>
30
+ <tr>
31
+ <td>1</td>
32
+ <td>1.1.x</td>
33
+ <td>(Various)</td>
34
+ </tr>
35
+ <tr>
36
+ <td>"0"</td>
37
+ <td colspan="2">
38
+ (Braid versions earlier than 1.1.0 have varying configuration formats and
39
+ features and do not have a well-defined compatibility scheme. Braid 1.1.0 and
40
+ newer refer to all of these formats as version "0" and are capable of correctly
41
+ upgrading most of them. We recommend upgrading to Braid 1.1.0 or newer if you
42
+ can.)
43
+ </td>
44
+ </tr>
45
+ </table>
46
+
47
+ <style>
48
+ header, section#downloads, .inner > hr {
49
+ display: none;
50
+ }
51
+ .inner {
52
+ padding-top: 35px; /* same as header when it is visible */
53
+ }
54
+ th, td {
55
+ border: 1px solid #6d6d6d;
56
+ padding: 2px;
57
+ }
58
+ </style>
@@ -35,6 +35,12 @@ module Braid
35
35
  value if value != self.class.name
36
36
  end
37
37
  end
38
+
39
+ class InternalError < BraidError
40
+ def message
41
+ "internal error: #{super}"
42
+ end
43
+ end
38
44
  end
39
45
 
40
46
  require 'braid/operations_lite'
@@ -49,3 +55,4 @@ require 'braid/commands/remove'
49
55
  require 'braid/commands/setup'
50
56
  require 'braid/commands/update'
51
57
  require 'braid/commands/status'
58
+ require 'braid/commands/upgrade_config'
@@ -10,7 +10,7 @@ module Braid
10
10
  verify_git_version!
11
11
  check_working_dir!
12
12
 
13
- klass = Commands.const_get(command.to_s.capitalize)
13
+ klass = Commands.const_get(command.to_s)
14
14
  klass.new.run(*args)
15
15
 
16
16
  rescue BraidError => error
@@ -32,7 +32,7 @@ module Braid
32
32
  end
33
33
 
34
34
  def config
35
- @config ||= Config.new
35
+ @config ||= Config.new({'mode' => config_mode})
36
36
  end
37
37
 
38
38
  def verbose?
@@ -45,11 +45,15 @@ module Braid
45
45
 
46
46
  private
47
47
 
48
+ def config_mode
49
+ Config::MODE_MAY_WRITE
50
+ end
51
+
48
52
  def setup_remote(mirror)
49
53
  existing_force = Braid.force
50
54
  begin
51
55
  Braid.force = true
52
- Command.run(:setup, mirror.path)
56
+ Command.run(:Setup, mirror.path)
53
57
  ensure
54
58
  Braid.force = existing_force
55
59
  end
@@ -133,9 +137,5 @@ module Braid
133
137
  new_revision
134
138
  end
135
139
  end
136
-
137
- def determine_target_revision(mirror, new_revision)
138
- git.rev_parse(mirror.versioned_path(new_revision))
139
- end
140
140
  end
141
141
  end
@@ -21,10 +21,10 @@ module Braid
21
21
  setup_remote(mirror)
22
22
  mirror.fetch
23
23
 
24
- new_revision = validate_new_revision(mirror, options['revision'])
25
- target_revision = determine_target_revision(mirror, new_revision)
24
+ new_revision = validate_new_revision(mirror, options['revision'])
25
+ target_item = mirror.upstream_item_for_revision(new_revision)
26
26
 
27
- git.read_tree_prefix_u(target_revision, mirror.path)
27
+ git.add_item_to_index(target_item, mirror.path, true)
28
28
 
29
29
  mirror.revision = new_revision
30
30
  config.update(mirror)
@@ -5,12 +5,12 @@ module Braid
5
5
  path ? diff_one(path, options) : diff_all(options)
6
6
  end
7
7
 
8
- protected
8
+ private
9
9
 
10
10
  def diff_all(options = {})
11
11
  # We don't want "git diff" to invoke the pager once for each mirror.
12
12
  # TODO: Invoke the default pager once for the entire output.
13
- Operations::with_modified_environment({"GIT_PAGER" => ''}) do
13
+ Operations::with_modified_environment({ 'GIT_PAGER' => ''}) do
14
14
  config.mirrors.each do |path|
15
15
  separator
16
16
  msg "Diffing #{path}\n"
@@ -33,23 +33,16 @@ module Braid
33
33
  setup_remote(mirror)
34
34
  mirror.fetch_base_revision_if_missing
35
35
 
36
- # We do not need to spend the time to copy the content outside the
37
- # mirror from HEAD because --relative will exclude it anyway. Rename
38
- # detection seems to apply only to the files included in the diff, so we
39
- # shouldn't have another bug like
40
- # https://github.com/cristibalan/braid/issues/41.
41
- base_tree = git.make_tree_with_subtree(nil, mirror.path,
42
- mirror.versioned_path(mirror.base_revision))
43
- # Git 1.7.2.2 release notes mention a bug when --relative is used
44
- # without a trailing slash, and our minimum git version is 1.6.0, so
45
- # attempt to work around the bug here.
46
- #
47
36
  # XXX: Warn if the user specifies file paths that are outside the
48
37
  # mirror? Currently, they just won't match anything.
49
- git.diff_to_stdout("--relative=#{mirror.path}/", base_tree, options['git_diff_args'])
38
+ git.diff_to_stdout(*mirror.diff_args(*options['git_diff_args']))
50
39
 
51
40
  clear_remote(mirror, options)
52
41
  end
42
+
43
+ def config_mode
44
+ Config::MODE_READ_ONLY
45
+ end
53
46
  end
54
47
  end
55
48
  end
@@ -33,7 +33,7 @@ module Braid
33
33
  clear_remote(mirror, options)
34
34
  return
35
35
  end
36
- local_mirror_tree = git.rev_parse("HEAD:#{mirror.path}")
36
+ local_mirror_item = git.get_tree_item('HEAD', mirror.path)
37
37
 
38
38
  odb_paths = [File.expand_path(git.repo_file_path('objects'))]
39
39
  if File.exist?(mirror.cached_url)
@@ -51,11 +51,13 @@ module Braid
51
51
  end
52
52
  user_name = git.config(%w(--local --get user.name))
53
53
  user_email = git.config(%w(--local --get user.email))
54
+ commit_gpgsign = git.config(%w(--local --get commit.gpgsign))
54
55
  Dir.chdir(clone_dir) do
55
56
  msg 'Cloning mirror with local changes.'
56
57
  git.init
57
58
  git.config(['--local', 'user.name', "\"#{user_name}\""]) if user_name
58
59
  git.config(['--local', 'user.email', "\"#{user_email}\""]) if user_email
60
+ git.config(['--local', 'commit.gpgsign', commit_gpgsign]) if commit_gpgsign
59
61
  # Adding other repositories as alternates is safe (we don't have to
60
62
  # worry about them being moved or deleted during the lifetime of this
61
63
  # temporary repository) and faster than fetching from them. We don't
@@ -68,9 +70,7 @@ module Braid
68
70
  git.fetch(remote_url, mirror.remote_ref)
69
71
  git.checkout(base_revision)
70
72
  git.rm_r(mirror.remote_path || '.')
71
- # Yes, when mirror.remote_path is unset, "git read-tree --prefix=/"
72
- # seems to work. :/
73
- git.read_tree_prefix_u(local_mirror_tree, mirror.remote_path || '')
73
+ git.add_item_to_index(local_mirror_item, mirror.remote_path || '', true)
74
74
  system('git commit -v')
75
75
  msg "Pushing changes to remote branch #{branch}."
76
76
  git.push(remote_url, "HEAD:refs/heads/#{branch}")
@@ -80,5 +80,11 @@ module Braid
80
80
  clear_remote(mirror, options)
81
81
  end
82
82
  end
83
+
84
+ private
85
+
86
+ def config_mode
87
+ Config::MODE_READ_ONLY # Surprisingly enough.
88
+ end
83
89
  end
84
90
  end
@@ -5,7 +5,7 @@ module Braid
5
5
  path ? setup_one(path) : setup_all
6
6
  end
7
7
 
8
- protected
8
+ private
9
9
 
10
10
  def setup_all
11
11
  msg 'Setting up all mirrors.'
@@ -31,6 +31,10 @@ module Braid
31
31
  url = use_local_cache? ? git_cache.path(mirror.url) : mirror.url
32
32
  git.remote_add(mirror.remote, url)
33
33
  end
34
+
35
+ def config_mode
36
+ Config::MODE_READ_ONLY
37
+ end
34
38
  end
35
39
  end
36
40
  end
@@ -5,7 +5,7 @@ module Braid
5
5
  path ? status_one(path, options) : status_all(options)
6
6
  end
7
7
 
8
- protected
8
+ private
9
9
 
10
10
  def status_all(options = {})
11
11
  print "\n"
@@ -41,6 +41,10 @@ module Braid
41
41
  print "\n"
42
42
  clear_remote(mirror, options)
43
43
  end
44
+
45
+ def config_mode
46
+ Config::MODE_READ_ONLY
47
+ end
44
48
  end
45
49
  end
46
50
  end