contentful_bootstrap 3.8.0 → 3.9.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 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