Skip to content

Commit 6150b05

Browse files
author
ruslan_tolstov
authored
Feature/multi schema (#1)
Added multi-schema support Added AZURE Blob support
1 parent e51a8ed commit 6150b05

File tree

17 files changed

+454
-102
lines changed

17 files changed

+454
-102
lines changed

.rubocop.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ Metrics/LineLength:
99
Style/Documentation:
1010
Enabled: false
1111

12+
Metrics/MethodLength:
13+
Enabled: false
14+
1215
Lint/AmbiguousBlockAssociation:
1316
Enabled: false
1417

Gemfile.lock

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
PATH
22
remote: .
33
specs:
4-
rswag_schema_export (0.1.0)
4+
rswag_schema_export (0.1.1)
55
aws-sdk-s3 (~> 1)
6+
azure-storage-blob (~> 1.1)
67

78
GEM
89
remote: https://rubygems.org/
@@ -27,28 +28,43 @@ GEM
2728
tzinfo (~> 1.1)
2829
ast (2.4.0)
2930
aws-eventstream (1.0.3)
30-
aws-partitions (1.184.0)
31-
aws-sdk-core (3.59.0)
31+
aws-partitions (1.210.0)
32+
aws-sdk-core (3.66.0)
3233
aws-eventstream (~> 1.0, >= 1.0.2)
3334
aws-partitions (~> 1.0)
3435
aws-sigv4 (~> 1.1)
3536
jmespath (~> 1.0)
36-
aws-sdk-kms (1.23.0)
37-
aws-sdk-core (~> 3, >= 3.58.0)
37+
aws-sdk-kms (1.24.0)
38+
aws-sdk-core (~> 3, >= 3.61.1)
3839
aws-sigv4 (~> 1.1)
39-
aws-sdk-s3 (1.45.0)
40-
aws-sdk-core (~> 3, >= 3.58.0)
40+
aws-sdk-s3 (1.48.0)
41+
aws-sdk-core (~> 3, >= 3.61.1)
4142
aws-sdk-kms (~> 1)
4243
aws-sigv4 (~> 1.1)
4344
aws-sigv4 (1.1.0)
4445
aws-eventstream (~> 1.0, >= 1.0.2)
46+
azure-core (0.1.15)
47+
faraday (~> 0.9)
48+
faraday_middleware (~> 0.10)
49+
nokogiri (~> 1.6)
50+
azure-storage-blob (1.1.0)
51+
azure-core (~> 0.1.13)
52+
azure-storage-common (~> 1.0)
53+
nokogiri (~> 1.6, >= 1.6.8)
54+
azure-storage-common (1.1.0)
55+
azure-core (~> 0.1.13)
56+
nokogiri (~> 1.6, >= 1.6.8)
4557
builder (3.2.3)
4658
coderay (1.1.2)
4759
concurrent-ruby (1.1.5)
4860
crass (1.0.4)
4961
diff-lcs (1.3)
5062
docile (1.3.2)
5163
erubi (1.8.0)
64+
faraday (0.15.4)
65+
multipart-post (>= 1.2, < 3)
66+
faraday_middleware (0.13.1)
67+
faraday (>= 0.7.4, < 1.0)
5268
i18n (1.6.0)
5369
concurrent-ruby (~> 1.0)
5470
jaro_winkler (1.5.3)
@@ -60,7 +76,8 @@ GEM
6076
method_source (0.9.2)
6177
mini_portile2 (2.4.0)
6278
minitest (5.11.3)
63-
nokogiri (1.10.3)
79+
multipart-post (2.1.1)
80+
nokogiri (1.10.4)
6481
mini_portile2 (~> 2.4.0)
6582
parallel (1.17.0)
6683
parser (2.6.3.0)

README.md

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ And then execute:
2020
Or install it yourself as:
2121

2222
$ gem install rswag_schema_export
23+
$ rails g rswag_schema_export:install
2324

2425
## Usage
2526

@@ -44,7 +45,7 @@ stages:
4445

4546
```diff
4647
# config/deploy.rb
47-
+ folders = %w[tmp/swagger]
48+
+ folders = %w[swagger]
4849
namespace :deploy do
4950
after :restart, :clear_cache do
5051
on roles(:web), in: :groups, limit: 3, wait: 10 do
@@ -60,12 +61,17 @@ end
6061
Set up ENVIRONMENT VARIABLES on your CI
6162

6263
```bash
63-
# Required
64-
RSWAG_SCHEMA_PATH='' # Example: tmp/swagger/swagger.json
65-
RSWAG_ACCESS_KEY_ID='' # Example: XXXXXXXXXX
66-
RSWAG_SECRET_ACCESS_KEY='' # Example: XXXXXXXXXXXXXXXXXXXXX
67-
RSWAG_REGION='' # Example: us-west-1
68-
RSWAG_BUCKET='' # Example: bucket-name
64+
# Required for AWS
65+
RSWAG_AWS_ACCESS_KEY_ID='' # Example: XXXXXXXXXX
66+
RSWAG_AWS_SECRET_ACCESS_KEY='' # Example: XXXXXXXXXXXXXXXXXXXXX
67+
RSWAG_AWS_REGION='' # Example: us-west-1
68+
RSWAG_AWS_BUCKET='' # Example: bucket-name
69+
70+
# Required for AZURE
71+
72+
RSWAG_AZURE_STORAGE_ACCOUNT_NAME='' # Example: XXXXX
73+
RSWAG_AZURE_STORAGE_ACCESS_KEY='' # Example: XXXXXXXXXXXXXXXXXXXXX
74+
RSWAG_AZURE_CONTAINER='' # Example: continter-name
6975

7076
# Optional
7177
STAGE='' # Default: develop
@@ -74,23 +80,23 @@ APP_NAME='' # Default: app
7480

7581
## Gitlab Variables
7682

77-
![image](https://user-images.githubusercontent.com/2664467/60773983-c69bdf80-a115-11e9-9f46-57d835ba4561.png)
78-
83+
![image](https://user-images.githubusercontent.com/2664467/64493266-bc699f00-d286-11e9-8827-e99d0eada9ce.png)
7984

80-
## rswag-api
85+
## rswag_schema_export
8186
```diff
82-
# config/initializers/rswag_api.rb
83-
Rswag::Api.configure do |c|
84-
+ c.swagger_root = Rails.root.to_s + '/tmp/swagger'
87+
# config/initializers/rswag_schema_export.rb
88+
RswagSchemaExport.configure do |c|
89+
+ c.schemas = ['swagger/client/swagger.json', 'swagger/backoffice/swagger.json']
90+
+ c.client = :aws
8591
end
92+
8693
```
8794

88-
## rswag-specs
95+
## rswag-api
8996
```diff
90-
# spec/swagger_helper.rb
91-
92-
RSpec.configure do |config|
93-
+ config.swagger_root = Rails.root.to_s + '/tmp/swagger'
97+
# config/initializers/rswag_api.rb
98+
Rswag::Api.configure do |c|
99+
+ c.swagger_root = Rails.root.to_s + '/swagger'
94100
end
95101
```
96102

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
require "rails/generators"
2+
3+
module RswagSchemaExport
4+
class InstallGenerator < Rails::Generators::Base
5+
source_root File.expand_path("templates", __dir__)
6+
7+
def add_initializer
8+
template("rswag_schema_export.rb", "config/initializers/rswag_schema_export.rb")
9+
end
10+
end
11+
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
RswagSchemaExport.configure do |c|
2+
# Set up your schemas
3+
#
4+
# c.schemas = ['swagger/client/swagger.json', 'swagger/backoffice/swagger.json']
5+
#
6+
# Set up your cloud provider - (:aws, :azure) :aws by default
7+
#
8+
# c.client = :aws
9+
end

lib/rswag_schema_export.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
require "rswag_schema_export/version"
2+
require "rswag_schema_export/configuration"
3+
require "rswag_schema_export/client"
24
require "rswag_schema_export/railtie" if defined?(Rails)
35
require "rswag_schema_export/schema_export"
46
require "rswag_schema_export/schema_import"
57

68
module RswagSchemaExport
9+
def self.configure
10+
yield(config)
11+
end
12+
13+
def self.config
14+
@config ||= Configuration.new
15+
end
716
end

lib/rswag_schema_export/client.rb

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
require "azure/storage/blob"
2+
require "aws-sdk-s3"
3+
4+
module RswagSchemaExport
5+
class Client
6+
attr_reader :stage, :app_name
7+
8+
def initialize(stage)
9+
@app_name = ENV["APP_NAME"] || "app"
10+
@stage = stage || "develop"
11+
end
12+
13+
def client # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity:
14+
if aws_client?
15+
abort("RSWAG_AWS_ACCESS_KEY_ID is not defined") unless ENV["RSWAG_AWS_ACCESS_KEY_ID"]
16+
abort("RSWAG_AWS_SECRET_ACCESS_KEY is not defined") unless ENV["RSWAG_AWS_SECRET_ACCESS_KEY"]
17+
abort("RSWAG_AWS_REGION is not defined") unless ENV["RSWAG_AWS_REGION"]
18+
abort("RSWAG_AWS_BUCKET is not defined") unless ENV["RSWAG_AWS_BUCKET"]
19+
20+
@client ||= Aws::S3::Resource.new(access_key_id: ENV["RSWAG_AWS_ACCESS_KEY_ID"],
21+
secret_access_key: ENV["RSWAG_AWS_SECRET_ACCESS_KEY"],
22+
region: ENV["RSWAG_AWS_REGION"])
23+
else
24+
abort("RSWAG_AZURE_STORAGE_ACCOUNT_NAME is not defined") unless ENV["RSWAG_AZURE_STORAGE_ACCOUNT_NAME"]
25+
abort("RSWAG_AZURE_STORAGE_ACCESS_KEY is not defined") unless ENV["RSWAG_AZURE_STORAGE_ACCESS_KEY"]
26+
abort("RSWAG_AZURE_CONTAINER is not defined") unless ENV["RSWAG_AZURE_CONTAINER"]
27+
28+
@client = Azure::Storage::Blob::BlobService.create(
29+
storage_account_name: ENV["RSWAG_AZURE_STORAGE_ACCOUNT_NAME"],
30+
storage_access_key: ENV["RSWAG_AZURE_STORAGE_ACCESS_KEY"]
31+
)
32+
end
33+
end
34+
35+
def upload_file(key, file)
36+
if aws_client?
37+
client.bucket(ENV["RSWAG_AWS_BUCKET"]).object(key).upload_file(file)
38+
else
39+
client.create_block_blob(ENV["RSWAG_AZURE_CONTAINER"], key, ::File.open(file, &:read))
40+
end
41+
end
42+
43+
def fetch_versions(schema_id)
44+
if aws_client?
45+
bucket.objects(prefix: "schemas/#{app_name}/#{stage}_#{schema_id}/versions").collect(&:key)
46+
else
47+
prefix = "schemas/#{app_name}/#{stage}_#{schema_id}/versions"
48+
client.list_blobs(ENV["RSWAG_AZURE_CONTAINER"], prefix: prefix).collect(&:name)
49+
end
50+
end
51+
52+
def copy_latest_version_to_root(last_schema_key, schema_id)
53+
if aws_client?
54+
bucket.object(last_schema_key)
55+
.copy_to("#{ENV['RSWAG_BUCKET']}/schemas/#{app_name}/#{stage}_#{schema_id}/schema.json")
56+
else
57+
client.copy_blob(ENV["RSWAG_AZURE_CONTAINER"], "schemas/#{app_name}/#{stage}_#{schema_id}/schema.json",
58+
ENV["RSWAG_AZURE_CONTAINER"], last_schema_key)
59+
end
60+
end
61+
62+
def download_file(schema_id, path)
63+
if aws_client?
64+
bucket.object("schemas/#{app_name}/#{stage}_#{schema_id}/schema.json").download_file(path)
65+
else
66+
_blob, content = client.get_blob(ENV["RSWAG_AZURE_CONTAINER"],
67+
"schemas/#{app_name}/#{stage}_#{schema_id}/schema.json")
68+
::File.open(path, "wb") { |f| f.write(content) }
69+
end
70+
end
71+
72+
def clean(versions)
73+
old_versions = versions - versions.sort.last(5)
74+
if aws_client?
75+
old_versions.each { |key| bucket.object(key).delete }
76+
else
77+
old_versions.each { |key| client.delete_blob(ENV["RSWAG_AZURE_CONTAINER"], key) }
78+
end
79+
end
80+
81+
private
82+
83+
def bucket
84+
@bucket ||= client.bucket(ENV["RSWAG_AWS_BUCKET"]) if aws_client?
85+
end
86+
87+
def aws_client?
88+
RswagSchemaExport.config.client&.to_sym == :aws
89+
end
90+
end
91+
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module RswagSchemaExport
2+
class Configuration
3+
attr_accessor :schemas, :client
4+
5+
def initialize
6+
@client = :aws
7+
end
8+
end
9+
end

lib/rswag_schema_export/schema_export.rb

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,27 @@
11
module RswagSchemaExport
22
class Export
3-
def run
4-
abort("RSWAG_SCHEMA_PATH is not defined. Example: tmp/swagger/swagger.json") unless ENV["RSWAG_SCHEMA_PATH"]
5-
abort("RSWAG_ACCESS_KEY_ID is not defined") unless ENV["RSWAG_ACCESS_KEY_ID"]
6-
abort("RSWAG_SECRET_ACCESS_KEY is not defined") unless ENV["RSWAG_SECRET_ACCESS_KEY"]
7-
abort("RSWAG_REGION is not defined") unless ENV["RSWAG_REGION"]
8-
abort("RSWAG_BUCKET is not defined") unless ENV["RSWAG_BUCKET"]
3+
def run # rubocop:disable Metrics/AbcSize
4+
abort("Set up RswagSchemaExport.config.schemas") unless RswagSchemaExport.config.schemas
95

10-
stage = ENV["STAGE"] || "develop"
11-
app_name = ENV["APP_NAME"] || "app"
6+
RswagSchemaExport.config.schemas.map do |schema|
7+
next if File.file?(schema)
128

13-
unless File.file?(ENV["RSWAG_SCHEMA_PATH"])
14-
message = "Not found schema at #{ENV['RSWAG_SCHEMA_PATH']}.
15-
For generate schema run: RAILS_ENV=test rake rswag:specs:swaggerize"
9+
message = "Not found schema at #{schema}.
10+
For generate schema run: RAILS_ENV=test rake rswag:specs:swaggerize"
1611
abort(message)
1712
end
1813

1914
begin
20-
s3 = Aws::S3::Resource.new(access_key_id: ENV["RSWAG_ACCESS_KEY_ID"],
21-
secret_access_key: ENV["RSWAG_SECRET_ACCESS_KEY"],
22-
region: ENV["RSWAG_REGION"])
15+
client = ::RswagSchemaExport::Client.new(ENV["STAGE"])
16+
RswagSchemaExport.config.schemas.map do |schema|
17+
schema_id = schema.gsub(/[^a-zA-Z0-9\-]/, "_")
18+
key = "schemas/#{client.app_name}/#{client.stage}_#{schema_id}/versions/#{Time.now.getutc.iso8601}.json"
19+
# Upload latest version to the cloud
20+
client.upload_file(key, schema)
2321

24-
key = "schemas/#{app_name}/#{stage}_schemas/versions/#{Time.now.getutc.iso8601}.json"
25-
# Download latest version to app
26-
s3.bucket(ENV["RSWAG_BUCKET"]).object(key).upload_file(ENV["RSWAG_SCHEMA_PATH"])
27-
28-
puts("Schema has been successfully exported. Stage: #{stage} | Key: #{key}")
22+
puts("Schema has been successfully exported. Stage: #{client.stage} | Key: #{key}")
23+
end
24+
puts("Export finished")
2925
rescue StandardError => e
3026
abort(e.message)
3127
end

0 commit comments

Comments
 (0)