kaze 2.0.0 → 2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -1
- data/README.md +12 -0
- data/lib/kaze/commands/app/base_stack.rb +37 -2
- data/lib/kaze/commands/app/hotwire_stack.rb +19 -1
- data/lib/kaze/commands/app/inertia_react_stack.rb +24 -1
- data/lib/kaze/commands/app/inertia_vue_stack.rb +25 -1
- data/lib/kaze/commands/app.rb +49 -4
- data/lib/kaze/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 701db9d43e1fa6af035b37096755ff20cad5d574ed2cf042d4ee9dad2b2513d0
|
|
4
|
+
data.tar.gz: e52ef54c1289863cac8afc289b569d5cf991e1dd1c43faea861593ee6116151e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 67c562979bb3627648c660bd1c3ce6b85f132ee54e2bc71477651ec8969ee731da08910f957b77cfaa61defe24d998c94172f292ebc67c87559f01b867ca0d2f
|
|
7
|
+
data.tar.gz: 98f645b2b95a8141b2440ea180eae7092bf8d5b4b4f070f94fa420a03c790090eeee92b062a1b8fe53514e631593494a59d7ca341d530e5f26e06d38773f33ca
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,24 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [2.1.0] - 2026-10-22
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- A `kaze upgrade [STACK]` command. Kaze copies files into an application and does not own them afterwards, so `kaze install` cannot tell a leftover from an older version apart from something you wrote, and has always left both alone. `upgrade` resolves that by asking instead of guessing: it lists the files an earlier Kaze installed that this version no longer ships, waits for you to agree, removes them, and then runs the normal install.
|
|
14
|
+
|
|
15
|
+
Only paths Kaze itself shipped are ever offered — the list per stack is fixed in the source, so nothing you added alongside them can be caught by it, and a directory is removed only once it is empty. `--dry-run` prints the list and stops; `--force` skips the prompt for scripts. Declining exits non-zero and changes nothing.
|
|
16
|
+
|
|
17
|
+
This replaces the manual file list in the 2.0.0 upgrade notes below. On the React stack it is the difference between an upgraded application building and not: `tsc` typechecks every file under `app/javascript`, so the old `Pages/Profile/Edit.tsx` fails the build until it is gone.
|
|
18
|
+
|
|
19
|
+
## [2.0.1] - 2026-10-22
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- `kaze install` run through `bundle exec` no longer fails to build gems with native extensions. Bundler exports `RUBYOPT` and `BUNDLE_*` so child processes join its bundle, which is wrong for a nested bundler call: the `bundle add` that kaze shells out to inherited them, and `extconf.rb` then loaded `bundler/setup` and tried to resolve a lockfile needing the very gem it was about to compile, failing with `Could not find bcrypt-… in locally installed gems`. The bundler shell-outs now run inside `Bundler.with_unbundled_env`.
|
|
24
|
+
|
|
25
|
+
The README's own instructions — `gem install kaze` then `kaze install` — were never affected, because that runs outside bundler. This reached `bundle exec kaze install`, which is how kaze's CI invokes it and how anyone who adds kaze to their Gemfile would.
|
|
26
|
+
|
|
9
27
|
## [2.0.0] - 2026-10-22
|
|
10
28
|
|
|
11
29
|
### Added
|
|
@@ -177,7 +195,9 @@ Together these take a freshly scaffolded Inertia application from seven npm advi
|
|
|
177
195
|
|
|
178
196
|
Releases before 1.0.0 are not catalogued here. See the [tags](https://github.com/cuonggt/kaze/tags) for their history.
|
|
179
197
|
|
|
180
|
-
[Unreleased]: https://github.com/cuonggt/kaze/compare/v2.
|
|
198
|
+
[Unreleased]: https://github.com/cuonggt/kaze/compare/v2.1.0...HEAD
|
|
199
|
+
[2.1.0]: https://github.com/cuonggt/kaze/compare/v2.0.1...v2.1.0
|
|
200
|
+
[2.0.1]: https://github.com/cuonggt/kaze/compare/v2.0.0...v2.0.1
|
|
181
201
|
[2.0.0]: https://github.com/cuonggt/kaze/compare/v1.4.0...v2.0.0
|
|
182
202
|
[1.4.0]: https://github.com/cuonggt/kaze/compare/v1.3.1...v1.4.0
|
|
183
203
|
[1.3.1]: https://github.com/cuonggt/kaze/compare/v1.3.0...v1.3.1
|
data/README.md
CHANGED
|
@@ -75,3 +75,15 @@ bin/dev
|
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
Next, you may navigate to your application's `/login` or `/register` URLs in your web browser. All of Kaze's routes are defined within the `config/routes.rb` file.
|
|
78
|
+
|
|
79
|
+
## Upgrading
|
|
80
|
+
|
|
81
|
+
Kaze copies files into your application and does not own them afterwards, so re-running `kaze install` cannot know whether a file it no longer ships was left over from an older version or written by you. `kaze upgrade` resolves that by asking:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
kaze upgrade react
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
It lists the files an earlier Kaze installed that this version no longer ships, waits for you to agree, removes them, and then runs the normal install. Only files Kaze itself shipped are ever listed — anything you added alongside them is untouched, and a directory is removed only once it is empty. Pass `--dry-run` to see the list and stop, or `--force` to skip the prompt in a script.
|
|
88
|
+
|
|
89
|
+
Upgrading from 1.x to 2.x matters on the React stack in particular: `tsc` typechecks every file under `app/javascript`, so the old `Pages/Profile/Edit.tsx` fails the build until it is gone.
|
|
@@ -7,12 +7,47 @@ class Kaze::Commands::App::BaseStack
|
|
|
7
7
|
raise NotImplementedError
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
+
# Paths from this stack's REMOVED_PATHS that the application still has. Only
|
|
11
|
+
# ever a subset of that list: `kaze upgrade` never touches a path Kaze did not
|
|
12
|
+
# put there itself.
|
|
13
|
+
def removable_paths
|
|
14
|
+
self.class::REMOVED_PATHS.select { |path| File.exist?("#{Dir.pwd}/#{path}") }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def remove_paths(paths)
|
|
18
|
+
paths.each { |path| FileUtils.rm_f("#{Dir.pwd}/#{path}") }
|
|
19
|
+
|
|
20
|
+
prune_empty_directories(paths)
|
|
21
|
+
end
|
|
22
|
+
|
|
10
23
|
private
|
|
11
24
|
|
|
25
|
+
# Deleting the last file in a directory leaves the directory behind. Walk back
|
|
26
|
+
# up from each one removing those that are now empty, and stop at the first
|
|
27
|
+
# that is not -- a directory with anything left in it is the application's.
|
|
28
|
+
def prune_empty_directories(paths)
|
|
29
|
+
paths.map { |path| File.dirname("#{Dir.pwd}/#{path}") }.uniq.sort_by(&:length).reverse.each do |dir|
|
|
30
|
+
while dir.start_with?("#{Dir.pwd}/app/") && Dir.exist?(dir) && Dir.empty?(dir)
|
|
31
|
+
Dir.rmdir(dir)
|
|
32
|
+
dir = File.dirname(dir)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
12
37
|
def bundle_command
|
|
13
38
|
@bundle_command ||= File.exist?("#{Dir.pwd}/bin/bundle") ? "#{Dir.pwd}/bin/bundle" : 'bundle'
|
|
14
39
|
end
|
|
15
40
|
|
|
41
|
+
# Bundler exports RUBYOPT and BUNDLE_* so that child processes join its
|
|
42
|
+
# bundle. That is wrong for a nested bundler call: when kaze itself is run
|
|
43
|
+
# through `bundle exec`, a `bundle add` it shells out to inherits them, and
|
|
44
|
+
# any gem with a native extension fails to build, because extconf.rb loads
|
|
45
|
+
# bundler/setup and tries to resolve a lockfile needing the very gem it is
|
|
46
|
+
# about to compile. Shell out to bundler with that environment removed.
|
|
47
|
+
def run_bundle_command(command)
|
|
48
|
+
Bundler.with_unbundled_env { run_command(command) }
|
|
49
|
+
end
|
|
50
|
+
|
|
16
51
|
def install_gems(gems = [], group = nil)
|
|
17
52
|
installed_gems = Bundler::Definition.build("#{Dir.pwd}/Gemfile", nil, {}).dependencies.map(&:name)
|
|
18
53
|
|
|
@@ -20,7 +55,7 @@ class Kaze::Commands::App::BaseStack
|
|
|
20
55
|
|
|
21
56
|
return true if gem_being_installed.empty?
|
|
22
57
|
|
|
23
|
-
status =
|
|
58
|
+
status = run_bundle_command("#{bundle_command} add #{gem_being_installed.join(" ")}#{group ? " --group \"#{group}\"" : ""}")
|
|
24
59
|
|
|
25
60
|
status.success?
|
|
26
61
|
end
|
|
@@ -32,7 +67,7 @@ class Kaze::Commands::App::BaseStack
|
|
|
32
67
|
|
|
33
68
|
return true if gems_being_removed.empty?
|
|
34
69
|
|
|
35
|
-
status =
|
|
70
|
+
status = run_bundle_command("#{bundle_command} remove #{gems_being_removed.join(" ")}")
|
|
36
71
|
|
|
37
72
|
status.success?
|
|
38
73
|
end
|
|
@@ -1,9 +1,27 @@
|
|
|
1
1
|
class Kaze::Commands::App::HotwireStack < Kaze::Commands::App::BaseStack
|
|
2
|
+
# Paths that earlier versions of Kaze installed here and this version no longer
|
|
3
|
+
# ships. `kaze upgrade` offers to delete whichever of them an application still
|
|
4
|
+
# has; anything removed in a future version belongs on this list too.
|
|
5
|
+
REMOVED_PATHS = [
|
|
6
|
+
'app/controllers/profile_controller.rb',
|
|
7
|
+
'app/controllers/password_controller.rb',
|
|
8
|
+
'app/components/nav_link_component.rb',
|
|
9
|
+
'app/components/responsive_nav_link_component.rb',
|
|
10
|
+
'app/views/layouts/_navigation.html.erb',
|
|
11
|
+
'app/views/profile/destroy.turbo_stream.erb',
|
|
12
|
+
'app/views/profile/edit.html.erb',
|
|
13
|
+
'app/views/profile/partials/_confirm_user_deletion_modal.html.erb',
|
|
14
|
+
'app/views/profile/partials/_delete_user_form.html.erb',
|
|
15
|
+
'app/views/profile/partials/_update_appearance_form.html.erb',
|
|
16
|
+
'app/views/profile/partials/_update_password_form.html.erb',
|
|
17
|
+
'app/views/profile/partials/_update_profile_information_form.html.erb'
|
|
18
|
+
].freeze
|
|
19
|
+
|
|
2
20
|
def install
|
|
3
21
|
# Gems...
|
|
4
22
|
return unless remove_gems([ 'sprockets-rails', 'stimulus-rails' ])
|
|
5
23
|
return unless install_gems([ 'propshaft', 'view_component', 'turbo-rails', 'dotenv', 'bcrypt' ])
|
|
6
|
-
return unless
|
|
24
|
+
return unless run_bundle_command("#{bundle_command} add tailwindcss-rails --version=\"~> 4.0\"").success?
|
|
7
25
|
return unless install_gems([ 'hotwire-livereload' ], 'development')
|
|
8
26
|
return unless install_gems([ 'factory_bot_rails', 'faker' ], 'development, test')
|
|
9
27
|
|
|
@@ -1,9 +1,32 @@
|
|
|
1
1
|
class Kaze::Commands::App::InertiaReactStack < Kaze::Commands::App::BaseStack
|
|
2
|
+
# Paths that earlier versions of Kaze installed here and this version no longer
|
|
3
|
+
# ships. `kaze upgrade` offers to delete whichever of them an application still
|
|
4
|
+
# has; anything removed in a future version belongs on this list too.
|
|
5
|
+
REMOVED_PATHS = [
|
|
6
|
+
'app/controllers/profile_controller.rb',
|
|
7
|
+
'app/controllers/password_controller.rb',
|
|
8
|
+
'app/javascript/Components/Checkbox.tsx',
|
|
9
|
+
'app/javascript/Components/DangerButton.tsx',
|
|
10
|
+
'app/javascript/Components/Dropdown.tsx',
|
|
11
|
+
'app/javascript/Components/InputLabel.tsx',
|
|
12
|
+
'app/javascript/Components/Modal.tsx',
|
|
13
|
+
'app/javascript/Components/NavLink.tsx',
|
|
14
|
+
'app/javascript/Components/PrimaryButton.tsx',
|
|
15
|
+
'app/javascript/Components/ResponsiveNavLink.tsx',
|
|
16
|
+
'app/javascript/Components/SecondaryButton.tsx',
|
|
17
|
+
'app/javascript/Components/TextInput.tsx',
|
|
18
|
+
'app/javascript/Pages/Profile/Edit.tsx',
|
|
19
|
+
'app/javascript/Pages/Profile/Partials/DeleteUserForm.tsx',
|
|
20
|
+
'app/javascript/Pages/Profile/Partials/UpdateAppearanceForm.tsx',
|
|
21
|
+
'app/javascript/Pages/Profile/Partials/UpdatePasswordForm.tsx',
|
|
22
|
+
'app/javascript/Pages/Profile/Partials/UpdateProfileInformationForm.tsx'
|
|
23
|
+
].freeze
|
|
24
|
+
|
|
2
25
|
def install
|
|
3
26
|
# Gems...
|
|
4
27
|
return unless remove_gems([ 'sprockets-rails', 'turbo-rails', 'stimulus-rails' ])
|
|
5
28
|
return unless install_gems([ 'propshaft', 'inertia_rails', 'vite_rails', 'dotenv', 'bcrypt', 'js-routes' ])
|
|
6
|
-
return unless
|
|
29
|
+
return unless run_bundle_command("#{bundle_command} add tailwindcss-rails --version=\"~> 4.0\"").success?
|
|
7
30
|
return unless install_gems([ 'factory_bot_rails', 'faker' ], 'development, test')
|
|
8
31
|
|
|
9
32
|
# NPM Packages...
|
|
@@ -1,9 +1,33 @@
|
|
|
1
1
|
class Kaze::Commands::App::InertiaVueStack < Kaze::Commands::App::BaseStack
|
|
2
|
+
# Paths that earlier versions of Kaze installed here and this version no longer
|
|
3
|
+
# ships. `kaze upgrade` offers to delete whichever of them an application still
|
|
4
|
+
# has; anything removed in a future version belongs on this list too.
|
|
5
|
+
REMOVED_PATHS = [
|
|
6
|
+
'app/controllers/profile_controller.rb',
|
|
7
|
+
'app/controllers/password_controller.rb',
|
|
8
|
+
'app/javascript/Components/Checkbox.vue',
|
|
9
|
+
'app/javascript/Components/DangerButton.vue',
|
|
10
|
+
'app/javascript/Components/Dropdown.vue',
|
|
11
|
+
'app/javascript/Components/DropdownLink.vue',
|
|
12
|
+
'app/javascript/Components/InputLabel.vue',
|
|
13
|
+
'app/javascript/Components/Modal.vue',
|
|
14
|
+
'app/javascript/Components/NavLink.vue',
|
|
15
|
+
'app/javascript/Components/PrimaryButton.vue',
|
|
16
|
+
'app/javascript/Components/ResponsiveNavLink.vue',
|
|
17
|
+
'app/javascript/Components/SecondaryButton.vue',
|
|
18
|
+
'app/javascript/Components/TextInput.vue',
|
|
19
|
+
'app/javascript/Pages/Profile/Edit.vue',
|
|
20
|
+
'app/javascript/Pages/Profile/Partials/DeleteUserForm.vue',
|
|
21
|
+
'app/javascript/Pages/Profile/Partials/UpdateAppearanceForm.vue',
|
|
22
|
+
'app/javascript/Pages/Profile/Partials/UpdatePasswordForm.vue',
|
|
23
|
+
'app/javascript/Pages/Profile/Partials/UpdateProfileInformationForm.vue'
|
|
24
|
+
].freeze
|
|
25
|
+
|
|
2
26
|
def install
|
|
3
27
|
# Gems...
|
|
4
28
|
return unless remove_gems([ 'sprockets-rails', 'turbo-rails', 'stimulus-rails' ])
|
|
5
29
|
return unless install_gems([ 'propshaft', 'inertia_rails', 'vite_rails', 'dotenv', 'bcrypt', 'js-routes' ])
|
|
6
|
-
return unless
|
|
30
|
+
return unless run_bundle_command("#{bundle_command} add tailwindcss-rails --version=\"~> 4.0\"").success?
|
|
7
31
|
return unless install_gems([ 'factory_bot_rails', 'faker' ], 'development, test')
|
|
8
32
|
|
|
9
33
|
# NPM Packages...
|
data/lib/kaze/commands/app.rb
CHANGED
|
@@ -7,10 +7,7 @@ class Kaze::Commands::App < Thor
|
|
|
7
7
|
|
|
8
8
|
desc 'install [STACK]', 'Install the Kaze controllers and resources. Supported stacks: hotwire, react, vue.'
|
|
9
9
|
def install(stack = 'hotwire')
|
|
10
|
-
|
|
11
|
-
say 'Kaze must be run in a new Rails application.', :red
|
|
12
|
-
exit 1
|
|
13
|
-
end
|
|
10
|
+
ensure_rails_application
|
|
14
11
|
|
|
15
12
|
# The stack installers stop at the first step that fails, so a falsy return
|
|
16
13
|
# means the application is half-installed. Exiting non-zero keeps that from
|
|
@@ -21,8 +18,56 @@ class Kaze::Commands::App < Thor
|
|
|
21
18
|
exit 1
|
|
22
19
|
end
|
|
23
20
|
|
|
21
|
+
desc 'upgrade [STACK]', 'Remove files an earlier Kaze installed that this version no longer ships, then install.'
|
|
22
|
+
method_option :force, type: :boolean, default: false, aliases: '-f', desc: 'Skip the confirmation prompt.'
|
|
23
|
+
method_option :'dry-run', type: :boolean, default: false, desc: 'List what would be removed and stop.'
|
|
24
|
+
def upgrade(stack = 'hotwire')
|
|
25
|
+
ensure_rails_application
|
|
26
|
+
|
|
27
|
+
stack = StackFactory.make(stack.to_sym)
|
|
28
|
+
paths = stack.removable_paths
|
|
29
|
+
|
|
30
|
+
if paths.empty?
|
|
31
|
+
say 'Nothing to remove. This application has none of the files earlier versions installed.', :green
|
|
32
|
+
else
|
|
33
|
+
say "Kaze no longer ships #{paths.length} #{paths.length == 1 ? 'file' : 'files'} this application still has:", :yellow
|
|
34
|
+
say ''
|
|
35
|
+
paths.each { |path| say " #{path}" }
|
|
36
|
+
say ''
|
|
37
|
+
say 'They are yours now, so check for your own changes before agreeing.', :yellow
|
|
38
|
+
|
|
39
|
+
return if options[:'dry-run']
|
|
40
|
+
|
|
41
|
+
unless options[:force] || yes?('Remove them? [y/N]')
|
|
42
|
+
say 'Nothing was removed.', :red
|
|
43
|
+
exit 1
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
stack.remove_paths(paths)
|
|
47
|
+
|
|
48
|
+
say ''
|
|
49
|
+
say "Removed #{paths.length} #{paths.length == 1 ? 'file' : 'files'}.", :green
|
|
50
|
+
say ''
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
return if options[:'dry-run']
|
|
54
|
+
|
|
55
|
+
exit 1 unless stack.install
|
|
56
|
+
rescue => e
|
|
57
|
+
say e.message, :red
|
|
58
|
+
exit 1
|
|
59
|
+
end
|
|
60
|
+
|
|
24
61
|
desc 'version', 'Show Kaze version'
|
|
25
62
|
def version
|
|
26
63
|
puts Kaze::VERSION
|
|
27
64
|
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
def ensure_rails_application
|
|
68
|
+
return if File.exist?("#{Dir.pwd}/bin/rails")
|
|
69
|
+
|
|
70
|
+
say 'Kaze must be run in a new Rails application.', :red
|
|
71
|
+
exit 1
|
|
72
|
+
end
|
|
28
73
|
end
|
data/lib/kaze/version.rb
CHANGED