5416: Add read-only clone_urls attribute to Repository resources, deprecate push_url...
authorTom Clegg <tom@curoverse.com>
Tue, 14 Apr 2015 20:56:04 +0000 (16:56 -0400)
committerTom Clegg <tom@curoverse.com>
Mon, 20 Apr 2015 20:58:51 +0000 (16:58 -0400)
apps/workbench/app/models/repository.rb
apps/workbench/app/views/pipeline_instances/_running_component.html.erb
doc/api/schema/Repository.html.textile.liquid
docker/api/application.yml.in
services/api/app/controllers/arvados/v1/schema_controller.rb
services/api/app/models/repository.rb
services/api/config/application.default.yml
services/api/test/functional/arvados/v1/repositories_controller_test.rb

index 48c7f9efcbc34a3402d0f57ea1ab2ecebf7691e1..aa7791388f72f4c50f8ccbc8a9392e698fa792d3 100644 (file)
@@ -59,12 +59,10 @@ class Repository < ArvadosBase
     @fresh = true
   end
 
-  # http_fetch_url returns an http:// or https:// fetch-url which can
-  # accept arvados API token authentication. The API server currently
-  # advertises SSH fetch-urls, which work for users with SSH keys but
-  # are useless for fetching repository content into workbench itself.
+  # http_fetch_url returns the first http:// or https:// url (if any)
+  # in the api response's clone_urls attribute.
   def http_fetch_url
-    "https://git.#{uuid[0,5]}.arvadosapi.com/#{name}.git"
+    clone_urls.andand.select { |u| /^http/ =~ u }.first
   end
 
   # run_git sets up the ARVADOS_API_TOKEN environment variable,
index cc3b4c83d5e3f741c5e806a72bc459b0623d55d2..2ab8da1f4ce2d258d8f098c5c78175d6fbcdf713 100644 (file)
           <div class="col-md-6">
             <table>
               <% # link to repo tree/file only if the repo is readable
-                 # and the commit is a sha1
+                 # and the commit is a sha1...
                  repo =
                  (/^[0-9a-f]{40}$/ =~ current_component[:script_version] and
                  Repository.where(name: current_component[:repository]).first)
+
+                 # ...and the api server provides an http:// or https:// url
+                 repo = nil unless repo.andand.http_fetch_url
                  %>
               <% [:script, :repository, :script_version, :supplied_script_version, :nondeterministic].each do |k| %>
                 <tr>
index 27cc711985f0a21f59b912bb9aa1cade80307b4b..0f9b25ec2ce911be6a0f5a822c82ec5e8bc1e5a8 100644 (file)
@@ -19,5 +19,7 @@ Each Repository has, in addition to the usual "attributes of Arvados resources":
 table(table table-bordered table-condensed).
 |_. Attribute|_. Type|_. Description|_. Example|
 |name|string|The name of the repository on disk.  Repository names must begin with a letter and contain only alphanumerics.  Unless the repository is owned by the system user, the name must begin with the owner's username, then be separated from the base repository name with @/@.  You may not create a repository that is owned by a user without a username.|@username/project1@|
-|fetch_url|string|The git remote's fetch URL for the repository.  Read-only.||
-|push_url|string|The git remote's push URL for the repository.  Read-only.||
+|clone_urls|array|URLs from which the repository can be cloned. Read-only.|@["git@git.zzzzz.arvadosapi.com:foo/bar.git",
+ "https://git.zzzzz.arvadosapi.com/foo/bar.git"]@|
+|fetch_url|string|URL suggested as a fetch-url in git config. Deprecated. Read-only.||
+|push_url|string|URL suggested as a push-url in git config. Deprecated. Read-only.||
index 3cfb5a99434aae37c2d84960490c08cc1f137eb3..627e775ed077f4ae5262ffb77cb4d58113870923 100644 (file)
@@ -20,7 +20,11 @@ development:
 
 production:
   host: api.dev.arvados
-  git_host: api.dev.arvados
+
+  git_repo_ssh_base: "git@api.dev.arvados:"
+
+  # Docker setup doesn't include arv-git-httpd yet.
+  git_repo_https_base: false
 
   # At minimum, you need a nice long randomly generated secret_token here.
   # Use a long string of alphanumeric characters (at least 36).
index 20e9690bb10608443bc4827251c00693c598b21d..dcc9c639793eebe17f39a21f05990c81512431ce 100644 (file)
@@ -28,7 +28,6 @@ class Arvados::V1::SchemaController < ApplicationController
         description: "The API to interact with Arvados.",
         documentationLink: "http://doc.arvados.org/api/index.html",
         defaultCollectionReplication: Rails.configuration.default_collection_replication,
-        gitHttpBase: Rails.configuration.git_http_base,
         protocol: "rest",
         baseUrl: root_url + "arvados/v1/",
         basePath: "/arvados/v1/",
index e83ac41fad7b4bcb55eab7aec5f5bbdc8d47ae73..f361a49db5dcd49b649d7e7f79c255e214eae97a 100644 (file)
@@ -13,23 +13,27 @@ class Repository < ArvadosModel
     t.add :name
     t.add :fetch_url
     t.add :push_url
+    t.add :clone_urls
   end
 
   def self.attributes_required_columns
-    super.merge({"push_url" => ["name"], "fetch_url" => ["name"]})
+    super.merge("clone_urls" => ["name"],
+                "fetch_url" => ["name"],
+                "push_url" => ["name"])
   end
 
+  # Deprecated. Use clone_urls instead.
   def push_url
-    prefix = new_record? ? Rails.configuration.uuid_prefix : uuid[0,5]
-    if prefix == Rails.configuration.uuid_prefix
-      host = Rails.configuration.git_host
-    end
-    host ||= "git.%s.arvadosapi.com" % prefix
-    "git@%s:%s.git" % [host, name]
+    ssh_clone_url
   end
 
+  # Deprecated. Use clone_urls instead.
   def fetch_url
-    push_url
+    ssh_clone_url
+  end
+
+  def clone_urls
+    [ssh_clone_url, https_clone_url].compact
   end
 
   def server_path
@@ -88,4 +92,24 @@ class Repository < ArvadosModel
       false
     end
   end
+
+  def ssh_clone_url
+    _clone_url :git_repo_ssh_base, 'git@git.%s.arvadosapi.com:'
+  end
+
+  def https_clone_url
+    _clone_url :git_repo_https_base, 'https://git.%s.arvadosapi.com/'
+  end
+
+  def _clone_url config_var, default_base_fmt
+    configured_base = Rails.configuration.send config_var
+    return nil if configured_base == false
+    prefix = new_record? ? Rails.configuration.uuid_prefix : uuid[0,5]
+    if prefix == Rails.configuration.uuid_prefix and configured_base != true
+      base = configured_base
+    else
+      base = default_base_fmt % prefix
+    end
+    '%s%s.git' % [base, name]
+  end
 end
index b45ed651f8a5e5f01129b948a050a509e41e4c12..0ea685a121534d78a51cde3ab65bc2198a375332 100644 (file)
@@ -59,10 +59,19 @@ common:
   # logic for deciding on a hostname.
   host: false
 
-  # If not false, this is the hostname that will be used to generate
-  # fetch_url and push_url for locally hosted git repositories.  By
-  # default, this is git.(uuid_prefix).arvadosapi.com
-  git_host: false
+  # Base part of SSH git clone url given with repository resources. If
+  # true, the default "git@git.(uuid_prefix).arvadosapi.com:" is
+  # used. If false, SSH clone URLs are not advertised. Include a
+  # trailing ":" or "/" if needed: it will not be added automatically.
+  git_repo_ssh_base: true
+
+  # Base part of HTTPS git clone urls given with repository
+  # resources. This is expected to be an arv-git-httpd service which
+  # accepts API tokens as HTTP-auth passwords. If true, the default
+  # "https://git.(uuid_prefix).arvadosapi.com/" is used. If false,
+  # HTTPS clone URLs are not advertised. Include a trailing ":" or "/"
+  # if needed: it will not be added automatically.
+  git_repo_https_base: true
 
   # If this is not false, HTML requests at the API server's root URL
   # are redirected to this location, and it is provided in the text of
@@ -76,11 +85,6 @@ common:
   # {git_repositories_dir}/arvados/.git
   git_repositories_dir: /var/lib/arvados/git
 
-  # If an arv-git-httpd service is running, advertise it in the
-  # discovery document by adding its public URI base here. Example:
-  # https://git.xxxxx.arvadosapi.com
-  git_http_base: false
-
   # This is a (bare) repository that stores commits used in jobs.  When a job
   # runs, the source commits are first fetched into this repository, then this
   # repository is used to deploy to compute nodes.  This should NOT be a
@@ -236,7 +240,8 @@ common:
   # should be at least 50 characters.
   secret_token: ~
 
-  # email address to which mail should be sent when the user creates profile for the first time
+  # Email address to notify whenever a user creates a profile for the
+  # first time
   user_profile_notification_address: false
 
   default_openid_prefix: https://www.google.com/accounts/o8/id
index fe5bb1cd09f92fdb390ce215c338f6ada750d534..7f4ed8e4f16745a4146fe563b0af5e9b8dd880ab 100644 (file)
@@ -97,26 +97,45 @@ class Arvados::V1::RepositoriesControllerTest < ActionController::TestCase
   end
 
   [
-    {config: "example.com", host: "example.com"},
-    {config: false, host: "git.zzzzz.arvadosapi.com"}
-  ].each do |set_git_host|
-    test "setting git_host to #{set_git_host[:host]} changes fetch/push_url to #{set_git_host[:config]}" do
-      Rails.configuration.git_host = set_git_host[:config]
+    {cfg: :git_repo_ssh_base, cfgval: "git@example.com:", match: %r"^git@example.com:/"},
+    {cfg: :git_repo_ssh_base, cfgval: true, match: %r"^git@git.zzzzz.arvadosapi.com:/"},
+    {cfg: :git_repo_ssh_base, cfgval: false, refute: /^git@/ },
+    {cfg: :git_repo_https_base, cfgval: "https://example.com/", match: %r"https://example.com/"},
+    {cfg: :git_repo_https_base, cfgval: true, match: %r"^https://git.zzzzz.arvadosapi.com/"},
+    {cfg: :git_repo_https_base, cfgval: false, refute: /^http/ },
+  ].each do |expect|
+    test "set #{expect[:cfg]} to #{expect[:cfgval]}" do
+      Rails.configuration.send expect[:cfg].to_s+"=", expect[:cfgval]
       authorize_with :active
-      get(:index)
+      get :index
       assert_response :success
-      assert_includes(json_response["items"].map { |r| r["fetch_url"] },
-                      "git@#{set_git_host[:host]}:active/foo.git")
-      assert_includes(json_response["items"].map { |r| r["push_url"] },
-                      "git@#{set_git_host[:host]}:active/foo.git")
+      json_response['items'].each do |r|
+        if expect[:refute]
+          r['clone_urls'].each do |u|
+            refute_match expect[:refute], u
+          end
+        else
+          assert r['clone_urls'].any? do |u|
+            expect[:prefix].match u
+          end
+        end
+      end
     end
   end
 
-  test "can select push_url in index" do
+  test "select push_url in index" do
     authorize_with :active
     get(:index, {select: ["uuid", "push_url"]})
     assert_response :success
     assert_includes(json_response["items"].map { |r| r["push_url"] },
                     "git@git.zzzzz.arvadosapi.com:active/foo.git")
   end
+
+  test "select clone_urls in index" do
+    authorize_with :active
+    get(:index, {select: ["uuid", "clone_urls"]})
+    assert_response :success
+    assert_includes(json_response["items"].map { |r| r["clone_urls"] }.flatten,
+                    "git@git.zzzzz.arvadosapi.com:active/foo.git")
+  end
 end