shopify-cli 1.2.0 → 1.5.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 (71) 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 +9 -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/CHANGELOG.md +25 -0
  11. data/Gemfile +3 -2
  12. data/Gemfile.lock +39 -37
  13. data/RELEASING.md +19 -29
  14. data/docs/core/index.md +16 -0
  15. data/lib/project_types/extension/cli.rb +7 -2
  16. data/lib/project_types/extension/commands/register.rb +1 -1
  17. data/lib/project_types/extension/features/argo/admin.rb +20 -0
  18. data/lib/project_types/extension/features/argo/base.rb +129 -0
  19. data/lib/project_types/extension/features/argo/checkout.rb +20 -0
  20. data/lib/project_types/extension/messages/messages.rb +8 -2
  21. data/lib/project_types/extension/models/type.rb +4 -0
  22. data/lib/project_types/extension/models/types/checkout_post_purchase.rb +2 -2
  23. data/lib/project_types/extension/models/types/product_subscription.rb +24 -0
  24. data/lib/project_types/node/cli.rb +4 -1
  25. data/lib/project_types/node/commands/connect.rb +15 -0
  26. data/lib/project_types/node/commands/create.rb +8 -4
  27. data/lib/project_types/node/messages/messages.rb +7 -6
  28. data/lib/project_types/rails/cli.rb +4 -1
  29. data/lib/project_types/rails/commands/connect.rb +15 -0
  30. data/lib/project_types/rails/commands/create.rb +8 -4
  31. data/lib/project_types/rails/messages/messages.rb +7 -4
  32. data/lib/project_types/script/cli.rb +2 -1
  33. data/lib/project_types/script/commands/enable.rb +12 -4
  34. data/lib/project_types/script/config/extension_points.yml +13 -12
  35. data/lib/project_types/script/errors.rb +4 -0
  36. data/lib/project_types/script/layers/application/build_script.rb +12 -16
  37. data/lib/project_types/script/layers/domain/errors.rb +3 -0
  38. data/lib/project_types/script/layers/domain/extension_point.rb +0 -1
  39. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +15 -50
  40. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +28 -7
  41. data/lib/project_types/script/layers/infrastructure/errors.rb +16 -0
  42. data/lib/project_types/script/layers/infrastructure/script_repository.rb +0 -12
  43. data/lib/project_types/script/layers/infrastructure/script_service.rb +2 -0
  44. data/lib/project_types/script/messages/messages.rb +23 -5
  45. data/lib/project_types/script/ui/error_handler.rb +31 -6
  46. data/lib/shopify-cli/api.rb +8 -10
  47. data/lib/shopify-cli/commands/config.rb +57 -1
  48. data/lib/shopify-cli/commands/connect.rb +32 -15
  49. data/lib/shopify-cli/commands/system.rb +9 -0
  50. data/lib/shopify-cli/core/entry_point.rb +1 -1
  51. data/lib/shopify-cli/core/monorail.rb +6 -4
  52. data/lib/shopify-cli/http_request.rb +15 -0
  53. data/lib/shopify-cli/js_deps.rb +1 -1
  54. data/lib/shopify-cli/js_system.rb +22 -5
  55. data/lib/shopify-cli/messages/messages.rb +44 -9
  56. data/lib/shopify-cli/partners_api.rb +17 -1
  57. data/lib/shopify-cli/process_supervision.rb +1 -1
  58. data/lib/shopify-cli/project.rb +12 -8
  59. data/lib/shopify-cli/project_type.rb +17 -1
  60. data/lib/shopify-cli/shopifolk.rb +86 -0
  61. data/lib/shopify-cli/task.rb +8 -0
  62. data/lib/shopify-cli/tasks/create_api_client.rb +13 -2
  63. data/lib/shopify-cli/tasks/ensure_env.rb +3 -0
  64. data/lib/shopify-cli/tasks/select_org_and_shop.rb +4 -0
  65. data/lib/shopify-cli/tunnel.rb +1 -1
  66. data/lib/shopify-cli/version.rb +1 -1
  67. data/lib/shopify_cli.rb +1 -0
  68. metadata +13 -5
  69. data/lib/project_types/extension/features/argo.rb +0 -48
  70. data/lib/project_types/extension/models/types/subscription_management.rb +0 -20
  71. data/lib/project_types/script/layers/infrastructure/assemblyscript_tsconfig.rb +0 -38
@@ -17,6 +17,13 @@ module Rails
17
17
  setting_gem_path: "GEM_PATH being set to %s",
18
18
  },
19
19
 
20
+ connect: {
21
+ connected: "Project now connected to {{green:%s}}",
22
+ production_warning: <<~MESSAGE,
23
+ {{yellow:! Warning: if you have connected to an {{bold:app in production}}, running {{command:serve}} may update the app URL and cause an outage.
24
+ MESSAGE
25
+ },
26
+
20
27
  create: {
21
28
  help: <<~HELP,
22
29
  {{command:%s create rails}}: Creates a ruby on rails app.
@@ -48,10 +55,6 @@ module Rails
48
55
  },
49
56
 
50
57
  info: {
51
- created: "{{v}} {{green:%s}} was created in your Partner Dashboard {{underline:%s}}",
52
- serve: "{{*}} Change directories to your new project folder {{green:%s}} and run {{command:%s serve}} " \
53
- "to start a local server",
54
- install: "{{*}} Then, visit {{underline:%s/test}} to install {{green:%s}} on your Dev Store",
55
58
  open_new_shell: "{{*}} {{yellow:After installing %s, please open a new Command Prompt or PowerShell " \
56
59
  "window to continue.}}",
57
60
  },
@@ -3,7 +3,8 @@
3
3
  module Script
4
4
  class Project < ShopifyCli::ProjectType
5
5
  hidden_feature(feature_set: :script_project)
6
- creator 'Script', 'Script::Commands::Create'
6
+ title('Script')
7
+ creator('Script::Commands::Create')
7
8
 
8
9
  register_command('Script::Commands::Push', 'push')
9
10
  register_command('Script::Commands::Disable', 'disable')
@@ -4,9 +4,7 @@ module Script
4
4
  module Commands
5
5
  class Enable < ShopifyCli::Command
6
6
  options do |parser, flags|
7
- parser.on('--config_props=KEYVALUEPAIRS', Array) do |t|
8
- flags[:config_props] = Hash[t.map { |s| s.split(':') }]
9
- end
7
+ parser.on('--config_props=KEYVALUEPAIRS', Array) { |t| flags[:config_props] = t }
10
8
  parser.on('--config_file=CONFIGFILEPATH') { |t| flags[:config_file] = t }
11
9
  end
12
10
 
@@ -47,7 +45,7 @@ module Script
47
45
  def acquire_configuration(config_file: nil, config_props: nil)
48
46
  properties = {}
49
47
  properties = YAML.load(File.read(config_file)) unless config_file.nil?
50
- properties = properties.merge(config_props) unless config_props.nil?
48
+ properties = properties.merge(parse_config_props(config_props)) unless config_props.nil?
51
49
 
52
50
  configuration = { entries: [] }
53
51
  properties.each do |key, value|
@@ -61,6 +59,16 @@ module Script
61
59
  raise Errors::InvalidConfigYAMLError, options.flags[:config_file]
62
60
  end
63
61
 
62
+ def parse_config_props(config_props)
63
+ Hash[
64
+ config_props.map do |s|
65
+ args = s.split(':').map(&:strip)
66
+ raise Errors::InvalidConfigProps unless args.size == 2
67
+ args
68
+ end
69
+ ]
70
+ end
71
+
64
72
  # No slice pre Ruby 2.5 so roll our own
65
73
  def slice(hash, *keys)
66
74
  Hash[hash.to_a - hash.select { |key, _value| !keys.include?(key) }.to_a]
@@ -1,24 +1,25 @@
1
1
  discount:
2
2
  assemblyscript:
3
3
  package: "@shopify/extension-point-as-discount"
4
- version: "^0.2.10"
5
- sdk-version: "^6.0.0"
6
- toolchain-version: "^1.1.0"
4
+ sdk-version: "^7.0.0"
5
+ toolchain-version: "^2.0.1"
7
6
  unit_limit_per_order:
8
7
  assemblyscript:
9
8
  package: "@shopify/extension-point-as-unit-limit-per-order"
10
- version: "^0.1.12"
11
- sdk-version: "^6.0.0"
12
- toolchain-version: "^1.1.0"
9
+ sdk-version: "^7.0.0"
10
+ toolchain-version: "^2.0.1"
13
11
  payment_filter:
14
12
  assemblyscript:
15
13
  package: "@shopify/extension-point-as-payment-filter"
16
- version: "^0.2.8"
17
- sdk-version: "^6.0.0"
18
- toolchain-version: "^1.1.0"
14
+ sdk-version: "^7.0.0"
15
+ toolchain-version: "^2.0.1"
19
16
  shipping_filter:
20
17
  assemblyscript:
21
18
  package: "@shopify/extension-point-as-shipping-filter"
22
- version: "^0.2.10"
23
- sdk-version: "^6.0.0"
24
- toolchain-version: "^1.1.0"
19
+ sdk-version: "^7.0.0"
20
+ toolchain-version: "^2.0.1"
21
+ tax_filter:
22
+ assemblyscript:
23
+ package: "@shopify/extension-point-as-tax-filter"
24
+ sdk-version: "^7.0.0"
25
+ toolchain-version: "^2.0.1"
@@ -6,6 +6,7 @@ module Script
6
6
  class InvalidScriptNameError < ScriptProjectError; end
7
7
  class NoExistingAppsError < ScriptProjectError; end
8
8
  class NoExistingOrganizationsError < ScriptProjectError; end
9
+
9
10
  class NoExistingStoresError < ScriptProjectError
10
11
  attr_reader :organization_id
11
12
  def initialize(organization_id)
@@ -13,7 +14,10 @@ module Script
13
14
  @organization_id = organization_id
14
15
  end
15
16
  end
17
+
16
18
  class ScriptProjectAlreadyExistsError < ScriptProjectError; end
19
+ class InvalidConfigProps < ScriptProjectError; end
20
+
17
21
  class InvalidConfigYAMLError < ScriptProjectError
18
22
  attr_reader :config_file
19
23
  def initialize(config_file)
@@ -6,32 +6,28 @@ module Script
6
6
  class BuildScript
7
7
  class << self
8
8
  def call(ctx:, task_runner:, script:)
9
- return if CLI::UI::Frame.open(ctx.message('script.application.building')) do
9
+ CLI::UI::Frame.open(ctx.message('script.application.building')) do
10
10
  begin
11
11
  UI::StrictSpinner.spin(ctx.message('script.application.building_script')) do |spinner|
12
- build(ctx, task_runner, script)
12
+ Infrastructure::PushPackageRepository
13
+ .new(ctx: ctx)
14
+ .create_push_package(script, task_runner.build, task_runner.compiled_type)
13
15
  spinner.update_title(ctx.message('script.application.built'))
14
16
  end
15
- true
16
17
  rescue StandardError => e
17
18
  CLI::UI::Frame.with_frame_color_override(:red) do
18
19
  ctx.puts("\n{{red:#{e.message}}}")
19
20
  end
20
- false
21
- end
22
- end
23
- raise Infrastructure::Errors::BuildError
24
- end
21
+ errors = [
22
+ Infrastructure::Errors::InvalidBuildScriptError,
23
+ Infrastructure::Errors::BuildScriptNotFoundError,
24
+ Infrastructure::Errors::WebAssemblyBinaryNotFoundError,
25
+ ]
25
26
 
26
- private
27
-
28
- def build(ctx, task_runner, script)
29
- script_repo = Infrastructure::ScriptRepository.new(ctx: ctx)
30
- script_content = script_repo.with_temp_build_context do
31
- task_runner.build
27
+ raise Infrastructure::Errors::BuildError unless errors.any? { |err| e.is_a?(err) }
28
+ raise
29
+ end
32
30
  end
33
- Infrastructure::PushPackageRepository.new(ctx: ctx)
34
- .create_push_package(script, script_content, task_runner.compiled_type)
35
31
  end
36
32
  end
37
33
  end
@@ -5,6 +5,7 @@ module Script
5
5
  module Domain
6
6
  module Errors
7
7
  class PushPackageNotFoundError < ScriptProjectError; end
8
+
8
9
  class InvalidExtensionPointError < ScriptProjectError
9
10
  attr_reader :type
10
11
  def initialize(type)
@@ -12,6 +13,7 @@ module Script
12
13
  @type = type
13
14
  end
14
15
  end
16
+
15
17
  class ScriptNotFoundError < ScriptProjectError
16
18
  attr_reader :script_name, :extension_point_type
17
19
  def initialize(extension_point_type, script_name)
@@ -20,6 +22,7 @@ module Script
20
22
  @extension_point_type = extension_point_type
21
23
  end
22
24
  end
25
+
23
26
  class ServiceFailureError < ScriptProjectError; end
24
27
  end
25
28
  end
@@ -19,7 +19,6 @@ module Script
19
19
 
20
20
  def initialize(config)
21
21
  @package = config["package"]
22
- @version = config["version"]
23
22
  @sdk_version = config["sdk-version"]
24
23
  @toolchain_version = config["toolchain-version"]
25
24
  end
@@ -10,11 +10,8 @@ module Script
10
10
  property! :script_name, accepts: String
11
11
  property! :path_to_project, accepts: String
12
12
 
13
- BOOTSTRAP_SRC = "npx --no-install shopify-scripts-bootstrap src %{src_base}"
14
- BOOTSTRAP_TEST = "npx --no-install shopify-scripts-bootstrap test %{test_base}"
15
- SOURCE_DIR = "src"
16
- TEST_DIR = "test"
17
- LANGUAGE = "ts"
13
+ BOOTSTRAP = "npx --no-install shopify-scripts-toolchain-as bootstrap --from %{extension_point} --dest %{base}"
14
+ MIN_NODE_VERSION = "14.5.0"
18
15
 
19
16
  def setup_dependencies
20
17
  write_npmrc
@@ -22,42 +19,12 @@ module Script
22
19
  end
23
20
 
24
21
  def bootstrap
25
- create_src_folder
26
- create_test_folder
27
- end
28
-
29
- private
30
-
31
- def create_src_folder
32
- ctx.mkdir_p(src_base)
33
- out, status = ctx.capture2e(format(BOOTSTRAP_SRC, src_base: src_base))
22
+ type = extension_point.type.gsub('_', '-')
23
+ out, status = ctx.capture2e(format(BOOTSTRAP, extension_point: type, base: path_to_project))
34
24
  raise Domain::Errors::ServiceFailureError, out unless status.success?
35
-
36
- write_tsconfig_file(SOURCE_DIR, ".")
37
- end
38
-
39
- def create_test_folder
40
- ctx.mkdir_p(test_base)
41
- out, status = ctx.capture2e(format(BOOTSTRAP_TEST, test_base: test_base))
42
- raise Domain::Errors::ServiceFailureError, out unless status.success?
43
-
44
- copy_template_file(test_base, 'as-pect.config.js')
45
- copy_template_file(test_base, 'as-pect.d.ts')
46
- write_tsconfig_file(TEST_DIR, "../#{SOURCE_DIR}")
47
25
  end
48
26
 
49
- def test_base
50
- "#{path_to_project}/#{TEST_DIR}"
51
- end
52
-
53
- def src_base
54
- "#{path_to_project}/#{SOURCE_DIR}"
55
- end
56
-
57
- def copy_template_file(destination, name)
58
- template_file = Project.project_filepath("templates/#{LANGUAGE}/#{name}")
59
- ctx.cp(template_file, "#{destination}/#{name}")
60
- end
27
+ private
61
28
 
62
29
  def write_npmrc
63
30
  ctx.system(
@@ -68,12 +35,10 @@ module Script
68
35
  )
69
36
  end
70
37
 
71
- def write_tsconfig_file(dir, path_to_source)
72
- AssemblyScriptTsConfig
73
- .new(dir_to_write_in: dir)
74
- .with_extends_assemblyscript_config(relative_path_to_node_modules: ".")
75
- .with_module_resolution_paths(paths: { "*": ["#{path_to_source}/*.ts"] })
76
- .write
38
+ def extension_point_version
39
+ out, status = ctx.capture2e("npm show #{extension_point.sdks[:ts].package} version --json")
40
+ raise Domain::Errors::ServiceFailureError, out unless status.success?
41
+ JSON.parse(out)
77
42
  end
78
43
 
79
44
  def write_package_json
@@ -84,20 +49,20 @@ module Script
84
49
  "devDependencies": {
85
50
  "@shopify/scripts-sdk-as": "#{extension_point.sdks[:ts].sdk_version}",
86
51
  "@shopify/scripts-toolchain-as": "#{extension_point.sdks[:ts].toolchain_version}",
87
- "#{extension_point.sdks[:ts].package}": "#{extension_point.sdks[:ts].version}",
52
+ "#{extension_point.sdks[:ts].package}": "^#{extension_point_version}",
88
53
  "@as-pect/cli": "4.0.0",
89
- "as-wasi": "^0.2.0",
90
- "assemblyscript": "^0.12.0"
54
+ "as-wasi": "^0.2.1",
55
+ "assemblyscript": "^0.14.0"
91
56
  },
92
57
  "scripts": {
93
- "test": "asp --config test/as-pect.config.js --summary --verbose"
58
+ "test": "asp --summary --verbose",
59
+ "build": "shopify-scripts-toolchain-as build --src src/script.ts --binary build/#{script_name}.wasm -- --lib node_modules --optimize --use Date="
94
60
  },
95
61
  "engines": {
96
- "node": ">=14.5"
62
+ "node": ">=#{MIN_NODE_VERSION}"
97
63
  }
98
64
  }
99
65
  HERE
100
-
101
66
  ctx.write("package.json", package_json)
102
67
  end
103
68
  end
@@ -4,9 +4,8 @@ module Script
4
4
  module Layers
5
5
  module Infrastructure
6
6
  class AssemblyScriptTaskRunner
7
- BYTECODE_FILE = "%{name}.wasm"
8
- SCRIPT_SDK_BUILD = "npx --no-install shopify-scripts-build --src=../%{source} --binary=#{BYTECODE_FILE} "\
9
- "-- --lib=../node_modules --optimize --use Date="
7
+ BYTECODE_FILE = "build/%{name}.wasm"
8
+ SCRIPT_SDK_BUILD = "npm run build"
10
9
 
11
10
  attr_reader :ctx, :script_name, :script_source_file
12
11
 
@@ -47,18 +46,40 @@ module Script
47
46
 
48
47
  require 'semantic/semantic'
49
48
  version = ::Semantic::Version.new(output[1..-1])
50
- unless version >= ::Semantic::Version.new("12.16.0")
51
- raise Errors::DependencyInstallError, "Node version must be >= v12.16.0. Current version: #{output.strip}."
49
+ unless version >= ::Semantic::Version.new(AssemblyScriptProjectCreator::MIN_NODE_VERSION)
50
+ raise Errors::DependencyInstallError,
51
+ "Node version must be >= v#{AssemblyScriptProjectCreator::MIN_NODE_VERSION}. "\
52
+ "Current version: #{output.strip}."
52
53
  end
53
54
  end
54
55
 
55
56
  def compile
56
- out, status = ctx.capture2e(format(SCRIPT_SDK_BUILD, source: script_source_file, name: script_name))
57
+ check_compilation_dependencies!
58
+
59
+ out, status = ctx.capture2e(SCRIPT_SDK_BUILD)
57
60
  raise Domain::Errors::ServiceFailureError, out unless status.success?
58
61
  end
59
62
 
63
+ def check_compilation_dependencies!
64
+ pkg = JSON.parse(File.read('package.json'))
65
+ build_script = pkg.dig('scripts', 'build')
66
+
67
+ raise Errors::BuildScriptNotFoundError,
68
+ "Build script not found" if build_script.nil?
69
+
70
+ unless build_script.start_with?("shopify-scripts")
71
+ raise Errors::InvalidBuildScriptError, "Invalid build script"
72
+ end
73
+ end
74
+
60
75
  def bytecode
61
- File.read(format(BYTECODE_FILE, name: script_name))
76
+ blob = format(BYTECODE_FILE, name: script_name)
77
+ raise Errors::WebAssemblyBinaryNotFoundError unless @ctx.file_exist?(blob)
78
+
79
+ contents = File.read(blob)
80
+ @ctx.rm(blob)
81
+
82
+ contents
62
83
  end
63
84
 
64
85
  def check_if_ep_dependencies_up_to_date!
@@ -9,7 +9,9 @@ module Script
9
9
  class AppScriptUndefinedError < ScriptProjectError; end
10
10
  class BuildError < ScriptProjectError; end
11
11
  class DependencyInstallError < ScriptProjectError; end
12
+ class EmptyResponseError < ScriptProjectError; end
12
13
  class ForbiddenError < ScriptProjectError; end
14
+
13
15
  class GraphqlError < ScriptProjectError
14
16
  attr_reader :errors
15
17
  def initialize(errors)
@@ -17,7 +19,9 @@ module Script
17
19
  super("GraphQL failed with errors: #{errors}")
18
20
  end
19
21
  end
22
+
20
23
  class ProjectCreatorNotFoundError < ScriptProjectError; end
24
+
21
25
  class ScriptRepushError < ScriptProjectError
22
26
  attr_reader :api_key
23
27
  def initialize(api_key)
@@ -25,15 +29,18 @@ module Script
25
29
  @api_key = api_key
26
30
  end
27
31
  end
32
+
28
33
  class ScriptServiceUserError < ScriptProjectError
29
34
  def initialize(query_name, errors)
30
35
  super("Failed performing #{query_name}. Errors: #{errors}.")
31
36
  end
32
37
  end
38
+
33
39
  class ShopAuthenticationError < ScriptProjectError; end
34
40
  class ShopScriptConflictError < ScriptProjectError; end
35
41
  class ShopScriptUndefinedError < ScriptProjectError; end
36
42
  class TaskRunnerNotFoundError < ScriptProjectError; end
43
+
37
44
  class PackagesOutdatedError < ScriptProjectError
38
45
  attr_reader :outdated_packages
39
46
  def initialize(outdated_packages)
@@ -41,6 +48,15 @@ module Script
41
48
  @outdated_packages = outdated_packages
42
49
  end
43
50
  end
51
+
52
+ class BuildScriptNotFoundError < ScriptProjectError; end
53
+ class InvalidBuildScriptError < ScriptProjectError; end
54
+
55
+ class WebAssemblyBinaryNotFoundError < ScriptProjectError
56
+ def initialize
57
+ super("WebAssembly binary not found")
58
+ end
59
+ end
44
60
  end
45
61
  end
46
62
  end
@@ -16,18 +16,6 @@ module Script
16
16
  Domain::Script.new(script_id(language), script_name, extension_point_type, language)
17
17
  end
18
18
 
19
- def with_temp_build_context
20
- prev_dir = Dir.pwd
21
- temp_dir = "#{project_base}/temp"
22
- ctx.mkdir_p(temp_dir)
23
- ctx.chdir(temp_dir)
24
- ctx.cp_r("#{src_base}/.", ".")
25
- yield
26
- ensure
27
- ctx.chdir(prev_dir)
28
- ctx.rm_rf(temp_dir)
29
- end
30
-
31
19
  def relative_path_to_src
32
20
  "src"
33
21
  end
@@ -146,6 +146,8 @@ module Script
146
146
  end
147
147
 
148
148
  def raise_if_graphql_failed(response)
149
+ raise Errors::EmptyResponseError if response.nil?
150
+
149
151
  return unless response.key?('errors')
150
152
  case error_code(response['errors'])
151
153
  when 'forbidden'