shopify-cli 2.6.2 → 2.6.6
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 +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
         |