appengine 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4841b00bed08c35d62dfd337ccd15cf5df775de9
4
- data.tar.gz: a3158e01aaccb61471b504d7a66983c24a58a560
3
+ metadata.gz: 06eae82181654cc6c73ea33d6fda3c5cc5f2469a
4
+ data.tar.gz: 33c1eae652eb721b503eb848e7e6034f0843c279
5
5
  SHA512:
6
- metadata.gz: 27445f16fa0d99b081992a8ea08427730dc4375b05f7a083763c5e6f9ee338652a6e8798eb47bc5293e51d9a4a22fe3c79322ca934284973826c3f7f6faf5741
7
- data.tar.gz: 734a601f646ee785f5af7f9cbdf77af271a6e2bc25ae80abeaad0a8c92a26562462d2be953fa981ea4a04b48b1646c316dc08022658ad4d954e755dc5fb48406
6
+ metadata.gz: e8fe8e5431795a42492b08e7b86d61a5c9e3d21d2aa28625a1928da674fad328ba3e080ff4c7f2df87e54b0621c51ab797d44d4f0f10c9e327e7122a443a3ea3
7
+ data.tar.gz: 67586c5fae41dbbe9ca43dca1dfc9c59f8dc5f5b6e447902826b47c0b5313f339852e07c26f234f3dca19213c595e6bf663048c72ad7896d2e3921c4c8e14b39
@@ -2,6 +2,19 @@
2
2
 
3
3
  This is the change history for the appengine gem.
4
4
 
5
+ ## v0.4.0 (2017-07-17)
6
+
7
+ * Provided rake tasks to access App Engine remote execution.
8
+ * Reimplemented AppEngine::Env as an alias to the google-cloud-env gem's
9
+ functionality.
10
+
11
+ ## v0.3.0 (2017-02-28)
12
+
13
+ * Replaced logger integration with a dependency on the stackdriver gem,
14
+ which supersedes it.
15
+ * Stubbed out the env class in preparation to change it to a dependency
16
+ on the upcoming google-cloud-env gem.
17
+
5
18
  ## v0.2.0 (2016-05-04)
6
19
 
7
20
  * Tools for integration with the Google Cloud Console logger, including
data/README.md CHANGED
@@ -4,18 +4,23 @@ Google App Engine Integration Tools
4
4
  This repository contains the "appengine" gem, a collection of libraries and
5
5
  plugins for integrating Ruby apps with Google App Engine. It is not required
6
6
  for deploying a ruby application to Google App Engine, but it provides a
7
- number of convenience hooks for better integrating into the App Engine
7
+ number of convenience hooks and tools for integrating into the App Engine
8
8
  environment.
9
9
 
10
10
  Currently, it includes:
11
11
 
12
12
  * Automatic Stackdriver instrumentation for Rails apps. This means logs,
13
- error reports, and latency traces are reported to the cloud console.
14
- * A placeholder for a class that provides app engine environment information
15
- such as project ID and VM info.
13
+ error reports, and latency traces are reported to the cloud console,
14
+ and debugger integration is available.
15
+ * A client and rake tasks for executing application commands in the App
16
+ Engine environment against production resources, useful for tasks such as
17
+ running production database migrations.
18
+ * Convenient access to environment information such as project ID and VM
19
+ properties.
16
20
 
17
21
  Planned for the near future:
18
22
 
23
+ * Tools for generating "app.yaml" configuration files for Ruby applications.
19
24
  * Streamlined implementation of health checks and other lifecycle hooks.
20
25
 
21
26
  For more information on using Google Cloud Platform to deploy Ruby apps,
@@ -36,6 +41,9 @@ may need to include the line:
36
41
  in your `config/application.rb` file if you aren't already requiring all
37
42
  bundled gems.
38
43
 
44
+ If you are running a different web framework, you may need to add some
45
+ initialization code to activate the features listed below.
46
+
39
47
  ## Logging and monitoring
40
48
 
41
49
  This library automatically installs the "stackdriver" gem, which instruments
@@ -47,6 +55,37 @@ monitoring features of Google App Engine, see:
47
55
  * [google-cloud-error_reporting instrumentation](http://googlecloudplatform.github.io/google-cloud-ruby/#/docs/google-cloud-error_reporting/latest/guides/instrumentation)
48
56
  * [google-cloud-trace instrumentation](http://googlecloudplatform.github.io/google-cloud-ruby/#/docs/google-cloud-trace/latest/guides/instrumentation)
49
57
 
58
+ Rails applications automatically activate this instrumentation when the gem
59
+ is present. You may opt out of individual services by providing appropriate
60
+ Rails configuration. See {AppEngine::Railtie} for more information.
61
+
62
+ Non-Rails applications must provide initialization code to activate this
63
+ instrumentation, typically by installing a Rack middleware. See the individual
64
+ service documentation links above for more information.
65
+
66
+ ## App Engine remote execution
67
+
68
+ This library provides rake tasks for App Engine remote execution, allowing
69
+ App Engine applications to perform on-demand tasks in the App Engine
70
+ environment. This may be used for safe running of ops and maintenance tasks,
71
+ such as database migrations, that access production cloud resources. For
72
+ example, you could run a production database migration in a Rails app using:
73
+
74
+ bundle exec rake appengine:exec -- bundle exec rake db:migrate
75
+
76
+ The migration would be run in VMs provided by Google Cloud. It uses a
77
+ privileged service account that will have access to the production cloud
78
+ resources, such as Cloud SQL instances, used by the application. This mechanism
79
+ is often much easier and safer than running the task on a local workstation and
80
+ granting that workstation direct access to those Cloud SQL instances.
81
+
82
+ See {AppEngine::Exec} for more information on App Engine remote execution.
83
+
84
+ See {AppEngine::Tasks} for more information on running the rake tasks. The
85
+ tasks are available automatically in Rails applications when the gem is
86
+ present. Non-Rails applications may install the tasks by adding the line
87
+ `require "appengine/tasks"` to the `Rakefile`.
88
+
50
89
  ## Development and support
51
90
 
52
91
  The source code for this gem is available on Github at
data/Rakefile CHANGED
@@ -33,4 +33,10 @@ end
33
33
  rd.options << '--all'
34
34
  end
35
35
 
36
+ require "yard"
37
+ require "yard/rake/yardoc_task"
38
+ YARD::Rake::YardocTask.new
39
+
40
+ load "lib/appengine/tasks.rb"
41
+
36
42
  task :default => [:test]
@@ -13,7 +13,7 @@
13
13
  # limitations under the License.
14
14
  ;
15
15
 
16
- # == Google AppEngine integration
16
+ # # Google AppEngine integration
17
17
  #
18
18
  # The AppEngine module includes optional tools helping Ruby applications to
19
19
  # integrate more closely with the Google App Engine environment.
@@ -22,8 +22,9 @@ module AppEngine
22
22
  end
23
23
 
24
24
 
25
- require 'appengine/version'
26
- require 'appengine/env'
27
- require 'appengine/railtie' if defined?(::Rails)
25
+ require "appengine/version"
26
+ require "appengine/env"
27
+ require "appengine/exec"
28
+ require "appengine/railtie" if defined? ::Rails
28
29
 
29
30
  require "stackdriver"
@@ -13,18 +13,26 @@
13
13
  # limitations under the License.
14
14
  ;
15
15
 
16
+ require "google/cloud/env"
17
+
16
18
 
17
19
  module AppEngine
18
20
 
19
21
  ##
20
- # A collection of functions for extracting App Engine environment information.
22
+ # A convenience object that provides information on the Google Cloud
23
+ # hosting environment. For example, you can call
21
24
  #
22
- module Env
23
-
24
- def self.app_engine?
25
- ::ENV["GAE_INSTANCE"] ? true : false
26
- end
27
-
28
- end
25
+ # if AppEngine::Env.app_engine?
26
+ # # Do something
27
+ # end
28
+ #
29
+ # Technically, `Env` is not actually a module, but is simply set to the
30
+ # `Google::Cloud.env` object.
31
+ #
32
+ # This is provided mostly for backward compatibility with previous usage, and
33
+ # is mildly deprecated. Generally, you should call `Google::Cloud.env`
34
+ # directly instead. See the documentation for the `google-cloud-env` gem.
35
+ #
36
+ Env = ::Google::Cloud.env
29
37
 
30
38
  end
@@ -0,0 +1,421 @@
1
+ # Copyright 2017 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ ;
15
+
16
+ require "yaml"
17
+ require "json"
18
+
19
+ require "appengine/util/gcloud"
20
+
21
+
22
+ module AppEngine
23
+
24
+ ##
25
+ # # App Engine remote execution
26
+ #
27
+ # This class provides a client for App Engine remote execution, allowing
28
+ # App Engine applications to perform on-demand tasks in the App Engine
29
+ # environment. This may be used for safe running of ops and maintenance
30
+ # tasks, such as database migrations, that access production cloud resources.
31
+ #
32
+ # ## About App Engine execution
33
+ #
34
+ # App Engine execution spins up an image of a deployed App Engine app, and
35
+ # runs a command in that image. For example, if your app runs on Ruby on
36
+ # Rails, then your app provides a `bin/rails` tool, and you may invoke it
37
+ # using App Engine execution---for example to run a command such as
38
+ # `bundle exec bin/rails db:migrate` in the image.
39
+ #
40
+ # When App Engine execution runs your command, it provides access to key
41
+ # elements of the App Engine environment, including:
42
+ # * The same runtime that runs your application in App Engine itself.
43
+ # * Any Cloud SQL connections requested by your application.
44
+ # * Any environment variables set by your application.
45
+ #
46
+ # The command runs on virtual machines provided by Google Cloud Container
47
+ # Builder, and has access to the credentials of the Cloud Container Builder
48
+ # service account.
49
+ #
50
+ # ## Prerequisites
51
+ #
52
+ # To use App Engine remote execution, you will need:
53
+ #
54
+ # * An app deployed to Google App Engine, of course!
55
+ # * The gcloud SDK installed and configured. See https://cloud.google.com/sdk/
56
+ # * The `appengine` gem.
57
+ #
58
+ # You may also need to grant the Cloud Container Builder service account
59
+ # any permissions needed by your command. Often, Project Editor permissions
60
+ # will be sufficient for most tasks. You can find the service account
61
+ # configuration in the IAM tab in the Cloud Console under the name
62
+ # `[your-project-number]@cloudbuild.gserviceaccount.com`.
63
+ #
64
+ # You may use the `AppEngine::Exec` class to run commands directly. However,
65
+ # in most cases, it will be easier to run commands via the provided rake
66
+ # tasks. See {AppEngine::Tasks} for more info.
67
+ #
68
+ # ## Configuring
69
+ #
70
+ # This class uses three parameters to specify which application image to use
71
+ # to run your command: `service`, `config_path`, and `version`.
72
+ #
73
+ # In most cases, you can use the defaults. The Exec class will look in your
74
+ # current directory for a file called `./app.yaml` which describes your App
75
+ # Engine service. It gets the service name from this file (or uses the
76
+ # "default" name if none is specified), then looks up the most recently
77
+ # created deployment version for that service. That deployment version then
78
+ # provides the application image that runs your command.
79
+ #
80
+ # If your app has multiple services, you may specify which config file
81
+ # (other than `./app.yaml`) describes the desired service, by providing the
82
+ # `config_path` parameter. Alternately, you may specify a service name
83
+ # directly by providing the `service` parameter. If you provide both
84
+ # parameters, `service` takes precedence.
85
+ #
86
+ # Usually, App Engine execution uses the image for the most recently created
87
+ # version of the service. (Note: the most recently created version is used,
88
+ # regardless of whether that version is currently receiving traffic.) If you
89
+ # want to use the image for a different version, you may specify a version
90
+ # by providing the `version` parameter.
91
+ #
92
+ # You may also provide a timeout, which is the length of time that App
93
+ # Engine execution will allow your command to run before it is considered to
94
+ # have stalled and is terminated. The timeout should be a string of the form
95
+ # `2h15m10s`. The default is `10m`.
96
+ #
97
+ # ## Resource usage and billing
98
+ #
99
+ # App Engine remote execution uses virtual machine resources provided by
100
+ # Google Cloud Container Builder. Generally, a certain number of usage
101
+ # minutes per day is covered under a free tier, but additional compute usage
102
+ # beyond that time is billed to your Google Cloud account. For more details,
103
+ # see https://cloud.google.com/container-builder/pricing
104
+ #
105
+ # If your command makes API calls or utilizes other cloud resources, you may
106
+ # also be billed for that usage. However, remote execution does not use
107
+ # actual App Engine instances, and you will not be billed for additional App
108
+ # Engine instance usage.
109
+ #
110
+ class Exec
111
+
112
+ @default_timeout = "10m".freeze
113
+ @default_service = "default".freeze
114
+ @default_config_path = "./app.yaml".freeze
115
+ @default_wrapper_image = "gcr.io/google-appengine/exec-wrapper".freeze
116
+
117
+
118
+ ##
119
+ # Base class for exec-related usage errors.
120
+ #
121
+ class UsageError < ::StandardError
122
+ end
123
+
124
+
125
+ ##
126
+ # Exception raised when the App Engine config file could not be found.
127
+ #
128
+ class ConfigFileNotFound < UsageError
129
+ def initialize config_path
130
+ @config_path = config_path
131
+ super "Config file #{config_path} not found."
132
+ end
133
+ attr_reader :config_path
134
+ end
135
+
136
+ ##
137
+ # Exception raised when the App Engine config file could not be parsed.
138
+ #
139
+ class BadConfigFileFormat < UsageError
140
+ def initialize config_path
141
+ @config_path = config_path
142
+ super "Config file #{config_path} malformed."
143
+ end
144
+ attr_reader :config_path
145
+ end
146
+
147
+ ##
148
+ # Exception raised when the given version could not be found, or no
149
+ # versions at all could be found for the given service.
150
+ #
151
+ class NoSuchVersion < UsageError
152
+ def initialize service, version=nil
153
+ @service = service
154
+ @version = version
155
+ if version
156
+ super "No such version \"#{version}\" for service \"#{service}\""
157
+ else
158
+ super "No versions found for service \"#{service}\""
159
+ end
160
+ end
161
+ attr_reader :service
162
+ attr_reader :version
163
+ end
164
+
165
+ ##
166
+ # Exception raised when an explicitly-specified service name conflicts with
167
+ # a config-specified service name.
168
+ #
169
+ class ServiceNameConflict < UsageError
170
+ def initialize service_name, config_name, config_path
171
+ @service_name = service_name
172
+ @config_name = config_name
173
+ @config_path = config_path
174
+ super "Service name conflicts with config file"
175
+ end
176
+ attr_reader :service_name
177
+ attr_reader :config_name
178
+ attr_reader :config_path
179
+ end
180
+
181
+
182
+ class << self
183
+
184
+ ## @return [String] Default command timeout.
185
+ attr_accessor :default_timeout
186
+
187
+ ## @return [String] Default service name if the config doesn't specify.
188
+ attr_accessor :default_service
189
+
190
+ ## @return [String] Path to default config file.
191
+ attr_accessor :default_config_path
192
+
193
+ ## @return [String] Docker image that implements the app engine wrapper.
194
+ attr_accessor :default_wrapper_image
195
+
196
+ ##
197
+ # Create an execution for a rake task.
198
+ #
199
+ # @param name [String] Name of the task
200
+ # @param args [Array<String>] Args to pass to the task
201
+ # @param env_args [Array<String>] Environment variable settings, each
202
+ # of the form `NAME=value`.
203
+ # @param service [String,nil] Name of the service. If omitted, obtains
204
+ # the service name from the config file.
205
+ # @param config_path [String,nil] App Engine config file to get the
206
+ # service name from if the service name is not provided directly.
207
+ # Defaults to the value of `AppEngine::Exec.default_config_path`.
208
+ # @param version [String,nil] Version string. Defaults to the most
209
+ # recently created version of the given service (which may not be the
210
+ # one currently receiving traffic).
211
+ # @param timeout [String,nil] Timeout string. Defaults to the value of
212
+ # `AppEngine::Exec.default_timeout`.
213
+ #
214
+ def new_rake_task name, args: [], env_args: [],
215
+ service: nil, config_path: nil, version: nil,
216
+ timeout: nil
217
+ escaped_args = args.map{ |arg|
218
+ arg.gsub(/[,\[\]]/){ |m| "\\#{m}" }
219
+ }
220
+ if escaped_args.empty?
221
+ name_with_args = name
222
+ else
223
+ name_with_args = "#{name}[#{escaped_args.join ','}]"
224
+ end
225
+ new ["bundle", "exec", "rake", name_with_args] + env_args,
226
+ service: service, config_path: config_path, version: version,
227
+ timeout: timeout
228
+ end
229
+
230
+ end
231
+
232
+
233
+ ##
234
+ # Create an execution for the given command.
235
+ #
236
+ # @param command [Array<String>] The command in array form.
237
+ # @param service [String,nil] Name of the service. If omitted, obtains
238
+ # the service name from the config file.
239
+ # @param config_path [String,nil] App Engine config file to get the
240
+ # service name from if the service name is not provided directly.
241
+ # Defaults to the value of `AppEngine::Exec.default_config_path`.
242
+ # @param version [String,nil] Version string. Defaults to the most
243
+ # recently created version of the given service (which may not be the
244
+ # one currently receiving traffic).
245
+ # @param timeout [String,nil] Timeout string. Defaults to the value of
246
+ # `AppEngine::Exec.default_timeout`.
247
+ #
248
+ def initialize command,
249
+ service: nil, config_path: nil, version: nil, timeout: nil
250
+ @command = command
251
+ @service = service
252
+ @config_path = config_path
253
+ @version = version
254
+ @timeout = timeout
255
+ @wrapper_image = nil
256
+
257
+ yield self if block_given?
258
+ end
259
+
260
+
261
+ ## @return [String,nil] The service name, or nil to read from the config.
262
+ attr_accessor :service
263
+
264
+ ## @return [String,nil] Path to the config file, or nil to use the default.
265
+ attr_accessor :config_path
266
+
267
+ ## @return [String,nil] Service version, or nil to use the most recent.
268
+ attr_accessor :version
269
+
270
+ ## @return [String,nil] Command timeout, or nil to use the default.
271
+ attr_accessor :timeout
272
+
273
+ ## @return [String,Array<String>] Command to run.
274
+ attr_accessor :command
275
+
276
+ ## @return [String] Custom wrapper image to use, or nil to use the default.
277
+ attr_accessor :wrapper_image
278
+
279
+
280
+ ##
281
+ # Executes the command synchronously. Streams the logs back to standard out
282
+ # and does not return until the command has completed or timed out.
283
+ #
284
+ def start
285
+ resolve_parameters
286
+
287
+ version_info = version_info @service, @version
288
+ env_variables = version_info["envVariables"] || {}
289
+ beta_settings = version_info["betaSettings"] || {}
290
+ cloud_sql_instances = beta_settings["cloud_sql_instances"] || []
291
+ image = version_info["deployment"]["container"]["image"]
292
+
293
+ config = build_config command, image, env_variables, cloud_sql_instances
294
+ file = ::Tempfile.new ["cloudbuild_", ".json"]
295
+ begin
296
+ ::JSON.dump config, file
297
+ file.flush
298
+ Util::Gcloud.execute [
299
+ "container", "builds", "submit",
300
+ "--no-source",
301
+ "--config=#{file.path}",
302
+ "--timeout=#{@timeout}"]
303
+ ensure
304
+ file.close!
305
+ end
306
+ end
307
+
308
+
309
+ private
310
+
311
+ ##
312
+ # @private
313
+ # Resolves and canonicalizes all the parameters.
314
+ #
315
+ def resolve_parameters
316
+ unless @command.is_a? Array
317
+ @command = ::Shellwords.parse @command.to_s
318
+ end
319
+
320
+ config_service = config_path = nil
321
+ if @config_path || !@service
322
+ config_service = begin
323
+ config_path = @config_path || Exec.default_config_path
324
+ ::YAML.load_file(config_path)["service"] || Exec.default_service
325
+ rescue ::Errno::ENOENT
326
+ raise ConfigFileNotFound.new config_path
327
+ rescue
328
+ raise BadConfigFileFormat.new config_path
329
+ end
330
+ end
331
+ if @service && config_service && @service != config_service
332
+ raise ServiceNameConflict.new @service, config_service, config_path
333
+ end
334
+
335
+ @service ||= config_service
336
+ @version ||= latest_version @service
337
+ @timeout ||= Exec.default_timeout
338
+ @wrapper_image ||= Exec.default_wrapper_image
339
+ end
340
+
341
+ ##
342
+ # @private
343
+ # Builds a cloudbuild config as a data structure.
344
+ #
345
+ # @param command [Array<String>] The command in array form.
346
+ # @param image [String] The fully qualified image path.
347
+ # @param env_variables[Hash<String,String>] Environment variables.
348
+ # @param cloud_sql_instances[String,Array<String>] Names of cloud sql
349
+ # instances to connect to.
350
+ #
351
+ def build_config command, image, env_variables, cloud_sql_instances
352
+ args = ["-i", image]
353
+ env_variables.each do |k, v|
354
+ args << "-e" << "#{k}=#{v}"
355
+ end
356
+ unless cloud_sql_instances.empty?
357
+ cloud_sql_instances = Array(cloud_sql_instances)
358
+ cloud_sql_instances.each do |sql|
359
+ args << "-s" << sql
360
+ end
361
+ end
362
+ args << "--"
363
+ args += command
364
+
365
+ {
366
+ "steps" => [
367
+ "name" => @wrapper_image,
368
+ "args" => args
369
+ ]
370
+ }
371
+ end
372
+
373
+ ##
374
+ # @private
375
+ # Returns the name of the most recently created version of the given
376
+ # service.
377
+ #
378
+ # @param service [String] Name of the service.
379
+ # @return [String] Name of the most recent version.
380
+ #
381
+ def latest_version service
382
+ result = Util::Gcloud.execute [
383
+ "app", "versions", "list",
384
+ "--service=#{service}",
385
+ "--format=get(version.id)",
386
+ "--sort-by=~version.createTime",
387
+ "--limit=1"],
388
+ capture: true, assert: false
389
+ result = result.split.first
390
+ raise NoSuchVersion.new(service) unless result
391
+ result
392
+ end
393
+
394
+ ##
395
+ # @private
396
+ # Returns full information on the given version of the given service.
397
+ #
398
+ # @param service [String] Name of the service. If omitted, the service
399
+ # "default" is used.
400
+ # @param version [String] Name of the version. If omitted, the most
401
+ # recently deployed is used.
402
+ # @return [Hash,nil] A collection of fields parsed from the JSON
403
+ # representation of the version, or nil if the requested version
404
+ # doesn't exist.
405
+ #
406
+ def version_info service, version
407
+ service ||= "default"
408
+ version ||= latest_version service
409
+ result = Util::Gcloud.execute [
410
+ "app", "versions", "describe", version,
411
+ "--service=#{service}",
412
+ "--format=json"],
413
+ capture: true, assert: false
414
+ result.strip!
415
+ raise NoSuchVersion.new(service, version) if result.empty?
416
+ ::JSON.parse result
417
+ end
418
+
419
+ end
420
+
421
+ end
@@ -13,35 +13,77 @@
13
13
  # limitations under the License.
14
14
  ;
15
15
 
16
- require 'fileutils'
17
-
18
16
 
19
17
  module AppEngine
20
18
 
21
-
22
- # == AppEngine Rails integration
19
+ ##
20
+ # # AppEngine Rails integration
23
21
  #
24
22
  # A Railtie providing Rails integration with the Google App Engine runtime
25
- # environment. Sets up the Rails logger to log to the Google Cloud Console
26
- # in production.
23
+ # environment.
24
+ #
25
+ # Specifically:
26
+ #
27
+ # * It installs the Stackdriver instrumentation, providing application
28
+ # diagnostics to the project's Stackdriver account.
29
+ # * It installs the rake tasks, providing the ability to execute commands
30
+ # on demand in the production App Engine environment.
27
31
  #
28
32
  # To use, just include the "appengine" gem in your gemfile, and make sure
29
33
  # it is required in your config/application.rb (if you are not already
30
34
  # using Bundler.require).
31
35
  #
32
- # === Configuration
36
+ # ## Configuration
37
+ #
38
+ # You may selectively deactivate features of this Railtie using Rails
39
+ # configuration keys. For example, to disable rake tasks, include the
40
+ # following line in one of your Rails configuration files:
41
+ #
42
+ # config.appengine.define_tasks = false
43
+ #
44
+ # The following configuration keys are supported. Additional keys specific
45
+ # to the various Stackdriver services may be defined in the individual
46
+ # libraries.
47
+ #
48
+ # ### appengine.define_tasks
49
+ #
50
+ # Causes rake tasks to be added to the application. Default is true. Set it
51
+ # to false to disable App Engine rake tasks.
52
+ #
53
+ # ### google_cloud.use_logging
54
+ #
55
+ # Activates Stackdriver Logging, collecting Rails logs so they appear on
56
+ # the Google Cloud console. Default is true. Set it to false to disable
57
+ # logging instrumentation.
58
+ #
59
+ # ### google_cloud.use_error_reporting
60
+ #
61
+ # Activates Stackdriver Error Reporting, collecting exceptions so they appear
62
+ # on the Google Cloud console. Default is true. Set it to false to disable
63
+ # error instrumentation.
64
+ #
65
+ # ### google_cloud.use_trace
66
+ #
67
+ # Activates Stackdriver Trace instrumentation, collecting application latency
68
+ # trace data so it appears on the Google Cloud conosle. Default is true. Set
69
+ # it to false to disable trace instrumentation.
70
+ #
71
+ # ### google_cloud.use_debugger
72
+ #
73
+ # Enables the Stackdriver Debugger. Default is true. Set it to false to
74
+ # disable debugging.
33
75
  #
34
- # This is a placeholder for now.
35
-
36
76
  class Railtie < ::Rails::Railtie
37
77
 
38
- # :stopdoc:
39
-
40
78
  config.appengine = ::ActiveSupport::OrderedOptions.new
79
+ config.appengine.define_tasks = true
41
80
 
42
- # :startdoc:
81
+ rake_tasks do |app|
82
+ if app.config.appengine.define_tasks
83
+ require "appengine/tasks"
84
+ end
85
+ end
43
86
 
44
87
  end
45
88
 
46
-
47
89
  end
@@ -0,0 +1,308 @@
1
+ # Copyright 2017 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ ;
15
+
16
+ # This file should be loaded or required from a Rakefile to define AppEngine
17
+ # related tasks.
18
+
19
+ require "shellwords"
20
+
21
+ require "appengine/util/gcloud"
22
+ require "appengine/exec"
23
+
24
+
25
+ module AppEngine
26
+
27
+ ##
28
+ # # App Engine Rake Tasks.
29
+ #
30
+ # To make these tasks available, add the line `require "appengine/tasks"`
31
+ # to your Rakefile. If your app uses Ruby on Rails, then the appengine gem
32
+ # provides a railtie that adds its tasks automatically, so you don't have
33
+ # to do anything beyond adding the gem to your Gemfile.
34
+ #
35
+ # The following tasks are defined:
36
+ #
37
+ # ## Rake appengine:exec
38
+ #
39
+ # Executes a given command in the context of an App Engine application, using
40
+ # App Engine remote execution. See {AppEngine::Exec} for more information on
41
+ # this capability.
42
+ #
43
+ # The command to be run may either be provided as a rake argument, or as
44
+ # command line arguments, delimited by two dashes `--`. (The dashes are
45
+ # needed to separate your command from rake arguments and flags.)
46
+ # For example, to run a production database migration, you can run either of
47
+ # the following equivalent commands:
48
+ #
49
+ # bundle exec rake "appengine:exec[bundle exec bin/rails db:migrate]"
50
+ # bundle exec rake appengine:exec -- bundle exec bin/rails db:migrate
51
+ #
52
+ # To display usage instructions, provide two dashes but no command:
53
+ #
54
+ # bundle exec rake appengine:exec --
55
+ #
56
+ # ### Parameters
57
+ #
58
+ # You may customize the behavior of App Engine execution through a few
59
+ # enviroment variable parameters. These are set via the normal mechanism at
60
+ # the end of a rake command line. For example, to set GAE_CONFIG:
61
+ #
62
+ # bundle exec rake appengine:exec GAE_CONFIG=myservice.yaml -- bundle exec bin/rails db:migrate
63
+ #
64
+ # Be sure to set these parameters before the double dash. Any arguments
65
+ # following the double dash are interpreted as part of the command itself.
66
+ #
67
+ # The following environment variable parameters are supported:
68
+ #
69
+ # #### GAE_CONFIG
70
+ #
71
+ # Path to the App Engine config file, used when your app has multiple
72
+ # services, or the config file is otherwise not called `./app.yaml`. The
73
+ # config file is used to determine the name of the App Engine service.
74
+ #
75
+ # #### GAE_SERVICE
76
+ #
77
+ # Name of the service to be used. If both `GAE_CONFIG` and `GAE_SERVICE` are
78
+ # provided and imply different service names, an error will be raised.
79
+ #
80
+ # #### GAE_VERSION
81
+ #
82
+ # The version of the service, used to identify which application image to
83
+ # use to run your command. If not specified, uses the most recently created
84
+ # version, regardless of whether that version is actually serving traffic.
85
+ #
86
+ # #### GAE_TIMEOUT
87
+ #
88
+ # Amount of time to wait before appengine:exec terminates the command.
89
+ # Expressed as a string formatted like: "2h15m10s". Default is "10m".
90
+ #
91
+ module Tasks
92
+
93
+ ## @private
94
+ CONFIG_ENV = "GAE_CONFIG"
95
+ ## @private
96
+ SERVICE_ENV = "GAE_SERVICE"
97
+ ## @private
98
+ VERSION_ENV = "GAE_VERSION"
99
+ ## @private
100
+ TIMEOUT_ENV = "GAE_TIMEOUT"
101
+
102
+ @defined = false
103
+
104
+ class << self
105
+
106
+ ##
107
+ # @private
108
+ # Define rake tasks.
109
+ #
110
+ def define
111
+ if @defined
112
+ puts "AppEngine rake tasks already defined."
113
+ return
114
+ end
115
+ @defined = true
116
+
117
+ setup_exec_task
118
+ end
119
+
120
+ private
121
+
122
+ def setup_exec_task
123
+ ::Rake.application.last_description =
124
+ "Execute the given command in Google App Engine."
125
+ ::Rake::Task.define_task "appengine:exec", [:cmd] do |t, args|
126
+ verify_gcloud_and_report_errors
127
+ if args[:cmd]
128
+ command = ::Shellwords.split args[:cmd]
129
+ else
130
+ i = (::ARGV.index{ |a| a.to_s == "--" } || -1) + 1
131
+ if i == 0
132
+ report_error <<~MESSAGE
133
+ No command provided for appengine:exec.
134
+ Did you remember to delimit it with two dashes? e.g.
135
+ bundle exec rake appengine:exec -- bundle exec ruby myscript.rb
136
+ For detailed usage instructions, provide two dashes but no command:
137
+ bundle exec rake appengine:exec --
138
+ MESSAGE
139
+ end
140
+ command = ::ARGV[i..-1]
141
+ if command.empty?
142
+ show_usage
143
+ exit
144
+ end
145
+ end
146
+ app_exec = Exec.new \
147
+ command,
148
+ service: ::ENV[SERVICE_ENV],
149
+ config_path: ::ENV[CONFIG_ENV],
150
+ version: ::ENV[VERSION_ENV],
151
+ timeout: ::ENV[TIMEOUT_ENV]
152
+ start_and_report_errors app_exec
153
+ exit
154
+ end
155
+ end
156
+
157
+ def show_usage
158
+ puts <<~USAGE
159
+ rake appengine:exec
160
+
161
+ This Rake task executes a given command in the context of an App Engine
162
+ application, using App Engine remote execution. For more information,
163
+ on this capability, see the AppEngine::Exec documentation at
164
+ http://www.rubydoc.info/gems/appengine/AppEngine/Exec
165
+
166
+ The command to be run may either be provided as a rake argument, or as
167
+ command line arguments delimited by two dashes `--`. (The dashes are
168
+ needed to separate your command from rake arguments and flags.)
169
+ For example, to run a production database migration, you can run either
170
+ of the following equivalent commands:
171
+
172
+ bundle exec rake "appengine:exec[bundle exec bin/rails db:migrate]"
173
+ bundle exec rake appengine:exec -- bundle exec bin/rails db:migrate
174
+
175
+ To display these usage instructions, provide two dashes but no command:
176
+
177
+ bundle exec rake appengine:exec --
178
+
179
+ You may customize the behavior of App Engine execution through a few
180
+ enviroment variable parameters. These are set via the normal mechanism at
181
+ the end of a rake command line. For example, to set GAE_CONFIG:
182
+
183
+ bundle exec rake appengine:exec GAE_CONFIG=myservice.yaml -- bundle exec bin/rails db:migrate
184
+
185
+ Be sure to set these parameters before the double dash. Any arguments
186
+ following the double dash are interpreted as part of the command itself.
187
+
188
+ The following environment variable parameters are supported:
189
+
190
+ GAE_CONFIG
191
+
192
+ Path to the App Engine config file, used when your app has multiple
193
+ services, or the config file is otherwise not called `./app.yaml`. The
194
+ config file is used to determine the name of the App Engine service.
195
+
196
+ GAE_SERVICE
197
+
198
+ Name of the service to be used. If both `GAE_CONFIG` and `GAE_SERVICE`
199
+ are provided and imply different service names, an error will be raised.
200
+
201
+ GAE_VERSION
202
+
203
+ The version of the service, used to identify which application image to
204
+ use to run your command. If not specified, uses the most recently created
205
+ version, regardless of whether that version is actually serving traffic.
206
+
207
+ GAE_TIMEOUT
208
+
209
+ Amount of time to wait before appengine:exec terminates the command.
210
+ Expressed as a string formatted like: "2h15m10s". Default is "10m".
211
+
212
+ This rake task is provided by the "appengine" gem. To make these tasks
213
+ available, add the following line to your Rakefile:
214
+
215
+ require "appengine/tasks"
216
+
217
+ If your app uses Ruby on Rails, the gem provides a railtie that adds its
218
+ tasks automatically, so you don't have to do anything beyond adding the
219
+ gem to your Gemfile.
220
+
221
+ For more information or to report issues, visit the Github page:
222
+ https://github.com/GoogleCloudPlatform/appengine-ruby
223
+ USAGE
224
+ end
225
+
226
+ def verify_gcloud_and_report_errors
227
+ Util::Gcloud.verify!
228
+ rescue Gcloud::BinaryNotFound
229
+ report_error <<~MESSAGE
230
+ Could not find the `gcloud` binary in your system path.
231
+ This tool requires the Google Cloud SDK. To download and install it,
232
+ visit https://cloud.google.com/sdk/downloads
233
+ MESSAGE
234
+ rescue Gcloud::GcloudNotAuthenticated
235
+ report_error <<~MESSAGE
236
+ The gcloud authorization has not been completed. If you have not yet
237
+ initialized the Google Cloud SDK, we recommend running the `gcloud init`
238
+ command as described at https://cloud.google.com/sdk/docs/initializing
239
+ Alternately, you may log in directly by running `gcloud auth login`.
240
+ MESSAGE
241
+ rescue Gcloud::ProjectNotSet
242
+ report_error <<~MESSAGE
243
+ The gcloud project configuration has not been set. If you have not yet
244
+ initialized the Google Cloud SDK, we recommend running the `gcloud init`
245
+ command as described at https://cloud.google.com/sdk/docs/initializing
246
+ Alternately, you may set the default project configuration directly by
247
+ running `gcloud config set project <project-name>`.
248
+ MESSAGE
249
+ end
250
+
251
+ def start_and_report_errors app_exec
252
+ app_exec.start
253
+ rescue Exec::ConfigFileNotFound => ex
254
+ report_error <<~MESSAGE
255
+ Could not determine which service should run this command because the App
256
+ Engine config file "#{ex.config_path}" was not found.
257
+ Specify the config file using the GAE_CONFIG argument. e.g.
258
+ bundle exec rake appengine:exec GAE_CONFIG=myapp.yaml -- myscript.sh
259
+ Alternately, you may specify a service name directly with GAE_SERVICE. e.g.
260
+ bundle exec rake appengine:exec GAE_SERVICE=myservice -- myscript.sh
261
+ MESSAGE
262
+ rescue Exec::BadConfigFileFormat => ex
263
+ report_error <<~MESSAGE
264
+ Could not determine which service should run this command because the App
265
+ Engine config file "#{ex.config_path}" was malformed.
266
+ It must be a valid YAML file.
267
+ Specify the config file using the GAE_CONFIG argument. e.g.
268
+ bundle exec rake appengine:exec GAE_CONFIG=myapp.yaml -- myscript.sh
269
+ Alternately, you may specify a service name directly with GAE_SERVICE. e.g.
270
+ bundle exec rake appengine:exec GAE_SERVICE=myservice -- myscript.sh
271
+ MESSAGE
272
+ rescue Exec::NoSuchVersion => ex
273
+ if ex.version
274
+ report_error <<~MESSAGE
275
+ Could not find version "#{ex.version}" of service "#{ex.service}".
276
+ Please double-check the version exists. To use the most recent version by
277
+ default, omit the GAE_VERSION argument.
278
+ MESSAGE
279
+ else
280
+ report_error <<~MESSAGE
281
+ Could not find any versions of service "#{ex.service}".
282
+ Please double-check that you have deployed this service. If you want to run
283
+ a command against a different service, you may provide a GAE_CONFIG argument
284
+ pointing to your App Engine config file, or a GAE_SERVICE argument to specify
285
+ a service directly.
286
+ MESSAGE
287
+ end
288
+ rescue Exec::ServiceNameConflict => ex
289
+ report_error <<~MESSAGE
290
+ The explicit service name "#{ex.service_name}" was requested
291
+ but conflicts with the service "#{ex.config_name}" from the
292
+ config file "#{ex.config_path}"
293
+ You should specify either GAE_SERVICE or GAE_CONFIG but not both.
294
+ MESSAGE
295
+ end
296
+
297
+ def report_error str
298
+ ::STDERR.puts str
299
+ exit 1
300
+ end
301
+
302
+ end
303
+
304
+ end
305
+ end
306
+
307
+
308
+ ::AppEngine::Tasks.define
@@ -0,0 +1,190 @@
1
+ # Copyright 2017 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ ;
15
+
16
+ require "shellwords"
17
+
18
+
19
+ module AppEngine
20
+ module Util
21
+
22
+ ##
23
+ # A collection of utility functions and classes for interacting with an
24
+ # installation of the gcloud SDK.
25
+ #
26
+ module Gcloud
27
+
28
+ ##
29
+ # Base class for gcloud related errors.
30
+ #
31
+ class Error < ::StandardError
32
+ end
33
+
34
+ ##
35
+ # Exception raised when the gcloud binary could not be found.
36
+ #
37
+ class BinaryNotFound < Gcloud::Error
38
+ def initialize
39
+ super "GCloud binary not found in path"
40
+ end
41
+ end
42
+
43
+ ##
44
+ # Exception raised when the project gcloud config is not set.
45
+ #
46
+ class ProjectNotSet < Gcloud::Error
47
+ def initialize
48
+ super "GCloud project configuration not set"
49
+ end
50
+ end
51
+
52
+ ##
53
+ # Exception raised when gcloud auth has not been completed.
54
+ #
55
+ class GcloudNotAuthenticated < Gcloud::Error
56
+ def initialize
57
+ super "GCloud not authenticated"
58
+ end
59
+ end
60
+
61
+ ##
62
+ # Exception raised when gcloud fails and returns an error.
63
+ #
64
+ class GcloudFailed < Gcloud::Error
65
+ def initialize code
66
+ super "GCloud failed with result code #{code}"
67
+ end
68
+ end
69
+
70
+ class << self
71
+
72
+ ##
73
+ # @private
74
+ # Returns the path to the gcloud binary, or nil if the binary could
75
+ # not be found.
76
+ #
77
+ # @return [String,nil] Path to the gcloud binary.
78
+ #
79
+ def binary_path
80
+ unless defined? @binary_path
81
+ @binary_path = `which gcloud`.strip
82
+ @binary_path = nil if @binary_path.empty?
83
+ end
84
+ @binary_path
85
+ end
86
+
87
+ ##
88
+ # @private
89
+ # Returns the path to the gcloud binary. Raises BinaryNotFound if the
90
+ # binary could not be found.
91
+ #
92
+ # @return [String] Path to the gcloud binary.
93
+ # @raise [BinaryNotFound] The gcloud binary is not present.
94
+ #
95
+ def binary_path!
96
+ value = binary_path
97
+ raise BinaryNotFound unless value
98
+ value
99
+ end
100
+
101
+ ##
102
+ # @private
103
+ # Returns the ID of the current project, or nil if no project has
104
+ # been set.
105
+ #
106
+ # @return [String,nil] ID of the current project.
107
+ #
108
+ def current_project
109
+ unless defined? @current_project
110
+ @current_project = execute [
111
+ "config", "list", "core/project", "--format=value(core.project)"
112
+ ], capture: true
113
+ @current_project = nil if @current_project.empty?
114
+ end
115
+ @current_project
116
+ end
117
+
118
+ ##
119
+ # @private
120
+ # Returns the ID of the current project. Raises ProjectNotSet if no
121
+ # project has been set in the gcloud configuration.
122
+ #
123
+ # @return [String] ID of the current project.
124
+ # @raise [ProjectNotSet] The project config has not been set.
125
+ #
126
+ def current_project!
127
+ value = current_project
128
+ raise ProjectNotSet if value.empty?
129
+ value
130
+ end
131
+
132
+ ##
133
+ # @private
134
+ # Verifies that all gcloud related dependencies are satisfied.
135
+ # Specifically, verifies that the gcloud binary is installed and
136
+ # authenticated, and a project has been set.
137
+ #
138
+ # @raise [BinaryNotFound] The gcloud binary is not present.
139
+ # @raise [ProjectNotSet] The project config has not been set.
140
+ # @raise [GcloudNotAuthenticated] Gcloud has not been authenticated.
141
+ #
142
+ def verify!
143
+ binary_path!
144
+ current_project!
145
+ auths = execute ["auth", "list", "--format=value(account)"],
146
+ capture: true
147
+ raise GcloudNotAuthenticated if auths.empty?
148
+ end
149
+
150
+ ##
151
+ # @private
152
+ # Execute a given gcloud command in a subshell.
153
+ #
154
+ # @param args [Array<String>] The gcloud args.
155
+ # @param echo [boolean] Whether to echo the command to the terminal.
156
+ # Defaults to false.
157
+ # @param capture [boolean] If true, return the output. If false, return
158
+ # a boolean indicating success or failure. Defaults to false.
159
+ # @param assert [boolean] If true, raise GcloudFailed on failure.
160
+ # Defaults to true.
161
+ # @return [String,Integer] Either the output or the success status,
162
+ # depending on the value of the `capture` parameter.
163
+ #
164
+ def execute args, echo: false, capture: false, assert: true
165
+ joined_args = ::Shellwords.join args
166
+ cmd = "#{binary_path!} #{joined_args}"
167
+ puts cmd if echo
168
+ result = capture ? `#{cmd}` : system(cmd)
169
+ code = $?.exitstatus
170
+ raise GcloudFailed.new($?.exitstatus) if assert && code != 0
171
+ result
172
+ end
173
+
174
+ ##
175
+ # @private
176
+ # Execute a given gcloud command in a subshell, and return the output
177
+ # as a string.
178
+ #
179
+ # @param args [Array<String>] The gcloud args.
180
+ # @return [String] The command output.
181
+ #
182
+ def capture args
183
+ execute args, capture: true
184
+ end
185
+
186
+ end
187
+ end
188
+
189
+ end
190
+ end
@@ -16,6 +16,6 @@
16
16
  module AppEngine
17
17
 
18
18
  # The current version of this gem, as a string.
19
- VERSION = '0.3.0'.freeze
19
+ VERSION = '0.4.0'.freeze
20
20
 
21
21
  end
@@ -22,7 +22,6 @@ module AppEngine
22
22
 
23
23
  class TestEnv < ::Minitest::Test # :nodoc:
24
24
 
25
-
26
25
  def test_app_engine
27
26
  ::ENV["GAE_INSTANCE"] = "instance-123"
28
27
  assert Env.app_engine?
@@ -30,7 +29,6 @@ module AppEngine
30
29
  refute Env.app_engine?
31
30
  end
32
31
 
33
-
34
32
  end
35
33
 
36
34
  end
metadata CHANGED
@@ -1,50 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appengine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
- - Adam Tanner
8
7
  - Daniel Azuma
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2017-02-28 00:00:00.000000000 Z
11
+ date: 2017-07-17 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
- name: stackdriver
14
+ name: google-cloud-env
16
15
  requirement: !ruby/object:Gem::Requirement
17
16
  requirements:
18
17
  - - "~>"
19
18
  - !ruby/object:Gem::Version
20
- version: '0.4'
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: 0.4.1
19
+ version: '1.0'
24
20
  type: :runtime
25
21
  prerelease: false
26
22
  version_requirements: !ruby/object:Gem::Requirement
27
23
  requirements:
28
24
  - - "~>"
29
25
  - !ruby/object:Gem::Version
30
- version: '0.4'
31
- - - ">="
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: stackdriver
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
32
39
  - !ruby/object:Gem::Version
33
- version: 0.4.1
40
+ version: '0.7'
34
41
  - !ruby/object:Gem::Dependency
35
42
  name: bundler
36
43
  requirement: !ruby/object:Gem::Requirement
37
44
  requirements:
38
45
  - - "~>"
39
46
  - !ruby/object:Gem::Version
40
- version: '1.14'
47
+ version: '1.15'
41
48
  type: :development
42
49
  prerelease: false
43
50
  version_requirements: !ruby/object:Gem::Requirement
44
51
  requirements:
45
52
  - - "~>"
46
53
  - !ruby/object:Gem::Version
47
- version: '1.14'
54
+ version: '1.15'
48
55
  - !ruby/object:Gem::Dependency
49
56
  name: minitest
50
57
  requirement: !ruby/object:Gem::Requirement
@@ -87,12 +94,27 @@ dependencies:
87
94
  - - "~>"
88
95
  - !ruby/object:Gem::Version
89
96
  version: '4.2'
97
+ - !ruby/object:Gem::Dependency
98
+ name: yard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.9'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.9'
90
111
  description: The appengine gem is a set of classes, plugins, and tools for integration
91
112
  with Google App Engine. It provides access to the App Engine runtime environment,
92
113
  including logging to the Google Cloud Console and interrogation of hosting properties.
93
- However, it is not required for deploying your Ruby application to App Engine.
114
+ It also provides rake tasks for managing your App Engine application, for example
115
+ to run production maintenance commands. This gem is not required to deploy your
116
+ Ruby application to App Engine.
94
117
  email:
95
- - adamtanner@google.com
96
118
  - dazuma@gmail.com
97
119
  executables: []
98
120
  extensions: []
@@ -105,7 +127,10 @@ files:
105
127
  - Rakefile
106
128
  - lib/appengine.rb
107
129
  - lib/appengine/env.rb
130
+ - lib/appengine/exec.rb
108
131
  - lib/appengine/railtie.rb
132
+ - lib/appengine/tasks.rb
133
+ - lib/appengine/util/gcloud.rb
109
134
  - lib/appengine/version.rb
110
135
  - test/test_env.rb
111
136
  homepage: https://github.com/GoogleCloudPlatform/appengine-ruby
@@ -128,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
128
153
  version: '0'
129
154
  requirements: []
130
155
  rubyforge_project:
131
- rubygems_version: 2.6.8
156
+ rubygems_version: 2.6.11
132
157
  signing_key:
133
158
  specification_version: 4
134
159
  summary: Google App Engine integration tools