shopify-cli 1.9.0 → 1.13.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 (79) 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 +27 -0
  6. data/Gemfile.lock +1 -1
  7. data/README.md +2 -1
  8. data/lib/project_types/extension/cli.rb +7 -1
  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 +18 -49
  13. data/lib/project_types/extension/features/argo_runtime.rb +81 -0
  14. data/lib/project_types/extension/features/argo_serve.rb +35 -27
  15. data/lib/project_types/extension/features/argo_serve_options.rb +41 -0
  16. data/lib/project_types/extension/features/argo_setup.rb +1 -1
  17. data/lib/project_types/extension/messages/messages.rb +5 -4
  18. data/lib/project_types/extension/models/npm_package.rb +14 -0
  19. data/lib/project_types/extension/models/specification.rb +3 -2
  20. data/lib/project_types/extension/models/specification_handlers/checkout_argo_extension.rb +18 -0
  21. data/lib/project_types/extension/models/specification_handlers/default.rb +33 -3
  22. data/lib/project_types/extension/models/version.rb +1 -1
  23. data/lib/project_types/extension/tasks/choose_next_available_port.rb +36 -0
  24. data/lib/project_types/extension/tasks/configure_features.rb +2 -0
  25. data/lib/project_types/extension/tasks/find_npm_packages.rb +106 -0
  26. data/lib/project_types/node/messages/messages.rb +4 -4
  27. data/lib/project_types/rails/messages/messages.rb +4 -4
  28. data/lib/project_types/script/cli.rb +17 -12
  29. data/lib/project_types/script/commands/push.rb +1 -1
  30. data/lib/project_types/script/config/extension_points.yml +2 -3
  31. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +5 -2
  32. data/lib/project_types/script/graphql/get_app_scripts.graphql +6 -0
  33. data/lib/project_types/script/layers/application/create_script.rb +2 -2
  34. data/lib/project_types/script/layers/application/push_script.rb +6 -3
  35. data/lib/project_types/script/layers/domain/errors.rb +0 -2
  36. data/lib/project_types/script/layers/domain/push_package.rb +4 -0
  37. data/lib/project_types/script/layers/domain/script_project.rb +21 -1
  38. data/lib/project_types/script/layers/infrastructure/command_runner.rb +19 -0
  39. data/lib/project_types/script/layers/infrastructure/errors.rb +30 -3
  40. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_project_creator.rb +97 -0
  41. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb +103 -0
  42. data/lib/project_types/script/layers/infrastructure/languages/project_creator.rb +26 -0
  43. data/lib/project_types/script/layers/infrastructure/languages/rust_project_creator.rb +73 -0
  44. data/lib/project_types/script/layers/infrastructure/languages/rust_task_runner.rb +60 -0
  45. data/lib/project_types/script/layers/infrastructure/languages/task_runner.rb +21 -0
  46. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +6 -5
  47. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +61 -34
  48. data/lib/project_types/script/layers/infrastructure/script_service.rb +14 -2
  49. data/lib/project_types/script/messages/messages.rb +20 -3
  50. data/lib/project_types/script/tasks/ensure_env.rb +85 -0
  51. data/lib/project_types/script/ui/error_handler.rb +25 -6
  52. data/lib/shopify-cli/admin_api.rb +7 -4
  53. data/lib/shopify-cli/js_system.rb +2 -2
  54. data/lib/shopify-cli/messages/messages.rb +51 -45
  55. data/lib/shopify-cli/method_object.rb +4 -4
  56. data/lib/shopify-cli/oauth.rb +9 -3
  57. data/lib/shopify-cli/packager.rb +1 -1
  58. data/lib/shopify-cli/partners_api.rb +7 -4
  59. data/lib/shopify-cli/partners_api/organizations.rb +3 -3
  60. data/lib/shopify-cli/resolve_constant.rb +1 -1
  61. data/lib/shopify-cli/resources/env_file.rb +2 -2
  62. data/lib/shopify-cli/shopifolk.rb +1 -1
  63. data/lib/shopify-cli/tasks/select_org_and_shop.rb +6 -4
  64. data/lib/shopify-cli/transform_data_structure.rb +1 -1
  65. data/lib/shopify-cli/tunnel.rb +22 -1
  66. data/lib/shopify-cli/version.rb +1 -1
  67. data/lib/shopify_cli.rb +0 -1
  68. data/vendor/deps/smart_properties/REVISION +1 -1
  69. data/vendor/deps/smart_properties/lib/smart_properties/property.rb +7 -1
  70. data/vendor/deps/smart_properties/lib/smart_properties/version.rb +1 -1
  71. metadata +19 -11
  72. data/.travis.yml +0 -14
  73. data/lib/project_types/extension/features/argo_renderer_package.rb +0 -32
  74. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +0 -100
  75. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +0 -95
  76. data/lib/project_types/script/layers/infrastructure/project_creator.rb +0 -24
  77. data/lib/project_types/script/layers/infrastructure/rust_project_creator.rb +0 -72
  78. data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +0 -59
  79. data/lib/project_types/script/layers/infrastructure/task_runner.rb +0 -19
@@ -0,0 +1,41 @@
1
+ module Extension
2
+ module Features
3
+ class ArgoServeOptions
4
+ include SmartProperties
5
+
6
+ property! :argo_runtime, accepts: Features::ArgoRuntime
7
+ property! :context, accepts: ShopifyCli::Context
8
+ property :port, accepts: Integer, default: 39351
9
+ property :public_url, accepts: String, default: ""
10
+ property! :required_fields, accepts: Array, default: -> { [] }
11
+ property! :renderer_package, accepts: Models::NpmPackage
12
+
13
+ YARN_SERVE_COMMAND = %w(server)
14
+ NPM_SERVE_COMMAND = %w(run-script server)
15
+
16
+ def yarn_serve_command
17
+ YARN_SERVE_COMMAND + options
18
+ end
19
+
20
+ def npm_serve_command
21
+ NPM_SERVE_COMMAND + ["--"] + options
22
+ end
23
+
24
+ private
25
+
26
+ def options
27
+ project = ExtensionProject.current
28
+ api_key = project.env.api_key
29
+
30
+ @serve_options ||= [].tap do |options|
31
+ options << "--port=#{port}" if argo_runtime.accepts_port?
32
+ options << "--shop=#{project.env.shop}" if required_fields.include?(:shop) && argo_runtime.accepts_shop?
33
+ options << "--apiKey=#{api_key}" if required_fields.include?(:api_key) && argo_runtime.accepts_api_key?
34
+ options << "--argoVersion=#{renderer_package.version}" if argo_runtime.accepts_argo_version?
35
+ options << "--uuid=#{project.registration_uuid}" if argo_runtime.accepts_uuid?
36
+ options << "--publicUrl=#{public_url}" if argo_runtime.accepts_tunnel_url?
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -9,7 +9,7 @@ module Extension
9
9
  SCRIPTS_DIRECTORY = "scripts"
10
10
 
11
11
  property! :git_template, accepts: String
12
- property! :dependency_checks, default: []
12
+ property! :dependency_checks, default: -> { [] }
13
13
 
14
14
  def call(directory_name, identifier, context)
15
15
  steps = [
@@ -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}}. "\
@@ -98,10 +100,8 @@ module Extension
98
100
  node_not_installed: "Node must be installed to create this extension.",
99
101
  version_too_low: "Your node version %s does not meet the minimum required version %s",
100
102
  },
101
- argo_missing_renderer_package_error: "%s Install the missing package and try again.",
102
- argo_renderer_package_invalid_version_error: <<~MESSAGE,
103
- The renderer package version is not a valid SemVer Version (http://semver.org)
104
- MESSAGE
103
+ argo_missing_renderer_package_error: "Extension template references invalid renderer package "\
104
+ "please contact Shopify for help.",
105
105
  yarn_install_error: "Something went wrong while running 'yarn install'. %s.",
106
106
  yarn_run_script_error: "Something went wrong while running script. %s.",
107
107
  },
@@ -117,6 +117,7 @@ module Extension
117
117
  },
118
118
  errors: {
119
119
  unknown_type: "Unknown extension type %s",
120
+ package_not_found: "`%s` package not found.",
120
121
  },
121
122
  }
122
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
@@ -10,8 +10,9 @@ module Extension
10
10
  property! :surface, converts: :to_str
11
11
  property! :renderer_package_name, converts: :to_str
12
12
  property! :git_template, converts: :to_str
13
- property! :required_fields, accepts: Array, default: []
14
- property! :required_shop_beta_flags, accepts: Array, default: []
13
+ property! :required_fields, accepts: Array, default: -> { [] }
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,50 @@ module Extension
42
42
  []
43
43
  end
44
44
 
45
- def serve(context)
46
- Features::ArgoServe.new(specification_handler: self, context: context).call
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(
55
+ specification_handler: self,
56
+ argo_runtime: argo_runtime(context),
57
+ context: context,
58
+ port: port,
59
+ tunnel_url: tunnel_url,
60
+ ).call
47
61
  end
48
62
 
49
63
  def renderer_package(context)
50
64
  argo.renderer_package(context)
51
65
  end
52
66
 
67
+ def argo_runtime(context)
68
+ @argo_runtime ||= Features::ArgoRuntime.new(
69
+ renderer: renderer_package(context),
70
+ cli: cli_package(context),
71
+ )
72
+ end
73
+
74
+ def cli_package(context)
75
+ cli_package_name = specification.features.argo&.cli_package_name
76
+ return unless cli_package_name
77
+
78
+ js_system = ShopifyCli::JsSystem.new(ctx: context)
79
+ Tasks::FindNpmPackages.exactly_one_of(cli_package_name, js_system: js_system)
80
+ .unwrap { |_e| context.abort(context.message("errors.package_not_found", cli_package_name)) }
81
+ end
82
+
53
83
  protected
54
84
 
55
85
  def argo
56
86
  Features::Argo.new(
57
87
  git_template: specification.features.argo.git_template,
58
- renderer_package_name: specification.features.argo.renderer_package_name,
88
+ renderer_package_name: specification.features.argo.renderer_package_name
59
89
  )
60
90
  end
61
91
 
@@ -9,7 +9,7 @@ module Extension
9
9
  property! :last_user_interaction_at, accepts: Time
10
10
  property :context, accepts: String
11
11
  property :location, accepts: String
12
- property :validation_errors, accepts: Models::ValidationError::IS_VALIDATION_ERROR_LIST, default: []
12
+ property :validation_errors, accepts: Models::ValidationError::IS_VALIDATION_ERROR_LIST, default: -> { [] }
13
13
  end
14
14
  end
15
15
  end
@@ -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
@@ -59,21 +59,21 @@ module Node
59
59
  installed: "Installed Heroku CLI",
60
60
  authenticating: "Authenticating with Heroku…",
61
61
  authenticated: "{{v}} Authenticated with Heroku",
62
- authenticated_with_account: "{{v}} Authenticated with Heroku as `%s`",
62
+ authenticated_with_account: "{{v}} Authenticated with Heroku as {{green:%s}}",
63
63
  deploying: "Deploying to Heroku…",
64
64
  deployed: "{{v}} Deployed to Heroku",
65
65
  git: {
66
66
  checking: "Checking git repo…",
67
67
  initialized: "Git repo initialized",
68
68
  what_branch: "What branch would you like to deploy?",
69
- branch_selected: "{{v}} Git branch `%s` selected for deploy",
69
+ branch_selected: "{{v}} Git branch {{green:%s}} selected for deploy",
70
70
  },
71
71
  app: {
72
72
  no_apps_found: "No existing Heroku app found. What would you like to do?",
73
73
  name: "What is your Heroku app’s name?",
74
74
  select: "Specify an existing Heroku app",
75
- selecting: "Selecting Heroku app `%s`…",
76
- selected: "{{v}} Heroku app `%s` selected",
75
+ selecting: "Selecting Heroku app %s",
76
+ selected: "{{v}} Heroku app {{green:%s}} selected",
77
77
  create: "Create a new Heroku app",
78
78
  creating: "Creating new Heroku app…",
79
79
  created: "{{v}} New Heroku app created",
@@ -89,7 +89,7 @@ module Rails
89
89
  downloaded: "Downloaded Heroku CLI",
90
90
  installing: "Installing Heroku CLI...",
91
91
  installed: "Installed Heroku CLI",
92
- authenticated_with_account: "{{v}} Authenticated with Heroku as `%s`",
92
+ authenticated_with_account: "{{v}} Authenticated with Heroku as {{green:%s}}",
93
93
  authenticating: "Authenticating with Heroku...",
94
94
  authenticated: "{{v}} Authenticated with Heroku",
95
95
  deploying: "Deploying to Heroku...",
@@ -109,14 +109,14 @@ module Rails
109
109
  checking: "Checking git repo...",
110
110
  initialized: "Git repo initialized",
111
111
  what_branch: "What branch would you like to deploy?",
112
- branch_selected: "{{v}} Git branch `%s` selected for deploy",
112
+ branch_selected: "{{v}} Git branch {{green:%s}} selected for deploy",
113
113
  },
114
114
  app: {
115
115
  no_apps_found: "No existing Heroku app found. What would you like to do?",
116
116
  name: "What is your Heroku app’s name?",
117
117
  select: "Specify an existing Heroku app",
118
- selecting: "Selecting Heroku app `%s`...",
119
- selected: "{{v}} Heroku app `%s` selected",
118
+ selecting: "Selecting Heroku app %s...",
119
+ selected: "{{v}} Heroku app {{green:%s}} selected",
120
120
  create: "Create a new Heroku app",
121
121
  creating: "Creating new Heroku app...",
122
122
  created: "{{v}} New Heroku app created",
@@ -24,6 +24,10 @@ module Script
24
24
  autoload :ScriptForm, Project.project_filepath("forms/script_form")
25
25
  end
26
26
 
27
+ module Tasks
28
+ autoload :EnsureEnv, Project.project_filepath("tasks/ensure_env")
29
+ end
30
+
27
31
  module Layers
28
32
  module Application
29
33
  autoload :BuildScript, Project.project_filepath("layers/application/build_script")
@@ -44,22 +48,23 @@ module Script
44
48
 
45
49
  module Infrastructure
46
50
  autoload :Errors, Project.project_filepath("layers/infrastructure/errors")
47
- autoload :AssemblyScriptDependencyManager,
48
- Project.project_filepath("layers/infrastructure/assemblyscript_dependency_manager")
49
- autoload :AssemblyScriptProjectCreator,
50
- Project.project_filepath("layers/infrastructure/assemblyscript_project_creator")
51
- autoload :AssemblyScriptTaskRunner, Project.project_filepath("layers/infrastructure/assemblyscript_task_runner")
52
- autoload :AssemblyScriptTsConfig, Project.project_filepath("layers/infrastructure/assemblyscript_tsconfig")
53
- autoload :RustProjectCreator,
54
- Project.project_filepath("layers/infrastructure/rust_project_creator.rb")
55
- autoload :RustTaskRunner, Project.project_filepath("layers/infrastructure/rust_task_runner")
56
-
51
+ autoload :CommandRunner, Project.project_filepath("layers/infrastructure/command_runner")
57
52
  autoload :PushPackageRepository, Project.project_filepath("layers/infrastructure/push_package_repository")
58
53
  autoload :ExtensionPointRepository, Project.project_filepath("layers/infrastructure/extension_point_repository")
59
- autoload :ProjectCreator, Project.project_filepath("layers/infrastructure/project_creator")
60
54
  autoload :ScriptProjectRepository, Project.project_filepath("layers/infrastructure/script_project_repository")
61
55
  autoload :ScriptService, Project.project_filepath("layers/infrastructure/script_service")
62
- autoload :TaskRunner, Project.project_filepath("layers/infrastructure/task_runner")
56
+
57
+ module Languages
58
+ autoload :AssemblyScriptProjectCreator,
59
+ Project.project_filepath("layers/infrastructure/languages/assemblyscript_project_creator")
60
+ autoload :AssemblyScriptTaskRunner,
61
+ Project.project_filepath("layers/infrastructure/languages/assemblyscript_task_runner")
62
+ autoload :ProjectCreator, Project.project_filepath("layers/infrastructure/languages/project_creator")
63
+ autoload :RustProjectCreator,
64
+ Project.project_filepath("layers/infrastructure/languages/rust_project_creator.rb")
65
+ autoload :RustTaskRunner, Project.project_filepath("layers/infrastructure/languages/rust_task_runner")
66
+ autoload :TaskRunner, Project.project_filepath("layers/infrastructure/languages/task_runner")
67
+ end
63
68
  end
64
69
  end
65
70