shopify-cli 2.7.1 → 2.7.2
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/CHANGELOG.md +10 -1
- data/Gemfile.lock +1 -1
- data/lib/project_types/extension/commands/build.rb +3 -8
- data/lib/project_types/extension/commands/create.rb +1 -3
- data/lib/project_types/extension/messages/messages.rb +0 -2
- data/lib/project_types/extension/models/development_server.rb +2 -2
- data/lib/project_types/rails/commands/create.rb +1 -3
- data/lib/project_types/script/cli.rb +5 -0
- data/lib/project_types/script/commands/create.rb +1 -3
- data/lib/project_types/script/commands/javy.rb +0 -2
- data/lib/project_types/script/commands/push.rb +2 -1
- data/lib/project_types/script/config/extension_points.yml +0 -26
- data/lib/project_types/script/forms/ask_app.rb +32 -0
- data/lib/project_types/script/forms/ask_org.rb +30 -0
- data/lib/project_types/script/forms/ask_script_uuid.rb +22 -0
- data/lib/project_types/script/forms/run_against_shopify_org.rb +14 -0
- data/lib/project_types/script/layers/application/build_script.rb +0 -1
- data/lib/project_types/script/layers/application/connect_app.rb +73 -0
- data/lib/project_types/script/layers/domain/script_project.rb +4 -0
- data/lib/project_types/script/layers/infrastructure/errors.rb +0 -1
- data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb +0 -4
- data/lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb +0 -4
- data/lib/project_types/script/messages/messages.rb +0 -2
- data/lib/project_types/script/ui/error_handler.rb +0 -5
- data/lib/project_types/theme/commands/pull.rb +3 -0
- data/lib/project_types/theme/commands/push.rb +6 -1
- data/lib/project_types/theme/commands/serve.rb +1 -1
- data/lib/project_types/theme/messages/messages.rb +9 -0
- data/lib/project_types/theme/ui/sync_progress_bar.rb +2 -2
- data/lib/shopify_cli/command/project_command.rb +20 -7
- data/lib/shopify_cli/commands/app/create/node.rb +1 -3
- data/lib/shopify_cli/commands/app/create/rails.rb +1 -3
- data/lib/shopify_cli/constants.rb +3 -0
- data/lib/shopify_cli/context.rb +9 -0
- data/lib/shopify_cli/environment.rb +4 -0
- data/lib/shopify_cli/identity_auth.rb +18 -0
- data/lib/shopify_cli/messages/messages.rb +1 -0
- data/lib/shopify_cli/partners_api.rb +1 -8
- data/lib/shopify_cli/services/app/serve/node_service.rb +1 -1
- data/lib/shopify_cli/services/app/serve/rails_service.rb +1 -1
- data/lib/shopify_cli/tasks/ensure_authenticated.rb +9 -3
- data/lib/shopify_cli/theme/dev_server.rb +4 -4
- data/lib/shopify_cli/theme/syncer/error_reporter.rb +45 -0
- data/lib/shopify_cli/theme/syncer/operation.rb +56 -0
- data/lib/shopify_cli/theme/syncer/standard_reporter.rb +32 -0
- data/lib/shopify_cli/theme/syncer.rb +40 -39
- data/lib/shopify_cli/theme/theme.rb +31 -19
- data/lib/shopify_cli/tunnel.rb +8 -10
- data/lib/shopify_cli/version.rb +1 -1
- metadata +10 -3
- data/lib/project_types/script/tasks/ensure_env.rb +0 -106
| @@ -86,6 +86,10 @@ module ShopifyCLI | |
| 86 86 | 
             
                  )
         | 
| 87 87 | 
             
                end
         | 
| 88 88 |  | 
| 89 | 
            +
                def self.auth_token(env_variables: ENV)
         | 
| 90 | 
            +
                  env_variables[Constants::EnvironmentVariables::AUTH_TOKEN]
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
             | 
| 89 93 | 
             
                def self.env_variable_truthy?(variable_name, env_variables: ENV)
         | 
| 90 94 | 
             
                  TRUTHY_ENV_VARIABLE_VALUES.include?(env_variables[variable_name.to_s])
         | 
| 91 95 | 
             
                end
         | 
| @@ -68,6 +68,24 @@ module ShopifyCLI | |
| 68 68 | 
             
                  request_exchange_tokens
         | 
| 69 69 | 
             
                end
         | 
| 70 70 |  | 
| 71 | 
            +
                def self.fetch_or_auth_partners_token(ctx:)
         | 
| 72 | 
            +
                  env_var_auth_token = Environment.auth_token
         | 
| 73 | 
            +
                  return env_var_auth_token if env_var_auth_token
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  ShopifyCLI::DB.get(:partners_exchange_token) do
         | 
| 76 | 
            +
                    IdentityAuth.new(ctx: ctx).authenticate
         | 
| 77 | 
            +
                    ShopifyCLI::DB.get(:partners_exchange_token)
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                def self.environment_auth_token?
         | 
| 82 | 
            +
                  !!Environment.auth_token
         | 
| 83 | 
            +
                end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                def self.authenticated?
         | 
| 86 | 
            +
                  environment_auth_token? || IDENTITY_ACCESS_TOKENS.all? { |key| ShopifyCLI::DB.exists?(key) }
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
             | 
| 71 89 | 
             
                def reauthenticate
         | 
| 72 90 | 
             
                  return if refresh_exchange_tokens || refresh_access_tokens
         | 
| 73 91 | 
             
                  ctx.abort(ctx.message("core.identity_auth.error.reauthenticate", ShopifyCLI::TOOL_NAME))
         | 
| @@ -457,6 +457,7 @@ module ShopifyCLI | |
| 457 457 | 
             
                        not_authenticated: "Failed to authenticate",
         | 
| 458 458 | 
             
                      },
         | 
| 459 459 | 
             
                      login_prompt: "Please ensure you've logged in with {{command:%s login}} and try again",
         | 
| 460 | 
            +
                      token_authentication: "%s environment variable. We'll authenticate using its value as a token.",
         | 
| 460 461 | 
             
                    },
         | 
| 461 462 |  | 
| 462 463 | 
             
                    options: {
         | 
| @@ -61,18 +61,11 @@ module ShopifyCLI | |
| 61 61 | 
             
                  def api_client(ctx)
         | 
| 62 62 | 
             
                    new(
         | 
| 63 63 | 
             
                      ctx: ctx,
         | 
| 64 | 
            -
                      token:  | 
| 64 | 
            +
                      token: IdentityAuth.fetch_or_auth_partners_token(ctx: ctx),
         | 
| 65 65 | 
             
                      url: "https://#{Environment.partners_domain}/api/cli/graphql",
         | 
| 66 66 | 
             
                    )
         | 
| 67 67 | 
             
                  end
         | 
| 68 68 |  | 
| 69 | 
            -
                  def access_token(ctx)
         | 
| 70 | 
            -
                    ShopifyCLI::DB.get(:partners_exchange_token) do
         | 
| 71 | 
            -
                      IdentityAuth.new(ctx: ctx).authenticate
         | 
| 72 | 
            -
                      ShopifyCLI::DB.get(:partners_exchange_token)
         | 
| 73 | 
            -
                    end
         | 
| 74 | 
            -
                  end
         | 
| 75 | 
            -
             | 
| 76 69 | 
             
                  def auth_failure_info(ctx, error)
         | 
| 77 70 | 
             
                    if error.response
         | 
| 78 71 | 
             
                      headers = %w(www-authenticate x-request-id)
         | 
| @@ -14,7 +14,7 @@ module ShopifyCLI | |
| 14 14 |  | 
| 15 15 | 
             
                      def call
         | 
| 16 16 | 
             
                        project = ShopifyCLI::Project.current
         | 
| 17 | 
            -
                        url = host || ShopifyCLI::Tunnel.start(context)
         | 
| 17 | 
            +
                        url = host || ShopifyCLI::Tunnel.start(context, port: port)
         | 
| 18 18 | 
             
                        raise ShopifyCLI::Abort,
         | 
| 19 19 | 
             
                          context.message("core.app.serve.error.host_must_be_https") if url.match(/^https/i).nil?
         | 
| 20 20 | 
             
                        project.env.update(context, :host, url)
         | 
| @@ -14,7 +14,7 @@ module ShopifyCLI | |
| 14 14 |  | 
| 15 15 | 
             
                      def call
         | 
| 16 16 | 
             
                        project = ShopifyCLI::Project.current
         | 
| 17 | 
            -
                        url = host || ShopifyCLI::Tunnel.start(context)
         | 
| 17 | 
            +
                        url = host || ShopifyCLI::Tunnel.start(context, port: port)
         | 
| 18 18 | 
             
                        raise ShopifyCLI::Abort,
         | 
| 19 19 | 
             
                          context.message("core.app.serve.error.host_must_be_https") if url.match(/^https/i).nil?
         | 
| 20 20 | 
             
                        project.env.update(context, :host, url)
         | 
| @@ -4,9 +4,15 @@ module ShopifyCLI | |
| 4 4 | 
             
              module Tasks
         | 
| 5 5 | 
             
                class EnsureAuthenticated < ShopifyCLI::Task
         | 
| 6 6 | 
             
                  def call(ctx)
         | 
| 7 | 
            -
                     | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 7 | 
            +
                    return if ShopifyCLI::Environment.acceptance_test?
         | 
| 8 | 
            +
                    unless ShopifyCLI::IdentityAuth.authenticated?
         | 
| 9 | 
            +
                      raise ShopifyCLI::Abort,
         | 
| 10 | 
            +
                        ctx.message("core.identity_auth.login_prompt", ShopifyCLI::TOOL_NAME)
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                    if ShopifyCLI::IdentityAuth.environment_auth_token?
         | 
| 13 | 
            +
                      ctx.puts(ctx.message("core.identity_auth.token_authentication",
         | 
| 14 | 
            +
                        ShopifyCLI::Constants::EnvironmentVariables::AUTH_TOKEN))
         | 
| 15 | 
            +
                    end
         | 
| 10 16 | 
             
                  end
         | 
| 11 17 | 
             
                end
         | 
| 12 18 | 
             
              end
         | 
| @@ -24,7 +24,7 @@ module ShopifyCLI | |
| 24 24 | 
             
                  class << self
         | 
| 25 25 | 
             
                    attr_accessor :ctx
         | 
| 26 26 |  | 
| 27 | 
            -
                    def start(ctx, root,  | 
| 27 | 
            +
                    def start(ctx, root, host: "127.0.0.1", port: 9292, poll: false)
         | 
| 28 28 | 
             
                      @ctx = ctx
         | 
| 29 29 | 
             
                      theme = DevelopmentTheme.new(ctx, root: root)
         | 
| 30 30 | 
             
                      ignore_filter = IgnoreFilter.from_path(root)
         | 
| @@ -36,7 +36,7 @@ module ShopifyCLI | |
| 36 36 | 
             
                      @app = LocalAssets.new(ctx, @app, theme: theme)
         | 
| 37 37 | 
             
                      @app = HotReload.new(ctx, @app, theme: theme, watcher: watcher, ignore_filter: ignore_filter)
         | 
| 38 38 | 
             
                      stopped = false
         | 
| 39 | 
            -
                      address = "http://#{ | 
| 39 | 
            +
                      address = "http://#{host}:#{port}"
         | 
| 40 40 |  | 
| 41 41 | 
             
                      theme.ensure_exists!
         | 
| 42 42 |  | 
| @@ -70,7 +70,7 @@ module ShopifyCLI | |
| 70 70 | 
             
                      watcher.start
         | 
| 71 71 | 
             
                      WebServer.run(
         | 
| 72 72 | 
             
                        @app,
         | 
| 73 | 
            -
                        BindAddress:  | 
| 73 | 
            +
                        BindAddress: host,
         | 
| 74 74 | 
             
                        Port: port,
         | 
| 75 75 | 
             
                        Logger: logger,
         | 
| 76 76 | 
             
                        AccessLog: [],
         | 
| @@ -83,7 +83,7 @@ module ShopifyCLI | |
| 83 83 | 
             
                    rescue Errno::EADDRINUSE
         | 
| 84 84 | 
             
                      abort_address_already_in_use(address)
         | 
| 85 85 | 
             
                    rescue Errno::EADDRNOTAVAIL
         | 
| 86 | 
            -
                      raise AddressBindingError, "Error binding to the address #{ | 
| 86 | 
            +
                      raise AddressBindingError, "Error binding to the address #{host}."
         | 
| 87 87 | 
             
                    end
         | 
| 88 88 |  | 
| 89 89 | 
             
                    def stop
         | 
| @@ -0,0 +1,45 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module ShopifyCLI
         | 
| 4 | 
            +
              module Theme
         | 
| 5 | 
            +
                class Syncer
         | 
| 6 | 
            +
                  ##
         | 
| 7 | 
            +
                  # ShopifyCLI::Theme::Syncer::ErrorReporter allows delaying log of errors,
         | 
| 8 | 
            +
                  # mainly to not break the progress bar.
         | 
| 9 | 
            +
                  #
         | 
| 10 | 
            +
                  class ErrorReporter
         | 
| 11 | 
            +
                    attr_reader :ctx, :delayed_errors
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    def initialize(ctx)
         | 
| 14 | 
            +
                      @ctx = ctx
         | 
| 15 | 
            +
                      @has_any_error = false
         | 
| 16 | 
            +
                      @delay_errors = false
         | 
| 17 | 
            +
                      @delayed_errors = []
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    def disable!
         | 
| 21 | 
            +
                      @delay_errors = true
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    def enable!
         | 
| 25 | 
            +
                      @delay_errors = false
         | 
| 26 | 
            +
                      @delayed_errors.each { |error| report(error) }
         | 
| 27 | 
            +
                      @delayed_errors.clear
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    def report(error_message)
         | 
| 31 | 
            +
                      if @delay_errors
         | 
| 32 | 
            +
                        @delayed_errors << error_message
         | 
| 33 | 
            +
                      else
         | 
| 34 | 
            +
                        @has_any_error = true
         | 
| 35 | 
            +
                        @ctx.error(error_message)
         | 
| 36 | 
            +
                      end
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    def has_any_error?
         | 
| 40 | 
            +
                      @has_any_error
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
            end
         | 
| @@ -0,0 +1,56 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module ShopifyCLI
         | 
| 4 | 
            +
              module Theme
         | 
| 5 | 
            +
                class Syncer
         | 
| 6 | 
            +
                  class Operation
         | 
| 7 | 
            +
                    attr_accessor :method, :file
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    COLOR_BY_STATUS = {
         | 
| 10 | 
            +
                      error: :red,
         | 
| 11 | 
            +
                      synced: :green,
         | 
| 12 | 
            +
                      fixed: :cyan,
         | 
| 13 | 
            +
                    }
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    def initialize(ctx, method, file)
         | 
| 16 | 
            +
                      @ctx = ctx
         | 
| 17 | 
            +
                      @method = method
         | 
| 18 | 
            +
                      @file = file
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    def to_s
         | 
| 22 | 
            +
                      "#{method} #{file_path}"
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    def as_error_message
         | 
| 26 | 
            +
                      as_message_with(status: :error)
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    def as_synced_message
         | 
| 30 | 
            +
                      as_message_with(status: :synced)
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    def as_fix_message
         | 
| 34 | 
            +
                      as_message_with(status: :fixed)
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    def file_path
         | 
| 38 | 
            +
                      file&.relative_path.to_s
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    private
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                    def as_message_with(status:)
         | 
| 44 | 
            +
                      status_color = COLOR_BY_STATUS[status]
         | 
| 45 | 
            +
                      status_text = @ctx.message("theme.serve.operation.status.#{status}").ljust(6)
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                      "#{timestamp} {{#{status_color}:#{status_text}}} {{>}} {{blue:#{self}}}"
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                    def timestamp
         | 
| 51 | 
            +
                      Time.now.strftime("%T")
         | 
| 52 | 
            +
                    end
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
            end
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module ShopifyCLI
         | 
| 4 | 
            +
              module Theme
         | 
| 5 | 
            +
                class Syncer
         | 
| 6 | 
            +
                  ##
         | 
| 7 | 
            +
                  # ShopifyCLI::Theme::Syncer::StdReporter allows disabling/enabling
         | 
| 8 | 
            +
                  # messages reported in the standard output (ShopifyCLI::Context#puts).
         | 
| 9 | 
            +
                  #
         | 
| 10 | 
            +
                  class StandardReporter
         | 
| 11 | 
            +
                    attr_reader :ctx
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    def initialize(ctx)
         | 
| 14 | 
            +
                      @enabled = true
         | 
| 15 | 
            +
                      @ctx = ctx
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    def disable!
         | 
| 19 | 
            +
                      @enabled = false
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    def enable!
         | 
| 23 | 
            +
                      @enabled = true
         | 
| 24 | 
            +
                    end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    def report(message)
         | 
| 27 | 
            +
                      ctx.puts(message) if @enabled
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         | 
| @@ -2,24 +2,31 @@ | |
| 2 2 | 
             
            require "thread"
         | 
| 3 3 | 
             
            require "json"
         | 
| 4 4 | 
             
            require "base64"
         | 
| 5 | 
            +
            require "forwardable"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            require_relative "syncer/error_reporter"
         | 
| 8 | 
            +
            require_relative "syncer/standard_reporter"
         | 
| 9 | 
            +
            require_relative "syncer/operation"
         | 
| 5 10 |  | 
| 6 11 | 
             
            module ShopifyCLI
         | 
| 7 12 | 
             
              module Theme
         | 
| 8 13 | 
             
                class Syncer
         | 
| 9 | 
            -
                   | 
| 10 | 
            -
             | 
| 11 | 
            -
                      "#{method} #{file&.relative_path}"
         | 
| 12 | 
            -
                    end
         | 
| 13 | 
            -
                  end
         | 
| 14 | 
            +
                  extend Forwardable
         | 
| 15 | 
            +
             | 
| 14 16 | 
             
                  API_VERSION = "unstable"
         | 
| 15 17 |  | 
| 16 18 | 
             
                  attr_reader :checksums
         | 
| 17 19 | 
             
                  attr_accessor :ignore_filter
         | 
| 18 20 |  | 
| 21 | 
            +
                  def_delegators :@error_reporter, :has_any_error?
         | 
| 22 | 
            +
             | 
| 19 23 | 
             
                  def initialize(ctx, theme:, ignore_filter: nil)
         | 
| 20 24 | 
             
                    @ctx = ctx
         | 
| 21 25 | 
             
                    @theme = theme
         | 
| 22 26 | 
             
                    @ignore_filter = ignore_filter
         | 
| 27 | 
            +
                    @error_reporter = ErrorReporter.new(ctx)
         | 
| 28 | 
            +
                    @standard_reporter = StandardReporter.new(ctx)
         | 
| 29 | 
            +
                    @reporters = [@error_reporter, @standard_reporter]
         | 
| 23 30 |  | 
| 24 31 | 
             
                    # Queue of `Operation`s waiting to be picked up from a thread for processing.
         | 
| 25 32 | 
             
                    @queue = Queue.new
         | 
| @@ -30,12 +37,19 @@ module ShopifyCLI | |
| 30 37 | 
             
                    # Mutex used to pause all threads when backing-off when hitting API rate limits
         | 
| 31 38 | 
             
                    @backoff_mutex = Mutex.new
         | 
| 32 39 |  | 
| 33 | 
            -
                    # Allows delaying log of errors, mainly to not break the progress bar.
         | 
| 34 | 
            -
                    @delay_errors = false
         | 
| 35 | 
            -
                    @delayed_errors = []
         | 
| 36 | 
            -
             | 
| 37 40 | 
             
                    # Latest theme assets checksums. Updated on each upload.
         | 
| 38 41 | 
             
                    @checksums = {}
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                    # Checksums of assets with errors. 
         | 
| 44 | 
            +
                    @error_checksums = []
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  def lock_io!
         | 
| 48 | 
            +
                    @reporters.each { |reporter| reporter.disable! }
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  def unlock_io!
         | 
| 52 | 
            +
                    @reporters.each { |reporter| reporter.enable! }
         | 
| 39 53 | 
             
                  end
         | 
| 40 54 |  | 
| 41 55 | 
             
                  def enqueue_updates(files)
         | 
| @@ -103,25 +117,14 @@ module ShopifyCLI | |
| 103 117 | 
             
                          break if operation.nil? # shutdown was called
         | 
| 104 118 | 
             
                          perform(operation)
         | 
| 105 119 | 
             
                        rescue Exception => e
         | 
| 106 | 
            -
                           | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 109 | 
            -
                          )
         | 
| 120 | 
            +
                          error_suffix = ": #{e}"
         | 
| 121 | 
            +
                          error_suffix += + "\n\t#{e.backtrace.join("\n\t")}" if @ctx.debug?
         | 
| 122 | 
            +
                          report_error(operation, error_suffix)
         | 
| 110 123 | 
             
                        end
         | 
| 111 124 | 
             
                      end
         | 
| 112 125 | 
             
                    end
         | 
| 113 126 | 
             
                  end
         | 
| 114 127 |  | 
| 115 | 
            -
                  def delay_errors!
         | 
| 116 | 
            -
                    @delay_errors = true
         | 
| 117 | 
            -
                  end
         | 
| 118 | 
            -
             | 
| 119 | 
            -
                  def report_errors!
         | 
| 120 | 
            -
                    @delay_errors = false
         | 
| 121 | 
            -
                    @delayed_errors.each { |error| report_error(error) }
         | 
| 122 | 
            -
                    @delayed_errors.clear
         | 
| 123 | 
            -
                  end
         | 
| 124 | 
            -
             | 
| 125 128 | 
             
                  def upload_theme!(delay_low_priority_files: false, delete: true, &block)
         | 
| 126 129 | 
             
                    fetch_checksums!
         | 
| 127 130 |  | 
| @@ -177,21 +180,27 @@ module ShopifyCLI | |
| 177 180 |  | 
| 178 181 | 
             
                  private
         | 
| 179 182 |  | 
| 183 | 
            +
                  def report_error(operation, error_suffix = "")
         | 
| 184 | 
            +
                    @error_checksums << @checksums[operation.file_path]
         | 
| 185 | 
            +
                    @error_reporter.report("#{operation.as_error_message}#{error_suffix}")
         | 
| 186 | 
            +
                  end
         | 
| 187 | 
            +
             | 
| 180 188 | 
             
                  def enqueue(method, file)
         | 
| 181 189 | 
             
                    raise ArgumentError, "file required" unless file
         | 
| 182 190 |  | 
| 183 | 
            -
                    operation = Operation.new(method, @theme[file])
         | 
| 191 | 
            +
                    operation = Operation.new(@ctx, method, @theme[file])
         | 
| 184 192 |  | 
| 185 193 | 
             
                    # Already enqueued
         | 
| 186 194 | 
             
                    return if @pending.include?(operation)
         | 
| 187 195 |  | 
| 188 | 
            -
                    if @ignore_filter&.ignore?(operation. | 
| 189 | 
            -
                      @ctx.debug("ignore #{operation. | 
| 196 | 
            +
                    if @ignore_filter&.ignore?(operation.file_path)
         | 
| 197 | 
            +
                      @ctx.debug("ignore #{operation.file_path}")
         | 
| 190 198 | 
             
                      return
         | 
| 191 199 | 
             
                    end
         | 
| 192 200 |  | 
| 193 201 | 
             
                    if [:update, :get].include?(method) && operation.file.exist? && !file_has_changed?(operation.file)
         | 
| 194 | 
            -
                       | 
| 202 | 
            +
                      is_fixed = !!@error_checksums.delete(operation.file.checksum)
         | 
| 203 | 
            +
                      @standard_reporter.report(operation.as_fix_message) if is_fixed
         | 
| 195 204 | 
             
                      return
         | 
| 196 205 | 
             
                    end
         | 
| 197 206 |  | 
| @@ -206,16 +215,16 @@ module ShopifyCLI | |
| 206 215 |  | 
| 207 216 | 
             
                    response = send(operation.method, operation.file)
         | 
| 208 217 |  | 
| 218 | 
            +
                    @standard_reporter.report(operation.as_synced_message)
         | 
| 219 | 
            +
             | 
| 209 220 | 
             
                    # Check if the API told us we're near the rate limit
         | 
| 210 221 | 
             
                    if !backingoff? && (limit = response["x-shopify-shop-api-call-limit"])
         | 
| 211 222 | 
             
                      used, total = limit.split("/").map(&:to_i)
         | 
| 212 223 | 
             
                      backoff_if_near_limit!(used, total)
         | 
| 213 224 | 
             
                    end
         | 
| 214 225 | 
             
                  rescue ShopifyCLI::API::APIRequestError => e
         | 
| 215 | 
            -
                     | 
| 216 | 
            -
             | 
| 217 | 
            -
                      parse_api_errors(e).join("\n  ")
         | 
| 218 | 
            -
                    )
         | 
| 226 | 
            +
                    error_suffix = ":\n  " + parse_api_errors(e).join("\n  ")
         | 
| 227 | 
            +
                    report_error(operation, error_suffix)
         | 
| 219 228 | 
             
                  ensure
         | 
| 220 229 | 
             
                    @pending.delete(operation)
         | 
| 221 230 | 
             
                  end
         | 
| @@ -295,14 +304,6 @@ module ShopifyCLI | |
| 295 304 | 
             
                    file.checksum != @checksums[file.relative_path.to_s]
         | 
| 296 305 | 
             
                  end
         | 
| 297 306 |  | 
| 298 | 
            -
                  def report_error(error)
         | 
| 299 | 
            -
                    if @delay_errors
         | 
| 300 | 
            -
                      @delayed_errors << error
         | 
| 301 | 
            -
                    else
         | 
| 302 | 
            -
                      @ctx.puts(error)
         | 
| 303 | 
            -
                    end
         | 
| 304 | 
            -
                  end
         | 
| 305 | 
            -
             | 
| 306 307 | 
             
                  def parse_api_errors(exception)
         | 
| 307 308 | 
             
                    parsed_body = JSON.parse(exception&.response&.body)
         | 
| 308 309 | 
             
                    message = parsed_body.dig("errors", "asset") || parsed_body["message"] || exception.message
         | 
| @@ -162,26 +162,38 @@ module ShopifyCLI | |
| 162 162 | 
             
                    }
         | 
| 163 163 | 
             
                  end
         | 
| 164 164 |  | 
| 165 | 
            -
                   | 
| 166 | 
            -
                     | 
| 167 | 
            -
                      ctx | 
| 168 | 
            -
             | 
| 169 | 
            -
                       | 
| 170 | 
            -
             | 
| 171 | 
            -
             | 
| 165 | 
            +
                  class << self
         | 
| 166 | 
            +
                    def all(ctx, root: nil)
         | 
| 167 | 
            +
                      _status, body = fetch_themes(ctx)
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                      body["themes"]
         | 
| 170 | 
            +
                        .sort_by { |theme_attrs| Time.parse(theme_attrs["updated_at"]) }
         | 
| 171 | 
            +
                        .reverse
         | 
| 172 | 
            +
                        .map { |theme_attrs| new(ctx, root: root, **allowed_attrs(theme_attrs)) }
         | 
| 173 | 
            +
                    end
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                    def live(ctx, root: nil)
         | 
| 176 | 
            +
                      _status, body = fetch_themes(ctx)
         | 
| 172 177 |  | 
| 173 | 
            -
             | 
| 174 | 
            -
             | 
| 175 | 
            -
             | 
| 176 | 
            -
             | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 179 | 
            -
             | 
| 180 | 
            -
             | 
| 181 | 
            -
             | 
| 182 | 
            -
             | 
| 183 | 
            -
             | 
| 184 | 
            -
             | 
| 178 | 
            +
                      body["themes"]
         | 
| 179 | 
            +
                        .find { |theme_attrs| theme_attrs["role"] == "main" }
         | 
| 180 | 
            +
                        .tap { |theme_attrs| break new(ctx, root: root, **allowed_attrs(theme_attrs)) }
         | 
| 181 | 
            +
                    end
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                    private
         | 
| 184 | 
            +
             | 
| 185 | 
            +
                    def allowed_attrs(attrs)
         | 
| 186 | 
            +
                      attrs.slice("id", "name", "role").transform_keys(&:to_sym)
         | 
| 187 | 
            +
                    end
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                    def fetch_themes(ctx)
         | 
| 190 | 
            +
                      AdminAPI.rest_request(
         | 
| 191 | 
            +
                        ctx,
         | 
| 192 | 
            +
                        shop: AdminAPI.get_shop_or_abort(ctx),
         | 
| 193 | 
            +
                        path: "themes.json",
         | 
| 194 | 
            +
                        api_version: "unstable",
         | 
| 195 | 
            +
                      )
         | 
| 196 | 
            +
                    end
         | 
| 185 197 | 
             
                  end
         | 
| 186 198 |  | 
| 187 199 | 
             
                  private
         | 
    
        data/lib/shopify_cli/tunnel.rb
    CHANGED
    
    | @@ -87,7 +87,7 @@ module ShopifyCLI | |
| 87 87 | 
             
                #
         | 
| 88 88 | 
             
                def auth(ctx, token)
         | 
| 89 89 | 
             
                  install(ctx)
         | 
| 90 | 
            -
                  ctx.system(ngrok_path, "authtoken", token)
         | 
| 90 | 
            +
                  ctx.system(ngrok_path(ctx), "authtoken", token)
         | 
| 91 91 | 
             
                end
         | 
| 92 92 |  | 
| 93 93 | 
             
                ##
         | 
| @@ -150,7 +150,7 @@ module ShopifyCLI | |
| 150 150 |  | 
| 151 151 | 
             
                def install(ctx)
         | 
| 152 152 | 
             
                  ngrok = "ngrok#{ctx.executable_file_extension}"
         | 
| 153 | 
            -
                  return if File.exist?(ngrok_path)
         | 
| 153 | 
            +
                  return if File.exist?(ngrok_path(ctx))
         | 
| 154 154 | 
             
                  check_prereq_command(ctx, "curl")
         | 
| 155 155 | 
             
                  check_prereq_command(ctx, ctx.linux? ? "unzip" : "tar")
         | 
| 156 156 | 
             
                  spinner = CLI::UI::SpinGroup.new
         | 
| @@ -170,7 +170,7 @@ module ShopifyCLI | |
| 170 170 | 
             
                  spinner.wait
         | 
| 171 171 |  | 
| 172 172 | 
             
                  # final check to see if ngrok is accessible
         | 
| 173 | 
            -
                  unless File.exist?(ngrok_path)
         | 
| 173 | 
            +
                  unless File.exist?(ngrok_path(ctx))
         | 
| 174 174 | 
             
                    ctx.abort(ctx.message("core.tunnel.error.ngrok", ngrok, ShopifyCLI.cache_dir))
         | 
| 175 175 | 
             
                  end
         | 
| 176 176 | 
             
                end
         | 
| @@ -182,12 +182,9 @@ module ShopifyCLI | |
| 182 182 | 
             
                  raise e.class, e.message
         | 
| 183 183 | 
             
                end
         | 
| 184 184 |  | 
| 185 | 
            -
                def ngrok_path
         | 
| 186 | 
            -
                   | 
| 187 | 
            -
             | 
| 188 | 
            -
             | 
| 189 | 
            -
                def ngrok_command(port)
         | 
| 190 | 
            -
                  "\"#{ngrok_path}\" http -inspect=false -log=stdout -log-level=debug #{port}"
         | 
| 185 | 
            +
                def ngrok_path(ctx)
         | 
| 186 | 
            +
                  ngrok = "ngrok#{ctx.executable_file_extension}"
         | 
| 187 | 
            +
                  File.join(ShopifyCLI.cache_dir, ngrok)
         | 
| 191 188 | 
             
                end
         | 
| 192 189 |  | 
| 193 190 | 
             
                def seconds_to_hm(seconds)
         | 
| @@ -195,7 +192,8 @@ module ShopifyCLI | |
| 195 192 | 
             
                end
         | 
| 196 193 |  | 
| 197 194 | 
             
                def start_ngrok(ctx, port)
         | 
| 198 | 
            -
                   | 
| 195 | 
            +
                  ngrok_command = "\"#{ngrok_path(ctx)}\" http -inspect=false -log=stdout -log-level=debug #{port}"
         | 
| 196 | 
            +
                  process = ShopifyCLI::ProcessSupervision.start(:ngrok, ngrok_command)
         | 
| 199 197 | 
             
                  log = fetch_url(ctx, process.log_path)
         | 
| 200 198 | 
             
                  [log.url, log.account]
         | 
| 201 199 | 
             
                end
         | 
    
        data/lib/shopify_cli/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: shopify-cli
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 2.7. | 
| 4 | 
            +
              version: 2.7.2
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Shopify
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2021-11- | 
| 11 | 
            +
            date: 2021-11-30 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -275,12 +275,17 @@ files: | |
| 275 275 | 
             
            - lib/project_types/script/commands/push.rb
         | 
| 276 276 | 
             
            - lib/project_types/script/config/extension_points.yml
         | 
| 277 277 | 
             
            - lib/project_types/script/errors.rb
         | 
| 278 | 
            +
            - lib/project_types/script/forms/ask_app.rb
         | 
| 279 | 
            +
            - lib/project_types/script/forms/ask_org.rb
         | 
| 280 | 
            +
            - lib/project_types/script/forms/ask_script_uuid.rb
         | 
| 278 281 | 
             
            - lib/project_types/script/forms/create.rb
         | 
| 282 | 
            +
            - lib/project_types/script/forms/run_against_shopify_org.rb
         | 
| 279 283 | 
             
            - lib/project_types/script/graphql/app_script_set.graphql
         | 
| 280 284 | 
             
            - lib/project_types/script/graphql/get_app_scripts.graphql
         | 
| 281 285 | 
             
            - lib/project_types/script/graphql/module_upload_url_generate.graphql
         | 
| 282 286 | 
             
            - lib/project_types/script/graphql/script_service_proxy.graphql
         | 
| 283 287 | 
             
            - lib/project_types/script/layers/application/build_script.rb
         | 
| 288 | 
            +
            - lib/project_types/script/layers/application/connect_app.rb
         | 
| 284 289 | 
             
            - lib/project_types/script/layers/application/create_script.rb
         | 
| 285 290 | 
             
            - lib/project_types/script/layers/application/extension_points.rb
         | 
| 286 291 | 
             
            - lib/project_types/script/layers/application/project_dependencies.rb
         | 
| @@ -308,7 +313,6 @@ files: | |
| 308 313 | 
             
            - lib/project_types/script/layers/infrastructure/script_uploader.rb
         | 
| 309 314 | 
             
            - lib/project_types/script/layers/infrastructure/service_locator.rb
         | 
| 310 315 | 
             
            - lib/project_types/script/messages/messages.rb
         | 
| 311 | 
            -
            - lib/project_types/script/tasks/ensure_env.rb
         | 
| 312 316 | 
             
            - lib/project_types/script/ui/error_handler.rb
         | 
| 313 317 | 
             
            - lib/project_types/script/ui/printing_spinner.rb
         | 
| 314 318 | 
             
            - lib/project_types/script/ui/strict_spinner.rb
         | 
| @@ -454,6 +458,9 @@ files: | |
| 454 458 | 
             
            - lib/shopify_cli/theme/ignore_filter.rb
         | 
| 455 459 | 
             
            - lib/shopify_cli/theme/mime_type.rb
         | 
| 456 460 | 
             
            - lib/shopify_cli/theme/syncer.rb
         | 
| 461 | 
            +
            - lib/shopify_cli/theme/syncer/error_reporter.rb
         | 
| 462 | 
            +
            - lib/shopify_cli/theme/syncer/operation.rb
         | 
| 463 | 
            +
            - lib/shopify_cli/theme/syncer/standard_reporter.rb
         | 
| 457 464 | 
             
            - lib/shopify_cli/theme/theme.rb
         | 
| 458 465 | 
             
            - lib/shopify_cli/transform_data_structure.rb
         | 
| 459 466 | 
             
            - lib/shopify_cli/tunnel.rb
         |