data-migration 1.0.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 +7 -0
- data/.editorconfig +14 -0
- data/.github/dependabot.yml +27 -0
- data/.github/workflows/_trunk_check.yml +15 -0
- data/.github/workflows/test.yml +42 -0
- data/.gitignore +24 -0
- data/.ruby-version +1 -0
- data/.trunk/.gitignore +9 -0
- data/.trunk/configs/.markdownlint.yaml +2 -0
- data/.trunk/configs/.shellcheckrc +7 -0
- data/.trunk/configs/.yamllint.yaml +7 -0
- data/.trunk/trunk.yaml +39 -0
- data/.vscode/extensions.json +18 -0
- data/.vscode/settings.json +7 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +246 -0
- data/LICENSE.md +21 -0
- data/README.md +141 -0
- data/data-migration.gemspec +44 -0
- data/lib/data_migration/config.rb +84 -0
- data/lib/data_migration/job.rb +63 -0
- data/lib/data_migration/task.rb +127 -0
- data/lib/data_migration.rb +37 -0
- data/lib/generators/data_migration_generator.rb +13 -0
- data/lib/generators/install_generator.rb +17 -0
- data/lib/generators/templates/data_migration.rb.tt +26 -0
- data/lib/generators/templates/install_data_migration_tasks.rb.tt +27 -0
- data/spec/data_migration/config_spec.rb +116 -0
- data/spec/data_migration/job_spec.rb +96 -0
- data/spec/data_migration/task_spec.rb +152 -0
- data/spec/data_migration_spec.rb +65 -0
- data/spec/fixtures/data_migrations/20241206200111_create_users.rb +17 -0
- data/spec/fixtures/data_migrations/20241206200112_create_bad_users.rb +5 -0
- data/spec/fixtures/data_migrations/20241206200113_change_users.rb +5 -0
- data/spec/fixtures/data_migrations/20241206200114_create_batch_users.rb +9 -0
- data/spec/fixtures/schema.rb +26 -0
- data/spec/generators/install_generator_spec.rb +48 -0
- data/spec/generators/migration_generator_spec.rb +50 -0
- data/spec/rails_helper.rb +21 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/support/junit_formatter.rb +6 -0
- data/spec/support/rails_helpers.rb +53 -0
- data/usr/bin/release.sh +35 -0
- metadata +246 -0
@@ -0,0 +1,152 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe DataMigration::Task do
|
4
|
+
subject(:task) { DataMigration::Task.create!(name: migration_name) }
|
5
|
+
|
6
|
+
let(:migration_name) { "20241206200111_create_users" }
|
7
|
+
let(:data_migrations_full_path) { File.expand_path("../fixtures/data_migrations", __dir__) }
|
8
|
+
|
9
|
+
before do
|
10
|
+
# allow(Rails).to receive(:root).and_return(rails_root)
|
11
|
+
# allow(Rails).to receive(:logger).and_return(rails_logger)
|
12
|
+
allow(DataMigration.config).to receive(:data_migrations_full_path).and_return(data_migrations_full_path)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#file_path" do
|
16
|
+
it "returns the full path to the migration file" do
|
17
|
+
expect(task.file_path).to eq("#{data_migrations_full_path}/#{migration_name}.rb")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#file_exists?" do
|
22
|
+
it "returns true if the file exists" do
|
23
|
+
expect(task.file_exists?).to be(true)
|
24
|
+
expect(task.valid?).to be(true)
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when the file does not exist" do
|
28
|
+
let(:migration_name) { "20241206200111_create_something_else" }
|
29
|
+
let(:task) { DataMigration::Task.new(name: migration_name) }
|
30
|
+
|
31
|
+
it "returns false" do
|
32
|
+
expect(task.file_exists?).to be(false)
|
33
|
+
expect(task.valid?).to be(false)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#requires_pause?" do
|
39
|
+
before do
|
40
|
+
task.status = :started
|
41
|
+
task.pause_minutes = 10
|
42
|
+
end
|
43
|
+
|
44
|
+
it "returns true if pause_minutes is positive and status is not paused" do
|
45
|
+
expect(task.requires_pause?).to be(true)
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when pause_minutes is 0" do
|
49
|
+
before do
|
50
|
+
task.pause_minutes = 0
|
51
|
+
end
|
52
|
+
|
53
|
+
it "returns false" do
|
54
|
+
expect(task.requires_pause?).to be(false)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "when status is paused" do
|
59
|
+
before do
|
60
|
+
task.status = :paused
|
61
|
+
end
|
62
|
+
|
63
|
+
it "returns false" do
|
64
|
+
expect(task.requires_pause?).to be(false)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "#perform_now" do
|
70
|
+
it "calls the job class with the task and arguments" do
|
71
|
+
kwargs = { foo: "bar" }
|
72
|
+
expect(DataMigration::Job).to receive(:perform_now).with(task.id, **kwargs)
|
73
|
+
task.perform_now(**kwargs)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#perform_later" do
|
78
|
+
it "calls the job class with the task and arguments" do
|
79
|
+
kwargs = { foo: "bar" }
|
80
|
+
expect(DataMigration::Job).to receive(:perform_later).with(task.id, **kwargs)
|
81
|
+
task.perform_later(**kwargs)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "#prepare" do
|
86
|
+
subject(:task) { DataMigration::Task.prepare(migration_name, pause_minutes: 10, jobs_limit: 5) }
|
87
|
+
|
88
|
+
it "creates a new task with the given name, pause, and jobs_limit" do
|
89
|
+
expect { task }.to change(DataMigration::Task, :count).by(1)
|
90
|
+
expect(task.name).to eq(migration_name)
|
91
|
+
expect(task.status).to be_nil
|
92
|
+
expect(task.pause_minutes).to eq(10)
|
93
|
+
expect(task.jobs_limit).to eq(5)
|
94
|
+
end
|
95
|
+
|
96
|
+
context "when chained with perform_now" do
|
97
|
+
it "calls the job class with the task and arguments" do
|
98
|
+
perform_args = { "foo" => "bar" }
|
99
|
+
expect(DataMigration::Job).to receive(:perform_now).with(task.id, **perform_args)
|
100
|
+
task.perform_now(**perform_args)
|
101
|
+
expect(task.kwargs).to eq(perform_args)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "#job_check_in!" do
|
107
|
+
subject(:job_check_in!) { task.job_check_in!(job_id, job_args: ["foo"], job_kwargs: { bar: "baz" }) }
|
108
|
+
|
109
|
+
let(:job_id) { "123" }
|
110
|
+
|
111
|
+
it "adds the job to the current_jobs hash" do
|
112
|
+
expect { job_check_in! }.to change { task.current_jobs.size }.by(1)
|
113
|
+
end
|
114
|
+
|
115
|
+
context "when there is a job with the same id" do
|
116
|
+
before do
|
117
|
+
task.job_check_in!(job_id, job_args: ["foo"], job_kwargs: { bar: "baz" })
|
118
|
+
end
|
119
|
+
|
120
|
+
it "raises a JobConflictError" do
|
121
|
+
expect { job_check_in! }.to raise_error(DataMigration::JobConflictError)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context "when default_jobs_limit is 1 and there are jobs" do
|
126
|
+
before do
|
127
|
+
DataMigration.config.default_jobs_limit = 1
|
128
|
+
task.job_check_in!("321", job_args: ["foo"], job_kwargs: { bar: "baz" })
|
129
|
+
end
|
130
|
+
|
131
|
+
it "raises a JobConcurrencyLimitError" do
|
132
|
+
expect { job_check_in! }.to raise_error(DataMigration::JobConcurrencyLimitError)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "#job_check_out!" do
|
138
|
+
subject(:job_check_out!) { task.job_check_out!(job_id) }
|
139
|
+
|
140
|
+
let(:job_id) { "123" }
|
141
|
+
|
142
|
+
before do
|
143
|
+
task.save!
|
144
|
+
task.job_check_in!(job_id, job_args: ["foo"], job_kwargs: { bar: "baz" })
|
145
|
+
end
|
146
|
+
|
147
|
+
it "removes the job from the current_jobs hash" do
|
148
|
+
expect { job_check_out! }.to change { task.current_jobs.size }.by(-1)
|
149
|
+
expect(task.current_jobs).not_to have_key(job_id)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe DataMigration do
|
4
|
+
let(:gem_specification) { Gem::Specification.load(File.expand_path("../../data-migration.gemspec", __FILE__)) }
|
5
|
+
|
6
|
+
it "has a version number" do
|
7
|
+
expect(described_class::VERSION).to eq gem_specification.version.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:changelog_file) { File.expand_path("../../CHANGELOG.md", __FILE__) }
|
11
|
+
it "has changelog for the version" do
|
12
|
+
expect(File.exist?(changelog_file)).to be true
|
13
|
+
expect(File.read(changelog_file)).to include("# #{gem_specification.version}")
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:license_file) { File.expand_path("../../LICENSE.md", __FILE__) }
|
17
|
+
it "has license" do
|
18
|
+
expect(File.exist?(license_file)).to be true
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:readme_file) { File.expand_path("../../README.md", __FILE__) }
|
22
|
+
it "has readme" do
|
23
|
+
expect(File.exist?(readme_file)).to be true
|
24
|
+
end
|
25
|
+
|
26
|
+
describe ".notify" do
|
27
|
+
subject(:notify) { DataMigration.notify("test") }
|
28
|
+
let(:action_reporter) { Class.new }
|
29
|
+
before do
|
30
|
+
stub_const("ActionReporter", action_reporter)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "sends message to ActionReporter" do
|
34
|
+
expect(action_reporter).to receive(:notify).with("test", context: {})
|
35
|
+
expect { notify }.not_to raise_error
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe ".perform_now" do
|
40
|
+
subject(:perform_now) { DataMigration.perform_now("test_perform_now") }
|
41
|
+
|
42
|
+
it "delegates to DataMigration::Task.perform_now" do
|
43
|
+
expect(DataMigration::Task).to receive(:perform_now).with("test_perform_now")
|
44
|
+
expect { perform_now }.not_to raise_error
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe ".perform_later" do
|
49
|
+
subject(:perform_later) { DataMigration.perform_later("test_perform_later") }
|
50
|
+
|
51
|
+
it "delegates to DataMigration::Task.perform_later" do
|
52
|
+
expect(DataMigration::Task).to receive(:perform_later).with("test_perform_later")
|
53
|
+
expect { perform_later }.not_to raise_error
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe ".prepare" do
|
58
|
+
subject(:prepare) { DataMigration.prepare("test_prepare") }
|
59
|
+
|
60
|
+
it "delegates to DataMigration::Task.prepare" do
|
61
|
+
expect(DataMigration::Task).to receive(:prepare).with("test_prepare")
|
62
|
+
expect { prepare }.not_to raise_error
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class CreateUsers
|
2
|
+
def perform(**kwargs)
|
3
|
+
User.find_or_create_by(email: "test@example.com")
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
if ENV["RUN_MIGRATION_TESTS"] && Object.const_defined?(:RSpec)
|
8
|
+
require "rails_helper"
|
9
|
+
|
10
|
+
RSpec.describe CreateUsers, type: :data_migration do
|
11
|
+
subject(:perform) { described_class.new.perform }
|
12
|
+
|
13
|
+
it do
|
14
|
+
expect { perform }.not_to raise_error
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
ActiveRecord::Schema.define(version: 2024_12_06_200411) do
|
2
|
+
create_table :data_migration_tasks, force: true do |t|
|
3
|
+
t.string "name", null: false
|
4
|
+
|
5
|
+
t.json "kwargs", default: {}, null: false
|
6
|
+
t.json "current_jobs", default: {}, null: false
|
7
|
+
|
8
|
+
t.string "status"
|
9
|
+
t.datetime "started_at"
|
10
|
+
t.datetime "completed_at"
|
11
|
+
|
12
|
+
t.bigint "operator_id"
|
13
|
+
t.string "operator_type"
|
14
|
+
|
15
|
+
t.integer "pause_minutes", default: 0, null: false
|
16
|
+
t.integer "jobs_limit"
|
17
|
+
|
18
|
+
t.datetime "created_at", null: false
|
19
|
+
t.datetime "updated_at", null: false
|
20
|
+
end
|
21
|
+
|
22
|
+
create_table :users, force: true do |t|
|
23
|
+
t.string :email
|
24
|
+
t.string :version
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
require "generators/install_generator"
|
4
|
+
|
5
|
+
describe InstallGenerator, type: :generator do
|
6
|
+
include FileUtils
|
7
|
+
|
8
|
+
subject(:generator) { described_class.start params }
|
9
|
+
|
10
|
+
let(:root_path) { rails_root(File.expand_path("../../../tmp/rspec", __FILE__)) }
|
11
|
+
|
12
|
+
let(:migration_name) { "data_migration_tasks" }
|
13
|
+
let(:params) { [migration_name] }
|
14
|
+
let(:created_files) { Dir["#{root_path}/db/migrate/*_#{migration_name}.rb"] }
|
15
|
+
let(:migration_content) { File.readlines(created_files.first).reject(&:blank?).map(&:strip) }
|
16
|
+
|
17
|
+
before do
|
18
|
+
mkdir_p root_path.to_s
|
19
|
+
allow(DataMigration.config).to receive(:schema_migrations_path).and_return("#{root_path}/db/migrate")
|
20
|
+
allow(Rails).to receive(:root).and_return(root_path)
|
21
|
+
end
|
22
|
+
|
23
|
+
after do
|
24
|
+
rm_rf root_path.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
it "creates a migration file" do
|
28
|
+
generator
|
29
|
+
|
30
|
+
expect(created_files).not_to be_empty
|
31
|
+
|
32
|
+
expect(migration_content).to include("create_table :data_migration_tasks, force: true do |t|")
|
33
|
+
end
|
34
|
+
|
35
|
+
context "when tasks_table_name is not default" do
|
36
|
+
before do
|
37
|
+
allow(DataMigration).to receive(:tasks_table_name).and_return("other_data_migration_tasks")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "creates a migration file with the correct table name" do
|
41
|
+
generator
|
42
|
+
|
43
|
+
expect(created_files).not_to be_empty
|
44
|
+
|
45
|
+
expect(migration_content).to include("create_table :other_data_migration_tasks, force: true do |t|")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
require "generators/data_migration_generator"
|
4
|
+
|
5
|
+
describe DataMigrationGenerator, type: :generator do
|
6
|
+
include FileUtils
|
7
|
+
|
8
|
+
subject(:generator) { described_class.start params }
|
9
|
+
|
10
|
+
let(:root_path) { rails_root(File.expand_path("../../../tmp/rspec", __FILE__)) }
|
11
|
+
|
12
|
+
let(:migration_name) { "create_users" }
|
13
|
+
let(:params) { [migration_name] }
|
14
|
+
let(:created_files) { Dir["#{root_path}/db/data_migrations/*_#{migration_name}.rb"] }
|
15
|
+
let(:migration_content) { File.readlines(created_files.first).reject(&:blank?).map(&:strip) }
|
16
|
+
|
17
|
+
before do
|
18
|
+
mkdir_p root_path.to_s
|
19
|
+
allow(DataMigration.config).to receive(:data_migrations_path).and_return("#{root_path}/db/data_migrations")
|
20
|
+
allow(Rails).to receive(:root).and_return(root_path)
|
21
|
+
end
|
22
|
+
|
23
|
+
after do
|
24
|
+
rm_rf root_path.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
it "creates a migration file" do
|
28
|
+
generator
|
29
|
+
|
30
|
+
expect(created_files).not_to be_empty
|
31
|
+
|
32
|
+
expect(migration_content).to include("class CreateUsers")
|
33
|
+
expect(migration_content).to include("def perform(**kwargs)")
|
34
|
+
expect(migration_content).to include("RSpec.describe CreateUsers, type: :data_migration do")
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when generate_spec is false" do
|
38
|
+
before do
|
39
|
+
DataMigration.config.generate_spec = false
|
40
|
+
end
|
41
|
+
|
42
|
+
it "does not add RSpec describe block" do
|
43
|
+
generator
|
44
|
+
|
45
|
+
expect(created_files).not_to be_empty
|
46
|
+
|
47
|
+
expect(migration_content).not_to include("RSpec.describe CreateUsers, type: :data_migration do")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "active_record"
|
2
|
+
|
3
|
+
require "data_migration"
|
4
|
+
|
5
|
+
require "support/rails_helpers"
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
include RailsHelpers
|
9
|
+
|
10
|
+
config.before(:suite) do
|
11
|
+
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
|
12
|
+
load File.expand_path("../fixtures/schema.rb", __FILE__)
|
13
|
+
end
|
14
|
+
|
15
|
+
config.before(:each) do
|
16
|
+
tables = ActiveRecord::Base.connection.tables
|
17
|
+
tables.each do |table|
|
18
|
+
ActiveRecord::Base.connection.execute("DELETE FROM #{table}")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "simplecov"
|
2
|
+
SimpleCov.start do
|
3
|
+
add_filter "/spec/"
|
4
|
+
add_filter { |source_file| source_file.lines.count < 5 }
|
5
|
+
end
|
6
|
+
|
7
|
+
require "simplecov-cobertura"
|
8
|
+
SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter
|
9
|
+
|
10
|
+
require "active_record"
|
11
|
+
|
12
|
+
require "data_migration"
|
13
|
+
|
14
|
+
Dir[File.expand_path("support/**/*.rb", __dir__)].each { |f| require_relative f }
|
15
|
+
|
16
|
+
RSpec.configure do |config|
|
17
|
+
include RailsHelpers
|
18
|
+
|
19
|
+
config.before(:suite) do
|
20
|
+
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
|
21
|
+
load File.expand_path("../fixtures/schema.rb", __FILE__)
|
22
|
+
end
|
23
|
+
|
24
|
+
config.before(:each) do
|
25
|
+
tables = ActiveRecord::Base.connection.tables
|
26
|
+
tables.each do |table|
|
27
|
+
ActiveRecord::Base.connection.execute("DELETE FROM #{table}")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module RailsHelpers
|
2
|
+
class User < ActiveRecord::Base
|
3
|
+
self.table_name = "users"
|
4
|
+
end
|
5
|
+
|
6
|
+
def rails_root(destination_root = File.expand_path("../../tmp/rspec", __dir__))
|
7
|
+
Class.new do
|
8
|
+
def initialize(destination_root)
|
9
|
+
@destination_root = destination_root
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
@destination_root
|
14
|
+
end
|
15
|
+
|
16
|
+
def join(*args)
|
17
|
+
File.join(@destination_root, *args)
|
18
|
+
end
|
19
|
+
end.new(destination_root)
|
20
|
+
end
|
21
|
+
|
22
|
+
def rails_env(env = "development")
|
23
|
+
Class.new do
|
24
|
+
def initialize(env)
|
25
|
+
@env = env.to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
def development?
|
29
|
+
@env == "development"
|
30
|
+
end
|
31
|
+
|
32
|
+
def test?
|
33
|
+
@env == "test"
|
34
|
+
end
|
35
|
+
|
36
|
+
def production?
|
37
|
+
@env == "production"
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_s
|
41
|
+
@env
|
42
|
+
end
|
43
|
+
end.new(env)
|
44
|
+
end
|
45
|
+
|
46
|
+
def rails_logger
|
47
|
+
Class.new do
|
48
|
+
def info(message)
|
49
|
+
puts message
|
50
|
+
end
|
51
|
+
end.new
|
52
|
+
end
|
53
|
+
end
|
data/usr/bin/release.sh
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
|
5
|
+
e() {
|
6
|
+
GREEN='\033[0;32m'
|
7
|
+
NC='\033[0m'
|
8
|
+
echo -e "${GREEN}$1${NC}"
|
9
|
+
eval "$1"
|
10
|
+
}
|
11
|
+
|
12
|
+
e "bundle"
|
13
|
+
e "bundle exec rspec"
|
14
|
+
|
15
|
+
if [[ $(git diff --shortstat 2>/dev/null | tail -n1) != "" ]]; then
|
16
|
+
echo -e "\033[1;31mgit working directory not clean, please commit your changes first \033[0m"
|
17
|
+
exit 1
|
18
|
+
fi
|
19
|
+
|
20
|
+
GEM_NAME="data-migration"
|
21
|
+
VERSION=$(grep -Eo "VERSION\s*=\s*\".+\"" lib/data_migration.rb | grep -Eo "[0-9.]{5,}")
|
22
|
+
GEM_FILE="$GEM_NAME-$VERSION.gem"
|
23
|
+
|
24
|
+
e "gem build $GEM_NAME.gemspec"
|
25
|
+
|
26
|
+
echo "Ready to release $GEM_FILE $VERSION"
|
27
|
+
read -p "Continue? [Y/n] " answer
|
28
|
+
if [[ "$answer" != "Y" ]]; then
|
29
|
+
echo "Exiting"
|
30
|
+
exit 1
|
31
|
+
fi
|
32
|
+
|
33
|
+
e "gem push $GEM_FILE"
|
34
|
+
e "git tag $VERSION && git push --tags"
|
35
|
+
e "gh release create $VERSION --generate-notes"
|