Ver código fonte

Merge pull request #550 from Shopify/add-first-release-version

Add release version and helper methods for switching versions
Alex Aitken 6 anos atrás
pai
commit
b19710463b

+ 78 - 33
lib/shopify_api/api_version.rb

@@ -2,39 +2,9 @@
 module ShopifyAPI
   class ApiVersion
     class UnknownVersion < StandardError; end
+    class InvalidVersion < StandardError; end
 
-    class NoVersion < ApiVersion
-      API_PREFIX = '/admin/'
-      GRAPHQL_PATH = '/admin/api/graphql.json'
-
-      def initialize
-        @version_name = "no_version"
-      end
-
-      def construct_api_path(path)
-        "#{API_PREFIX}#{path}"
-      end
-
-      def construct_graphql_path
-        GRAPHQL_PATH
-      end
-    end
-
-    class Unstable < ApiVersion
-      API_PREFIX = '/admin/api/unstable/'
-
-      def initialize
-        @version_name = "unstable"
-      end
-
-      def construct_api_path(path)
-        "#{API_PREFIX}#{path}"
-      end
-
-      def construct_graphql_path
-        construct_api_path('graphql.json')
-      end
-    end
+    include Comparable
 
     def self.coerce_to_version(version_or_name)
       return version_or_name if version_or_name.is_a?(ApiVersion)
@@ -60,6 +30,10 @@ module ShopifyAPI
       define_version(Unstable.new)
     end
 
+    def self.latest_stable_version
+      @versions.values.select(&:stable?).sort.last
+    end
+
     def to_s
       @version_name
     end
@@ -74,7 +48,15 @@ module ShopifyAPI
     end
 
     def hash
-      version_name.hash
+      @version_name.hash
+    end
+
+    def <=>(other)
+      numeric_version <=> other.numeric_version
+    end
+
+    def stable?
+      false
     end
 
     def construct_api_path(_path)
@@ -84,5 +66,68 @@ module ShopifyAPI
     def construct_graphql_path
       raise NotImplementedError
     end
+
+    protected
+
+    attr_reader :numeric_version
+
+    class NoVersion < ApiVersion
+      API_PREFIX = '/admin/'
+
+      def initialize
+        @version_name = "no_version"
+        @numeric_version = 0
+      end
+
+      def construct_api_path(path)
+        "#{API_PREFIX}#{path}"
+      end
+
+      def construct_graphql_path
+        '/admin/api/graphql.json'
+      end
+    end
+
+    class Unstable < ApiVersion
+      API_PREFIX = '/admin/api/unstable/'
+
+      def initialize
+        @version_name = "unstable"
+        @url = API_PREFIX
+        @numeric_version = 9_000_00
+      end
+
+      def construct_api_path(path)
+        "#{@url}#{path}"
+      end
+
+      def construct_graphql_path
+        construct_api_path("graphql.json")
+      end
+    end
+
+    class Release < ApiVersion
+      FORMAT = /^\d{4}-\d{2}$/.freeze
+      API_PREFIX = '/admin/api/'
+
+      def initialize(version_number)
+        raise InvalidVersion, version_number unless version_number.match(FORMAT)
+        @version_name = version_number
+        @url = "#{API_PREFIX}#{version_number}/"
+        @numeric_version = version_number.tr('-', '').to_i
+      end
+
+      def stable?
+        true
+      end
+
+      def construct_api_path(path)
+        "#{@url}#{path}"
+      end
+
+      def construct_graphql_path
+        construct_api_path('graphql.json')
+      end
+    end
   end
 end

+ 21 - 5
lib/shopify_api/session.rb

@@ -20,12 +20,14 @@ module ShopifyAPI
         params.each { |k,value| public_send("#{k}=", value) }
       end
 
-      def temp(domain:, token:, api_version:, &_block)
+      def temp(domain:, token:, api_version:, &block)
         session = new(domain: domain, token: token, api_version: api_version)
-        original_site = ShopifyAPI::Base.site.to_s
-        original_token = ShopifyAPI::Base.headers['X-Shopify-Access-Token']
-        original_version = ShopifyAPI::Base.api_version
-        original_session = new(domain: original_site, token: original_token, api_version: original_version)
+
+        with_session(session, &block)
+      end
+
+      def with_session(session, &_block)
+        original_session = extract_current_session
 
         begin
           ShopifyAPI::Base.activate_session(session)
@@ -35,6 +37,13 @@ module ShopifyAPI
         end
       end
 
+      def with_version(api_version, &block)
+        original_session = extract_current_session
+        session = new(domain: original_session.site, token: original_session.token, api_version: api_version)
+
+        with_session(session, &block)
+      end
+
       def prepare_domain(domain)
         return nil if domain.blank?
         # remove http:// or https://
@@ -66,6 +75,13 @@ module ShopifyAPI
         params = params.except(:signature, :hmac, :action, :controller)
         params.map{|k,v| "#{URI.escape(k.to_s, '&=%')}=#{URI.escape(v.to_s, '&%')}"}.sort.join('&')
       end
+
+      def extract_current_session
+        site = ShopifyAPI::Base.site.to_s
+        token = ShopifyAPI::Base.headers['X-Shopify-Access-Token']
+        version = ShopifyAPI::Base.api_version
+        new(domain: site, token: token, api_version: version)
+      end
     end
 
     def initialize(domain:, token:, api_version:, extra: {})

+ 80 - 0
test/api_version_test.rb

@@ -75,6 +75,86 @@ class ApiVersionTest < Test::Unit::TestCase
     ])
   end
 
+  test 'allows a release version with the correct format format to be created' do
+    assert ShopifyAPI::ApiVersion::Release.new('2019-03')
+  end
+
+  test 'release versions must follow the format' do
+    assert_raises ShopifyAPI::ApiVersion::InvalidVersion do
+      assert ShopifyAPI::ApiVersion::Release.new('crazy-name')
+    end
+  end
+
+  test 'release versions create a url that is /admin/api/<version_name>/' do
+    assert_equal(
+      '/admin/api/2022-03/shop.json',
+      ShopifyAPI::ApiVersion::Release.new('2022-03').construct_api_path('shop.json')
+    )
+  end
+
+  test 'two versions with the same version number are equal' do
+    version_1 = ShopifyAPI::ApiVersion::Release.new('2018-09')
+    version_2 = ShopifyAPI::ApiVersion::Release.new('2018-09')
+
+    assert_equal version_2, version_1
+  end
+
+  test 'two versions with the different version numbers are not equal' do
+    version_1 = ShopifyAPI::ApiVersion::Release.new('2019-07')
+    version_2 = ShopifyAPI::ApiVersion::Release.new('2019-11')
+
+    refute_equal version_2, version_1
+  end
+
+  test 'release verions are stable' do
+    assert_predicate ShopifyAPI::ApiVersion::Release.new('2019-11'), :stable?
+  end
+
+  test 'no release version are not stable' do
+    refute_predicate ShopifyAPI::ApiVersion::NoVersion.new, :stable?
+    refute_predicate ShopifyAPI::ApiVersion::Unstable.new, :stable?
+  end
+
+  test 'release versions are ordered by version number with unstable always being the newest and no version always being the oldest' do
+    version_1 = ShopifyAPI::ApiVersion::Release.new('2017-11')
+    version_2 = ShopifyAPI::ApiVersion::Release.new('2019-11')
+    version_3 = ShopifyAPI::ApiVersion::Release.new('2039-01')
+    version_4 = ShopifyAPI::ApiVersion::Release.new('2039-02')
+    unstable = ShopifyAPI::ApiVersion::Unstable.new
+    no_version = ShopifyAPI::ApiVersion::NoVersion.new
+
+    assert_equal([
+      no_version,
+      version_1,
+      version_2,
+      version_3,
+      version_4,
+      unstable,
+    ], [
+      version_3,
+      version_1,
+      no_version,
+      version_4,
+      unstable,
+      version_2,
+    ].sort)
+  end
+
+  test 'latest_stable_version will return the version that is newest and stable' do
+    ShopifyAPI::ApiVersion.clear_defined_versions
+    ShopifyAPI::ApiVersion.define_version(ShopifyAPI::ApiVersion::Release.new('2017-11'))
+    ShopifyAPI::ApiVersion.define_version(ShopifyAPI::ApiVersion::Release.new('2019-11'))
+    ShopifyAPI::ApiVersion.define_version(ShopifyAPI::ApiVersion::Release.new('2039-01'))
+    ShopifyAPI::ApiVersion.define_version(ShopifyAPI::ApiVersion::Release.new('2039-02'))
+    ShopifyAPI::ApiVersion.define_version(ShopifyAPI::ApiVersion::Unstable.new)
+    ShopifyAPI::ApiVersion.define_version(ShopifyAPI::ApiVersion::NoVersion.new)
+
+    assert_equal(
+      ShopifyAPI::ApiVersion::Release.new('2039-02'),
+      ShopifyAPI::ApiVersion.latest_stable_version
+    )
+  end
+
   class TestApiVersion < ShopifyAPI::ApiVersion
     def initialize(name)
       @version_name = name

+ 58 - 3
test/session_test.rb

@@ -76,8 +76,6 @@ class SessionTest < Test::Unit::TestCase
   end
 
   test "#temp reset ShopifyAPI::Base.site to original value" do
-
-    ShopifyAPI::Session.setup(:api_key => "key", :secret => "secret")
     session1 = ShopifyAPI::Session.new(domain: 'fakeshop.myshopify.com', token: 'token1', api_version: :no_version)
     ShopifyAPI::Base.activate_session(session1)
 
@@ -93,6 +91,62 @@ class SessionTest < Test::Unit::TestCase
     assert_equal(ShopifyAPI::ApiVersion::NoVersion.new, ShopifyAPI::Base.api_version)
   end
 
+  test "#with_session activates the session for the duration of the block" do
+    session1 = ShopifyAPI::Session.new(domain: 'fakeshop.myshopify.com', token: 'token1', api_version: :no_version)
+    ShopifyAPI::Base.activate_session(session1)
+
+    other_session = ShopifyAPI::Session.new(
+      domain: "testshop.myshopify.com",
+      token: "any-token",
+      api_version: :unstable
+    )
+
+    ShopifyAPI::Session.with_session(other_session) do
+      @assigned_site = ShopifyAPI::Base.site
+      @assigned_version = ShopifyAPI::Base.api_version
+    end
+
+    assert_equal('https://testshop.myshopify.com', @assigned_site.to_s)
+    assert_equal('https://fakeshop.myshopify.com', ShopifyAPI::Base.site.to_s)
+
+    assert_equal(ShopifyAPI::ApiVersion::Unstable.new, @assigned_version)
+    assert_equal(ShopifyAPI::ApiVersion::NoVersion.new, ShopifyAPI::Base.api_version)
+  end
+
+  test "#with_session resets the activated session even if there an exception during the block" do
+    session1 = ShopifyAPI::Session.new(domain: 'fakeshop.myshopify.com', token: 'token1', api_version: :no_version)
+    ShopifyAPI::Base.activate_session(session1)
+
+    other_session = ShopifyAPI::Session.new(
+      domain: "testshop.myshopify.com",
+      token: "any-token",
+      api_version: :unstable
+    )
+
+    assert_raises StandardError do
+      ShopifyAPI::Session.with_session(other_session) { raise StandardError, "" }
+    end
+
+    assert_equal('https://fakeshop.myshopify.com', ShopifyAPI::Base.site.to_s)
+    assert_equal(ShopifyAPI::ApiVersion::NoVersion.new, ShopifyAPI::Base.api_version)
+  end
+
+  test "#with_version will adjust the actvated api version for the duration of the block" do
+    session1 = ShopifyAPI::Session.new(domain: 'fakeshop.myshopify.com', token: 'token1', api_version: :no_version)
+    ShopifyAPI::Base.activate_session(session1)
+
+    ShopifyAPI::Session.with_version(:unstable) do
+      @assigned_site = ShopifyAPI::Base.site
+      @assigned_version = ShopifyAPI::Base.api_version
+    end
+
+    assert_equal('https://fakeshop.myshopify.com', @assigned_site.to_s)
+    assert_equal('https://fakeshop.myshopify.com', ShopifyAPI::Base.site.to_s)
+
+    assert_equal(ShopifyAPI::ApiVersion::Unstable.new, @assigned_version)
+    assert_equal(ShopifyAPI::ApiVersion::NoVersion.new, ShopifyAPI::Base.api_version)
+  end
+
   test "create_permission_url returns correct url with single scope no redirect uri" do
     ShopifyAPI::Session.setup(:api_key => "My_test_key", :secret => "My test secret")
     session = ShopifyAPI::Session.new(
@@ -290,6 +344,7 @@ class SessionTest < Test::Unit::TestCase
   end
 
   def any_api_version
-    [ShopifyAPI::ApiVersion::NoVersion.new, ShopifyAPI::ApiVersion::Unstable.new].sample(1).first
+    version_name = [:no_version, :unstable].sample(1).first
+    ShopifyAPI::ApiVersion.coerce_to_version(version_name)
   end
 end