shopify-cli 1.9.1 → 1.13.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.github/PULL_REQUEST_TEMPLATE.md +1 -0
  3. data/.github/workflows/build.yml +28 -0
  4. data/.github/workflows/release.yml +2 -4
  5. data/CHANGELOG.md +28 -0
  6. data/Gemfile.lock +1 -1
  7. data/README.md +2 -1
  8. data/lib/project_types/extension/cli.rb +6 -2
  9. data/lib/project_types/extension/commands/serve.rb +69 -1
  10. data/lib/project_types/extension/commands/tunnel.rb +3 -1
  11. data/lib/project_types/extension/extension_project.rb +1 -0
  12. data/lib/project_types/extension/features/argo.rb +15 -24
  13. data/lib/project_types/extension/features/argo_runtime.rb +91 -0
  14. data/lib/project_types/extension/features/argo_serve.rb +35 -27
  15. data/lib/project_types/extension/features/argo_serve_options.rb +42 -0
  16. data/lib/project_types/extension/messages/messages.rb +5 -1
  17. data/lib/project_types/extension/models/npm_package.rb +14 -0
  18. data/lib/project_types/extension/models/specification.rb +1 -0
  19. data/lib/project_types/extension/models/specification_handlers/checkout_argo_extension.rb +18 -0
  20. data/lib/project_types/extension/models/specification_handlers/default.rb +33 -3
  21. data/lib/project_types/extension/tasks/choose_next_available_port.rb +36 -0
  22. data/lib/project_types/extension/tasks/configure_features.rb +2 -0
  23. data/lib/project_types/extension/tasks/find_npm_packages.rb +106 -0
  24. data/lib/project_types/script/cli.rb +17 -12
  25. data/lib/project_types/script/commands/push.rb +6 -2
  26. data/lib/project_types/script/config/extension_points.yml +2 -3
  27. data/lib/project_types/script/graphql/get_app_scripts.graphql +6 -0
  28. data/lib/project_types/script/layers/application/create_script.rb +2 -2
  29. data/lib/project_types/script/layers/application/push_script.rb +2 -1
  30. data/lib/project_types/script/layers/domain/errors.rb +0 -2
  31. data/lib/project_types/script/layers/domain/script_project.rb +17 -1
  32. data/lib/project_types/script/layers/infrastructure/command_runner.rb +19 -0
  33. data/lib/project_types/script/layers/infrastructure/errors.rb +12 -3
  34. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_project_creator.rb +97 -0
  35. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb +103 -0
  36. data/lib/project_types/script/layers/infrastructure/languages/project_creator.rb +26 -0
  37. data/lib/project_types/script/layers/infrastructure/languages/rust_project_creator.rb +73 -0
  38. data/lib/project_types/script/layers/infrastructure/languages/rust_task_runner.rb +60 -0
  39. data/lib/project_types/script/layers/infrastructure/languages/task_runner.rb +21 -0
  40. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +4 -5
  41. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +22 -29
  42. data/lib/project_types/script/layers/infrastructure/script_service.rb +7 -1
  43. data/lib/project_types/script/messages/messages.rb +14 -4
  44. data/lib/project_types/script/tasks/ensure_env.rb +104 -0
  45. data/lib/project_types/script/ui/error_handler.rb +7 -6
  46. data/lib/shopify-cli/admin_api.rb +7 -4
  47. data/lib/shopify-cli/messages/messages.rb +48 -43
  48. data/lib/shopify-cli/method_object.rb +4 -4
  49. data/lib/shopify-cli/oauth.rb +7 -1
  50. data/lib/shopify-cli/partners_api.rb +7 -4
  51. data/lib/shopify-cli/partners_api/organizations.rb +3 -3
  52. data/lib/shopify-cli/resources/env_file.rb +1 -1
  53. data/lib/shopify-cli/shopifolk.rb +1 -1
  54. data/lib/shopify-cli/tasks/select_org_and_shop.rb +6 -4
  55. data/lib/shopify-cli/tunnel.rb +22 -1
  56. data/lib/shopify-cli/version.rb +1 -1
  57. data/lib/shopify_cli.rb +0 -1
  58. metadata +19 -11
  59. data/.travis.yml +0 -14
  60. data/lib/project_types/extension/features/argo_renderer_package.rb +0 -47
  61. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +0 -100
  62. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +0 -95
  63. data/lib/project_types/script/layers/infrastructure/project_creator.rb +0 -24
  64. data/lib/project_types/script/layers/infrastructure/rust_project_creator.rb +0 -72
  65. data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +0 -59
  66. data/lib/project_types/script/layers/infrastructure/task_runner.rb +0 -19
@@ -8,7 +8,8 @@ module Script
8
8
  def call(ctx:, force:)
9
9
  script_project_repo = Infrastructure::ScriptProjectRepository.new(ctx: ctx)
10
10
  script_project = script_project_repo.get
11
- task_runner = Infrastructure::TaskRunner.for(ctx, script_project.language, script_project.script_name)
11
+ task_runner = Infrastructure::Languages::TaskRunner
12
+ .for(ctx, script_project.language, script_project.script_name)
12
13
 
13
14
  ProjectDependencies.install(ctx: ctx, task_runner: task_runner)
14
15
  BuildScript.call(ctx: ctx, task_runner: task_runner, script_project: script_project)
@@ -39,8 +39,6 @@ module Script
39
39
  end
40
40
  end
41
41
 
42
- class ServiceFailureError < ScriptProjectError; end
43
-
44
42
  class MetadataNotFoundError < ScriptProjectError; end
45
43
 
46
44
  class MetadataValidationError < ScriptProjectError; end
@@ -6,6 +6,8 @@ module Script
6
6
  class ScriptProject
7
7
  include SmartProperties
8
8
 
9
+ UUID_ENV_KEY = "UUID"
10
+
9
11
  property! :id, accepts: String
10
12
  property :env, accepts: ShopifyCli::Resources::EnvFile
11
13
 
@@ -29,8 +31,22 @@ module Script
29
31
  env&.api_key
30
32
  end
31
33
 
34
+ def api_secret
35
+ env&.secret
36
+ end
37
+
32
38
  def uuid
33
- env&.extra&.[]("UUID")
39
+ uuid_defined? && !raw_uuid.empty? ? raw_uuid : nil
40
+ end
41
+
42
+ def uuid_defined?
43
+ !raw_uuid.nil?
44
+ end
45
+
46
+ private
47
+
48
+ def raw_uuid
49
+ env&.extra&.[](UUID_ENV_KEY)
34
50
  end
35
51
  end
36
52
  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(out)
76
+ @out = out
77
+ @cmd = cmd
78
+ end
79
+ end
80
+
72
81
  class ScriptRepushError < ScriptProjectError
73
- attr_reader :api_key
74
- def initialize(api_key)
82
+ attr_reader :uuid
83
+ def initialize(uuid)
75
84
  super()
76
- @api_key = api_key
85
+ @uuid = uuid
77
86
  end
78
87
  end
79
88
 
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Infrastructure
6
+ module Languages
7
+ class AssemblyScriptProjectCreator
8
+ include SmartProperties
9
+ property! :ctx, accepts: ShopifyCli::Context
10
+ property! :extension_point, accepts: Domain::ExtensionPoint
11
+ property! :script_name, accepts: String
12
+ property! :path_to_project, accepts: String
13
+
14
+ BOOTSTRAP = "npx --no-install shopify-scripts-toolchain-as bootstrap --from %{extension_point} --dest %{base}"
15
+ BUILD = "shopify-scripts-toolchain-as build --src src/shopify_main.ts " \
16
+ "--binary build/script.wasm --metadata build/metadata.json"
17
+ MIN_NODE_VERSION = "14.5.0"
18
+ ASC_ARGS = "-- --lib node_modules --optimize --use Date="
19
+
20
+ def setup_dependencies
21
+ write_npmrc
22
+ write_package_json
23
+ end
24
+
25
+ def bootstrap
26
+ command_runner.call(bootstap_command)
27
+ end
28
+
29
+ private
30
+
31
+ def command_runner
32
+ @command_runner ||= CommandRunner.new(ctx: ctx)
33
+ end
34
+
35
+ def write_npmrc
36
+ command_runner.call("npm --userconfig ./.npmrc config set @shopify:registry https://registry.npmjs.com")
37
+ command_runner.call("npm --userconfig ./.npmrc config set engine-strict true")
38
+ end
39
+
40
+ def extension_point_version
41
+ return extension_point.sdks.assemblyscript.version if extension_point.sdks.assemblyscript.versioned?
42
+
43
+ out = command_runner.call("npm show #{extension_point.sdks.assemblyscript.package} version --json")
44
+ "^#{JSON.parse(out)}"
45
+ end
46
+
47
+ def write_package_json
48
+ package_json = <<~HERE
49
+ {
50
+ "name": "#{script_name}",
51
+ "version": "1.0.0",
52
+ "devDependencies": {
53
+ "@shopify/scripts-sdk-as": "#{extension_point.sdks.assemblyscript.sdk_version}",
54
+ "@shopify/scripts-toolchain-as": "#{extension_point.sdks.assemblyscript.toolchain_version}",
55
+ "#{extension_point.sdks.assemblyscript.package}": "#{extension_point_version}",
56
+ "@as-pect/cli": "^6.0.0",
57
+ "assemblyscript": "^0.18.13"
58
+ },
59
+ "scripts": {
60
+ "test": "asp --summary --verbose",
61
+ "build": "#{build_command}"
62
+ },
63
+ "engines": {
64
+ "node": ">=#{MIN_NODE_VERSION}"
65
+ }
66
+ }
67
+ HERE
68
+ ctx.write("package.json", package_json)
69
+ end
70
+
71
+ def bootstap_command
72
+ type = extension_point.dasherize_type
73
+ base_command = format(BOOTSTRAP, extension_point: type, base: path_to_project)
74
+ domain = extension_point.domain
75
+
76
+ if domain.nil?
77
+ base_command
78
+ else
79
+ "#{base_command} --domain #{domain}"
80
+ end
81
+ end
82
+
83
+ def build_command
84
+ type = extension_point.dasherize_type
85
+ domain = extension_point.domain
86
+
87
+ if domain.nil?
88
+ "#{BUILD} #{ASC_ARGS}"
89
+ else
90
+ "#{BUILD} --domain #{domain} --ep #{type} #{ASC_ARGS}"
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Infrastructure
6
+ module Languages
7
+ class AssemblyScriptTaskRunner
8
+ BYTECODE_FILE = "build/%{name}.wasm"
9
+ METADATA_FILE = "build/metadata.json"
10
+ SCRIPT_SDK_BUILD = "npm run build"
11
+
12
+ attr_reader :ctx, :script_name
13
+
14
+ def initialize(ctx, script_name)
15
+ @ctx = ctx
16
+ @script_name = script_name
17
+ end
18
+
19
+ def build
20
+ compile
21
+ bytecode
22
+ end
23
+
24
+ def compiled_type
25
+ "wasm"
26
+ end
27
+
28
+ def install_dependencies
29
+ check_node_version!
30
+
31
+ output, status = ctx.capture2e("npm install --no-audit --no-optional --legacy-peer-deps --loglevel error")
32
+ raise Errors::DependencyInstallError, output unless status.success?
33
+ end
34
+
35
+ def dependencies_installed?
36
+ # Assuming if node_modules folder exist at root of script folder, all deps are installed
37
+ ctx.dir_exist?("node_modules")
38
+ end
39
+
40
+ def metadata
41
+ unless @ctx.file_exist?(METADATA_FILE)
42
+ msg = @ctx.message("script.error.metadata_not_found_cause", METADATA_FILE)
43
+ raise Domain::Errors::MetadataNotFoundError, msg
44
+ end
45
+
46
+ raw_contents = File.read(METADATA_FILE)
47
+ Domain::Metadata.create_from_json(@ctx, raw_contents)
48
+ end
49
+
50
+ private
51
+
52
+ def check_node_version!
53
+ output, status = @ctx.capture2e("node", "--version")
54
+ raise Errors::DependencyInstallError, output unless status.success?
55
+
56
+ require "semantic/semantic"
57
+ version = ::Semantic::Version.new(output[1..-1])
58
+ unless version >= ::Semantic::Version.new(AssemblyScriptProjectCreator::MIN_NODE_VERSION)
59
+ raise Errors::DependencyInstallError,
60
+ "Node version must be >= v#{AssemblyScriptProjectCreator::MIN_NODE_VERSION}. "\
61
+ "Current version: #{output.strip}."
62
+ end
63
+ end
64
+
65
+ def compile
66
+ check_compilation_dependencies!
67
+ CommandRunner.new(ctx: ctx).call(SCRIPT_SDK_BUILD)
68
+ end
69
+
70
+ def check_compilation_dependencies!
71
+ pkg = JSON.parse(File.read("package.json"))
72
+ build_script = pkg.dig("scripts", "build")
73
+
74
+ raise Errors::BuildScriptNotFoundError,
75
+ "Build script not found" if build_script.nil?
76
+
77
+ unless build_script.start_with?("shopify-scripts")
78
+ raise Errors::InvalidBuildScriptError, "Invalid build script"
79
+ end
80
+ end
81
+
82
+ def bytecode
83
+ legacy_filename = format(BYTECODE_FILE, name: script_name)
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
93
+
94
+ contents = ctx.binread(bytecode_file)
95
+ ctx.rm(bytecode_file)
96
+
97
+ contents
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Infrastructure
6
+ module Languages
7
+ class ProjectCreator
8
+ PROJECT_CREATORS = {
9
+ "assemblyscript" => AssemblyScriptProjectCreator,
10
+ "rust" => RustProjectCreator,
11
+ }
12
+
13
+ def self.for(ctx, language, extension_point, script_name, path_to_project)
14
+ raise Errors::ProjectCreatorNotFoundError unless PROJECT_CREATORS[language]
15
+ PROJECT_CREATORS[language].new(
16
+ ctx: ctx,
17
+ extension_point: extension_point,
18
+ script_name: script_name,
19
+ path_to_project: path_to_project
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Infrastructure
6
+ module Languages
7
+ class RustProjectCreator
8
+ include SmartProperties
9
+ property! :ctx, accepts: ShopifyCli::Context
10
+ property! :extension_point, accepts: Domain::ExtensionPoint
11
+ property! :script_name, accepts: String
12
+ property! :path_to_project, accepts: String
13
+
14
+ ORIGIN_BRANCH = "main"
15
+ SAMPLE_PATH = "default"
16
+
17
+ def setup_dependencies
18
+ git_init
19
+ setup_remote
20
+ setup_sparse_checkout
21
+ pull
22
+ clean
23
+ set_script_name
24
+ end
25
+
26
+ def bootstrap
27
+ end
28
+
29
+ private
30
+
31
+ def command_runner
32
+ @command_runner ||= CommandRunner.new(ctx: ctx)
33
+ end
34
+
35
+ def git_init
36
+ command_runner.call("git init")
37
+ end
38
+
39
+ def setup_remote
40
+ repo = extension_point.sdks.rust.package
41
+ command_runner.call("git remote add -f origin #{repo}")
42
+ end
43
+
44
+ def setup_sparse_checkout
45
+ type = extension_point.type
46
+ command_runner.call("git config core.sparsecheckout true")
47
+ command_runner.call("echo #{type}/#{SAMPLE_PATH} >> .git/info/sparse-checkout")
48
+ end
49
+
50
+ def pull
51
+ command_runner.call("git pull origin #{ORIGIN_BRANCH}")
52
+ end
53
+
54
+ def clean
55
+ type = extension_point.type
56
+ ctx.rm_rf(".git")
57
+ source = File.join(path_to_project, File.join(type, SAMPLE_PATH))
58
+ FileUtils.copy_entry(source, path_to_project)
59
+ ctx.rm_rf(type)
60
+ end
61
+
62
+ def set_script_name
63
+ config_file = "Cargo.toml"
64
+ upstream_name = "#{extension_point.type.gsub("_", "-")}-default"
65
+ contents = File.read(config_file)
66
+ new_contents = contents.sub(upstream_name, script_name)
67
+ File.write(config_file, new_contents)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+ module Script
3
+ module Layers
4
+ module Infrastructure
5
+ module Languages
6
+ class RustTaskRunner
7
+ attr_reader :ctx
8
+
9
+ BUILD_TARGET = "wasm32-unknown-unknown"
10
+ METADATA_FILE = "build/metadata.json"
11
+ CARGO_BUILD_CMD = "cargo build --target=#{BUILD_TARGET} --release"
12
+
13
+ def initialize(ctx, _)
14
+ @ctx = ctx
15
+ end
16
+
17
+ def dependencies_installed?
18
+ true
19
+ end
20
+
21
+ def install_dependencies
22
+ end
23
+
24
+ def build
25
+ compile
26
+ bytecode
27
+ end
28
+
29
+ def compiled_type
30
+ "wasm"
31
+ end
32
+
33
+ def metadata
34
+ unless @ctx.file_exist?(METADATA_FILE)
35
+ msg = @ctx.message("script.error.metadata_not_found_cause", METADATA_FILE)
36
+ raise Domain::Errors::MetadataNotFoundError, msg
37
+ end
38
+
39
+ raw_contents = File.read(METADATA_FILE)
40
+ Domain::Metadata.create_from_json(@ctx, raw_contents)
41
+ end
42
+
43
+ private
44
+
45
+ def compile
46
+ CommandRunner.new(ctx: ctx).call(CARGO_BUILD_CMD)
47
+ end
48
+
49
+ def bytecode
50
+ binary_name = "script.wasm"
51
+ binary_path = "target/#{BUILD_TARGET}/release/#{binary_name}"
52
+ raise Errors::WebAssemblyBinaryNotFoundError unless ctx.file_exist?(binary_path)
53
+
54
+ ctx.binread(binary_path)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end