shopify-cli 1.10.0 → 1.11.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 +4 -4
- data/.github/PULL_REQUEST_TEMPLATE.md +1 -0
- data/CHANGELOG.md +9 -1
- data/Gemfile.lock +1 -1
- data/lib/project_types/extension/cli.rb +6 -2
- data/lib/project_types/extension/commands/serve.rb +69 -1
- data/lib/project_types/extension/commands/tunnel.rb +3 -1
- data/lib/project_types/extension/extension_project.rb +1 -0
- data/lib/project_types/extension/features/argo.rb +15 -24
- data/lib/project_types/extension/features/argo_runtime.rb +63 -0
- data/lib/project_types/extension/features/argo_serve.rb +35 -25
- data/lib/project_types/extension/features/argo_serve_options.rb +40 -0
- data/lib/project_types/extension/messages/messages.rb +3 -0
- data/lib/project_types/extension/models/npm_package.rb +14 -0
- data/lib/project_types/extension/models/specification.rb +1 -0
- data/lib/project_types/extension/models/specification_handlers/checkout_argo_extension.rb +18 -0
- data/lib/project_types/extension/models/specification_handlers/default.rb +28 -3
- data/lib/project_types/extension/tasks/choose_next_available_port.rb +36 -0
- data/lib/project_types/extension/tasks/configure_features.rb +2 -0
- data/lib/project_types/extension/tasks/find_npm_packages.rb +106 -0
- data/lib/project_types/script/cli.rb +1 -0
- data/lib/project_types/script/layers/domain/errors.rb +0 -2
- data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +12 -17
- data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +13 -7
- data/lib/project_types/script/layers/infrastructure/command_runner.rb +19 -0
- data/lib/project_types/script/layers/infrastructure/errors.rb +12 -3
- data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +4 -4
- data/lib/project_types/script/layers/infrastructure/rust_project_creator.rb +9 -10
- data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +5 -6
- data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +2 -28
- data/lib/project_types/script/layers/infrastructure/script_service.rb +1 -1
- data/lib/project_types/script/messages/messages.rb +6 -4
- data/lib/project_types/script/tasks/ensure_env.rb +10 -2
- data/lib/project_types/script/ui/error_handler.rb +7 -6
- data/lib/shopify-cli/messages/messages.rb +47 -43
- data/lib/shopify-cli/method_object.rb +4 -4
- data/lib/shopify-cli/oauth.rb +7 -1
- data/lib/shopify-cli/partners_api/organizations.rb +3 -3
- data/lib/shopify-cli/tasks/select_org_and_shop.rb +6 -4
- data/lib/shopify-cli/tunnel.rb +22 -1
- data/lib/shopify-cli/version.rb +1 -1
- metadata +10 -4
- data/lib/project_types/extension/features/argo_renderer_package.rb +0 -47
@@ -56,8 +56,10 @@ module Extension
|
|
56
56
|
},
|
57
57
|
serve: {
|
58
58
|
frame_title: "Serving extension...",
|
59
|
+
no_available_ports_found: "No available ports found to run extension.",
|
59
60
|
serve_failure_message: "Failed to run extension code.",
|
60
61
|
serve_missing_information: "Missing shop or api_key.",
|
62
|
+
tunnel_already_running: "A tunnel running on another port has been detected. Close the tunnel and try again.",
|
61
63
|
},
|
62
64
|
tunnel: {
|
63
65
|
missing_token: "{{x}} {{red:auth requires a token argument}}. "\
|
@@ -115,6 +117,7 @@ module Extension
|
|
115
117
|
},
|
116
118
|
errors: {
|
117
119
|
unknown_type: "Unknown extension type %s",
|
120
|
+
package_not_found: "`%s` package not found.",
|
118
121
|
},
|
119
122
|
}
|
120
123
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "semantic/semantic"
|
2
|
+
|
3
|
+
module Extension
|
4
|
+
module Models
|
5
|
+
NpmPackage = Struct.new(:name, :version, keyword_init: true) do
|
6
|
+
include Comparable
|
7
|
+
|
8
|
+
def <=>(other)
|
9
|
+
return nil unless name == other.name
|
10
|
+
Semantic::Version.new(version) <=> Semantic::Version.new(other.version)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -12,6 +12,7 @@ module Extension
|
|
12
12
|
property! :git_template, converts: :to_str
|
13
13
|
property! :required_fields, accepts: Array, default: -> { [] }
|
14
14
|
property! :required_shop_beta_flags, accepts: Array, default: -> { [] }
|
15
|
+
property! :cli_package_name, accepts: String, converts: :to_str, default: ""
|
15
16
|
end
|
16
17
|
|
17
18
|
def self.build(feature_set_attributes)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Extension
|
4
|
+
module Models
|
5
|
+
module SpecificationHandlers
|
6
|
+
class CheckoutArgoExtension < Default
|
7
|
+
PERMITTED_CONFIG_KEYS = [:metafields, :extension_points]
|
8
|
+
|
9
|
+
def config(context)
|
10
|
+
{
|
11
|
+
**Features::ArgoConfig.parse_yaml(context, PERMITTED_CONFIG_KEYS),
|
12
|
+
**argo.config(context),
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -42,20 +42,45 @@ module Extension
|
|
42
42
|
[]
|
43
43
|
end
|
44
44
|
|
45
|
-
def
|
46
|
-
|
45
|
+
def choose_port?(context)
|
46
|
+
argo_runtime(context).accepts_port?
|
47
|
+
end
|
48
|
+
|
49
|
+
def establish_tunnel?(context)
|
50
|
+
argo_runtime(context).accepts_tunnel_url?
|
51
|
+
end
|
52
|
+
|
53
|
+
def serve(context:, port:, tunnel_url:)
|
54
|
+
Features::ArgoServe.new(specification_handler: self, argo_runtime: argo_runtime(context),
|
55
|
+
context: context, port: port, tunnel_url: tunnel_url).call
|
47
56
|
end
|
48
57
|
|
49
58
|
def renderer_package(context)
|
50
59
|
argo.renderer_package(context)
|
51
60
|
end
|
52
61
|
|
62
|
+
def argo_runtime(context)
|
63
|
+
@argo_runtime ||= Features::ArgoRuntime.new(
|
64
|
+
renderer: renderer_package(context),
|
65
|
+
cli: cli_package(context)
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
def cli_package(context)
|
70
|
+
cli_package_name = specification.features.argo&.cli_package_name
|
71
|
+
return unless cli_package_name
|
72
|
+
|
73
|
+
js_system = ShopifyCli::JsSystem.new(ctx: context)
|
74
|
+
Tasks::FindNpmPackages.exactly_one_of(cli_package_name, js_system: js_system)
|
75
|
+
.unwrap { |_e| context.abort(context.message("errors.package_not_found", cli_package_name)) }
|
76
|
+
end
|
77
|
+
|
53
78
|
protected
|
54
79
|
|
55
80
|
def argo
|
56
81
|
Features::Argo.new(
|
57
82
|
git_template: specification.features.argo.git_template,
|
58
|
-
renderer_package_name: specification.features.argo.renderer_package_name
|
83
|
+
renderer_package_name: specification.features.argo.renderer_package_name
|
59
84
|
)
|
60
85
|
end
|
61
86
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "shopify_cli"
|
3
|
+
require "socket"
|
4
|
+
|
5
|
+
module Extension
|
6
|
+
module Tasks
|
7
|
+
class ChooseNextAvailablePort
|
8
|
+
include ShopifyCli::MethodObject
|
9
|
+
|
10
|
+
property! :from
|
11
|
+
property! :to, default: -> { from + 10 }
|
12
|
+
property! :host, default: "localhost"
|
13
|
+
|
14
|
+
def call
|
15
|
+
available_port = port_range(from: from, to: to).find { |p| available?(host, p) }
|
16
|
+
raise ArgumentError, "Ports between #{from} and #{to} are unavailable" if available_port.nil?
|
17
|
+
available_port
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def port_range(from:, to:)
|
23
|
+
(from..to)
|
24
|
+
end
|
25
|
+
|
26
|
+
def available?(host, port)
|
27
|
+
Socket.tcp(host, port, connect_timeout: 1) do |socket|
|
28
|
+
socket.close
|
29
|
+
false
|
30
|
+
end
|
31
|
+
rescue Errno::ECONNREFUSED
|
32
|
+
true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -42,10 +42,12 @@ module Extension
|
|
42
42
|
renderer_package_name: "@shopify/argo-admin",
|
43
43
|
required_fields: [:shop, :api_key],
|
44
44
|
required_shop_beta_flags: [:argo_admin_beta],
|
45
|
+
cli_package_name: "@shopify/argo-admin-cli",
|
45
46
|
},
|
46
47
|
checkout: {
|
47
48
|
git_template: "https://github.com/Shopify/argo-checkout-template.git",
|
48
49
|
renderer_package_name: "@shopify/argo-checkout",
|
50
|
+
cli_package_name: "@shopify/argo-run",
|
49
51
|
},
|
50
52
|
}
|
51
53
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Extension
|
2
|
+
module Tasks
|
3
|
+
class FindNpmPackages
|
4
|
+
include ShopifyCli::MethodObject
|
5
|
+
|
6
|
+
property! :js_system, accepts: ShopifyCli::JsSystem
|
7
|
+
property! :production_only, accepts: [true, false], default: false, reader: :production_only?
|
8
|
+
|
9
|
+
def self.at_least_one_of(*package_names, **config)
|
10
|
+
new(**config).at_least_one_of(*package_names)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.all(*package_names, **config)
|
14
|
+
new(**config).all(*package_names)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.exactly_one_of(*package_names, **config)
|
18
|
+
new(**config).exactly_one_of(*package_names)
|
19
|
+
end
|
20
|
+
|
21
|
+
def all(*package_names)
|
22
|
+
call(*package_names) do |found_packages|
|
23
|
+
found_package_names = found_packages.map(&:name)
|
24
|
+
next found_packages if Set.new(found_package_names) == Set.new(package_names)
|
25
|
+
raise PackageResolutionFailed, format(
|
26
|
+
"Missing packages: %s",
|
27
|
+
(package_names - found_package_names).join(", ")
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def at_least_one_of(*package_names)
|
33
|
+
call(*package_names) do |found_packages|
|
34
|
+
found_package_names = found_packages.map(&:name)
|
35
|
+
next found_packages unless (found_package_names & package_names).empty?
|
36
|
+
raise PackageResolutionFailed, format(
|
37
|
+
"Expected at least one of the following packages: %s",
|
38
|
+
package_names.join(", ")
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def exactly_one_of(*package_names)
|
44
|
+
call(*package_names) do |found_packages|
|
45
|
+
case found_packages.count
|
46
|
+
when 0
|
47
|
+
raise PackageResolutionFailed, format(
|
48
|
+
"Expected one of the following packages: %s",
|
49
|
+
package_names.join(", ")
|
50
|
+
)
|
51
|
+
when 1
|
52
|
+
found_packages.first.tap do |found_package|
|
53
|
+
next found_package if package_names.include?(found_package.name)
|
54
|
+
raise PackageResolutionFailed, format(
|
55
|
+
"Expected the following package: %s",
|
56
|
+
found_package.name
|
57
|
+
)
|
58
|
+
end
|
59
|
+
else
|
60
|
+
raise PackageResolutionFailed, "Found more than one package"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def call(*package_names, &validate)
|
66
|
+
validate ||= ->(found_packages) { found_packages }
|
67
|
+
|
68
|
+
unless package_names.all? { |name| name.is_a?(String) }
|
69
|
+
raise ArgumentError, "Expected a list of package names"
|
70
|
+
end
|
71
|
+
|
72
|
+
ShopifyCli::Result
|
73
|
+
.call(&method(:list_packages))
|
74
|
+
.then(&method(:search_packages).curry[package_names])
|
75
|
+
.then(&method(:filter_duplicates))
|
76
|
+
.then(&validate)
|
77
|
+
end
|
78
|
+
|
79
|
+
def list_packages
|
80
|
+
result, error, status =
|
81
|
+
js_system.call(yarn: yarn_list, npm: npm_list, capture_response: true)
|
82
|
+
raise error unless status.success?
|
83
|
+
result
|
84
|
+
end
|
85
|
+
|
86
|
+
def yarn_list
|
87
|
+
production_only? ? %w[list --production] : %w[list]
|
88
|
+
end
|
89
|
+
|
90
|
+
def npm_list
|
91
|
+
production_only? ? %w[list --prod --depth=1] : %w[list --depth=1]
|
92
|
+
end
|
93
|
+
|
94
|
+
def search_packages(packages, package_list)
|
95
|
+
pattern = /(#{packages.join("|")})@(\d.*)$/
|
96
|
+
package_list.scan(pattern).map do |(name, version)|
|
97
|
+
Models::NpmPackage.new(name: name, version: version.strip)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def filter_duplicates(packages)
|
102
|
+
packages.reject { |p| p.version.match(/deduped/) }.uniq
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -54,6 +54,7 @@ module Script
|
|
54
54
|
Project.project_filepath("layers/infrastructure/assemblyscript_project_creator")
|
55
55
|
autoload :AssemblyScriptTaskRunner, Project.project_filepath("layers/infrastructure/assemblyscript_task_runner")
|
56
56
|
autoload :AssemblyScriptTsConfig, Project.project_filepath("layers/infrastructure/assemblyscript_tsconfig")
|
57
|
+
autoload :CommandRunner, Project.project_filepath("layers/infrastructure/command_runner")
|
57
58
|
autoload :RustProjectCreator,
|
58
59
|
Project.project_filepath("layers/infrastructure/rust_project_creator.rb")
|
59
60
|
autoload :RustTaskRunner, Project.project_filepath("layers/infrastructure/rust_task_runner")
|
@@ -12,7 +12,7 @@ module Script
|
|
12
12
|
|
13
13
|
BOOTSTRAP = "npx --no-install shopify-scripts-toolchain-as bootstrap --from %{extension_point} --dest %{base}"
|
14
14
|
BUILD = "shopify-scripts-toolchain-as build --src src/shopify_main.ts " \
|
15
|
-
"--binary build
|
15
|
+
"--binary build/script.wasm --metadata build/metadata.json"
|
16
16
|
MIN_NODE_VERSION = "14.5.0"
|
17
17
|
ASC_ARGS = "-- --lib node_modules --optimize --use Date="
|
18
18
|
|
@@ -22,28 +22,24 @@ module Script
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def bootstrap
|
25
|
-
|
26
|
-
raise Domain::Errors::ServiceFailureError, out unless status.success?
|
25
|
+
command_runner.call(bootstap_command)
|
27
26
|
end
|
28
27
|
|
29
28
|
private
|
30
29
|
|
30
|
+
def command_runner
|
31
|
+
@command_runner ||= CommandRunner.new(ctx: ctx)
|
32
|
+
end
|
33
|
+
|
31
34
|
def write_npmrc
|
32
|
-
|
33
|
-
|
34
|
-
)
|
35
|
-
ctx.system(
|
36
|
-
"npm", "--userconfig", "./.npmrc", "config", "set", "engine-strict", "true"
|
37
|
-
)
|
35
|
+
command_runner.call("npm --userconfig ./.npmrc config set @shopify:registry https://registry.npmjs.com")
|
36
|
+
command_runner.call("npm --userconfig ./.npmrc config set engine-strict true")
|
38
37
|
end
|
39
38
|
|
40
39
|
def extension_point_version
|
41
|
-
if extension_point.sdks.assemblyscript.versioned?
|
42
|
-
return extension_point.sdks.assemblyscript.version
|
43
|
-
end
|
40
|
+
return extension_point.sdks.assemblyscript.version if extension_point.sdks.assemblyscript.versioned?
|
44
41
|
|
45
|
-
out
|
46
|
-
raise Domain::Errors::ServiceFailureError, out unless status.success?
|
42
|
+
out = command_runner.call("npm show #{extension_point.sdks.assemblyscript.package} version --json")
|
47
43
|
"^#{JSON.parse(out)}"
|
48
44
|
end
|
49
45
|
|
@@ -85,13 +81,12 @@ module Script
|
|
85
81
|
|
86
82
|
def build_command
|
87
83
|
type = extension_point.dasherize_type
|
88
|
-
base_command = format(BUILD, script_name: script_name)
|
89
84
|
domain = extension_point.domain
|
90
85
|
|
91
86
|
if domain.nil?
|
92
|
-
"#{
|
87
|
+
"#{BUILD} #{ASC_ARGS}"
|
93
88
|
else
|
94
|
-
"#{
|
89
|
+
"#{BUILD} --domain #{domain} --ep #{type} #{ASC_ARGS}"
|
95
90
|
end
|
96
91
|
end
|
97
92
|
end
|
@@ -63,9 +63,7 @@ module Script
|
|
63
63
|
|
64
64
|
def compile
|
65
65
|
check_compilation_dependencies!
|
66
|
-
|
67
|
-
out, status = ctx.capture2e(SCRIPT_SDK_BUILD)
|
68
|
-
raise Domain::Errors::ServiceFailureError, out unless status.success?
|
66
|
+
CommandRunner.new(ctx: ctx).call(SCRIPT_SDK_BUILD)
|
69
67
|
end
|
70
68
|
|
71
69
|
def check_compilation_dependencies!
|
@@ -81,11 +79,19 @@ module Script
|
|
81
79
|
end
|
82
80
|
|
83
81
|
def bytecode
|
84
|
-
|
85
|
-
|
82
|
+
legacy_filename = format(BYTECODE_FILE, name: script_name)
|
83
|
+
filename = format(BYTECODE_FILE, name: "script")
|
84
|
+
|
85
|
+
bytecode_file = if ctx.file_exist?(filename)
|
86
|
+
filename
|
87
|
+
elsif ctx.file_exist?(legacy_filename)
|
88
|
+
legacy_filename
|
89
|
+
else
|
90
|
+
raise Errors::WebAssemblyBinaryNotFoundError
|
91
|
+
end
|
86
92
|
|
87
|
-
contents = ctx.binread(
|
88
|
-
ctx.rm(
|
93
|
+
contents = ctx.binread(bytecode_file)
|
94
|
+
ctx.rm(bytecode_file)
|
89
95
|
|
90
96
|
contents
|
91
97
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Script
|
4
|
+
module Layers
|
5
|
+
module Infrastructure
|
6
|
+
class CommandRunner
|
7
|
+
include SmartProperties
|
8
|
+
|
9
|
+
property! :ctx, accepts: ShopifyCli::Context
|
10
|
+
|
11
|
+
def call(cmd)
|
12
|
+
out, status = ctx.capture2e(cmd)
|
13
|
+
raise Errors::SystemCallFailureError.new(out: out.chomp, cmd: cmd) unless status.success?
|
14
|
+
out
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -69,11 +69,20 @@ module Script
|
|
69
69
|
|
70
70
|
class ProjectCreatorNotFoundError < ScriptProjectError; end
|
71
71
|
|
72
|
+
class SystemCallFailureError < ScriptProjectError
|
73
|
+
attr_reader :out, :cmd
|
74
|
+
def initialize(out:, cmd:)
|
75
|
+
super()
|
76
|
+
@out = out
|
77
|
+
@cmd = cmd
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
72
81
|
class ScriptRepushError < ScriptProjectError
|
73
|
-
attr_reader :
|
74
|
-
def initialize(
|
82
|
+
attr_reader :uuid
|
83
|
+
def initialize(uuid)
|
75
84
|
super()
|
76
|
-
@
|
85
|
+
@uuid = uuid
|
77
86
|
end
|
78
87
|
end
|
79
88
|
|
@@ -8,7 +8,7 @@ module Script
|
|
8
8
|
property! :ctx, accepts: ShopifyCli::Context
|
9
9
|
|
10
10
|
def create_push_package(script_project:, script_content:, compiled_type:, metadata:)
|
11
|
-
build_file_path = file_path(script_project.id,
|
11
|
+
build_file_path = file_path(script_project.id, compiled_type)
|
12
12
|
write_to_path(build_file_path, script_content)
|
13
13
|
|
14
14
|
Domain::PushPackage.new(
|
@@ -24,7 +24,7 @@ module Script
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def get_push_package(script_project:, compiled_type:, metadata:)
|
27
|
-
build_file_path = file_path(script_project.id,
|
27
|
+
build_file_path = file_path(script_project.id, compiled_type)
|
28
28
|
raise Domain::PushPackageNotFoundError unless ctx.file_exist?(build_file_path)
|
29
29
|
|
30
30
|
script_content = ctx.binread(build_file_path)
|
@@ -47,8 +47,8 @@ module Script
|
|
47
47
|
ctx.binwrite(path, content)
|
48
48
|
end
|
49
49
|
|
50
|
-
def file_path(path_to_script,
|
51
|
-
"#{path_to_script}/build
|
50
|
+
def file_path(path_to_script, compiled_type)
|
51
|
+
"#{path_to_script}/build/script.#{compiled_type}"
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|