contentful_bootstrap 3.8.0 → 3.9.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: e1ca35ef188d6a3d38b7c2f97eae1d7f2ac3d815
4
- data.tar.gz: 79ab058638c98f8c151de7fb932ff644707ffef5
3
+ metadata.gz: 4d0bf2dba800e936efa11794d15440a1da64db05
4
+ data.tar.gz: 9af2801f2a777c99d2dd4f46bb6323964b7592a9
5
5
  SHA512:
6
- metadata.gz: 522a5774bb87c0efd7a969572c580c77a498d5eb3460bfec192c1782e0e9736591761ee87e57e9d4837c7e8f8cd6fd62f09b62940c9fbd66c3984620bf8d94f4
7
- data.tar.gz: 3aa214a216e55b2af983e532a9dc5a44d1e74fa8594174cb9fc45c2e254f4894e9f7c373041c59bf0b82313ade49529fd54163f08e1003b04628f190aa97d38a
6
+ metadata.gz: 9de02a76a5062f9c084f886168c9d41d800cb72d44bfdab9c8437e61ed9dbab30b1d0d4bdfb821e9bb95262ff86aaabe3f831f37a4f64a86e88bdebe07d6feb1
7
+ data.tar.gz: 0b37f36ec8d8b5cd26112f071180bcbdaa1838ec239b485bb1f22dbdd2f32bda827e6d6fcd8a6cbf8d73046a722db6130d5744ec39a15f5edea703f3a555e33d
data/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v3.9.0
6
+ ### Fixed
7
+ * Fixed `quiet` not being forwarded properly to `generate_json` and `update_space`
8
+ * Fixed `X-Contentful-User-Agent` headers now use `application` instead of `integration` header.
9
+
10
+ ### Added
11
+ * Added `--use-preview` flag to `generate_json` command [#62](https://github.com/contentful/contentful-bootstrap.rb/issues/62)
12
+ * Added `--no-publish` flag to `create_space` and `update_space` commands [#62](https://github.com/contentful/contentful-bootstrap.rb/issues/62)
13
+
14
+ ### Changed
15
+ * `generate_json` now imports all available content in your space [#62](https://github.com/contentful/contentful-bootstrap.rb/issues/62)
16
+ * Assets can now be updated when using `update_space`.
17
+
5
18
  ## v3.8.0
6
19
  ### Changed
7
20
  * Changed `Contentful::Bootstrap::CreateCommand#organizations` to use the new public `/organizations` endpoint.
data/README.md CHANGED
@@ -26,7 +26,7 @@ $ gem install contentful_bootstrap
26
26
  You can create spaces by doing:
27
27
 
28
28
  ```bash
29
- $ contentful_bootstrap create_space <space_name> [--template template_name] [--json-template template_path] [--locale locale_code] [--mark-processed] [--config CONFIG_PATH] [--quiet]
29
+ $ contentful_bootstrap create_space <space_name> [--template template_name] [--json-template template_path] [--locale locale_code] [--mark-processed] [--no-publish] [--config CONFIG_PATH] [--quiet]
30
30
  ```
31
31
 
32
32
  You can also generate new Delivery API Tokens by doing:
@@ -38,13 +38,13 @@ $ contentful_bootstrap generate_token <space_id> [--name token_name] [--config C
38
38
  You can also generate JSON Templates from existing spaces by doing:
39
39
 
40
40
  ```bash
41
- $ contentful_bootstrap generate_json <space_id> <delivery_api_access_token> [--output-file OUTPUT PATH] [--content-types-only] [--quiet]
41
+ $ contentful_bootstrap generate_json <space_id> <delivery_api_access_token> [--output-file OUTPUT PATH] [--content-types-only] [--use-preview] [--quiet]
42
42
  ```
43
43
 
44
44
  You can update existing spaces from JSON Templates by doing:
45
45
 
46
46
  ```bash
47
- $ contentful_bootstrap update_space <space_id> -j template_path [--mark-processed] [--skip-content-types] [--quiet]
47
+ $ contentful_bootstrap update_space <space_id> -j template_path [--mark-processed] [--skip-content-types] [--no-publish] [--quiet]
48
48
  ```
49
49
 
50
50
  ### Built-in templates
@@ -89,6 +89,7 @@ options = {
89
89
  json_template: "/path/to/template.json", # Will use the JSON file specified as a Template
90
90
  locale: "es-AR", # Will create the space with the specified locale code as default locale, defaults to "en-US"
91
91
  mark_processed: false, # if true will mark all resources as 'bootstrapProcessed' and will be avoided for update_space calls (doesnt affect create_space)
92
+ no_publish: false, # if true it won't publish your entries or assets
92
93
  trigger_oauth: true, # if true will trigger OAuth process
93
94
  quiet: false, # if true will not output to STDOUT
94
95
  no_input: false # if true all input operations won't be done, exceptions thrown with alternatives through configuration file in cases in which it cannot proceed
@@ -105,6 +106,7 @@ options = {
105
106
  mark_processed: false, # if true will mark all resources as 'bootstrapProcessed and will be avoided on future update_space calls
106
107
  trigger_oauth: true, # if true will trigger OAuth process
107
108
  skip_content_types: false, # if true will avoid creating the content types
109
+ no_publish: false, # if true it won't publish your entries or assets
108
110
  quiet: false, # if true will not output to STDOUT
109
111
  no_input: false # if true all input operations won't be done, exceptions thrown with alternatives through configuration file in cases in which it cannot proceed
110
112
  }
@@ -134,10 +136,12 @@ To Generate a JSON Template from an exising Space
134
136
  ```ruby
135
137
  Contentful::Bootstrap::CommandRunner.new.generate_json(
136
138
  "space_id",
137
- access_token: "delivery_api_access_token",
139
+ access_token: "delivery_or_preview_api_access_token",
140
+ use_preview: false, # if true will fetch from the Preview API instead of Delivery API
138
141
  filename: nil, # path to file in which to store JSON
139
142
  content_types_only: false, # if true will not fetch Entries and Assets
140
- quiet: false # if true will not output to STDOUT - only when filename is provided
143
+ quiet: false, # if true will not output to STDOUT - only when filename is provided
144
+ no_input: false # if true all input operations won't be done, exceptions thrown with alternatives through configuration file in cases in which it cannot proceed
141
145
  )
142
146
  ```
143
147
 
@@ -147,7 +151,9 @@ Additionally, you can send an options hash with the following keys:
147
151
  ```ruby
148
152
  options = {
149
153
  access_token: "access_token" # REQUIRED
154
+ use_preview: false, # if true will fetch from the Preview API instead of Delivery API
150
155
  filename: "template.json", # Will save the JSON to the specified file
156
+ content_types_only: false, # if true will not fetch Entries and Assets
151
157
  quiet: false, # if true will not output to STDOUT
152
158
  no_input: false # if true all input operations won't be done, exceptions thrown with alternatives through configuration file in cases in which it cannot proceed
153
159
  }
@@ -186,6 +192,37 @@ a common baseline. You can find a complete example [here](./examples/templates/c
186
192
  Using the `--mark-processed` option alongside `--json-template` will mark all resources as `bootstrapProcessed`,
187
193
  which will make it so `update_space` calls avoid already created resources. (A resource being either a Content Type, Entry or Asset).
188
194
 
195
+ ## Workflow for backing up draft/updated content
196
+
197
+ In many cases, you want to have a dump of your whole space, including draft/updated content.
198
+ To achieve this, do the following:
199
+
200
+ 1. Export the content:
201
+
202
+ ```bash
203
+ # Export published content
204
+ contentful_bootstrap generate_json <SPACE_ID> <DELIVERY_TOKEN> -o bootstrap-published.json
205
+
206
+ # Export draft/updated content
207
+ contentful_bootstrap generate_json <SPACE_ID> <PREVIEW_TOKEN> -o bootstrap-preview.json --use-preview
208
+ ```
209
+
210
+ > Notice that on the second command we're using the `--use-preview` flag to use the Preview API to fetch the content.
211
+
212
+ 2. Create or update a space with the templates:
213
+
214
+ ```bash
215
+ # Import published content
216
+ contentful_bootstrap update_space <SPACE_ID> -j bootstrap-published.json
217
+
218
+ # Import draft/updated content
219
+ contentful_bootstrap update_space <SPACE_ID> -j bootstrap-preview.json --no-publish
220
+ ```
221
+
222
+ > Notice that on the second command we're using the `--no-publish` flag to avoid publishing content that was originally draft/updated.
223
+
224
+ With this simple two-step process, you ensure that your content is fully reproducible, even if it's in draft state.
225
+
189
226
  ## Contributing
190
227
 
191
228
  Feel free to improve this tool by submitting a Pull Request. For more information,
@@ -26,6 +26,9 @@ subcommands = {
26
26
  opts.on("-q", "--quiet", "Don't output to STDOUT") do |q|
27
27
  options[:quiet] = q
28
28
  end
29
+ opts.on("-n", "--no-publish", "Don't publish") do |n|
30
+ options[:no_publish] = n
31
+ end
29
32
  opts.on_tail("-h", "--help", "Print this message") do
30
33
  puts opts
31
34
  end
@@ -47,6 +50,9 @@ subcommands = {
47
50
  opts.on("-c CONFIG_PATH", "--config CONFIG_PATH", "Specify Configuration Path") do |c|
48
51
  options[:config_path] = c
49
52
  end
53
+ opts.on("-n", "--no-publish", "Don't publish") do |n|
54
+ options[:no_publish] = n
55
+ end
50
56
  opts.on("-q", "--quiet", "Don't output to STDOUT") do |q|
51
57
  options[:quiet] = q
52
58
  end
@@ -74,6 +80,9 @@ subcommands = {
74
80
  opts.on("-t", "--content-types-only", "Only fetch Content Types") do |t|
75
81
  options[:content_types_only] = t
76
82
  end
83
+ opts.on("-p", "--use-preview", "Use Preview API") do |p|
84
+ options[:use_preview] = p
85
+ end
77
86
  opts.on("-o OUTPUT_PATH", "--output-file OUTPUT_PATH", "Specify Output File") do |f|
78
87
  options[:filename] = f
79
88
  end
@@ -33,11 +33,13 @@ module Contentful
33
33
  filename = options.fetch(:filename, nil)
34
34
  access_token = options.fetch(:access_token, nil)
35
35
  content_types_only = options.fetch(:content_types_only, false)
36
+ quiet = options.fetch(:quiet, false)
37
+ use_preview = options.fetch(:use_preview, false)
36
38
 
37
39
  fail 'Access Token required' if access_token.nil?
38
40
 
39
41
  Contentful::Bootstrap::Commands::GenerateJson.new(
40
- space_id, access_token, filename, content_types_only
42
+ space_id, access_token, filename, content_types_only, quiet, use_preview
41
43
  ).run
42
44
  end
43
45
  end
@@ -39,8 +39,8 @@ module Contentful
39
39
  @token.read,
40
40
  default_locale: options.fetch(:locale, "en-US"),
41
41
  raise_errors: true,
42
- integration_name: 'bootstrap',
43
- integration_version: ::Contentful::Bootstrap::VERSION
42
+ application_name: 'bootstrap',
43
+ application_version: ::Contentful::Bootstrap::VERSION
44
44
  )
45
45
  end
46
46
 
@@ -14,6 +14,7 @@ module Contentful
14
14
  @json_template = options.fetch(:json_template, nil)
15
15
  @mark_processed = options.fetch(:mark_processed, false)
16
16
  @locale = options.fetch(:locale, "en-US")
17
+ @no_publish = options.fetch(:no_publish, false)
17
18
 
18
19
  super(token, space, options)
19
20
  end
@@ -106,7 +107,7 @@ module Contentful
106
107
  def create_json_template(space)
107
108
  if ::File.exist?(@json_template)
108
109
  output "Creating JSON Template '#{@json_template}'"
109
- Templates::JsonTemplate.new(space, @json_template, @mark_processed, true, quiet).run
110
+ Templates::JsonTemplate.new(space, @json_template, @mark_processed, true, quiet, false, @no_publish).run
110
111
  output "JSON Template '#{@json_template}' created!"
111
112
  else
112
113
  output "JSON Template '#{@json_template}' does not exist. Please check that you specified the correct file name."
@@ -5,38 +5,50 @@ module Contentful
5
5
  module Bootstrap
6
6
  module Commands
7
7
  class GenerateJson
8
- attr_reader :space_id, :filename, :access_token, :content_types_only
9
- def initialize(space_id, access_token, filename = nil, content_types_only = false, quiet = false)
8
+ attr_reader :space_id, :filename, :access_token, :content_types_only, :use_preview
9
+ def initialize(space_id, access_token, filename = nil, content_types_only = false, quiet = false, use_preview = false)
10
10
  @space_id = space_id
11
11
  @access_token = access_token
12
12
  @filename = filename
13
13
  @content_types_only = content_types_only
14
14
  @quiet = quiet
15
+ @use_preview = use_preview
15
16
  end
16
17
 
17
18
  def run
18
19
  if access_token.nil?
19
- puts 'Access Token not specified'
20
- puts 'Exiting!'
21
- exit
20
+ output 'Access Token not specified'
21
+ output 'Exiting!'
22
+ exit(1)
22
23
  end
23
24
 
24
- puts "Generating JSON Template '#{filename}' for Space: '#{space_id}'"
25
+ output "Generating JSON Template for Space: '#{space_id}'"
26
+ output
25
27
 
26
- json = Contentful::Bootstrap::Generator.new(space_id, access_token, content_types_only).generate_json
28
+ json = Contentful::Bootstrap::Generator.new(
29
+ space_id,
30
+ access_token,
31
+ content_types_only,
32
+ use_preview
33
+ ).generate_json
27
34
 
28
- puts
29
35
  write(json)
30
36
  end
31
37
 
32
38
  def write(json)
33
39
  if filename.nil?
34
- puts "#{json}\n"
40
+ output "#{json}\n"
35
41
  else
36
- puts "Saving JSON template to '#{filename}'" unless @quiet
42
+ output "Saving JSON template to '#{filename}'"
37
43
  ::File.write(filename, json)
38
44
  end
39
45
  end
46
+
47
+ protected
48
+
49
+ def output(text = nil)
50
+ Support.output(text, @quiet)
51
+ end
40
52
  end
41
53
  end
42
54
  end
@@ -12,6 +12,8 @@ module Contentful
12
12
  @json_template = options.fetch(:json_template, nil)
13
13
  @mark_processed = options.fetch(:mark_processed, false)
14
14
  @skip_content_types = options.fetch(:skip_content_types, false)
15
+ @no_publish = options.fetch(:no_publish, false)
16
+ @quiet = options.fetch(:quiet, false)
15
17
 
16
18
  super(token, space_id, options)
17
19
  end
@@ -49,7 +51,7 @@ module Contentful
49
51
  def update_json_template(space)
50
52
  if ::File.exist?(@json_template)
51
53
  output "Updating from JSON Template '#{@json_template}'"
52
- Templates::JsonTemplate.new(space, @json_template, @mark_processed, true, false, @skip_content_types).run
54
+ Templates::JsonTemplate.new(space, @json_template, @mark_processed, true, @quiet, @skip_content_types, @no_publish).run
53
55
  output "JSON Template '#{@json_template}' updated!"
54
56
  else
55
57
  output "JSON Template '#{@json_template}' does not exist. Please check that you specified the correct file name."
@@ -7,14 +7,18 @@ require 'contentful/bootstrap/version'
7
7
  module Contentful
8
8
  module Bootstrap
9
9
  class Generator
10
+ DELIVERY_API_URL = 'cdn.contentful.com'.freeze
11
+ PREVIEW_API_URL = 'preview.contentful.com'.freeze
12
+
10
13
  attr_reader :content_types_only, :client
11
14
 
12
- def initialize(space_id, access_token, content_types_only)
15
+ def initialize(space_id, access_token, content_types_only, use_preview)
13
16
  @client = Contentful::Client.new(
14
17
  access_token: access_token,
15
18
  space: space_id,
16
- integration_name: 'bootstrap',
17
- integration_version: ::Contentful::Bootstrap::VERSION
19
+ application_name: 'bootstrap',
20
+ application_version: ::Contentful::Bootstrap::VERSION,
21
+ api_url: use_preview ? PREVIEW_API_URL : DELIVERY_API_URL
18
22
  )
19
23
  @content_types_only = content_types_only
20
24
  end
@@ -30,20 +34,6 @@ module Contentful
30
34
 
31
35
  private
32
36
 
33
- def assets
34
- return [] if content_types_only
35
-
36
- proccessed_assets = @client.assets(limit: 1000).map do |asset|
37
- result = { 'id' => asset.sys[:id], 'title' => asset.title }
38
- result['file'] = {
39
- 'filename' => ::File.basename(asset.file.file_name, '.*'),
40
- 'url' => "https:#{asset.file.url}"
41
- }
42
- result
43
- end
44
- proccessed_assets.sort_by { |item| item['id'] }
45
- end
46
-
47
37
  def content_types
48
38
  proccessed_content_types = @client.content_types.map do |type|
49
39
  result = { 'id' => type.sys[:id], 'name' => type.name }
@@ -58,22 +48,54 @@ module Contentful
58
48
  proccessed_content_types.sort_by { |item| item['id'] }
59
49
  end
60
50
 
51
+ def assets
52
+ return [] if content_types_only
53
+
54
+ processed_assets = []
55
+
56
+ query = { order: 'sys.createdAt', limit: 1000 }
57
+ assets_count = @client.assets(limit: 1).total
58
+ ((assets_count / 1000) + 1).times do |i|
59
+ query[:skip] = i * 1000
60
+
61
+ @client.assets(query).each do |asset|
62
+ processed_asset = {
63
+ 'id' => asset.sys[:id],
64
+ 'title' => asset.title,
65
+ 'file' => {
66
+ 'filename' => ::File.basename(asset.file.file_name, '.*'),
67
+ 'url' => "https:#{asset.file.url}"
68
+ }
69
+ }
70
+ processed_assets << processed_asset
71
+ end
72
+ end
73
+
74
+ processed_assets.sort_by { |item| item['id'] }
75
+ end
76
+
61
77
  def entries
62
78
  return {} if content_types_only
63
79
 
64
80
  entries = {}
65
81
 
66
- @client.entries(limit: 1000).each do |entry|
67
- result = { 'sys' => { 'id' => entry.sys[:id] }, 'fields' => {} }
82
+ query = { order: 'sys.createdAt', limit: 1000 }
83
+ entries_count = @client.entries(limit: 1).total
84
+ ((entries_count / 1000) + 1).times do |i|
85
+ query[:skip] = i * 1000
68
86
 
69
- entry.fields.each do |key, value|
70
- value = map_field(value)
71
- result['fields'][field_id(entry, key)] = value unless value.nil?
72
- end
87
+ @client.entries(query).each do |entry|
88
+ result = { 'sys' => { 'id' => entry.sys[:id] }, 'fields' => {} }
73
89
 
74
- ct_id = entry.content_type.sys[:id]
75
- entries[ct_id] = [] if entries[ct_id].nil?
76
- entries[ct_id] << result
90
+ entry.fields.each do |key, value|
91
+ value = map_field(value)
92
+ result['fields'][field_id(entry, key)] = value unless value.nil?
93
+ end
94
+
95
+ ct_id = entry.content_type.sys[:id]
96
+ entries[ct_id] = [] if entries[ct_id].nil?
97
+ entries[ct_id] << result
98
+ end
77
99
  end
78
100
 
79
101
  entries
@@ -8,10 +8,11 @@ module Contentful
8
8
  class Base
9
9
  attr_reader :space, :skip_content_types
10
10
 
11
- def initialize(space, quiet = false, skip_content_types = false)
11
+ def initialize(space, quiet = false, skip_content_types = false, no_publish = false)
12
12
  @space = space
13
13
  @quiet = quiet
14
14
  @skip_content_types = skip_content_types
15
+ @no_publish = no_publish
15
16
  end
16
17
 
17
18
  def run
@@ -108,29 +109,39 @@ module Contentful
108
109
  end
109
110
 
110
111
  def create_assets
111
- assets.each do |asset|
112
+ assets.each do |asset_json|
112
113
  begin
113
- output "Creating Asset '#{asset['title']}'"
114
+ output "Creating Asset '#{asset_json['title']}'"
114
115
  asset = space.assets.create(
115
- id: asset['id'],
116
- title: asset['title'],
117
- file: asset['file']
116
+ id: asset_json['id'],
117
+ title: asset_json['title'],
118
+ file: asset_json['file']
118
119
  )
119
120
  asset.process_file
121
+ rescue Contentful::Management::Conflict
122
+ output "Asset '#{asset_json['id']}' already created! Updating instead."
120
123
 
121
- attempts = 0
122
- while attempts < 10
123
- unless space.assets.find(asset.id).file.url.nil?
124
- asset.publish
125
- break
126
- end
124
+ asset = space.assets.find(asset_json['id']).tap do |a|
125
+ a.title = asset_json['title']
126
+ a.file = asset_json['file']
127
+ end
127
128
 
128
- sleep(1) # Wait for Process
129
- attempts += 1
129
+ asset.save
130
+ asset.process_file
131
+ end
132
+ end
133
+
134
+ assets.each do |asset_json|
135
+ attempts = 0
136
+ while attempts < 10
137
+ asset = space.assets.find(asset_json['id'])
138
+ unless asset.file.url.nil?
139
+ asset.publish unless @no_publish
140
+ break
130
141
  end
131
- rescue Contentful::Management::Conflict
132
- output "Asset '#{asset['id']}' already created! Skipping"
133
- next
142
+
143
+ sleep(1) # Wait for Process
144
+ attempts += 1
134
145
  end
135
146
  end
136
147
  end
@@ -203,7 +214,9 @@ module Contentful
203
214
  entry.id
204
215
  end
205
216
 
206
- processed_entries.each { |e| space.entries.find(e).publish }
217
+ processed_entries.each do |e|
218
+ space.entries.find(e).publish unless @no_publish
219
+ end
207
220
  end
208
221
  end
209
222
  end