semmy 1.1.0 → 1.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3593823ef6863af335da8379285319b3bfcef4ca60b8130ccb1ff98633694c3f
4
- data.tar.gz: bf08cbcca120b4e42792fe66ba370f751a92712c033b415f28f45814de76d1b1
3
+ metadata.gz: ce09082714dcb3d35eb9667425bf29167c3d3a768138b272a7b09af7ff592343
4
+ data.tar.gz: 819dd6a572482aced62c3a3b80ab28d4af69a09276401cca60f0536df602194d
5
5
  SHA512:
6
- metadata.gz: 2f1a2f9f3476e805531cdf4b15db7d9cb7b8fcc589f88db711ae58a7e86f0cb8626047ee563de135b1fb35d733705e3f0eb37de65ed4f130a9545642497d2981
7
- data.tar.gz: 1b936d088d33fdeb0d6c0c09caee081d6072784ee7fc16d4622555eba5ce1630d4d731884cef94bd53f16c9c80127581ca6cb75487a7bb99137e24b267128a6b
6
+ metadata.gz: f4e4fb1222c83d1e94ccf400719c36d21501fb1f4219cae6a314ce389fce167bbeb2f5a881fc0cf2bf7fe42c72ee63e2fbaec43a7e5a89cf83528bd589884925
7
+ data.tar.gz: 6bbcad0f49ab3726535dde84915a57f139708ebefd97fe1879dc8e1a97c22a6c051162c0ee4279bdb76df4bd4c793fc0805e56886776dc85db09963aedf6368f
data/CHANGELOG.md CHANGED
@@ -1,17 +1,13 @@
1
1
  # CHANGELOG
2
2
 
3
- ### Version 1.1.0
3
+ ### Version 1.3.0
4
4
 
5
- 2019-01-23
5
+ 2026-09-11
6
6
 
7
- [Compare changes](https://github.com/tf/semmy/compare/1-0-stable...v1.1.0)
7
+ [Compare changes](https://github.com/tf/semmy/compare/1-2-stable...v1.3.0)
8
8
 
9
- - Run same tasks as on `master` when running on major version stable
10
- branch (e.g. `2-x-stable`).
11
-
12
- - Bug fix: Ensure test install of gem during `release:prepare` does not hang
13
- waiting for interactive input on uninstall.
9
+ - Support releasing from Jujutsu repositories.
14
10
 
15
11
  See
16
- [1-0-stable branch](https://github.com/tf/semmy/blob/1-0-stable/CHANGELOG.md)
12
+ [1-2-stable branch](https://github.com/tf/semmy/blob/1-2-stable/CHANGELOG.md)
17
13
  for previous changes.
data/README.md CHANGED
@@ -21,6 +21,28 @@ tags.
21
21
  Patch level versions are released via backports to the stable
22
22
  branches.
23
23
 
24
+ ### Jujutsu Repositories
25
+
26
+ Semmy detects a `.jj` directory and drives
27
+ [Jujutsu](https://jj-vcs.github.io/jj/) instead of Git. Bookmarks take
28
+ the place of branches: since jj has no checked out branch, the
29
+ bookmark of the closest ancestor commit is used and the commit tasks
30
+ move it forward explicitly. The release branch is resolved once per
31
+ rake run, before `branches:create_stable` places a second bookmark on
32
+ the same commit.
33
+
34
+ Bundler's `release` task shells out to Git, and colocated jj
35
+ repositories leave `HEAD` detached, which would make its push step
36
+ fail with `src refspec refs/heads/HEAD does not match any`. Semmy
37
+ attaches `HEAD` to the release branch in a prerequisite of Bundler's
38
+ `release:source_control_push` task. Only the ref is moved, never the
39
+ working copy, and jj detaches `HEAD` again on its next working copy
40
+ update.
41
+
42
+ This requires the working copy commit to sit directly on top of the
43
+ release branch. Otherwise the release aborts with a hint to run
44
+ `jj new master`.
45
+
24
46
  ### Version Suffix
25
47
 
26
48
  The version in the gem's version file is increased in a separate
@@ -67,6 +89,15 @@ Add the tasks to your Rakefile:
67
89
 
68
90
  Semmy::Tasks.install
69
91
 
92
+ You can pass config options:
93
+
94
+ # Rakefile
95
+ require 'semmy'
96
+
97
+ Semmy::Tasks.install do |config|
98
+ # see Semmy::Configuration for options
99
+ end
100
+
70
101
  ## Usage
71
102
 
72
103
  Semmy defines a new task to prepare a release:
@@ -100,6 +131,22 @@ The resulting commit graph looks like:
100
131
  * (v1.2.0, 1-2-stable) Prepare 1.2.0 release
101
132
  * Some new feature
102
133
 
134
+ By default, the new stable branch and the bump commit are not pushed
135
+ automatically. This can be activated by setting the
136
+ `push_branches_after_release` config option to `true`.
137
+
138
+ This will be the new default once Semmy 2.0 is released. You can opt
139
+ into the future default behavior globally without changing config
140
+ options on the project level by setting the
141
+ `SEMMY_PUSH_BRANCHES_AFTER_RELEASE` environment variable to `on`.
142
+
143
+ Branches will be pushed to the remote passed as an argument to the
144
+ `release` task:
145
+
146
+ $ rake release[upstream]
147
+
148
+ By default, branches are pushed to `origin`.
149
+
103
150
  ### Releasing a Patch Level Version
104
151
 
105
152
  Assume an important bug fix has been added to `master`:
@@ -3,6 +3,7 @@ module Semmy
3
3
  attr_accessor :development_version_suffix
4
4
 
5
5
  attr_accessor :stable_branch_name
6
+ attr_accessor :push_branches_after_release
6
7
 
7
8
  attr_accessor :prepare_commit_message
8
9
  attr_accessor :bump_commit_message
@@ -25,6 +26,7 @@ module Semmy
25
26
  @development_version_suffix = 'dev'
26
27
 
27
28
  @stable_branch_name = '%{major}-%{minor}-stable'
29
+ @push_branches_after_release = ENV['SEMMY_PUSH_BRANCHES_AFTER_RELEASE'] == 'on'
28
30
 
29
31
  @prepare_commit_message = 'Prepare %{version} release'
30
32
  @bump_commit_message = 'Bump version to %{version}'
@@ -0,0 +1,34 @@
1
+ require 'git'
2
+
3
+ module Semmy
4
+ module Scm
5
+ module Git
6
+ extend self
7
+
8
+ def current_branch
9
+ repository.current_branch
10
+ end
11
+
12
+ def commit_all(message, _branch)
13
+ repository.commit_all(message)
14
+ end
15
+
16
+ def create_branch(name, _base)
17
+ repository.branch(name).create
18
+ end
19
+
20
+ def push(remote, name)
21
+ repository.push(remote, name)
22
+ end
23
+
24
+ def attach_git_head(_branch)
25
+ end
26
+
27
+ private
28
+
29
+ def repository
30
+ ::Git.open('.')
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,85 @@
1
+ require 'open3'
2
+
3
+ module Semmy
4
+ module Scm
5
+ module Jj
6
+ extend self
7
+
8
+ class CommandFailed < Error; end
9
+ class BookmarkNotFound < Error; end
10
+ class GitHeadMismatch < Error; end
11
+
12
+ def current_branch
13
+ jj('log', '--no-graph',
14
+ '--revisions', 'heads(::@ & bookmarks())',
15
+ '--template', 'local_bookmarks.map(|bookmark| bookmark.name()).join("\n")')
16
+ .split("\n").first
17
+ end
18
+
19
+ def commit_all(message, branch)
20
+ bookmark = required_bookmark(branch)
21
+
22
+ jj('commit', '--message', message)
23
+ jj('bookmark', 'set', bookmark, '--revision', '@-')
24
+ end
25
+
26
+ def create_branch(name, base)
27
+ jj('bookmark', 'create', name, '--revision', required_bookmark(base))
28
+ end
29
+
30
+ def push(remote, name)
31
+ unless bookmark?(name)
32
+ fail(BookmarkNotFound, "Bookmark #{name} does not exist.")
33
+ end
34
+
35
+ jj('git', 'push', '--remote', remote, '--bookmark', name)
36
+ end
37
+
38
+ def attach_git_head(branch)
39
+ bookmark = required_bookmark(branch)
40
+ reference = "refs/heads/#{bookmark}"
41
+
42
+ unless git('rev-parse', 'HEAD') == git('rev-parse', reference)
43
+ fail(GitHeadMismatch,
44
+ "Git HEAD is not at #{bookmark}. " \
45
+ "Run `jj new #{bookmark}` before releasing.")
46
+ end
47
+
48
+ Shell.info("Attaching git HEAD to #{bookmark}.")
49
+ git('symbolic-ref', 'HEAD', reference)
50
+ end
51
+
52
+ private
53
+
54
+ def required_bookmark(name)
55
+ name ||
56
+ fail(BookmarkNotFound,
57
+ 'No bookmark found in ancestors of working copy commit.')
58
+ end
59
+
60
+ def bookmark?(name)
61
+ !jj('bookmark', 'list', '--template', 'name ++ "\n"', name).strip.empty?
62
+ end
63
+
64
+ def jj(*args)
65
+ run('jj', *args)
66
+ end
67
+
68
+ def git(*args)
69
+ run('git', *args)
70
+ end
71
+
72
+ def run(command, *args)
73
+ stdout, stderr, status = Open3.capture3(command, *args)
74
+
75
+ unless status.success?
76
+ fail(CommandFailed,
77
+ "Command `#{command} #{args.join(' ')}` failed:\n#{stderr}")
78
+ end
79
+
80
+ Shell.sub_process_output(stderr.chomp) unless stderr.empty?
81
+ stdout
82
+ end
83
+ end
84
+ end
85
+ end
data/lib/semmy/scm.rb CHANGED
@@ -1,17 +1,46 @@
1
+ require 'pathname'
2
+
3
+ require 'semmy/scm/git'
4
+ require 'semmy/scm/jj'
5
+
1
6
  module Semmy
2
7
  module Scm
3
8
  extend self
4
9
 
5
10
  def on_master?
6
- git.current_branch == 'master'
11
+ release_branch == 'master'
7
12
  end
8
13
 
9
14
  def on_minor_version_stable?(stable_branch_name)
10
- !!git.current_branch.match(stable_branch_matcher(stable_branch_name))
15
+ !!release_branch.to_s.match(stable_branch_matcher(stable_branch_name))
11
16
  end
12
17
 
13
18
  def on_major_version_stable?(stable_branch_name)
14
- !!git.current_branch.match(major_version_stable_branch_matcher(stable_branch_name))
19
+ !!release_branch.to_s.match(major_version_stable_branch_matcher(stable_branch_name))
20
+ end
21
+
22
+ def commit_all(message)
23
+ repository.commit_all(message, release_branch)
24
+ end
25
+
26
+ def create_branch(name)
27
+ repository.create_branch(name, release_branch)
28
+ end
29
+
30
+ def push(remote, name)
31
+ repository.push(remote, name)
32
+ end
33
+
34
+ def attach_git_head
35
+ repository.attach_git_head(release_branch)
36
+ end
37
+
38
+ def release_branch
39
+ @release_branch ||= repository.current_branch
40
+ end
41
+
42
+ def reset
43
+ @release_branch = nil
15
44
  end
16
45
 
17
46
  private
@@ -24,8 +53,13 @@ module Semmy
24
53
  Regexp.new(stable_branch_name.gsub(/%\{\w+\}/, '[0-9]+'))
25
54
  end
26
55
 
27
- def git
28
- Git.open('.')
56
+ def repository
57
+ Pathname.pwd.ascend do |directory|
58
+ return Jj if directory.join('.jj').directory?
59
+ return Git if directory.join('.git').exist?
60
+ end
61
+
62
+ Git
29
63
  end
30
64
  end
31
65
  end
@@ -1,22 +1,48 @@
1
- require 'git'
2
-
3
1
  module Semmy
4
2
  module Tasks
5
3
  class Branches < Base
6
4
  def define
7
5
  namespace 'branches' do
8
6
  task 'create_stable' do
9
- name = config.stable_branch_name %
10
- VersionString.components(Project.version)
7
+ Shell.info("Creating stable branch #{stable_branch_name}.")
8
+
9
+ Scm.create_branch(stable_branch_name)
10
+ end
11
11
 
12
- Shell.info("Creating stable branch #{name}.")
12
+ task 'push_master', [:remote] do |_, args|
13
+ push_branch(args[:remote], 'master')
14
+ end
13
15
 
14
- git.branch(name).create
16
+ task 'push_previous_stable', [:remote] do |_, args|
17
+ push_branch(args[:remote], previous_stable_branch_name)
18
+ end
19
+
20
+ task 'attach_git_head' do
21
+ Scm.attach_git_head
15
22
  end
16
23
  end
24
+ end
25
+
26
+ private
27
+
28
+ def stable_branch_name
29
+ VersionString.stable_branch_name(Project.version,
30
+ config.stable_branch_name)
31
+ end
32
+
33
+ def previous_stable_branch_name
34
+ VersionString.previous_stable_branch_name(Project.version,
35
+ config.stable_branch_name)
36
+ end
37
+
38
+ def push_branch(remote, name)
39
+ remote ||= 'origin'
17
40
 
18
- def git
19
- Git.open('.')
41
+ if config.push_branches_after_release
42
+ Shell.info("Pushing #{name} to #{remote}.")
43
+ Scm.push(remote, name)
44
+ else
45
+ Shell.info("NOTE: Remember to push #{name} to #{remote}.")
20
46
  end
21
47
  end
22
48
  end
@@ -1,5 +1,3 @@
1
- require 'git'
2
-
3
1
  module Semmy
4
2
  module Tasks
5
3
  class Commit < Base
@@ -8,7 +6,7 @@ module Semmy
8
6
  task 'prepare' do
9
7
  Shell.info('Creating prepare commit.')
10
8
 
11
- git.commit_all(config.prepare_commit_message % {
9
+ Scm.commit_all(config.prepare_commit_message % {
12
10
  version: Project.version
13
11
  })
14
12
  end
@@ -16,15 +14,11 @@ module Semmy
16
14
  task 'bump' do
17
15
  Shell.info('Creating bump commit.')
18
16
 
19
- git.commit_all(config.bump_commit_message % {
17
+ Scm.commit_all(config.bump_commit_message % {
20
18
  version: Project.version
21
19
  })
22
20
  end
23
21
  end
24
-
25
- def git
26
- Git.open('.')
27
- end
28
22
  end
29
23
  end
30
24
  end
data/lib/semmy/tasks.rb CHANGED
@@ -26,6 +26,8 @@ module Semmy
26
26
  Branches.new(config)
27
27
  end
28
28
 
29
+ task 'release:source_control_push' => 'semmy:branches:attach_git_head'
30
+
29
31
  desc 'Prepare minor or major release'
30
32
  task 'release:prepare:master' => [
31
33
  'semmy:versioning:remove_development_version_suffix',
@@ -49,22 +51,24 @@ module Semmy
49
51
  end
50
52
  end
51
53
 
52
- task 'release:after:master' => [
54
+ task 'release:after:master', [:remote] => [
53
55
  'semmy:branches:create_stable',
54
56
  'semmy:versioning:bump_minor',
55
57
  'semmy:changelog:update_for_minor',
56
- 'semmy:commit:bump'
58
+ 'semmy:commit:bump',
59
+ 'semmy:branches:push_master',
60
+ 'semmy:branches:push_previous_stable'
57
61
  ]
58
62
 
59
63
  desc 'Prepare repository for development of next verion'
60
- task 'release:after' do
64
+ task 'release:after', [:remote] do |_, args|
61
65
  if Scm.on_master? || Scm.on_major_version_stable?(config.stable_branch_name)
62
- Rake.application['release:after:master'].invoke
66
+ Rake.application['release:after:master'].invoke(args[:remote])
63
67
  end
64
68
  end
65
69
 
66
- task 'release' do
67
- Rake.application['release:after'].invoke
70
+ task 'release', [:remote] do |_, args|
71
+ Rake.application['release:after'].invoke(args[:remote])
68
72
  end
69
73
 
70
74
  task 'bump:patch' => [
data/lib/semmy/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Semmy
2
- VERSION = '1.1.0'
2
+ VERSION = '1.3.0'
3
3
  end
@@ -62,6 +62,10 @@ module Semmy
62
62
  components.join('.')
63
63
  end
64
64
 
65
+ def stable_branch_name(version, stable_branch_name_pattern)
66
+ stable_branch_name_pattern % VersionString.components(version)
67
+ end
68
+
65
69
  def previous_stable_branch_name(version, stable_branch_name_pattern)
66
70
  stable_branch_name_pattern % previous_minor_version_components(version)
67
71
  end
data/semmy.gemspec CHANGED
@@ -22,8 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.add_dependency 'unindent', '~> 1.0'
23
23
  spec.add_dependency 'rainbow', '~> 2.1'
24
24
 
25
- spec.add_development_dependency 'bundler', '~> 1.10'
26
- spec.add_development_dependency 'rake', '~> 11.0'
25
+ spec.add_development_dependency 'rake', '~> 13.0'
27
26
  spec.add_development_dependency 'rspec', '~> 3.0'
28
27
  spec.add_development_dependency 'rubocop', '~> 0.42.0'
29
28
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: semmy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Fischbach
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-01-23 00:00:00.000000000 Z
11
+ date: 2026-09-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: git
@@ -52,34 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '2.1'
55
- - !ruby/object:Gem::Dependency
56
- name: bundler
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '1.10'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '1.10'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: rake
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - "~>"
74
60
  - !ruby/object:Gem::Version
75
- version: '11.0'
61
+ version: '13.0'
76
62
  type: :development
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
66
  - - "~>"
81
67
  - !ruby/object:Gem::Version
82
- version: '11.0'
68
+ version: '13.0'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: rspec
85
71
  requirement: !ruby/object:Gem::Requirement
@@ -108,7 +94,7 @@ dependencies:
108
94
  - - "~>"
109
95
  - !ruby/object:Gem::Version
110
96
  version: 0.42.0
111
- description:
97
+ description:
112
98
  email:
113
99
  - mail@timfischbach.de
114
100
  executables: []
@@ -140,6 +126,8 @@ files:
140
126
  - lib/semmy/project.rb
141
127
  - lib/semmy/ruby_gems.rb
142
128
  - lib/semmy/scm.rb
129
+ - lib/semmy/scm/git.rb
130
+ - lib/semmy/scm/jj.rb
143
131
  - lib/semmy/shell.rb
144
132
  - lib/semmy/tasks.rb
145
133
  - lib/semmy/tasks/base.rb
@@ -157,7 +145,7 @@ homepage: https://github.com/tf/semmy
157
145
  licenses:
158
146
  - MIT
159
147
  metadata: {}
160
- post_install_message:
148
+ post_install_message:
161
149
  rdoc_options: []
162
150
  require_paths:
163
151
  - lib
@@ -172,9 +160,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
160
  - !ruby/object:Gem::Version
173
161
  version: '0'
174
162
  requirements: []
175
- rubyforge_project:
176
- rubygems_version: 2.7.5
177
- signing_key:
163
+ rubygems_version: 3.4.19
164
+ signing_key:
178
165
  specification_version: 4
179
166
  summary: Rake tasks for a semantic versioning of gems
180
167
  test_files: []