shopify-cli 1.3.0 → 1.6.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.
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