From 533f4cdf30b38c587f7a91f0dfd898b907ecd944 Mon Sep 17 00:00:00 2001
From: Ciro Santilli <ciro.santilli@gmail.com>
Date: Wed, 22 Oct 2014 10:54:59 +0200
Subject: [PATCH] gitlab shell works if multiple rubies installed

Before this it would fail because git hooks automatically prepend
things to the path, which can lead the wrong Ruby version to be called
in which dependencies are not installed.

To make sure that this is correct, the forked_merge_requests commented
out test that depends on this change was uncommented.

For that test to pass, it is also necessary to setup the mock server
on port 3001 under test_env.rb.
---
 GITLAB_SHELL_VERSION                          |  2 +-
 config/application.rb                         |  2 +
 config/gitlab.yml.example                     |  2 +-
 .../initializers/gitlab_shell_secret_token.rb | 20 +------
 .../project/forked_merge_requests.feature     | 26 +++++----
 lib/gitlab/backend/shell.rb                   | 21 ++++++++
 lib/tasks/gitlab/shell.rake                   | 12 +++--
 spec/support/test_env.rb                      | 53 ++++++++++++++++++-
 8 files changed, 98 insertions(+), 40 deletions(-)

diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index ccbccc3dc62..276cbf9e285 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-2.2.0
+2.3.0
diff --git a/config/application.rb b/config/application.rb
index 44a5d68d126..8300cf57a61 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -92,5 +92,7 @@ module Gitlab
 
     redis_config_hash[:namespace] = 'cache:gitlab'
     config.cache_store = :redis_store, redis_config_hash
+
+    ENV['GITLAB_PATH_OUTSIDE_HOOK'] = ENV['PATH']
   end
 end
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index bb0ffae0b70..14b5e134ce2 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -307,7 +307,7 @@ test:
     enabled: true
   gitlab:
     host: localhost
-    port: 80
+    port: 3001
 
     # When you run tests we clone and setup gitlab-shell
     # In order to setup it correctly you need to specify
diff --git a/config/initializers/gitlab_shell_secret_token.rb b/config/initializers/gitlab_shell_secret_token.rb
index 8d2b771e535..250b86caaf0 100644
--- a/config/initializers/gitlab_shell_secret_token.rb
+++ b/config/initializers/gitlab_shell_secret_token.rb
@@ -1,19 +1 @@
-# Be sure to restart your server when you modify this file.
-
-require 'securerandom'
-
-# Your secret key for verifying the gitlab_shell.
-
-
-secret_file = Rails.root.join('.gitlab_shell_secret')
-gitlab_shell_symlink = File.join(Gitlab.config.gitlab_shell.path, '.gitlab_shell_secret')
-
-unless File.exist? secret_file
-  # Generate a new token of 16 random hexadecimal characters and store it in secret_file.
-  token = SecureRandom.hex(16)
-  File.write(secret_file, token)
-end
-
-if File.exist?(Gitlab.config.gitlab_shell.path) && !File.exist?(gitlab_shell_symlink)
-  FileUtils.symlink(secret_file, gitlab_shell_symlink)
-end
\ No newline at end of file
+Gitlab::Shell.setup_secret_token
diff --git a/features/project/forked_merge_requests.feature b/features/project/forked_merge_requests.feature
index d9fbb875c28..7442145d87e 100644
--- a/features/project/forked_merge_requests.feature
+++ b/features/project/forked_merge_requests.feature
@@ -11,20 +11,18 @@ Feature: Project Forked Merge Requests
     And I submit the merge request
     Then I should see merge request "Merge Request On Forked Project"
 
-  # TODO: Improve it so it does not fail randomly
-  #
-  #@javascript
-  #Scenario: I can edit a forked merge request
-    #Given I visit project "Forked Shop" merge requests page
-    #And I click link "New Merge Request"
-    #And I fill out a "Merge Request On Forked Project" merge request
-    #And I submit the merge request
-    #And I should see merge request "Merge Request On Forked Project"
-    #And I click link edit "Merge Request On Forked Project"
-    #Then I see the edit page prefilled for "Merge Request On Forked Project"
-    #And I update the merge request title
-    #And I save the merge request
-    #Then I should see the edited merge request
+  @javascript
+  Scenario: I can edit a forked merge request
+    Given I visit project "Forked Shop" merge requests page
+    And I click link "New Merge Request"
+    And I fill out a "Merge Request On Forked Project" merge request
+    And I submit the merge request
+    And I should see merge request "Merge Request On Forked Project"
+    And I click link edit "Merge Request On Forked Project"
+    Then I see the edit page prefilled for "Merge Request On Forked Project"
+    And I update the merge request title
+    And I save the merge request
+    Then I should see the edited merge request
 
   @javascript
   Scenario: I cannot submit an invalid merge request
diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb
index aabc7f1e69a..7b10ab539eb 100644
--- a/lib/gitlab/backend/shell.rb
+++ b/lib/gitlab/backend/shell.rb
@@ -1,3 +1,5 @@
+require 'securerandom'
+
 module Gitlab
   class Shell
     class AccessDenied < StandardError; end
@@ -13,6 +15,25 @@ module Gitlab
         @version_required ||= File.read(Rails.root.
                                         join('GITLAB_SHELL_VERSION')).strip
       end
+
+      # Be sure to restart your server when you modify this method.
+      def setup_secret_token
+        secret_file = Rails.root.join('.gitlab_shell_secret')
+        gitlab_shell_symlink = File.join(Gitlab.config.gitlab_shell.path,
+                                         '.gitlab_shell_secret')
+
+        unless File.exist? secret_file
+          # Generate a new token of 16 random hexadecimal characters
+          # and store it in secret_file.
+          token = SecureRandom.hex(16)
+          File.write(secret_file, token)
+        end
+
+        if File.exist?(Gitlab.config.gitlab_shell.path) &&
+          !File.exist?(gitlab_shell_symlink)
+          FileUtils.symlink(secret_file, gitlab_shell_symlink)
+        end
+      end
     end
 
     # Init new repository
diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake
index 202e55c89ad..d3cc7135c54 100644
--- a/lib/tasks/gitlab/shell.rake
+++ b/lib/tasks/gitlab/shell.rake
@@ -22,10 +22,14 @@ namespace :gitlab do
 
       # Make sure we're on the right tag
       Dir.chdir(target_dir) do
+        # Allows to change the origin URL to the fork
+        # when developing gitlab-shell.
+        sh(*%W(git remote set-url origin #{args.repo}))
+
         # First try to checkout without fetching
         # to avoid stalling tests if the Internet is down.
-        reset = "git reset --hard $(git describe #{args.tag} || git describe origin/#{args.tag})"
-        sh "#{reset} || git fetch origin && #{reset}"
+        reset = "(rev=\"$(git describe #{args.tag} || git describe \"origin/#{args.tag}\")\" && git reset --hard \"$rev\")"
+        sh "#{reset} || (git fetch --tags origin && #{reset})"
 
         config = {
           user: user,
@@ -37,7 +41,7 @@ namespace :gitlab do
             bin: %x{which redis-cli}.chomp,
             namespace: "resque:gitlab"
           }.stringify_keys,
-          log_level: "INFO",
+          log_level: Rails.env.test? ? 'DEBUG' : 'INFO',
           audit_usernames: false
         }.stringify_keys
 
@@ -66,6 +70,8 @@ namespace :gitlab do
       File.open(File.join(home_dir, ".ssh", "environment"), "w+") do |f|
         f.puts "PATH=#{ENV['PATH']}"
       end
+
+      Gitlab::Shell.setup_secret_token
     end
 
     desc "GITLAB | Setup gitlab-shell"
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index e6db410fb1c..eb665b8b618 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -1,4 +1,5 @@
 require 'rspec/mocks'
+require 'webrick'
 
 module TestEnv
   extend self
@@ -24,8 +25,6 @@ module TestEnv
     disable_mailer if opts[:mailer] == false
 
     # Clean /tmp/tests
-    tmp_test_path = Rails.root.join('tmp', 'tests')
-
     if File.directory?(tmp_test_path)
       Dir.entries(tmp_test_path).each do |entry|
         unless ['.', '..', 'gitlab-shell', factory_repo_name].include?(entry)
@@ -39,6 +38,8 @@ module TestEnv
     # Setup GitLab shell for test instance
     setup_gitlab_shell
 
+    setup_internal_api_mock
+
     # Create repository for FactoryGirl.create(:project)
     setup_factory_repo
   end
@@ -108,4 +109,52 @@ module TestEnv
   def factory_repo_name
     'gitlab-test'
   end
+
+  def tmp_test_path
+    Rails.root.join('tmp', 'tests')
+  end
+
+  def internal_api_mock_pid_path
+    File.join(tmp_test_path, 'internal_api_mock.pid')
+  end
+
+  # This mock server exists because during testing GitLab is not served
+  # on any port, but gitlab-shell needs to ask the GitLab internal API
+  # if it is OK to push to repositories. This can happen during blob web
+  # edit tests. The server always replies yes: this should not modify affect
+  # web interface tests.
+  def setup_internal_api_mock
+    begin
+      server = WEBrick::HTTPServer.new(
+        BindAddress: '0.0.0.0',
+        Port: Gitlab.config.gitlab.port,
+        AccessLog: [],
+        Logger: WEBrick::Log.new('/dev/null')
+      )
+    rescue => ex
+      ex.message.prepend('could not start mock server on configured port. ')
+      raise ex
+    end
+    fork do
+      trap(:INT) { server.shutdown }
+      server.mount_proc('/') do |_req, res|
+        res.status = 200
+        res.body = 'true'
+      end
+      WEBrick::Daemon.start do
+        File.write(internal_api_mock_pid_path, Process.pid)
+      end
+      server.start
+    end
+    # Ideally this should be called from `config.after(:suite)`,
+    # but on Spinach when user hits Ctrl+C the server does not get killed
+    # if the hook is set up with `Spinach.hooks.after_run`.
+    at_exit do
+      # The file should exist on normal operation,
+      # but certain errors can lead to it not existing.
+      if File.exists?(internal_api_mock_pid_path)
+        Process.kill(:INT, File.read(internal_api_mock_pid_path).to_i)
+      end
+    end
+  end
 end
-- 
GitLab