web_rake 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e01fea2418b7eaccb61e4a536870df1ffd7d21c6637da249f1489e89b3c82d8d
4
+ data.tar.gz: b355c7545ac8027223d4e1fcb2c4c63a02eb6a13ebc3b4f4dcbbc2219622a70a
5
+ SHA512:
6
+ metadata.gz: 7e842bd3432fb67758c398543d8858ab3094e52ca8ddae73ee24681b90e7d9900d2c61c227e2d465a9149999a9b4a467841e3dd24d6b29380858d9f884c3d4d2
7
+ data.tar.gz: 32712a2c211e7bcdc280b112be8a048feb9d6033bb06a5704f0ec0483719c38e57a5a28128a5e7f662bd60f89d5f3891b1961e867353741b6c56ac739fca9637
data/MIT-LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2024 Your Name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # WebRake
2
+
3
+ WebRake is a Rails engine designed for production environments that provides a secure web interface for executing essential Rake tasks in your deployed Rails application. It includes HTTP basic authentication for security and automatically mounts at `/rails/tasks` without requiring any route configuration.
4
+
5
+ ## Purpose
6
+
7
+ This gem is specifically designed for production/deployed applications where you need quick access to:
8
+ - Seed your database with `db:seed`
9
+ - Run custom data population tasks (like `sample_data`)
10
+ - Execute other custom maintenance tasks
11
+
12
+ Perfect for situations where you don't have shell access or need to quickly run tasks on deployed platforms like Render, Heroku, or similar services.
13
+
14
+ ## Features
15
+
16
+ - Exposes `db:seed` and custom Rake tasks from `lib/tasks/` directory
17
+ - Web interface with one-click task execution
18
+ - HTTP basic authentication for security
19
+ - Real-time output capture (stdout and stderr)
20
+ - Execution timing and status reporting
21
+ - Clean, responsive UI
22
+ - Zero configuration required for routes
23
+
24
+ ## Which Tasks Are Shown
25
+
26
+ WebRake displays:
27
+ - The `db:seed` task for database seeding
28
+ - Custom Rake tasks defined in your `lib/tasks/` directory
29
+
30
+ System tasks (like `db:migrate`, `db:drop`, `assets:precompile`, etc.) are intentionally hidden for security reasons.
31
+
32
+ ## Installation
33
+
34
+ Add this line to your application's Gemfile:
35
+
36
+ ```ruby
37
+ gem 'web_rake'
38
+ ```
39
+
40
+ And then execute:
41
+
42
+ ```bash
43
+ bundle install
44
+ ```
45
+
46
+ Or install it yourself as:
47
+
48
+ ```bash
49
+ gem install web_rake
50
+ ```
51
+
52
+ ## Configuration
53
+
54
+ ### Environment Variables
55
+
56
+ WebRake uses HTTP basic authentication to protect access to the rake task interface. Set these environment variables in your `.env` file or deployment configuration:
57
+
58
+ ```bash
59
+ WEB_RAKE_USERNAME=your_username
60
+ WEB_RAKE_PASSWORD=your_secure_password
61
+ ```
62
+
63
+ **Important:** Choose strong credentials, especially in production environments, as anyone with these credentials can execute rake tasks on your application.
64
+
65
+ ### Optional Ruby Configuration
66
+
67
+ You can also configure the credentials programmatically in an initializer:
68
+
69
+ ```ruby
70
+ # config/initializers/web_rake.rb
71
+ WebRake.configure do |config|
72
+ config.username = 'custom_username'
73
+ config.password = 'custom_password'
74
+ end
75
+ ```
76
+
77
+ Note: Environment variables take precedence over Ruby configuration.
78
+
79
+ ## Usage
80
+
81
+ Once installed and configured, WebRake automatically mounts at `/rails/tasks` in your Rails application.
82
+
83
+ 1. Navigate to `http://your-app.com/rails/tasks`
84
+ 2. Enter your HTTP basic auth credentials
85
+ 3. You'll see a list of all available Rake tasks with descriptions
86
+ 4. Click "Run Task" on any task to execute it
87
+ 5. View the output, errors (if any), and execution time
88
+
89
+ ## How It Works
90
+
91
+ - WebRake is a Rails engine that automatically mounts itself at `/rails/tasks`
92
+ - It discovers all loaded Rake tasks in your Rails application
93
+ - Tasks are executed in the same process as your Rails app
94
+ - Output is captured using StringIO redirection
95
+ - Tasks are automatically re-enabled after execution for repeat runs
96
+
97
+ ## Development
98
+
99
+ After checking out the repo, run:
100
+
101
+ ```bash
102
+ bundle install
103
+ ```
104
+
105
+ To run tests:
106
+
107
+ ```bash
108
+ bundle exec rspec
109
+ ```
110
+
111
+ ## Contributing
112
+
113
+ Bug reports and pull requests are welcome on GitHub at https://github.com/firstdraft/web_rake.
114
+
115
+ ## License
116
+
117
+ 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,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,15 @@
1
+ module WebRake
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+
5
+ before_action :authenticate
6
+
7
+ private
8
+
9
+ def authenticate
10
+ authenticate_or_request_with_http_basic do |username, password|
11
+ username == WebRake.username && password == WebRake.password
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,152 @@
1
+ module WebRake
2
+ class TasksController < ApplicationController
3
+ before_action :ensure_environment_loaded
4
+
5
+ def index
6
+ @tasks = custom_tasks.sort_by(&:name)
7
+ end
8
+
9
+ def show
10
+ @task = find_task
11
+ redirect_to root_path, alert: "Task not found" unless @task
12
+ end
13
+
14
+ def execute
15
+ task_name = params[:id].gsub('__', ':')
16
+
17
+ # Check if this is one of our allowed tasks (custom tasks + db:seed)
18
+ allowed_tasks = extract_task_names_from_files + ['db:seed']
19
+ unless allowed_tasks.include?(task_name)
20
+ redirect_to root_path, alert: "Task not found"
21
+ return
22
+ end
23
+
24
+ start_time = Time.current
25
+ output = []
26
+ errors = []
27
+ success = false
28
+
29
+ begin
30
+ original_stdout = $stdout
31
+ original_stderr = $stderr
32
+
33
+ $stdout = StringIO.new
34
+ $stderr = StringIO.new
35
+
36
+ # Run the rake task in a subprocess to avoid state issues
37
+ # This ensures clean execution every time
38
+ require 'open3'
39
+
40
+ # Build the rake command
41
+ rake_command = "bundle exec rake #{task_name}"
42
+
43
+ # Execute the command and capture output
44
+ stdout_str, stderr_str, status = Open3.capture3(rake_command)
45
+
46
+ output = stdout_str.split("\n")
47
+ errors = stderr_str.split("\n") if stderr_str.present?
48
+ success = status.success?
49
+ rescue => e
50
+ errors << e.message
51
+ errors.concat(e.backtrace) if Rails.env.development?
52
+ ensure
53
+ $stdout = original_stdout if original_stdout
54
+ $stderr = original_stderr if original_stderr
55
+ end
56
+
57
+ end_time = Time.current
58
+ duration = (end_time - start_time).round(2)
59
+
60
+ # Create a simple task object for the view
61
+ task = OpenStruct.new(name: task_name)
62
+
63
+ render :execute, locals: {
64
+ task: task,
65
+ output: output,
66
+ errors: errors,
67
+ success: success,
68
+ duration: duration
69
+ }
70
+ end
71
+
72
+ private
73
+
74
+ def ensure_environment_loaded
75
+ # Ensure Rails environment is available for tasks that depend on it
76
+ Rails.application.load_tasks if Rake::Task.tasks.empty?
77
+ end
78
+
79
+ def custom_tasks
80
+ # First, get the names of tasks defined in lib/tasks files
81
+ custom_task_names = extract_task_names_from_files
82
+
83
+ # Always include db:seed task
84
+ custom_task_names << 'db:seed'
85
+
86
+ # Ensure all tasks are loaded
87
+ Rails.application.load_tasks
88
+
89
+ # Get only the tasks that match our custom task names
90
+ custom_task_names.filter_map do |name|
91
+ Rake::Task[name] rescue nil
92
+ end.select(&:actions)
93
+ end
94
+
95
+ def extract_task_names_from_files
96
+ task_names = []
97
+
98
+ # Parse each rake file to extract task names
99
+ Dir.glob(Rails.root.join('lib/tasks/**/*.rake')).each do |file|
100
+ content = File.read(file)
101
+
102
+ # Match various task definition patterns
103
+
104
+ # Pattern for: task({ :sample_data => :environment })
105
+ content.scan(/task\s*\(\s*\{\s*:([a-zA-Z_][a-zA-Z0-9_]*)\s*=>/).each do |match|
106
+ task_names << match[0]
107
+ end
108
+
109
+ # Pattern for: task :sample_data => :environment
110
+ content.scan(/task\s+:([a-zA-Z_][a-zA-Z0-9_]*)\s*=>/).each do |match|
111
+ task_names << match[0]
112
+ end
113
+
114
+ # Pattern for: task "sample_data" => :environment
115
+ content.scan(/task\s+["']([a-zA-Z_][a-zA-Z0-9_]*)["']\s*=>/).each do |match|
116
+ task_names << match[0]
117
+ end
118
+
119
+ # Pattern for: task sample_data: :environment (Ruby 1.9+ syntax)
120
+ content.scan(/task\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*:/).each do |match|
121
+ task_names << match[0]
122
+ end
123
+
124
+ # Pattern for: task(:sample_data)
125
+ content.scan(/task\s*\(\s*:([a-zA-Z_][a-zA-Z0-9_]*)\s*\)/).each do |match|
126
+ task_names << match[0]
127
+ end
128
+
129
+ # Pattern for: desc "..." \n task :name
130
+ content.scan(/desc\s+.*?\n\s*task\s+:([a-zA-Z_][a-zA-Z0-9_]*)/).each do |match|
131
+ task_names << match[0]
132
+ end
133
+ end
134
+
135
+ task_names.uniq
136
+ end
137
+
138
+ def find_task
139
+ task_name = params[:id].gsub('__', ':')
140
+
141
+ # Check if this is one of our allowed tasks (custom tasks + db:seed)
142
+ allowed_tasks = extract_task_names_from_files + ['db:seed']
143
+ return nil unless allowed_tasks.include?(task_name)
144
+
145
+ # Ensure tasks are loaded
146
+ Rails.application.load_tasks
147
+
148
+ # Find the task
149
+ Rake::Task[task_name] rescue nil
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,95 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Web Rake</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <%= csrf_meta_tags %>
7
+ <%= csp_meta_tag %>
8
+
9
+ <style>
10
+ * {
11
+ margin: 0;
12
+ padding: 0;
13
+ box-sizing: border-box;
14
+ }
15
+
16
+ body {
17
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
18
+ line-height: 1.6;
19
+ color: #333;
20
+ background-color: #f5f5f5;
21
+ }
22
+
23
+ .container {
24
+ max-width: 1200px;
25
+ margin: 0 auto;
26
+ padding: 20px;
27
+ }
28
+
29
+ .header {
30
+ background-color: #2c3e50;
31
+ color: white;
32
+ padding: 1rem 0;
33
+ margin-bottom: 2rem;
34
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
35
+ }
36
+
37
+ .header h1 {
38
+ margin: 0;
39
+ font-size: 1.8rem;
40
+ }
41
+
42
+ .header a {
43
+ color: white;
44
+ text-decoration: none;
45
+ }
46
+
47
+ .alert {
48
+ padding: 12px 20px;
49
+ margin-bottom: 20px;
50
+ border-radius: 4px;
51
+ background-color: #f8d7da;
52
+ color: #721c24;
53
+ border: 1px solid #f5c6cb;
54
+ }
55
+
56
+ .notice {
57
+ padding: 12px 20px;
58
+ margin-bottom: 20px;
59
+ border-radius: 4px;
60
+ background-color: #d4edda;
61
+ color: #155724;
62
+ border: 1px solid #c3e6cb;
63
+ }
64
+
65
+ .content {
66
+ background-color: white;
67
+ padding: 30px;
68
+ border-radius: 8px;
69
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
70
+ }
71
+ </style>
72
+ </head>
73
+
74
+ <body>
75
+ <div class="header">
76
+ <div class="container">
77
+ <h1><%= link_to "Web Rake", root_path %></h1>
78
+ </div>
79
+ </div>
80
+
81
+ <div class="container">
82
+ <% if flash[:alert] %>
83
+ <div class="alert"><%= flash[:alert] %></div>
84
+ <% end %>
85
+
86
+ <% if flash[:notice] %>
87
+ <div class="notice"><%= flash[:notice] %></div>
88
+ <% end %>
89
+
90
+ <div class="content">
91
+ <%= yield %>
92
+ </div>
93
+ </div>
94
+ </body>
95
+ </html>
@@ -0,0 +1,193 @@
1
+ <style>
2
+ .execution-header {
3
+ margin-bottom: 30px;
4
+ padding-bottom: 20px;
5
+ border-bottom: 2px solid #dee2e6;
6
+ }
7
+
8
+ .task-title {
9
+ font-size: 1.8rem;
10
+ color: #2c3e50;
11
+ margin-bottom: 10px;
12
+ }
13
+
14
+ .execution-summary {
15
+ display: flex;
16
+ gap: 20px;
17
+ margin-top: 15px;
18
+ }
19
+
20
+ .summary-item {
21
+ display: flex;
22
+ align-items: center;
23
+ gap: 5px;
24
+ }
25
+
26
+ .status-badge {
27
+ padding: 4px 12px;
28
+ border-radius: 4px;
29
+ font-weight: 600;
30
+ font-size: 0.9rem;
31
+ }
32
+
33
+ .status-success {
34
+ background-color: #d4edda;
35
+ color: #155724;
36
+ }
37
+
38
+ .status-error {
39
+ background-color: #f8d7da;
40
+ color: #721c24;
41
+ }
42
+
43
+ .duration-badge {
44
+ background-color: #d1ecf1;
45
+ color: #0c5460;
46
+ padding: 4px 12px;
47
+ border-radius: 4px;
48
+ font-size: 0.9rem;
49
+ }
50
+
51
+ .output-section {
52
+ margin-bottom: 30px;
53
+ }
54
+
55
+ .output-header {
56
+ font-size: 1.2rem;
57
+ color: #495057;
58
+ margin-bottom: 15px;
59
+ display: flex;
60
+ align-items: center;
61
+ gap: 10px;
62
+ }
63
+
64
+ .output-count {
65
+ background-color: #6c757d;
66
+ color: white;
67
+ padding: 2px 8px;
68
+ border-radius: 12px;
69
+ font-size: 0.75rem;
70
+ }
71
+
72
+ .output-box {
73
+ background-color: #f8f9fa;
74
+ border: 1px solid #dee2e6;
75
+ border-radius: 4px;
76
+ padding: 15px;
77
+ font-family: 'Courier New', monospace;
78
+ font-size: 0.9rem;
79
+ line-height: 1.5;
80
+ max-height: 400px;
81
+ overflow-y: auto;
82
+ }
83
+
84
+ .output-line {
85
+ margin-bottom: 4px;
86
+ white-space: pre-wrap;
87
+ word-break: break-all;
88
+ }
89
+
90
+ .error-output {
91
+ background-color: #fff5f5;
92
+ border-color: #feb2b2;
93
+ color: #742a2a;
94
+ }
95
+
96
+ .empty-output {
97
+ color: #6c757d;
98
+ font-style: italic;
99
+ }
100
+
101
+ .actions {
102
+ margin-top: 30px;
103
+ padding-top: 20px;
104
+ border-top: 2px solid #dee2e6;
105
+ display: flex;
106
+ gap: 10px;
107
+ }
108
+
109
+ .btn {
110
+ padding: 10px 20px;
111
+ border-radius: 4px;
112
+ text-decoration: none;
113
+ font-size: 1rem;
114
+ border: none;
115
+ cursor: pointer;
116
+ transition: all 0.3s ease;
117
+ }
118
+
119
+ .btn-primary {
120
+ background-color: #007bff;
121
+ color: white;
122
+ }
123
+
124
+ .btn-primary:hover {
125
+ background-color: #0056b3;
126
+ }
127
+
128
+ .btn-secondary {
129
+ background-color: #6c757d;
130
+ color: white;
131
+ }
132
+
133
+ .btn-secondary:hover {
134
+ background-color: #545b62;
135
+ }
136
+ </style>
137
+
138
+ <div class="execution-header">
139
+ <h2 class="task-title">Task: <%= task.name %></h2>
140
+
141
+ <div class="execution-summary">
142
+ <div class="summary-item">
143
+ <span>Status:</span>
144
+ <span class="status-badge <%= success ? 'status-success' : 'status-error' %>">
145
+ <%= success ? '✓ Success' : '✗ Failed' %>
146
+ </span>
147
+ </div>
148
+
149
+ <div class="summary-item">
150
+ <span>Duration:</span>
151
+ <span class="duration-badge"><%= duration %> seconds</span>
152
+ </div>
153
+ </div>
154
+ </div>
155
+
156
+ <% if output.any? %>
157
+ <div class="output-section">
158
+ <h3 class="output-header">
159
+ Output
160
+ <span class="output-count"><%= output.count %> lines</span>
161
+ </h3>
162
+ <div class="output-box">
163
+ <% output.each do |line| %>
164
+ <div class="output-line"><%= line %></div>
165
+ <% end %>
166
+ </div>
167
+ </div>
168
+ <% else %>
169
+ <div class="output-section">
170
+ <h3 class="output-header">Output</h3>
171
+ <div class="output-box">
172
+ <div class="empty-output">No output generated</div>
173
+ </div>
174
+ </div>
175
+ <% end %>
176
+
177
+ <% if errors.any? %>
178
+ <div class="output-section">
179
+ <h3 class="output-header">
180
+ Errors
181
+ <span class="output-count"><%= errors.count %> lines</span>
182
+ </h3>
183
+ <div class="output-box error-output">
184
+ <% errors.each do |line| %>
185
+ <div class="output-line"><%= line %></div>
186
+ <% end %>
187
+ </div>
188
+ </div>
189
+ <% end %>
190
+
191
+ <div class="actions">
192
+ <%= link_to "Back to Tasks", root_path, class: "btn btn-primary" %>
193
+ </div>
@@ -0,0 +1,109 @@
1
+ <style>
2
+ .tasks-list {
3
+ list-style: none;
4
+ }
5
+
6
+ .task-item {
7
+ padding: 15px;
8
+ margin-bottom: 10px;
9
+ background-color: #f8f9fa;
10
+ border-radius: 4px;
11
+ border: 1px solid #dee2e6;
12
+ transition: all 0.3s ease;
13
+ }
14
+
15
+ .task-item:hover {
16
+ background-color: #e9ecef;
17
+ transform: translateX(5px);
18
+ }
19
+
20
+ .task-header {
21
+ display: flex;
22
+ justify-content: space-between;
23
+ align-items: center;
24
+ margin-bottom: 8px;
25
+ }
26
+
27
+ .task-name {
28
+ font-weight: 600;
29
+ color: #2c3e50;
30
+ font-size: 1.1rem;
31
+ }
32
+
33
+ .task-description {
34
+ color: #6c757d;
35
+ margin-bottom: 10px;
36
+ }
37
+
38
+ .run-button {
39
+ background-color: #28a745;
40
+ color: white;
41
+ border: none;
42
+ padding: 8px 16px;
43
+ border-radius: 4px;
44
+ cursor: pointer;
45
+ font-size: 14px;
46
+ transition: background-color 0.3s ease;
47
+ }
48
+
49
+ .run-button:hover {
50
+ background-color: #218838;
51
+ }
52
+
53
+ .page-header {
54
+ margin-bottom: 30px;
55
+ padding-bottom: 20px;
56
+ border-bottom: 2px solid #dee2e6;
57
+ }
58
+
59
+ .page-title {
60
+ font-size: 2rem;
61
+ color: #2c3e50;
62
+ margin-bottom: 10px;
63
+ }
64
+
65
+ .page-subtitle {
66
+ color: #6c757d;
67
+ }
68
+
69
+ .empty-state {
70
+ text-align: center;
71
+ padding: 60px 20px;
72
+ color: #6c757d;
73
+ }
74
+ </style>
75
+
76
+ <div class="page-header">
77
+ <h2 class="page-title">
78
+ Available Rake Tasks
79
+ </h2>
80
+ <p class="page-subtitle">Click any task to run it. Showing db:seed and custom tasks from lib/tasks/</p>
81
+ </div>
82
+
83
+ <% if @tasks.any? %>
84
+ <ul class="tasks-list">
85
+ <% @tasks.each do |task| %>
86
+ <li class="task-item">
87
+ <div class="task-header">
88
+ <span class="task-name"><%= task.name %></span>
89
+ </div>
90
+
91
+ <% if task.comment.present? %>
92
+ <div class="task-description"><%= task.comment %></div>
93
+ <% end %>
94
+
95
+ <%= form_with url: execute_task_path(id: task.name.gsub(':', '__')),
96
+ method: :post,
97
+ local: true do |form| %>
98
+ <%= form.submit "Run Task", class: "run-button" %>
99
+ <% end %>
100
+ </li>
101
+ <% end %>
102
+ </ul>
103
+ <% else %>
104
+ <div class="empty-state">
105
+ <h3>No Custom Rake Tasks Found</h3>
106
+ <p>No rake tasks were found in your lib/tasks/ directory.</p>
107
+ <p>Create a .rake file in lib/tasks/ with tasks that depend on :environment.</p>
108
+ </div>
109
+ <% end %>
data/config/routes.rb ADDED
@@ -0,0 +1,6 @@
1
+ WebRake::Engine.routes.draw do
2
+ root to: 'tasks#index'
3
+
4
+ get '/:id', to: 'tasks#show', as: :task
5
+ post '/:id/execute', to: 'tasks#execute', as: :execute_task
6
+ end
@@ -0,0 +1,16 @@
1
+ module WebRake
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace WebRake
4
+
5
+ initializer 'web_rake.mount_routes' do |app|
6
+ app.routes.append do
7
+ mount WebRake::Engine, at: '/rails/tasks'
8
+ end
9
+ end
10
+
11
+ initializer 'web_rake.configure_credentials' do |app|
12
+ WebRake.username = ENV.fetch('WEB_RAKE_USERNAME', 'admin')
13
+ WebRake.password = ENV.fetch('WEB_RAKE_PASSWORD', 'password')
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ module WebRake
2
+ VERSION = '0.1.0'
3
+ end
data/lib/web_rake.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'web_rake/version'
2
+ require 'web_rake/engine'
3
+
4
+ module WebRake
5
+ mattr_accessor :username
6
+ mattr_accessor :password
7
+
8
+ def self.configure
9
+ yield self
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: web_rake
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ben Purinton
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2025-09-15 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rails
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 7.0.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 7.0.0
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec-rails
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: sqlite3
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ description: A Rails engine that provides a web interface for discovering and running
55
+ Rake tasks with HTTP basic authentication
56
+ email:
57
+ - ben@firstdraft.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - MIT-LICENSE
63
+ - README.md
64
+ - Rakefile
65
+ - app/controllers/web_rake/application_controller.rb
66
+ - app/controllers/web_rake/tasks_controller.rb
67
+ - app/views/layouts/web_rake/application.html.erb
68
+ - app/views/web_rake/tasks/execute.html.erb
69
+ - app/views/web_rake/tasks/index.html.erb
70
+ - config/routes.rb
71
+ - lib/web_rake.rb
72
+ - lib/web_rake/engine.rb
73
+ - lib/web_rake/version.rb
74
+ homepage: https://github.com/firstdraft/web_rake
75
+ licenses:
76
+ - MIT
77
+ metadata:
78
+ homepage_uri: https://github.com/firstdraft/web_rake
79
+ source_code_uri: https://github.com/firstdraft/web_rake
80
+ changelog_uri: https://github.com/firstdraft/web_rake/blob/main/CHANGELOG.md
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 2.7.0
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubygems_version: 3.6.5
96
+ specification_version: 4
97
+ summary: Web interface for running Rake tasks
98
+ test_files: []