shopify-cli 2.6.2 → 2.6.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/PULL_REQUEST_TEMPLATE.md +15 -4
- data/.github/workflows/shopify.yml +3 -6
- data/CHANGELOG.md +89 -99
- data/CONTRIBUTING.md +9 -1
- data/Dockerfile +22 -4
- data/Gemfile +2 -0
- data/Gemfile.lock +7 -3
- data/RELEASING.md +17 -30
- data/Rakefile +0 -5
- data/lib/project_types/extension/cli.rb +1 -0
- data/lib/project_types/extension/commands/create.rb +1 -0
- data/lib/project_types/extension/features/argo.rb +9 -10
- data/lib/project_types/extension/features/argo_serve.rb +1 -1
- data/lib/project_types/extension/forms/create.rb +1 -1
- data/lib/project_types/extension/forms/questions/ask_template.rb +2 -1
- data/lib/project_types/extension/messages/messages.rb +1 -0
- data/lib/project_types/extension/models/server_config/extension.rb +2 -0
- data/lib/project_types/extension/models/specification_handlers/checkout_post_purchase.rb +1 -1
- data/lib/project_types/extension/models/specification_handlers/checkout_ui_extension.rb +1 -1
- data/lib/project_types/extension/tasks/converters/server_config_converter.rb +4 -5
- data/lib/project_types/extension/tasks/find_package_from_json.rb +37 -0
- data/lib/project_types/extension/tasks/load_server_config.rb +6 -1
- data/lib/project_types/node/commands/serve.rb +7 -16
- data/lib/project_types/node/messages/messages.rb +0 -5
- data/lib/project_types/php/commands/serve.rb +6 -9
- data/lib/project_types/php/messages/messages.rb +1 -4
- data/lib/project_types/rails/commands/create.rb +45 -16
- data/lib/project_types/rails/commands/serve.rb +7 -8
- data/lib/project_types/rails/forms/create.rb +0 -1
- data/lib/project_types/rails/messages/messages.rb +1 -4
- data/lib/project_types/script/commands/create.rb +4 -5
- data/lib/project_types/script/config/extension_points.yml +10 -0
- data/lib/project_types/script/errors.rb +0 -18
- data/lib/project_types/script/graphql/app_script_set.graphql +2 -0
- data/lib/project_types/script/layers/application/build_script.rb +2 -1
- data/lib/project_types/script/layers/application/create_script.rb +2 -2
- data/lib/project_types/script/layers/application/push_script.rb +15 -1
- data/lib/project_types/script/layers/domain/push_package.rb +5 -2
- data/lib/project_types/script/layers/domain/script_json.rb +1 -1
- data/lib/project_types/script/layers/infrastructure/api_clients/partners_proxy_api_client.rb +0 -4
- data/lib/project_types/script/layers/infrastructure/errors.rb +17 -2
- data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb +29 -13
- data/lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb +29 -13
- data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +4 -2
- data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +3 -4
- data/lib/project_types/script/layers/infrastructure/script_service.rb +7 -2
- data/lib/project_types/script/messages/messages.rb +9 -22
- data/lib/project_types/script/ui/error_handler.rb +16 -26
- data/lib/project_types/theme/commands/serve.rb +2 -0
- data/lib/project_types/theme/messages/messages.rb +6 -0
- data/lib/shopify_cli/app_type_detector.rb +32 -0
- data/lib/shopify_cli/command.rb +6 -1
- data/lib/shopify_cli/command_options/command_serve_options.rb +43 -0
- data/lib/shopify_cli/command_options.rb +7 -0
- data/lib/shopify_cli/commands/login.rb +3 -3
- data/lib/shopify_cli/commands/reporting.rb +38 -0
- data/lib/shopify_cli/commands/switch.rb +1 -1
- data/lib/shopify_cli/commands.rb +1 -0
- data/lib/shopify_cli/constants.rb +7 -3
- data/lib/shopify_cli/core/monorail.rb +9 -20
- data/lib/shopify_cli/environment.rb +15 -1
- data/lib/shopify_cli/exception_reporter.rb +29 -15
- data/lib/shopify_cli/messages/messages.rb +48 -19
- data/lib/shopify_cli/migrator/migration.rb +1 -1
- data/lib/shopify_cli/migrator/migrations/1631709766_noop.rb +1 -1
- data/lib/shopify_cli/migrator/migrations/1633691650_merge_reporting_configuration.rb +41 -0
- data/lib/shopify_cli/migrator.rb +9 -11
- data/lib/shopify_cli/reporting_configuration_controller.rb +64 -0
- data/lib/shopify_cli/services/base_service.rb +13 -0
- data/lib/shopify_cli/services/reporting_service.rb +16 -0
- data/lib/shopify_cli/services.rb +6 -0
- data/lib/shopify_cli/theme/dev_server/watcher.rb +2 -2
- data/lib/shopify_cli/theme/dev_server.rb +3 -2
- data/lib/shopify_cli/version.rb +1 -1
- data/lib/shopify_cli.rb +4 -0
- data/shopify-cli.gemspec +2 -13
- data/utilities/docker/container.rb +97 -0
- data/utilities/docker.rb +45 -3
- metadata +18 -10
- data/ext/shopify-cli/extconf.rb +0 -60
- data/lib/project_types/script/graphql/app_script_update_or_create.graphql +0 -0
- data/lib/shopify_cli/exception_reporter/permission_controller.rb +0 -54
@@ -4,7 +4,6 @@ module Script
|
|
4
4
|
module Layers
|
5
5
|
module Infrastructure
|
6
6
|
module Errors
|
7
|
-
class AppNotInstalledError < ScriptProjectError; end
|
8
7
|
class BuildError < ScriptProjectError; end
|
9
8
|
class ScriptJsonSyntaxError < ScriptProjectError; end
|
10
9
|
|
@@ -40,6 +39,23 @@ module Script
|
|
40
39
|
end
|
41
40
|
end
|
42
41
|
|
42
|
+
class APILibraryNotFoundError < ScriptProjectError
|
43
|
+
attr_reader :library_name
|
44
|
+
def initialize(library_name)
|
45
|
+
super()
|
46
|
+
@library_name = library_name
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class LanguageLibraryForAPINotFoundError < ScriptProjectError
|
51
|
+
attr_reader :language, :api
|
52
|
+
def initialize(language:, api:)
|
53
|
+
super()
|
54
|
+
@language = language
|
55
|
+
@api = api
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
43
59
|
class DependencyInstallError < ScriptProjectError; end
|
44
60
|
class DeprecatedEPError < ScriptProjectError; end
|
45
61
|
class EmptyResponseError < ScriptProjectError; end
|
@@ -84,7 +100,6 @@ module Script
|
|
84
100
|
end
|
85
101
|
|
86
102
|
class ScriptProjectAlreadyExistsError < ScriptProjectError; end
|
87
|
-
class ShopAuthenticationError < ScriptProjectError; end
|
88
103
|
class TaskRunnerNotFoundError < ScriptProjectError; end
|
89
104
|
class BuildScriptNotFoundError < ScriptProjectError; end
|
90
105
|
class InvalidBuildScriptError < ScriptProjectError; end
|
@@ -5,7 +5,7 @@ module Script
|
|
5
5
|
module Infrastructure
|
6
6
|
module Languages
|
7
7
|
class AssemblyScriptTaskRunner
|
8
|
-
BYTECODE_FILE = "build
|
8
|
+
BYTECODE_FILE = "build/script.wasm"
|
9
9
|
METADATA_FILE = "build/metadata.json"
|
10
10
|
SCRIPT_SDK_BUILD = "npm run build"
|
11
11
|
|
@@ -47,8 +47,33 @@ module Script
|
|
47
47
|
Domain::Metadata.create_from_json(@ctx, raw_contents)
|
48
48
|
end
|
49
49
|
|
50
|
+
def library_version(library_name)
|
51
|
+
output = JSON.parse(CommandRunner.new(ctx: ctx).call("npm -s list --json"))
|
52
|
+
library_version_from_npm_list(output, library_name)
|
53
|
+
rescue Errors::SystemCallFailureError => error
|
54
|
+
library_version_from_npm_list_error_output(error, library_name)
|
55
|
+
end
|
56
|
+
|
50
57
|
private
|
51
58
|
|
59
|
+
def library_version_from_npm_list_error_output(error, library_name)
|
60
|
+
# npm list can return a failure status code, even when returning the correct data.
|
61
|
+
# This causes the CommandRunner to throw a SystemCallFailure error that contains the data.
|
62
|
+
# In here, we check that the output contains `npm list`'s structure and extract the version.
|
63
|
+
output = JSON.parse(error.out)
|
64
|
+
raise error unless output.key?("dependencies")
|
65
|
+
|
66
|
+
library_version_from_npm_list(output, library_name)
|
67
|
+
rescue JSON::ParserError
|
68
|
+
raise error
|
69
|
+
end
|
70
|
+
|
71
|
+
def library_version_from_npm_list(output, library_name)
|
72
|
+
output.dig("dependencies", library_name, "version").tap do |version|
|
73
|
+
raise Errors::APILibraryNotFoundError, library_name unless version
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
52
77
|
def check_node_version!
|
53
78
|
output, status = @ctx.capture2e("node", "--version")
|
54
79
|
raise Errors::DependencyInstallError, output unless status.success?
|
@@ -80,19 +105,10 @@ module Script
|
|
80
105
|
end
|
81
106
|
|
82
107
|
def bytecode
|
83
|
-
|
84
|
-
filename = format(BYTECODE_FILE, name: "script")
|
85
|
-
|
86
|
-
bytecode_file = if ctx.file_exist?(filename)
|
87
|
-
filename
|
88
|
-
elsif ctx.file_exist?(legacy_filename)
|
89
|
-
legacy_filename
|
90
|
-
else
|
91
|
-
raise Errors::WebAssemblyBinaryNotFoundError
|
92
|
-
end
|
108
|
+
raise Errors::WebAssemblyBinaryNotFoundError unless ctx.file_exist?(BYTECODE_FILE)
|
93
109
|
|
94
|
-
contents = ctx.binread(
|
95
|
-
ctx.rm(
|
110
|
+
contents = ctx.binread(BYTECODE_FILE)
|
111
|
+
ctx.rm(BYTECODE_FILE)
|
96
112
|
|
97
113
|
contents
|
98
114
|
end
|
@@ -5,7 +5,7 @@ module Script
|
|
5
5
|
module Infrastructure
|
6
6
|
module Languages
|
7
7
|
class TypeScriptTaskRunner
|
8
|
-
BYTECODE_FILE = "build
|
8
|
+
BYTECODE_FILE = "build/index.wasm"
|
9
9
|
METADATA_FILE = "build/metadata.json"
|
10
10
|
SCRIPT_SDK_BUILD = "npm run build"
|
11
11
|
GEN_METADATA = "npm run gen-metadata"
|
@@ -48,8 +48,33 @@ module Script
|
|
48
48
|
Domain::Metadata.create_from_json(@ctx, raw_contents)
|
49
49
|
end
|
50
50
|
|
51
|
+
def library_version(library_name)
|
52
|
+
output = JSON.parse(CommandRunner.new(ctx: ctx).call("npm -s list --json"))
|
53
|
+
library_version_from_npm_list(output, library_name)
|
54
|
+
rescue Errors::SystemCallFailureError => error
|
55
|
+
library_version_from_npm_list_error_output(error, library_name)
|
56
|
+
end
|
57
|
+
|
51
58
|
private
|
52
59
|
|
60
|
+
def library_version_from_npm_list_error_output(error, library_name)
|
61
|
+
# npm list can return a failure status code, even when returning the correct data.
|
62
|
+
# This causes the CommandRunner to throw a SystemCallFailure error that contains the data.
|
63
|
+
# In here, we check that the output contains `npm list`'s structure and extract the version.
|
64
|
+
output = JSON.parse(error.out)
|
65
|
+
raise error unless output.key?("dependencies")
|
66
|
+
|
67
|
+
library_version_from_npm_list(output, library_name)
|
68
|
+
rescue JSON::ParserError
|
69
|
+
raise error
|
70
|
+
end
|
71
|
+
|
72
|
+
def library_version_from_npm_list(output, library_name)
|
73
|
+
output.dig("dependencies", library_name, "version").tap do |version|
|
74
|
+
raise Errors::APILibraryNotFoundError, library_name unless version
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
53
78
|
def check_node_version!
|
54
79
|
output, status = @ctx.capture2e("node", "--version")
|
55
80
|
raise Errors::DependencyInstallError, output unless status.success?
|
@@ -82,19 +107,10 @@ module Script
|
|
82
107
|
end
|
83
108
|
|
84
109
|
def bytecode
|
85
|
-
|
86
|
-
filename = format(BYTECODE_FILE, name: "index")
|
87
|
-
|
88
|
-
bytecode_file = if ctx.file_exist?(filename)
|
89
|
-
filename
|
90
|
-
elsif ctx.file_exist?(legacy_filename)
|
91
|
-
legacy_filename
|
92
|
-
else
|
93
|
-
raise Errors::WebAssemblyBinaryNotFoundError
|
94
|
-
end
|
110
|
+
raise Errors::WebAssemblyBinaryNotFoundError unless ctx.file_exist?(BYTECODE_FILE)
|
95
111
|
|
96
|
-
contents = ctx.binread(
|
97
|
-
ctx.rm(
|
112
|
+
contents = ctx.binread(BYTECODE_FILE)
|
113
|
+
ctx.rm(BYTECODE_FILE)
|
98
114
|
|
99
115
|
contents
|
100
116
|
end
|
@@ -7,7 +7,7 @@ module Script
|
|
7
7
|
include SmartProperties
|
8
8
|
property! :ctx, accepts: ShopifyCLI::Context
|
9
9
|
|
10
|
-
def create_push_package(script_project:, script_content:, compiled_type:, metadata:)
|
10
|
+
def create_push_package(script_project:, script_content:, compiled_type:, metadata:, library:)
|
11
11
|
build_file_path = file_path(script_project.id, compiled_type)
|
12
12
|
write_to_path(build_file_path, script_content)
|
13
13
|
|
@@ -19,10 +19,11 @@ module Script
|
|
19
19
|
compiled_type: compiled_type,
|
20
20
|
metadata: metadata,
|
21
21
|
script_json: script_project.script_json,
|
22
|
+
library: library
|
22
23
|
)
|
23
24
|
end
|
24
25
|
|
25
|
-
def get_push_package(script_project:, compiled_type:, metadata:)
|
26
|
+
def get_push_package(script_project:, compiled_type:, metadata:, library:)
|
26
27
|
build_file_path = file_path(script_project.id, compiled_type)
|
27
28
|
raise Domain::PushPackageNotFoundError unless ctx.file_exist?(build_file_path)
|
28
29
|
|
@@ -34,6 +35,7 @@ module Script
|
|
34
35
|
script_content: script_content,
|
35
36
|
metadata: metadata,
|
36
37
|
script_json: script_project.script_json,
|
38
|
+
library: library
|
37
39
|
)
|
38
40
|
end
|
39
41
|
|
@@ -81,10 +81,10 @@ module Script
|
|
81
81
|
)
|
82
82
|
end
|
83
83
|
|
84
|
-
def update_or_create_script_json(title
|
84
|
+
def update_or_create_script_json(title:)
|
85
85
|
script_json = ScriptJsonRepository
|
86
86
|
.new(ctx: ctx)
|
87
|
-
.update_or_create(title: title
|
87
|
+
.update_or_create(title: title)
|
88
88
|
|
89
89
|
Domain::ScriptProject.new(
|
90
90
|
id: ctx.root,
|
@@ -148,11 +148,10 @@ module Script
|
|
148
148
|
current_script_json || raise(Domain::Errors::NoScriptJsonFile)
|
149
149
|
end
|
150
150
|
|
151
|
-
def update_or_create(title
|
151
|
+
def update_or_create(title:)
|
152
152
|
json = current_script_json&.content || {}
|
153
153
|
json["version"] ||= "1"
|
154
154
|
json["title"] = title
|
155
|
-
json["configurationUi"] = !!configuration_ui
|
156
155
|
|
157
156
|
ctx.write(SCRIPT_JSON_FILENAME, JSON.pretty_generate(json))
|
158
157
|
|
@@ -18,7 +18,8 @@ module Script
|
|
18
18
|
force: false,
|
19
19
|
metadata:,
|
20
20
|
script_json:,
|
21
|
-
module_upload_url
|
21
|
+
module_upload_url:,
|
22
|
+
library:
|
22
23
|
)
|
23
24
|
query_name = "app_script_set"
|
24
25
|
variables = {
|
@@ -33,6 +34,10 @@ module Script
|
|
33
34
|
configurationUi: script_json.configuration_ui,
|
34
35
|
configurationDefinition: script_json.configuration&.to_json,
|
35
36
|
moduleUploadUrl: module_upload_url,
|
37
|
+
library: {
|
38
|
+
language: library[:language],
|
39
|
+
version: library[:version],
|
40
|
+
},
|
36
41
|
}
|
37
42
|
resp_hash = make_request(query_name: query_name, variables: variables)
|
38
43
|
user_errors = resp_hash["data"]["appScriptSet"]["userErrors"]
|
@@ -41,7 +46,7 @@ module Script
|
|
41
46
|
|
42
47
|
if user_errors.any? { |e| e["tag"] == "already_exists_error" }
|
43
48
|
raise Errors::ScriptRepushError, uuid
|
44
|
-
elsif (e = user_errors.any? { |err| err["tag"] == "
|
49
|
+
elsif (e = user_errors.any? { |err| err["tag"] == "configuration_definition_syntax_error" })
|
45
50
|
raise Errors::ScriptJsonSyntaxError
|
46
51
|
elsif (e = user_errors.find { |err| err["tag"] == "configuration_definition_missing_keys_error" })
|
47
52
|
raise Errors::ScriptJsonMissingKeysError, e["message"]
|
@@ -27,10 +27,6 @@ module Script
|
|
27
27
|
"extension_point_type or script_name.",
|
28
28
|
invalid_context_help: "Add these values and try again.",
|
29
29
|
|
30
|
-
invalid_config_props_cause: "{{command:--config-props}} is formatted incorrectly.",
|
31
|
-
invalid_config_props_help: "Try again using this format: "\
|
32
|
-
"{{cyan:--config-props='name1:value1, name2:value2'}}",
|
33
|
-
|
34
30
|
invalid_script_name_cause: "Invalid script name.",
|
35
31
|
invalid_script_name_help: "Replace or remove unsupported characters. Valid characters "\
|
36
32
|
"are numbers, letters, hyphens, or underscores.",
|
@@ -42,9 +38,6 @@ module Script
|
|
42
38
|
no_existing_orgs_cause: "You don't have any partner organizations.",
|
43
39
|
no_existing_orgs_help: "Visit https://partners.shopify.com/ to create a partners account.",
|
44
40
|
|
45
|
-
no_existing_stores_cause: "You don't have any stores in your Partner Dashboard.",
|
46
|
-
no_existing_stores_help: "Visit https://partners.shopify.com/%{organization_id}/stores/ to create one.",
|
47
|
-
|
48
41
|
project_exists_cause: "A directory with this same name already exists.",
|
49
42
|
project_exists_help: "Try again and enter a different name for the script.",
|
50
43
|
|
@@ -54,9 +47,6 @@ module Script
|
|
54
47
|
invalid_language_cause: "Invalid language %s.",
|
55
48
|
invalid_language_help: "Allowed values: %s.",
|
56
49
|
|
57
|
-
invalid_config: "Can't change the configuration values because %1$s is missing or "\
|
58
|
-
"it isn't formatted properly.",
|
59
|
-
|
60
50
|
missing_script_json_field_cause: "The script.json file is missing the required %s field.",
|
61
51
|
missing_script_json_field_help: "Add the field and try again.",
|
62
52
|
|
@@ -91,8 +81,8 @@ module Script
|
|
91
81
|
system_call_failure_cause: "An error was returned while running {{command:%{cmd}}}.",
|
92
82
|
system_call_failure_help: "Review the following error and try again.\n{{red:%{out}}}",
|
93
83
|
|
94
|
-
metadata_validation_cause: "
|
95
|
-
metadata_validation_help: "
|
84
|
+
metadata_validation_cause: "The Script API metadata is incorrect.",
|
85
|
+
metadata_validation_help: "The 'schemaVersions.major' field contains an unsupported version.",
|
96
86
|
|
97
87
|
metadata_schema_versions_missing: "Invalid Script metadata:" \
|
98
88
|
" 'schemaVersions' field is missing",
|
@@ -107,7 +97,6 @@ module Script
|
|
107
97
|
metadata_not_found_help: "Ensure the 'shopify/scripts-toolchain-as' package is up to date and " \
|
108
98
|
"'package.json' contains a 'scripts/build' entry with a " \
|
109
99
|
"'--metadata build/metadata.json' argument",
|
110
|
-
app_not_installed_cause: "App not installed on store.",
|
111
100
|
|
112
101
|
build_error_cause: "Something went wrong while building the script.",
|
113
102
|
build_error_help: "Correct the errors and try again.",
|
@@ -126,9 +115,6 @@ module Script
|
|
126
115
|
script_repush_cause: "A version of this script already exists on the app.",
|
127
116
|
script_repush_help: "Use {{cyan:--force}} to replace the existing script.",
|
128
117
|
|
129
|
-
shop_auth_cause: "Unable to authenticate with the store.",
|
130
|
-
shop_auth_help: "Try again.",
|
131
|
-
|
132
118
|
invalid_build_script: "The root package.json contains an invalid build command that " \
|
133
119
|
"is needed to compile your script to WebAssembly.",
|
134
120
|
build_script_not_found: "The root package.json is missing the build command that " \
|
@@ -148,6 +134,12 @@ module Script
|
|
148
134
|
|
149
135
|
script_upload_cause: "Fail to upload script.",
|
150
136
|
script_upload_help: "Try again.",
|
137
|
+
|
138
|
+
api_library_not_found_cause: "Script can't be created because API library %{library_name} is missing from the dependencies",
|
139
|
+
api_library_not_found_help: "This error can occur because the API library was removed from your system or there is a problem with dependencies in the repository.",
|
140
|
+
|
141
|
+
language_library_for_api_not_found_cause: "Script can’t be pushed because the %{language} library for API %{api} is missing.",
|
142
|
+
language_library_for_api_not_found_help: "Make sure extension_point.yml contains the correct API library.",
|
151
143
|
},
|
152
144
|
|
153
145
|
create: {
|
@@ -156,8 +148,7 @@ module Script
|
|
156
148
|
Usage: {{command:%1$s script create}}
|
157
149
|
Options:
|
158
150
|
{{command:--name=NAME}} Script project name. Use any string.
|
159
|
-
{{command:--
|
160
|
-
{{command:--no-config-ui}} Specify this option when you don’t want your script to render an interface in Shopify admin.
|
151
|
+
{{command:--api=TYPE}} Script API name. Allowed values: %2$s.
|
161
152
|
HELP
|
162
153
|
|
163
154
|
error: {
|
@@ -206,10 +197,6 @@ module Script
|
|
206
197
|
built: "Built",
|
207
198
|
pushing: "Pushing",
|
208
199
|
pushed: "Pushed",
|
209
|
-
disabling: "Disabling",
|
210
|
-
disabled: "Disabled",
|
211
|
-
enabling: "Enabling",
|
212
|
-
enabled: "Enabled",
|
213
200
|
ensure_env: {
|
214
201
|
organization: "Partner organization {{green:%s (%s)}}.",
|
215
202
|
organization_select: "Which partner organization do you want to use?",
|
@@ -44,15 +44,6 @@ module Script
|
|
44
44
|
cause_of_error: ShopifyCLI::Context.message("script.error.invalid_context_cause"),
|
45
45
|
help_suggestion: ShopifyCLI::Context.message("script.error.invalid_context_help"),
|
46
46
|
}
|
47
|
-
when Errors::InvalidConfigProps
|
48
|
-
{
|
49
|
-
cause_of_error: ShopifyCLI::Context.message("script.error.invalid_config_props_cause"),
|
50
|
-
help_suggestion: ShopifyCLI::Context.message("script.error.invalid_config_props_help"),
|
51
|
-
}
|
52
|
-
when Errors::InvalidConfigYAMLError
|
53
|
-
{
|
54
|
-
cause_of_error: ShopifyCLI::Context.message("script.error.invalid_config", e.config_file),
|
55
|
-
}
|
56
47
|
when Layers::Infrastructure::Errors::InvalidLanguageError
|
57
48
|
{
|
58
49
|
cause_of_error: ShopifyCLI::Context.message("script.error.invalid_language_cause", e.language),
|
@@ -76,14 +67,6 @@ module Script
|
|
76
67
|
cause_of_error: ShopifyCLI::Context.message("script.error.no_existing_orgs_cause"),
|
77
68
|
help_suggestion: ShopifyCLI::Context.message("script.error.no_existing_orgs_help"),
|
78
69
|
}
|
79
|
-
when Errors::NoExistingStoresError
|
80
|
-
{
|
81
|
-
cause_of_error: ShopifyCLI::Context.message("script.error.no_existing_stores_cause"),
|
82
|
-
help_suggestion: ShopifyCLI::Context.message(
|
83
|
-
"script.error.no_existing_stores_help",
|
84
|
-
organization_id: e.organization_id
|
85
|
-
),
|
86
|
-
}
|
87
70
|
when Layers::Infrastructure::Errors::ScriptProjectAlreadyExistsError
|
88
71
|
{
|
89
72
|
cause_of_error: ShopifyCLI::Context.message("script.error.project_exists_cause"),
|
@@ -135,10 +118,6 @@ module Script
|
|
135
118
|
cause_of_error: ShopifyCLI::Context.message("script.error.no_script_json_file_cause"),
|
136
119
|
help_suggestion: ShopifyCLI::Context.message("script.error.no_script_json_file_help"),
|
137
120
|
}
|
138
|
-
when Layers::Infrastructure::Errors::AppNotInstalledError
|
139
|
-
{
|
140
|
-
cause_of_error: ShopifyCLI::Context.message("script.error.app_not_installed_cause"),
|
141
|
-
}
|
142
121
|
when Layers::Infrastructure::Errors::BuildError
|
143
122
|
{
|
144
123
|
cause_of_error: ShopifyCLI::Context.message("script.error.build_error_cause"),
|
@@ -217,11 +196,6 @@ module Script
|
|
217
196
|
cause_of_error: ShopifyCLI::Context.message("script.error.script_repush_cause"),
|
218
197
|
help_suggestion: ShopifyCLI::Context.message("script.error.script_repush_help"),
|
219
198
|
}
|
220
|
-
when Layers::Infrastructure::Errors::ShopAuthenticationError
|
221
|
-
{
|
222
|
-
cause_of_error: ShopifyCLI::Context.message("script.error.shop_auth_cause"),
|
223
|
-
help_suggestion: ShopifyCLI::Context.message("script.error.shop_auth_help"),
|
224
|
-
}
|
225
199
|
when Layers::Infrastructure::Errors::BuildScriptNotFoundError
|
226
200
|
{
|
227
201
|
cause_of_error: ShopifyCLI::Context.message("script.error.build_script_not_found"),
|
@@ -250,6 +224,22 @@ module Script
|
|
250
224
|
cause_of_error: ShopifyCLI::Context.message("script.error.script_upload_cause"),
|
251
225
|
help_suggestion: ShopifyCLI::Context.message("script.error.script_upload_help"),
|
252
226
|
}
|
227
|
+
when Layers::Infrastructure::Errors::APILibraryNotFoundError
|
228
|
+
{
|
229
|
+
cause_of_error: ShopifyCLI::Context
|
230
|
+
.message("script.error.api_library_not_found_cause", library_name: e.library_name),
|
231
|
+
help_suggestion: ShopifyCLI::Context.message("script.error.api_library_not_found_help"),
|
232
|
+
}
|
233
|
+
when Layers::Infrastructure::Errors::LanguageLibraryForAPINotFoundError
|
234
|
+
{
|
235
|
+
cause_of_error: ShopifyCLI::Context
|
236
|
+
.message(
|
237
|
+
"script.error.language_library_for_api_not_found_cause",
|
238
|
+
language: e.language,
|
239
|
+
api: e.api
|
240
|
+
),
|
241
|
+
help_suggestion: ShopifyCLI::Context.message("script.error.language_library_for_api_not_found_help"),
|
242
|
+
}
|
253
243
|
end
|
254
244
|
end
|
255
245
|
end
|
@@ -5,7 +5,9 @@ module Theme
|
|
5
5
|
class Command
|
6
6
|
class Serve < ShopifyCLI::SubCommand
|
7
7
|
options do |parser, flags|
|
8
|
+
parser.on("--bind=HOST") { |bind| flags[:bind] = bind.to_s }
|
8
9
|
parser.on("--port=PORT") { |port| flags[:port] = port.to_i }
|
10
|
+
parser.on("--poll") { flags[:poll] = true }
|
9
11
|
end
|
10
12
|
|
11
13
|
def call(*)
|
@@ -88,7 +88,13 @@ module Theme
|
|
88
88
|
serve: {
|
89
89
|
help: <<~HELP,
|
90
90
|
Uploads the current theme as a development theme to the connected store, then prints theme editor and preview URLs to your terminal. While running, changes will push to the store in real time.
|
91
|
+
|
91
92
|
Usage: {{command:%s theme serve}}
|
93
|
+
|
94
|
+
Options:
|
95
|
+
{{command:--port=PORT}} Local port to serve theme preview from
|
96
|
+
{{command:--poll}} Force polling to detect file changes
|
97
|
+
{{command:--bind=HOST}} Set which network interface the web server listens on
|
92
98
|
HELP
|
93
99
|
serve: "Viewing theme…",
|
94
100
|
open_fail: "Couldn't open the theme",
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module ShopifyCLI
|
4
|
+
class AppTypeDetector
|
5
|
+
Error = Class.new(StandardError)
|
6
|
+
TypeNotFoundError = Class.new(Error)
|
7
|
+
|
8
|
+
def self.detect(project_directory:)
|
9
|
+
return :node if node?(project_directory: project_directory)
|
10
|
+
return :rails if rails?(project_directory: project_directory)
|
11
|
+
return :php if php?(project_directory: project_directory)
|
12
|
+
raise TypeNotFoundError, "Couldn't detect the project type in directory: #{project_directory}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.node?(project_directory:)
|
16
|
+
package_json_path = File.join(project_directory, "package.json")
|
17
|
+
return false unless File.exist?(package_json_path)
|
18
|
+
package_json = JSON.parse(File.read(package_json_path))
|
19
|
+
!package_json.dig("scripts", "dev").nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.rails?(project_directory:)
|
23
|
+
rails_binstub_path = File.join(project_directory, "bin/rails")
|
24
|
+
File.exist?(rails_binstub_path)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.php?(project_directory:)
|
28
|
+
bootstrap_app_path = File.join(project_directory, "bootstrap/app.php")
|
29
|
+
File.exist?(bootstrap_app_path)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/shopify_cli/command.rb
CHANGED
@@ -27,7 +27,12 @@ module ShopifyCLI
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def options(&block)
|
30
|
-
|
30
|
+
existing_options = @_options
|
31
|
+
# We prevent new options calls to override existing blocks by nesting them.
|
32
|
+
@_options = ->(parser, flags) {
|
33
|
+
existing_options&.call(parser, flags)
|
34
|
+
block.call(parser, flags)
|
35
|
+
}
|
31
36
|
end
|
32
37
|
|
33
38
|
def subcommand(const, cmd, path = nil)
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "shopify_cli"
|
2
|
+
|
3
|
+
module ShopifyCLI
|
4
|
+
module CommandOptions
|
5
|
+
module CommandServeOptions
|
6
|
+
def self.included(base)
|
7
|
+
base.extend(ClassMethods)
|
8
|
+
base.class_eval do
|
9
|
+
def port
|
10
|
+
return ShopifyCLI::Tunnel::PORT.to_s unless options.flags.key?(:port)
|
11
|
+
port = options.flags[:port].to_i
|
12
|
+
@ctx.abort(@ctx.message("core.app.serve.error.invalid_port", options.flags[:port])) unless port > 0
|
13
|
+
port
|
14
|
+
end
|
15
|
+
|
16
|
+
def host
|
17
|
+
host = options.flags[:host]
|
18
|
+
unless host.nil?
|
19
|
+
@ctx.abort(@ctx.message("core.app.serve.error.host_must_be_https")) if host.match(/^https/i).nil?
|
20
|
+
end
|
21
|
+
host
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module ClassMethods
|
27
|
+
def parse_host_option
|
28
|
+
options do |parser, flags|
|
29
|
+
parser.on("--host=HOST") do |h|
|
30
|
+
flags[:host] = h.gsub('"', "")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_port_option
|
36
|
+
options do |parser, flags|
|
37
|
+
parser.on("--port=PORT") { |port| flags[:port] = port }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -15,7 +15,7 @@ module ShopifyCLI
|
|
15
15
|
|
16
16
|
def call(*)
|
17
17
|
shop = (options.flags[:shop] || @ctx.getenv("SHOPIFY_SHOP" || nil))
|
18
|
-
ShopifyCLI::DB.set(shop: self.class.validate_shop(shop)) unless shop.nil?
|
18
|
+
ShopifyCLI::DB.set(shop: self.class.validate_shop(shop, context: @ctx)) unless shop.nil?
|
19
19
|
|
20
20
|
if shop.nil? && Shopifolk.check
|
21
21
|
Shopifolk.reset
|
@@ -41,9 +41,9 @@ module ShopifyCLI
|
|
41
41
|
ShopifyCLI::Context.message("core.login.help", ShopifyCLI::TOOL_NAME)
|
42
42
|
end
|
43
43
|
|
44
|
-
def self.validate_shop(shop)
|
44
|
+
def self.validate_shop(shop, context:)
|
45
45
|
permanent_domain = shop_to_permanent_domain(shop)
|
46
|
-
|
46
|
+
context.abort(context.message("core.login.invalid_shop", shop)) unless permanent_domain
|
47
47
|
permanent_domain
|
48
48
|
end
|
49
49
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "shopify_cli"
|
2
|
+
|
3
|
+
module ShopifyCLI
|
4
|
+
module Commands
|
5
|
+
class Reporting < ShopifyCLI::Command
|
6
|
+
def call(args, _name)
|
7
|
+
enable_reporting = reporting_enabled?(args)
|
8
|
+
Services::ReportingService.call(enable: enable_reporting)
|
9
|
+
|
10
|
+
message = if enable_reporting
|
11
|
+
@ctx.message("core.reporting.turned_on_message")
|
12
|
+
else
|
13
|
+
@ctx.message("core.reporting.turned_off_message", ShopifyCLI::TOOL_NAME)
|
14
|
+
end
|
15
|
+
@ctx.puts(message)
|
16
|
+
end
|
17
|
+
|
18
|
+
def reporting_enabled?(args)
|
19
|
+
case args.first
|
20
|
+
when nil
|
21
|
+
@ctx.abort(@ctx.message("core.reporting.missing_argument", ShopifyCLI::TOOL_NAME))
|
22
|
+
when "on"
|
23
|
+
true
|
24
|
+
when "off"
|
25
|
+
false
|
26
|
+
else
|
27
|
+
@ctx.abort(
|
28
|
+
@ctx.message("core.reporting.invalid_argument", ShopifyCLI::TOOL_NAME, args.first)
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.help
|
34
|
+
ShopifyCLI::Context.message("core.reporting.help", ShopifyCLI::TOOL_NAME)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -16,7 +16,7 @@ module ShopifyCLI
|
|
16
16
|
end
|
17
17
|
|
18
18
|
shop = if options.flags[:shop]
|
19
|
-
Login.validate_shop(options.flags[:shop])
|
19
|
+
Login.validate_shop(options.flags[:shop], context: @ctx)
|
20
20
|
elsif (org_id = DB.get(:organization_id))
|
21
21
|
res = ShopifyCLI::Tasks::SelectOrgAndShop.call(@ctx, organization_id: org_id)
|
22
22
|
res[:shop_domain]
|
data/lib/shopify_cli/commands.rb
CHANGED
@@ -23,6 +23,7 @@ module ShopifyCLI
|
|
23
23
|
register :Login, "login", "shopify_cli/commands/login", true
|
24
24
|
register :Logout, "logout", "shopify_cli/commands/logout", true
|
25
25
|
register :Populate, "populate", "shopify_cli/commands/populate", true
|
26
|
+
register :Reporting, "reporting", "shopify_cli/commands/reporting", true
|
26
27
|
register :Store, "store", "shopify_cli/commands/store", true
|
27
28
|
register :Switch, "switch", "shopify_cli/commands/switch", true
|
28
29
|
register :System, "system", "shopify_cli/commands/system", true
|
@@ -15,10 +15,10 @@ module ShopifyCLI
|
|
15
15
|
|
16
16
|
module Config
|
17
17
|
module Sections
|
18
|
-
module
|
19
|
-
NAME = "
|
18
|
+
module Analytics
|
19
|
+
NAME = "analytics"
|
20
20
|
module Fields
|
21
|
-
|
21
|
+
ENABLED = "enabled"
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -39,7 +39,11 @@ module ShopifyCLI
|
|
39
39
|
|
40
40
|
# Environments
|
41
41
|
TEST = "SHOPIFY_CLI_TEST"
|
42
|
+
ACCEPTANCE_TEST = "SHOPIFY_CLI_ACCEPTANCE_TEST"
|
42
43
|
DEVELOPMENT = "SHOPIFY_CLI_DEVELOPMENT"
|
44
|
+
|
45
|
+
# Monorail
|
46
|
+
MONORAIL_REAL_EVENTS = "MONORAIL_REAL_EVENTS"
|
43
47
|
end
|
44
48
|
|
45
49
|
module Identity
|