one_off 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2cc793a7ba8fa8c0f6a59bf94feda1a7e1c90a7902dc68fe3a641e608db9ecf8
4
+ data.tar.gz: 88fd5c273f09d626cf41ed28060695d86da63f8daf984aa1979eaad547230c21
5
+ SHA512:
6
+ metadata.gz: a1e15673ac6fd993c35375bdfb8efee813c757d5ae8898f2dac672c13cab3b822a234ce8c670f2981b6ed4daceaa36a38f672f8be8573a909762690cdb4ef8bd
7
+ data.tar.gz: 2b6ef33ec59955e18e64cf2089df84a31e2e4248f51ae5e4c378bf6c6772d476d7b2cd98cecd6a5a84bc1c54e99049829b157edd6217222d2a15e4bb17679ca8
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2020 Hamed Asghari
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # OneOff
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'one_off'
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install one_off
22
+ ```
23
+
24
+ ## Contributing
25
+ Contribution directions go here.
26
+
27
+ ## License
28
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+
9
+ require 'rdoc/task'
10
+
11
+ RDoc::Task.new(:rdoc) do |rdoc|
12
+ rdoc.rdoc_dir = 'rdoc'
13
+ rdoc.title = 'OneOff'
14
+ rdoc.options << '--line-numbers'
15
+ rdoc.rdoc_files.include('README.md')
16
+ rdoc.rdoc_files.include('lib/**/*.rb')
17
+ end
18
+
19
+ APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
20
+ load 'rails/tasks/engine.rake'
21
+
22
+ load 'rails/tasks/statistics.rake'
23
+
24
+ require 'bundler/gem_tasks'
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OneOff
4
+ class ApplicationJob < ActiveJob::Base
5
+ end
6
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OneOff
4
+ class ExecutorJob < ApplicationJob
5
+ def perform(file)
6
+ require "#{Rails.root}/db/one_off/#{file.filename}"
7
+ Rails.logger.info "=== Starting one_off task #{file.task_name}"
8
+ OneOff.const_get(file.task_name.camelize).new.call
9
+ Rails.logger.info "=== Finished one_off task #{file.task_name}"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OneOff
4
+ class ApplicationRecord < ActiveRecord::Base
5
+ self.abstract_class = true
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OneOff
4
+ class Task < ApplicationRecord
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateOneOffTasks < ActiveRecord::Migration[6.0]
4
+ def change
5
+ create_table :one_off_tasks do |t|
6
+ t.string :version
7
+ end
8
+
9
+ add_index :one_off_tasks, :version, unique: true
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ This generator will create a one_off script to be executed when code is deployed to production.
3
+
4
+ Example:
5
+ rails generate one_off name_of_your_task
6
+
7
+ This will create:
8
+ db/one_off/<timestamp>_name_of_your_task.rb
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators'
4
+
5
+ class OneOffGenerator < Rails::Generators::NamedBase
6
+ def create_one_off_file
7
+ timestamp = Time.zone.now.strftime('%Y%m%d%H%M%S')
8
+ create_file "db/one_off/#{timestamp}_#{file_name}.rb", <<~FILE
9
+ require 'one_off/environments'
10
+
11
+ module OneOff
12
+ class #{class_name}
13
+ include Environments
14
+
15
+ environments :development, :production
16
+
17
+ def perform
18
+ end
19
+ end
20
+ end
21
+ FILE
22
+ end
23
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OneOff
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace OneOff
6
+ config.generators.api_only = true
7
+ end
8
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OneOff
4
+ module Environments
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ def call
9
+ perform if Array.wrap(self.class.__environments).include?(Rails.env)
10
+ end
11
+
12
+ def perform
13
+ raise NotImplementedError
14
+ end
15
+ end
16
+
17
+ class_methods do
18
+ attr_reader :__environments
19
+
20
+ def environments(*envs)
21
+ @__environments = envs.map(&:to_s)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OneOff
4
+ class File
5
+ include GlobalID::Identification
6
+
7
+ REGEX = /\A(\d{14})_(\w+)\z/.freeze
8
+
9
+ class << self
10
+ def all
11
+ Dir.glob('db/one_off/*.rb', base: Rails.root)
12
+ .map { |f| ::File.basename(f, '.rb') }
13
+ .select { |f| REGEX.match(f) }
14
+ .map { |f| new(f) }
15
+ end
16
+
17
+ def find(id)
18
+ all.find { |file| file.id == id.to_i }
19
+ end
20
+ end
21
+
22
+ attr_reader :filename
23
+
24
+ def initialize(filename)
25
+ @filename = filename
26
+ end
27
+
28
+ def file_name_match
29
+ @file_name_match ||= REGEX.match(filename)
30
+ end
31
+
32
+ def version
33
+ file_name_match[1].to_i
34
+ end
35
+
36
+ alias id version
37
+
38
+ def task_name
39
+ file_name_match[2]
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OneOff
4
+ class Migrator
5
+ class << self
6
+ def run(files: pending_files)
7
+ files.sort_by(&:version).each do |file|
8
+ OneOff::ExecutorJob.perform_later(file)
9
+ Rails.logger.info "=== Queued one_off task #{file.task_name}"
10
+ OneOff::Task.create_or_find_by!(version: file.version)
11
+ end
12
+ end
13
+
14
+ def db_versions
15
+ @db_versions ||= OneOff::Task.pluck(:version).map(&:to_i)
16
+ end
17
+
18
+ def pending_files
19
+ OneOff::File.all.index_by(&:version).except(*db_versions).values
20
+ end
21
+
22
+ def matching(pattern)
23
+ OneOff::File.all.select { |f| f.filename.match? pattern }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OneOff
4
+ VERSION = '1.0.0'
5
+ end
data/lib/one_off.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'one_off/engine'
4
+ require 'one_off/file'
5
+
6
+ module OneOff
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :one_off do
4
+ task run: :environment do
5
+ require 'one_off/migrator'
6
+ OneOff::Migrator.run
7
+ end
8
+
9
+ task :matching, [:search_string] => [:environment] do |_t, args|
10
+ require 'one_off/migrator'
11
+ OneOff::Migrator.run files: OneOff::Migrator.matching(args.search_string)
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: one_off
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Hamed Asghari
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-03-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 6.0.2
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 6.0.2.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 6.0.2
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 6.0.2.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: pg
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec-rails
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.9'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.9'
61
+ - !ruby/object:Gem::Dependency
62
+ name: simplecov
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - '='
66
+ - !ruby/object:Gem::Version
67
+ version: 0.16.1
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '='
73
+ - !ruby/object:Gem::Version
74
+ version: 0.16.1
75
+ description: A Rails plugin that creates a one_off script to be executed when code
76
+ is deployed to production
77
+ email:
78
+ - hasghari@g2.com
79
+ executables: []
80
+ extensions: []
81
+ extra_rdoc_files: []
82
+ files:
83
+ - MIT-LICENSE
84
+ - README.md
85
+ - Rakefile
86
+ - app/jobs/one_off/application_job.rb
87
+ - app/jobs/one_off/executor_job.rb
88
+ - app/models/one_off/application_record.rb
89
+ - app/models/one_off/task.rb
90
+ - db/migrate/20200324033752_create_one_off_tasks.rb
91
+ - lib/generators/one_off/USAGE
92
+ - lib/generators/one_off/one_off_generator.rb
93
+ - lib/one_off.rb
94
+ - lib/one_off/engine.rb
95
+ - lib/one_off/environments.rb
96
+ - lib/one_off/file.rb
97
+ - lib/one_off/migrator.rb
98
+ - lib/one_off/version.rb
99
+ - lib/tasks/one_off_tasks.rake
100
+ homepage: https://github.com/g2crowd/one_off
101
+ licenses:
102
+ - MIT
103
+ metadata: {}
104
+ post_install_message:
105
+ rdoc_options: []
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ requirements: []
119
+ rubygems_version: 3.0.6
120
+ signing_key:
121
+ specification_version: 4
122
+ summary: A Rails plugin with a generator to create one off scripts
123
+ test_files: []