shopify-cli 1.3.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (206) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +2 -2
  3. data/.github/CONTRIBUTING.md +9 -1
  4. data/.github/PULL_REQUEST_TEMPLATE.md +10 -1
  5. data/.github/workflows/release.yml +61 -0
  6. data/.github/workflows/triage.yml +22 -0
  7. data/.gitignore +0 -1
  8. data/.rubocop.yml +61 -8
  9. data/.rubocop_todo.yml +11 -0
  10. data/.travis.yml +1 -0
  11. data/CHANGELOG.md +30 -0
  12. data/Gemfile +3 -2
  13. data/Gemfile.lock +39 -37
  14. data/README.md +39 -7
  15. data/RELEASING.md +19 -29
  16. data/Rakefile +2 -0
  17. data/dev.yml +2 -2
  18. data/docs/_config.yml +1 -18
  19. data/docs/app/node/commands/index.md +2 -80
  20. data/docs/app/node/index.md +2 -33
  21. data/docs/app/rails/commands/index.md +2 -78
  22. data/docs/app/rails/index.md +2 -34
  23. data/docs/core/index.md +2 -84
  24. data/docs/getting-started/index.md +2 -25
  25. data/docs/getting-started/install/index.md +1 -118
  26. data/docs/getting-started/migrate/index.md +2 -94
  27. data/docs/getting-started/uninstall/index.md +2 -35
  28. data/docs/getting-started/upgrade/index.md +2 -39
  29. data/docs/help/start-app/index.md +2 -4
  30. data/docs/index.md +2 -24
  31. data/install.sh +1 -1
  32. data/lib/project_types/extension/cli.rb +21 -11
  33. data/lib/project_types/extension/commands/extension_command.rb +2 -2
  34. data/lib/project_types/extension/features/argo.rb +117 -0
  35. data/lib/project_types/extension/forms/create.rb +2 -2
  36. data/lib/project_types/extension/models/specification.rb +35 -0
  37. data/lib/project_types/extension/models/specification_handlers/checkout_post_purchase.rb +19 -0
  38. data/lib/project_types/extension/models/specification_handlers/default.rb +67 -0
  39. data/lib/project_types/extension/models/specifications.rb +77 -0
  40. data/lib/project_types/extension/tasks/configure_features.rb +52 -0
  41. data/lib/project_types/extension/tasks/fetch_specifications.rb +38 -0
  42. data/lib/project_types/node/cli.rb +4 -1
  43. data/lib/project_types/node/commands/connect.rb +15 -0
  44. data/lib/project_types/node/commands/create.rb +10 -4
  45. data/lib/project_types/node/commands/generate.rb +2 -11
  46. data/lib/project_types/node/messages/messages.rb +16 -50
  47. data/lib/project_types/rails/cli.rb +4 -1
  48. data/lib/project_types/rails/commands/connect.rb +15 -0
  49. data/lib/project_types/rails/commands/create.rb +15 -12
  50. data/lib/project_types/rails/forms/create.rb +1 -1
  51. data/lib/project_types/rails/gem.rb +1 -1
  52. data/lib/project_types/rails/messages/messages.rb +8 -5
  53. data/lib/project_types/script/cli.rb +9 -5
  54. data/lib/project_types/script/commands/create.rb +6 -4
  55. data/lib/project_types/script/commands/enable.rb +12 -4
  56. data/lib/project_types/script/commands/push.rb +5 -13
  57. data/lib/project_types/script/config/extension_points.yml +17 -12
  58. data/lib/project_types/script/errors.rb +21 -0
  59. data/lib/project_types/script/forms/create.rb +26 -2
  60. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +10 -1
  61. data/lib/project_types/script/layers/application/build_script.rb +18 -17
  62. data/lib/project_types/script/layers/application/create_script.rb +12 -10
  63. data/lib/project_types/script/layers/application/extension_points.rb +24 -0
  64. data/lib/project_types/script/layers/application/push_script.rb +18 -16
  65. data/lib/project_types/script/layers/domain/errors.rb +7 -0
  66. data/lib/project_types/script/layers/domain/extension_point.rb +62 -7
  67. data/lib/project_types/script/layers/domain/metadata.rb +55 -0
  68. data/lib/project_types/script/layers/domain/push_package.rb +25 -6
  69. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +17 -52
  70. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +42 -11
  71. data/lib/project_types/script/layers/infrastructure/errors.rb +16 -0
  72. data/lib/project_types/script/layers/infrastructure/extension_point_repository.rb +10 -4
  73. data/lib/project_types/script/layers/infrastructure/project_creator.rb +2 -1
  74. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +25 -13
  75. data/lib/project_types/script/layers/infrastructure/rust_project_creator.rb +72 -0
  76. data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +59 -0
  77. data/lib/project_types/script/layers/infrastructure/script_service.rb +9 -1
  78. data/lib/project_types/script/layers/infrastructure/task_runner.rb +4 -3
  79. data/lib/project_types/script/messages/messages.rb +55 -4
  80. data/lib/project_types/script/script_project.rb +25 -16
  81. data/lib/project_types/script/ui/error_handler.rb +59 -1
  82. data/lib/project_types/theme/cli.rb +40 -0
  83. data/lib/project_types/theme/commands/connect.rb +54 -0
  84. data/lib/project_types/theme/commands/create.rb +48 -0
  85. data/lib/project_types/theme/commands/deploy.rb +38 -0
  86. data/lib/project_types/theme/commands/generate.rb +20 -0
  87. data/lib/project_types/theme/commands/generate/env.rb +79 -0
  88. data/lib/project_types/theme/commands/push.rb +55 -0
  89. data/lib/project_types/theme/commands/serve.rb +31 -0
  90. data/lib/project_types/theme/forms/connect.rb +34 -0
  91. data/lib/project_types/theme/forms/create.rb +22 -0
  92. data/lib/project_types/theme/messages/messages.rb +147 -0
  93. data/lib/project_types/theme/tasks/ensure_themekit_installed.rb +78 -0
  94. data/lib/project_types/theme/themekit.rb +113 -0
  95. data/lib/shopify-cli/admin_api.rb +42 -2
  96. data/lib/shopify-cli/api.rb +34 -33
  97. data/lib/shopify-cli/commands/config.rb +24 -0
  98. data/lib/shopify-cli/commands/connect.rb +32 -15
  99. data/lib/shopify-cli/commands/system.rb +10 -1
  100. data/lib/shopify-cli/context.rb +23 -2
  101. data/lib/shopify-cli/core/entry_point.rb +1 -1
  102. data/lib/shopify-cli/core/monorail.rb +6 -4
  103. data/lib/shopify-cli/feature.rb +0 -2
  104. data/lib/shopify-cli/http_request.rb +27 -0
  105. data/lib/shopify-cli/js_deps.rb +1 -1
  106. data/lib/shopify-cli/messages/messages.rb +31 -7
  107. data/lib/shopify-cli/method_object.rb +104 -0
  108. data/lib/shopify-cli/partners_api.rb +25 -3
  109. data/lib/shopify-cli/process_supervision.rb +1 -1
  110. data/lib/shopify-cli/project.rb +12 -8
  111. data/lib/shopify-cli/project_type.rb +18 -2
  112. data/lib/shopify-cli/resolve_constant.rb +25 -0
  113. data/lib/shopify-cli/result.rb +432 -0
  114. data/lib/shopify-cli/shopifolk.rb +87 -0
  115. data/lib/shopify-cli/task.rb +8 -0
  116. data/lib/shopify-cli/tasks/create_api_client.rb +13 -2
  117. data/lib/shopify-cli/tasks/ensure_env.rb +3 -0
  118. data/lib/shopify-cli/tasks/select_org_and_shop.rb +10 -5
  119. data/lib/shopify-cli/tunnel.rb +8 -2
  120. data/lib/shopify-cli/version.rb +1 -1
  121. data/lib/shopify_cli.rb +5 -1
  122. data/shopify.fish +1 -1
  123. data/shopify.sh +1 -1
  124. data/vendor/deps/cli-kit/REVISION +1 -1
  125. data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +2 -2
  126. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +3 -3
  127. data/vendor/deps/cli-ui/REVISION +1 -1
  128. data/vendor/deps/cli-ui/lib/cli/ui.rb +26 -22
  129. data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +4 -6
  130. data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +3 -3
  131. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +8 -9
  132. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +1 -1
  133. data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +1 -0
  134. data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +15 -3
  135. data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +4 -11
  136. data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +3 -5
  137. data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +10 -10
  138. data/vendor/deps/cli-ui/lib/cli/ui/version.rb +1 -1
  139. data/vendor/deps/cli-ui/lib/cli/ui/wrap.rb +56 -0
  140. data/vendor/deps/webrick/.gitignore +9 -0
  141. data/vendor/deps/webrick/Gemfile +3 -0
  142. data/vendor/deps/webrick/LICENSE.txt +22 -0
  143. data/vendor/deps/webrick/README.md +61 -0
  144. data/vendor/deps/webrick/Rakefile +10 -0
  145. data/vendor/deps/webrick/lib/webrick.rb +232 -0
  146. data/vendor/deps/webrick/lib/webrick/accesslog.rb +157 -0
  147. data/vendor/deps/webrick/lib/webrick/cgi.rb +313 -0
  148. data/vendor/deps/webrick/lib/webrick/compat.rb +36 -0
  149. data/vendor/deps/webrick/lib/webrick/config.rb +158 -0
  150. data/vendor/deps/webrick/lib/webrick/cookie.rb +172 -0
  151. data/vendor/deps/webrick/lib/webrick/htmlutils.rb +30 -0
  152. data/vendor/deps/webrick/lib/webrick/httpauth.rb +96 -0
  153. data/vendor/deps/webrick/lib/webrick/httpauth/authenticator.rb +117 -0
  154. data/vendor/deps/webrick/lib/webrick/httpauth/basicauth.rb +116 -0
  155. data/vendor/deps/webrick/lib/webrick/httpauth/digestauth.rb +395 -0
  156. data/vendor/deps/webrick/lib/webrick/httpauth/htdigest.rb +132 -0
  157. data/vendor/deps/webrick/lib/webrick/httpauth/htgroup.rb +97 -0
  158. data/vendor/deps/webrick/lib/webrick/httpauth/htpasswd.rb +158 -0
  159. data/vendor/deps/webrick/lib/webrick/httpauth/userdb.rb +53 -0
  160. data/vendor/deps/webrick/lib/webrick/httpproxy.rb +354 -0
  161. data/vendor/deps/webrick/lib/webrick/httprequest.rb +636 -0
  162. data/vendor/deps/webrick/lib/webrick/httpresponse.rb +564 -0
  163. data/vendor/deps/webrick/lib/webrick/https.rb +152 -0
  164. data/vendor/deps/webrick/lib/webrick/httpserver.rb +294 -0
  165. data/vendor/deps/webrick/lib/webrick/httpservlet.rb +23 -0
  166. data/vendor/deps/webrick/lib/webrick/httpservlet/abstract.rb +152 -0
  167. data/vendor/deps/webrick/lib/webrick/httpservlet/cgi_runner.rb +47 -0
  168. data/vendor/deps/webrick/lib/webrick/httpservlet/cgihandler.rb +126 -0
  169. data/vendor/deps/webrick/lib/webrick/httpservlet/erbhandler.rb +88 -0
  170. data/vendor/deps/webrick/lib/webrick/httpservlet/filehandler.rb +552 -0
  171. data/vendor/deps/webrick/lib/webrick/httpservlet/prochandler.rb +47 -0
  172. data/vendor/deps/webrick/lib/webrick/httpstatus.rb +194 -0
  173. data/vendor/deps/webrick/lib/webrick/httputils.rb +512 -0
  174. data/vendor/deps/webrick/lib/webrick/httpversion.rb +76 -0
  175. data/vendor/deps/webrick/lib/webrick/log.rb +156 -0
  176. data/vendor/deps/webrick/lib/webrick/server.rb +381 -0
  177. data/vendor/deps/webrick/lib/webrick/ssl.rb +215 -0
  178. data/vendor/deps/webrick/lib/webrick/utils.rb +265 -0
  179. data/vendor/deps/webrick/lib/webrick/version.rb +18 -0
  180. data/vendor/deps/webrick/webrick.gemspec +74 -0
  181. metadata +77 -27
  182. data/docs/Gemfile +0 -5
  183. data/docs/Gemfile.lock +0 -258
  184. data/docs/_data/nav.yml +0 -35
  185. data/docs/_includes/footer.html +0 -15
  186. data/docs/_includes/head.html +0 -19
  187. data/docs/_includes/sidebar_nav.html +0 -22
  188. data/docs/_includes/toc.html +0 -112
  189. data/docs/_layouts/default.html +0 -79
  190. data/docs/css/docs.css +0 -157
  191. data/docs/images/header.png +0 -0
  192. data/docs/installing-ruby.md +0 -28
  193. data/lib/project_types/extension/features/argo/admin.rb +0 -20
  194. data/lib/project_types/extension/features/argo/base.rb +0 -129
  195. data/lib/project_types/extension/features/argo/checkout.rb +0 -20
  196. data/lib/project_types/extension/models/type.rb +0 -81
  197. data/lib/project_types/extension/models/types/checkout_post_purchase.rb +0 -23
  198. data/lib/project_types/extension/models/types/product_subscription.rb +0 -24
  199. data/lib/project_types/node/commands/generate/billing.rb +0 -39
  200. data/lib/project_types/node/commands/generate/page.rb +0 -59
  201. data/lib/project_types/node/commands/generate/webhook.rb +0 -37
  202. data/lib/project_types/script/layers/domain/script.rb +0 -18
  203. data/lib/project_types/script/layers/infrastructure/assemblyscript_tsconfig.rb +0 -38
  204. data/lib/project_types/script/layers/infrastructure/script_repository.rb +0 -59
  205. data/lib/project_types/script/templates/ts/as-pect.config.js +0 -27
  206. data/lib/project_types/script/templates/ts/as-pect.d.ts +0 -1
@@ -0,0 +1,78 @@
1
+ module Theme
2
+ module Tasks
3
+ class EnsureThemekitInstalled < ShopifyCli::Task
4
+ URL = 'https://shopify-themekit.s3.amazonaws.com/releases/latest.json'
5
+ OSMAP = {
6
+ mac: 'darwin-amd64',
7
+ linux: 'linux-amd64',
8
+ windows: 'windows-amd64',
9
+ }
10
+ VERSION_CHECK_INTERVAL = 604800
11
+ VERSION_CHECK_SECTION = 'themekit_version_check'
12
+ LAST_CHECKED_AT_FIELD = 'last_checked_at'
13
+
14
+ def call(ctx)
15
+ _out, stat = ctx.capture2e(Themekit::THEMEKIT)
16
+ unless stat.success?
17
+ CLI::UI::Frame.open(ctx.message('theme.tasks.ensure_themekit_installed.installing_themekit')) do
18
+ install_themekit(ctx)
19
+ end
20
+ end
21
+
22
+ now = Time.now.to_i
23
+ if ShopifyCli::Feature.enabled?(:themekit_auto_update) && (time_of_last_check + VERSION_CHECK_INTERVAL) < now
24
+ CLI::UI::Frame.open(ctx.message('theme.tasks.ensure_themekit_installed.updating_themekit')) do
25
+ unless Themekit.update(ctx)
26
+ ctx.abort(ctx.message('theme.tasks.ensure_themekit_installed.errors.update_fail'))
27
+ end
28
+ update_time_of_last_check(now)
29
+ end
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def install_themekit(ctx)
36
+ require 'json'
37
+ require 'fileutils'
38
+ require 'digest'
39
+ require 'open-uri'
40
+
41
+ begin
42
+ begin
43
+ releases = JSON.parse(Net::HTTP.get(URI(URL)))
44
+ release = releases["platforms"].find { |r| r["name"] == OSMAP[ctx.os] }
45
+ rescue
46
+ ctx.abort(ctx.message('theme.tasks.ensure_themekit_installed.errors.releases_fail'))
47
+ end
48
+
49
+ ctx.puts(ctx.message('theme.tasks.ensure_themekit_installed.downloading', releases['version']))
50
+ _out, stat = ctx.capture2e('curl', '-o', Themekit::THEMEKIT, release["url"])
51
+ ctx.abort(ctx.message('theme.tasks.ensure_themekit_installed.errors.write_fail')) unless stat.success?
52
+
53
+ ctx.puts(ctx.message('theme.tasks.ensure_themekit_installed.verifying'))
54
+ if Digest::MD5.file(Themekit::THEMEKIT) == release['digest']
55
+ FileUtils.chmod("+x", Themekit::THEMEKIT)
56
+ ctx.puts(ctx.message('theme.tasks.ensure_themekit_installed.successful'))
57
+
58
+ auto = CLI::UI.confirm(ctx.message('theme.tasks.ensure_themekit_installed.auto_update'))
59
+ ShopifyCli::Feature.set(:themekit_auto_update, auto)
60
+ else
61
+ ctx.abort(ctx.message('theme.tasks.ensure_themekit_installed.errors.digest_fail'))
62
+ end
63
+ rescue StandardError, ShopifyCli::Abort => e
64
+ FileUtils.rm(Themekit::THEMEKIT) if File.exist?(Themekit::THEMEKIT)
65
+ raise e
66
+ end
67
+ end
68
+
69
+ def time_of_last_check
70
+ (val = ShopifyCli::Config.get(VERSION_CHECK_SECTION, LAST_CHECKED_AT_FIELD)) ? val.to_i : 0
71
+ end
72
+
73
+ def update_time_of_last_check(time)
74
+ ShopifyCli::Config.set(VERSION_CHECK_SECTION, LAST_CHECKED_AT_FIELD, time)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,113 @@
1
+ module Theme
2
+ class Themekit
3
+ THEMEKIT = File.join(ShopifyCli.cache_dir, "themekit")
4
+
5
+ class << self
6
+ def add_flags(flags)
7
+ flags.map do |key, value|
8
+ flag = "--#{key}"
9
+ flag += "=#{value}" if value.is_a?(String)
10
+ flag
11
+ end
12
+ end
13
+
14
+ def connect(ctx, store:, password:, themeid:, env:)
15
+ command = build_command('get', env)
16
+ command << "--password=#{password}"
17
+ command << "--store=#{store}"
18
+ command << "--themeid=#{themeid}"
19
+
20
+ stat = ctx.system(*command)
21
+ stat.success?
22
+ end
23
+
24
+ def create(ctx, password:, store:, name:, env:)
25
+ command = build_command('new', env)
26
+ command << "--password=#{password}"
27
+ command << "--store=#{store}"
28
+ command << "--name=#{name}"
29
+
30
+ stat = ctx.system(*command)
31
+ stat.success?
32
+ end
33
+
34
+ def deploy(ctx, flags: nil, env:)
35
+ unless push(ctx, flags: flags, env: env)
36
+ ctx.abort(ctx.message('theme.deploy.push_fail'))
37
+ end
38
+ ctx.done(ctx.message('theme.deploy.info.pushed'))
39
+
40
+ command = build_command('publish', env)
41
+ (command << flags).compact!
42
+ command.flatten!
43
+
44
+ stat = ctx.system(*command)
45
+ stat.success?
46
+ end
47
+
48
+ def generate_env(ctx, store:, password:, themeid:, env:)
49
+ command = build_command('configure', env)
50
+ command << "--password=#{password}"
51
+ command << "--store=#{store}"
52
+ command << "--themeid=#{themeid}"
53
+
54
+ stat = ctx.system(*command)
55
+ stat.success?
56
+ end
57
+
58
+ def push(ctx, files: nil, flags: nil, remove: false, env:)
59
+ action = remove ? 'remove' : 'deploy'
60
+ command = build_command(action, env)
61
+
62
+ (command << files << flags).compact!
63
+ command.flatten!
64
+
65
+ stat = ctx.system(*command)
66
+ stat.success?
67
+ end
68
+
69
+ def query_themes(ctx, store:, password:)
70
+ begin
71
+ resp = ::ShopifyCli::AdminAPI.rest_request(
72
+ ctx,
73
+ shop: store,
74
+ token: password,
75
+ path: "themes.json",
76
+ )
77
+ rescue ShopifyCli::API::APIRequestUnauthorizedError
78
+ ctx.abort(ctx.message('theme.themekit.query_themes.bad_password'))
79
+ rescue StandardError
80
+ ctx.abort(ctx.message('theme.themekit.query_themes.not_connect'))
81
+ end
82
+
83
+ resp[1]['themes'].map { |theme| [theme['name'], theme['id']] }.to_h
84
+ end
85
+
86
+ def serve(ctx, flags: nil, env:)
87
+ command = build_command('open', env)
88
+ out, stat = ctx.capture2e(*command)
89
+ ctx.puts(out)
90
+ ctx.abort(ctx.message('theme.serve.open_fail')) unless stat.success?
91
+
92
+ command = build_command('watch', env)
93
+ (command << flags).compact!
94
+ command.flatten!
95
+ ctx.system(*command)
96
+ end
97
+
98
+ def update(ctx)
99
+ command = build_command('update')
100
+ ctx.system(*command)
101
+ end
102
+
103
+ private
104
+
105
+ def build_command(action, env = nil)
106
+ command = [THEMEKIT, action]
107
+ command << '--no-update-notifier'
108
+ command << "--env=#{env}" if env
109
+ command
110
+ end
111
+ end
112
+ end
113
+ end
@@ -43,6 +43,46 @@ module ShopifyCli
43
43
  end
44
44
  end
45
45
 
46
+ ##
47
+ #
48
+ #
49
+ #
50
+ # #### Parameters
51
+ # - `ctx`: running context from your command
52
+ # - `shop`: shop domain string for shop whose admin you are calling
53
+ # - `path`: path string (excluding prefixes and API version) for specific JSON that you are requesting
54
+ # ex. "data.json" instead of "/admin/api/unstable/data.json"
55
+ # - `body`: data string for corresponding REST request types
56
+ # - `method`: REST request string for the type of request; if nil, will perform GET request
57
+ # - `api_version`: API version string to specify version; if nil, latest will be used
58
+ # - `token`: shop password string for authentication to shop
59
+ #
60
+ # #### Raises
61
+ #
62
+ # * http 404 will raise a ShopifyCli::API::APIRequestNotFoundError
63
+ # * http 400..499 will raise a ShopifyCli::API::APIRequestClientError
64
+ # * http 500..599 will raise a ShopifyCli::API::APIRequestServerError
65
+ # * All other codes will raise ShopifyCli::API::APIRequestUnexpectedError
66
+ #
67
+ # #### Returns
68
+ #
69
+ # * `resp` - JSON response array
70
+ #
71
+ # #### Example
72
+ #
73
+ # ShopifyCli::AdminAPI.rest_request(@ctx,
74
+ # shop: 'shop.myshopify.com',
75
+ # path: 'data.json',
76
+ # token: 'password')
77
+ #
78
+ def rest_request(ctx, shop:, path:, body: nil, method: "GET", api_version: nil, token: nil)
79
+ ShopifyCli::DB.set(admin_access_token: token) unless token.nil?
80
+ url = URI::HTTPS.build(host: shop, path: "/admin/api/#{fetch_api_version(ctx, api_version, shop)}/#{path}")
81
+ resp = api_client(ctx, api_version, shop, path: path).request(url: url.to_s, body: body, method: method)
82
+ ShopifyCli::DB.set(admin_access_token: nil) unless token.nil?
83
+ resp
84
+ end
85
+
46
86
  private
47
87
 
48
88
  def authenticated_req(ctx, shop)
@@ -65,12 +105,12 @@ module ShopifyCli
65
105
  ).authenticate("https://#{shop}/admin/oauth")
66
106
  end
67
107
 
68
- def api_client(ctx, api_version, shop)
108
+ def api_client(ctx, api_version, shop, path: 'graphql.json')
69
109
  new(
70
110
  ctx: ctx,
71
111
  auth_header: 'X-Shopify-Access-Token',
72
112
  token: admin_access_token(ctx, shop),
73
- url: "https://#{shop}/admin/api/#{fetch_api_version(ctx, api_version, shop)}/graphql.json",
113
+ url: "https://#{shop}/admin/api/#{fetch_api_version(ctx, api_version, shop)}/#{path}",
74
114
  )
75
115
  end
76
116
 
@@ -1,5 +1,4 @@
1
1
  require 'shopify_cli'
2
- require 'net/http'
3
2
 
4
3
  module ShopifyCli
5
4
  class API
@@ -25,47 +24,31 @@ module ShopifyCli
25
24
 
26
25
  def query(query_name, variables: {})
27
26
  _, resp = request(
28
- load_query(query_name),
29
- variables: variables,
30
- headers: default_headers,
31
- graphql_url: url,
27
+ body: JSON.dump(query: load_query(query_name).tr("\n", ""), variables: variables),
28
+ url: url,
32
29
  )
33
30
  ctx.debug(resp)
34
31
  resp
35
- rescue API::APIRequestServerError, API::APIRequestUnexpectedError
32
+ rescue API::APIRequestServerError, API::APIRequestUnexpectedError => e
36
33
  ctx.puts(ctx.message('core.api.error.internal_server_error'))
34
+ ctx.debug(ctx.message('core.api.error.internal_server_error_debug', e.message))
37
35
  end
38
36
 
39
- protected
40
-
41
- def load_query(name)
42
- project_type = ShopifyCli::Project.current_project_type
43
- project_file_path = File.join(
44
- ShopifyCli::ROOT, 'lib', 'project_types', project_type.to_s, 'graphql', "#{name}.graphql"
45
- )
46
- if !project_type.nil? && File.exist?(project_file_path)
47
- File.read(project_file_path)
48
- else
49
- File.read(File.join(ShopifyCli::ROOT, 'lib', 'graphql', "#{name}.graphql"))
50
- end
51
- end
52
-
53
- private
54
-
55
- def request(body, graphql_url:, variables: {}, headers: {})
37
+ def request(url:, body: nil, headers: {}, method: "POST")
56
38
  CLI::Kit::Util.begin do
57
- uri = URI.parse(graphql_url)
39
+ uri = URI.parse(url)
58
40
  unless uri.is_a?(URI::HTTP)
59
- ctx.abort("Invalid URL: #{graphql_url}")
41
+ ctx.abort(ctx.message('core.api.error.invalid_url', url))
60
42
  end
61
- http = ::Net::HTTP.new(uri.host, uri.port)
62
- http.use_ssl = true
63
43
 
64
- req = ::Net::HTTP::Post.new(uri.request_uri)
65
- req.body = JSON.dump(query: body.tr("\n", ""), variables: variables)
66
- req['Content-Type'] = 'application/json'
67
- headers.each { |header, value| req[header] = value }
68
- response = http.request(req)
44
+ # we delay this require so as to avoid a performance hit on starting the CLI
45
+ require 'shopify-cli/http_request'
46
+ headers = default_headers.merge(headers)
47
+ response = if method == "POST"
48
+ HttpRequest.post(uri, body, headers)
49
+ elsif method == "GET"
50
+ HttpRequest.get(uri, body, headers)
51
+ end
69
52
 
70
53
  case response.code.to_i
71
54
  when 200..399
@@ -88,6 +71,22 @@ module ShopifyCli
88
71
  end
89
72
  end
90
73
 
74
+ protected
75
+
76
+ def load_query(name)
77
+ project_type = ShopifyCli::Project.current_project_type
78
+ project_file_path = File.join(
79
+ ShopifyCli::ROOT, 'lib', 'project_types', project_type.to_s, 'graphql', "#{name}.graphql"
80
+ )
81
+ if !project_type.nil? && File.exist?(project_file_path)
82
+ File.read(project_file_path)
83
+ else
84
+ File.read(File.join(ShopifyCli::ROOT, 'lib', 'graphql', "#{name}.graphql"))
85
+ end
86
+ end
87
+
88
+ private
89
+
91
90
  def current_sha
92
91
  @current_sha ||= Git.sha(dir: ShopifyCli::ROOT)
93
92
  end
@@ -95,7 +94,9 @@ module ShopifyCli
95
94
  def default_headers
96
95
  {
97
96
  'User-Agent' => "Shopify App CLI #{ShopifyCli::VERSION} #{current_sha} | #{ctx.uname}",
98
- }.merge(auth_headers(token))
97
+ }.tap do |headers|
98
+ headers['X-Shopify-Cli-Employee'] = '1' if Shopifolk.acting_as_shopify_organization?
99
+ end.merge(auth_headers(token))
99
100
  end
100
101
 
101
102
  def auth_headers(token)
@@ -7,6 +7,7 @@ module ShopifyCli
7
7
 
8
8
  subcommand :Feature, 'feature'
9
9
  subcommand :Analytics, 'analytics'
10
+ subcommand :ShopifolkBeta, 'shopifolk-beta'
10
11
 
11
12
  def call(*)
12
13
  @ctx.puts(self.class.help)
@@ -71,6 +72,29 @@ module ShopifyCli
71
72
  end
72
73
  end
73
74
  end
75
+
76
+ class ShopifolkBeta < ShopifyCli::SubCommand
77
+ options do |parser, flags|
78
+ parser.on('--enable') { flags[:action] = 'enable' }
79
+ parser.on('--disable') { flags[:action] = 'disable' }
80
+ parser.on('--status') { flags[:action] = 'status' }
81
+ end
82
+
83
+ def call(_args, _name)
84
+ is_enabled = ShopifyCli::Config.get_bool('shopifolk-beta', 'enabled')
85
+ if options.flags[:action] == 'disable' && is_enabled
86
+ ShopifyCli::Config.set('shopifolk-beta', 'enabled', false)
87
+ @ctx.puts(@ctx.message('core.config.shopifolk_beta.disabled'))
88
+ elsif options.flags[:action] == 'enable' && !is_enabled
89
+ ShopifyCli::Config.set('shopifolk-beta', 'enabled', true)
90
+ @ctx.puts(@ctx.message('core.config.shopifolk_beta.enabled'))
91
+ elsif is_enabled
92
+ @ctx.puts(@ctx.message('core.config.shopifolk_beta.is_enabled'))
93
+ else
94
+ @ctx.puts(@ctx.message('core.config.shopifolk_beta.is_disabled'))
95
+ end
96
+ end
97
+ end
74
98
  end
75
99
  end
76
100
  end
@@ -3,23 +3,33 @@ require 'shopify_cli'
3
3
  module ShopifyCli
4
4
  module Commands
5
5
  class Connect < ShopifyCli::Command
6
- def call(*)
7
- project_type = ask_project_type unless Project.has_current?
8
-
9
- if Project.has_current? && Project.current && Project.current.env
10
- @ctx.puts @ctx.message('core.connect.already_connected_warning')
11
- prod_warning = @ctx.message('core.connect.production_warning')
12
- @ctx.puts prod_warning if [:rails, :node].include?(Project.current_project_type)
6
+ class << self
7
+ def call(args, command_name)
8
+ ProjectType.load_type(args[0]) unless args.empty?
9
+ super
13
10
  end
14
11
 
15
- org = ShopifyCli::Tasks::EnsureEnv.call(@ctx, regenerate: true)
16
- write_cli_yml(project_type, org['id']) unless Project.has_current?
17
- api_key = Project.current(force_reload: true).env['api_key']
18
- @ctx.puts(@ctx.message('core.connect.connected', get_app(org['apps'], api_key).first["title"]))
12
+ def help
13
+ ShopifyCli::Context.message('core.connect.help', ShopifyCli::TOOL_NAME)
14
+ end
19
15
  end
20
16
 
21
- def get_app(apps, api_key)
22
- apps.select { |app| app["apiKey"] == api_key }
17
+ def call(args, command_name)
18
+ if Project.current&.env
19
+ @ctx.puts(@ctx.message('core.connect.already_connected_warning'))
20
+ end
21
+
22
+ project_type = ask_project_type
23
+
24
+ klass = ProjectType.load_type(project_type)&.connect_command
25
+
26
+ if klass
27
+ klass.ctx = @ctx
28
+ klass.call(args, command_name, 'connect')
29
+ else
30
+ app = default_connect(project_type)
31
+ @ctx.done(@ctx.message('core.connect.connected', app))
32
+ end
23
33
  end
24
34
 
25
35
  def ask_project_type
@@ -30,6 +40,13 @@ module ShopifyCli
30
40
  end
31
41
  end
32
42
 
43
+ def default_connect(project_type)
44
+ org = ShopifyCli::Tasks::EnsureEnv.call(@ctx, regenerate: true)
45
+ write_cli_yml(project_type, org['id']) unless Project.has_current?
46
+ api_key = Project.current(force_reload: true).env['api_key']
47
+ get_app(org['apps'], api_key).first['title']
48
+ end
49
+
33
50
  def write_cli_yml(project_type, org_id)
34
51
  ShopifyCli::Project.write(
35
52
  @ctx,
@@ -39,8 +56,8 @@ module ShopifyCli
39
56
  @ctx.done(@ctx.message('core.connect.cli_yml_saved'))
40
57
  end
41
58
 
42
- def self.help
43
- ShopifyCli::Context.message('core.connect.help', ShopifyCli::TOOL_NAME)
59
+ def get_app(apps, api_key)
60
+ apps.select { |app| app["apiKey"] == api_key }
44
61
  end
45
62
  end
46
63
  end