Commit 5c99afcf authored by Z.J. van de Weg's avatar Z.J. van de Weg

Merge branch 'master' into zj-mattermost-slash-config

parents 5d197230 022242c3
......@@ -15,6 +15,7 @@ variables:
USE_BUNDLE_INSTALL: "true"
GIT_DEPTH: "20"
PHANTOMJS_VERSION: "2.1.1"
GET_SOURCES_ATTEMPTS: "3"
before_script:
- source ./scripts/prepare_build.sh
......
......@@ -11,6 +11,7 @@
licensePath: "/api/:version/templates/licenses/:key",
gitignorePath: "/api/:version/templates/gitignores/:key",
gitlabCiYmlPath: "/api/:version/templates/gitlab_ci_ymls/:key",
dockerfilePath: "/api/:version/dockerfiles/:key",
issuableTemplatePath: "/:namespace_path/:project_path/templates/:type/:key",
group: function(group_id, callback) {
var url = Api.buildUrl(Api.groupPath)
......@@ -120,6 +121,10 @@
return callback(file);
});
},
dockerfileYml: function(key, callback) {
var url = Api.buildUrl(Api.dockerfilePath).replace(':key', key);
$.get(url, callback);
},
issueTemplate: function(namespacePath, projectPath, key, type, callback) {
var url = Api.buildUrl(Api.issuableTemplatePath)
.replace(':key', key)
......
/* global Api */
/*= require blob/template_selector */
(() => {
const global = window.gl || (window.gl = {});
class BlobDockerfileSelector extends gl.TemplateSelector {
requestFile(query) {
return Api.dockerfileYml(query.name, this.requestFileSuccess.bind(this));
}
requestFileSuccess(file) {
return super.requestFileSuccess(file);
}
}
global.BlobDockerfileSelector = BlobDockerfileSelector;
})();
(() => {
const global = window.gl || (window.gl = {});
class BlobDockerfileSelectors {
constructor({ editor, $dropdowns } = {}) {
this.editor = editor;
this.$dropdowns = $dropdowns || $('.js-dockerfile-selector');
this.initSelectors();
}
initSelectors() {
const editor = this.editor;
this.$dropdowns.each((i, dropdown) => {
const $dropdown = $(dropdown);
return new gl.BlobDockerfileSelector({
editor,
pattern: /(Dockerfile)/,
data: $dropdown.data('data'),
wrapper: $dropdown.closest('.js-dockerfile-selector-wrap'),
dropdown: $dropdown,
});
});
}
}
global.BlobDockerfileSelectors = BlobDockerfileSelectors;
})();
......@@ -36,6 +36,9 @@
new gl.BlobCiYamlSelectors({
editor: this.editor
});
new gl.BlobDockerfileSelectors({
editor: this.editor
});
}
EditBlob.prototype.initModePanesAndLinks = function() {
......
......@@ -75,7 +75,8 @@
.soft-wrap-toggle,
.license-selector,
.gitignore-selector,
.gitlab-ci-yml-selector {
.gitlab-ci-yml-selector,
.dockerfile-selector {
display: inline-block;
vertical-align: top;
font-family: $regular_font;
......@@ -105,7 +106,8 @@
.gitignore-selector,
.license-selector,
.gitlab-ci-yml-selector {
.gitlab-ci-yml-selector,
.dockerfile-selector {
.dropdown {
line-height: 21px;
}
......
......@@ -191,6 +191,10 @@ module BlobHelper
@gitlab_ci_ymls ||= Gitlab::Template::GitlabCiYmlTemplate.dropdown_names
end
def dockerfile_names
@dockerfile_names ||= Gitlab::Template::DockerfileTemplate.dropdown_names
end
def blob_editor_paths
{
'relative-url-root' => Rails.application.config.relative_url_root,
......
......@@ -21,6 +21,8 @@
= dropdown_tag("Choose a .gitignore template", options: { toggle_class: 'btn js-gitignore-selector', title: "Choose a template", filter: true, placeholder: "Filter", data: { data: gitignore_names } } )
.gitlab-ci-yml-selector.js-gitlab-ci-yml-selector-wrap.hidden
= dropdown_tag("Choose a GitLab CI Yaml template", options: { toggle_class: 'btn js-gitlab-ci-yml-selector', title: "Choose a template", filter: true, placeholder: "Filter", data: { data: gitlab_ci_ymls } } )
.dockerfile-selector.js-dockerfile-selector-wrap.hidden
= dropdown_tag("Choose a Dockerfile template", options: { toggle_class: 'btn js-dockerfile-selector', title: "Choose a template", filter: true, placeholder: "Filter", data: { data: dockerfile_names } } )
= button_tag class: 'soft-wrap-toggle btn', type: 'button' do
%span.no-wrap
= custom_icon('icon_no_wrap')
......
---
title: Accept environment variables from the `pre-receive` script
merge_request: 7967
author:
---
title: Add support for Dockerfile templates
merge_request: 7247
author:
#!/bin/bash
set -xe
# rsync --delete -av config/{routes.rb,routes,initializers,application.rb} zj-gitlab:/opt/gitlab/embedded/service/gitlab-rails/config/
rsync --delete -av lib/mattermost zj-gitlab:/opt/gitlab/embedded/service/gitlab-rails/lib
# rsync --delete -av vendor/{assets,gitignore,gitlab-ci-yml} zj-gitlab:/opt/gitlab/embedded/service/gitlab-rails/vendor/
# rsync --delete -av ../gitlab-shell/{bin,lib,spec,hooks} zj-gitlab:/opt/gitlab/embedded/service/gitlab-shell
#ssh gitlab-test 'cd /opt/gitlab/embedded/service/gitlab-rails && /opt/gitlab/embedded/bin/bundle install --deployment'
#ssh gitlab-test 'export NO_PRIVILEGE_DROP=true; export USE_DB=false; gitlab-rake assets:precompile'
ssh zj-gitlab gitlab-ctl restart
......@@ -61,6 +61,9 @@ version of Runner required.
| **CI_RUNNER_DESCRIPTION** | 8.10 | 0.5 | The description of the runner as saved in GitLab |
| **CI_RUNNER_TAGS** | 8.10 | 0.5 | The defined runner tags |
| **CI_DEBUG_TRACE** | all | 1.7 | Whether [debug tracing](#debug-tracing) is enabled |
| **GET_SOURCES_ATTEMPTS** | 8.15 | 1.9 | Number of attempts to fetch sources running a build |
| **ARTIFACT_DOWNLOAD_ATTEMPTS** | 8.15 | 1.9 | Number of attempts to download artifacts running a build |
| **RESTORE_CACHE_ATTEMPTS** | 8.15 | 1.9 | Number of attempts to restore the cache running a build |
| **GITLAB_USER_ID** | 8.12 | all | The id of the user who started the build |
| **GITLAB_USER_EMAIL** | 8.12 | all | The email of the user who started the build |
......
......@@ -1034,6 +1034,31 @@ variables:
GIT_STRATEGY: none
```
## Build stages attempts
> Introduced in GitLab, it requires GitLab Runner v1.9+.
You can set the number for attempts the running build will try to execute each
of the following stages:
| Variable | Description |
|-------------------------|-------------|
| **GET_SOURCES_ATTEMPTS** | Number of attempts to fetch sources running a build |
| **ARTIFACT_DOWNLOAD_ATTEMPTS** | Number of attempts to download artifacts running a build |
| **RESTORE_CACHE_ATTEMPTS** | Number of attempts to restore the cache running a build |
The default is one single attempt.
Example:
```
variables:
GET_SOURCES_ATTEMPTS: "3"
```
You can set the them in the global [`variables`](#variables) section or the [`variables`](#job-variables)
section for individual jobs.
## Shallow cloning
> Introduced in GitLab 8.9 as an experimental feature. May change in future
......
@admin
Feature: Admin Applications
Background:
Given I sign in as an admin
And I visit applications page
Scenario: I can manage application
Then I click on new application button
And I should see application form
Then I fill application form out and submit
And I see application
Then I click edit
And I see edit application form
Then I change name of application and submit
And I see that application was changed
Then I visit applications page
And I click to remove application
Then I see that application is removed
\ No newline at end of file
@admin
Feature: Admin Deploy Keys
Background:
Given I sign in as an admin
And there are public deploy keys in system
Scenario: Deploy Keys list
When I visit admin deploy keys page
Then I should see all public deploy keys
Scenario: Deploy Keys new
When I visit admin deploy keys page
And I click 'New Deploy Key'
And I submit new deploy key
Then I should be on admin deploy keys page
And I should see newly created deploy key
class Spinach::Features::AdminApplications < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedAdmin
step 'I click on new application button' do
click_on 'New Application'
end
step 'I should see application form' do
expect(page).to have_content "New application"
end
step 'I fill application form out and submit' do
fill_in :doorkeeper_application_name, with: 'test'
fill_in :doorkeeper_application_redirect_uri, with: 'https://test.com'
click_on "Submit"
end
step 'I see application' do
expect(page).to have_content "Application: test"
expect(page).to have_content "Application Id"
expect(page).to have_content "Secret"
end
step 'I click edit' do
click_on "Edit"
end
step 'I see edit application form' do
expect(page).to have_content "Edit application"
end
step 'I change name of application and submit' do
expect(page).to have_content "Edit application"
fill_in :doorkeeper_application_name, with: 'test_changed'
click_on "Submit"
end
step 'I see that application was changed' do
expect(page).to have_content "test_changed"
expect(page).to have_content "Application Id"
expect(page).to have_content "Secret"
end
step 'I click to remove application' do
page.within '.oauth-applications' do
click_on "Destroy"
end
end
step "I see that application is removed" do
expect(page.find(".oauth-applications")).not_to have_content "test_changed"
end
end
......@@ -207,10 +207,6 @@ module SharedPaths
visit admin_spam_logs_path
end
step 'I visit applications page' do
visit admin_applications_path
end
# ----------------------------------------
# Generic Project
# ----------------------------------------
......
......@@ -52,6 +52,14 @@ module API
:push_code
]
end
def parse_allowed_environment_variables
return if params[:env].blank?
JSON.parse(params[:env])
rescue JSON::ParserError
end
end
end
end
......@@ -32,7 +32,11 @@ module API
if wiki?
Gitlab::GitAccessWiki.new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities)
else
Gitlab::GitAccess.new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities)
Gitlab::GitAccess.new(actor,
project,
protocol,
authentication_abilities: ssh_authentication_abilities,
env: parse_allowed_environment_variables)
end
access_status = access.check(params[:action], params[:changes])
......
......@@ -8,6 +8,10 @@ module API
gitlab_ci_ymls: {
klass: Gitlab::Template::GitlabCiYmlTemplate,
gitlab_version: 8.9
},
dockerfiles: {
klass: Gitlab::Template::DockerfileTemplate,
gitlab_version: 8.15
}
}.freeze
PROJECT_TEMPLATE_REGEX =
......@@ -51,7 +55,7 @@ module API
end
params do
optional :popular, type: Boolean, desc: 'If passed, returns only popular licenses'
end
end
get route do
options = {
featured: declared(params).popular.present? ? true : nil
......@@ -69,7 +73,7 @@ module API
end
params do
requires :name, type: String, desc: 'The name of the template'
end
end
get route, requirements: { name: /[\w\.-]+/ } do
not_found!('License') unless Licensee::License.find(declared(params).name)
......@@ -78,7 +82,7 @@ module API
present template, with: Entities::RepoLicense
end
end
GLOBAL_TEMPLATE_TYPES.each do |template_type, properties|
klass = properties[:klass]
gitlab_version = properties[:gitlab_version]
......@@ -104,7 +108,7 @@ module API
end
params do
requires :name, type: String, desc: 'The name of the template'
end
end
get route do
new_template = klass.find(declared(params).name)
......
......@@ -3,11 +3,12 @@ module Gitlab
class ChangeAccess
attr_reader :user_access, :project
def initialize(change, user_access:, project:)
def initialize(change, user_access:, project:, env: {})
@oldrev, @newrev, @ref = change.values_at(:oldrev, :newrev, :ref)
@branch_name = Gitlab::Git.branch_name(@ref)
@user_access = user_access
@project = project
@env = env
end
def exec
......@@ -68,7 +69,7 @@ module Gitlab
end
def forced_push?
Gitlab::Checks::ForcePush.force_push?(@project, @oldrev, @newrev)
Gitlab::Checks::ForcePush.force_push?(@project, @oldrev, @newrev, env: @env)
end
def matching_merge_request?
......
module Gitlab
module Checks
class ForcePush
def self.force_push?(project, oldrev, newrev)
def self.force_push?(project, oldrev, newrev, env: {})
return false if project.empty_repo?
# Created or deleted branch
if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev)
false
else
missed_ref, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --git-dir=#{project.repository.path_to_repo} rev-list --max-count=1 #{oldrev} ^#{newrev}))
missed_ref.present?
missed_ref, exit_status = Gitlab::Git::RevList.new(oldrev, newrev, project: project, env: env).execute
if exit_status == 0
missed_ref.present?
else
raise "Got a non-zero exit code while calling out to `git rev-list` in the force-push check."
end
end
end
end
......
module Gitlab
module Git
class RevList
attr_reader :project, :env
ALLOWED_VARIABLES = %w[GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES].freeze
def initialize(oldrev, newrev, project:, env: nil)
@project = project
@env = env.presence || {}
@args = [Gitlab.config.git.bin_path,
"--git-dir=#{project.repository.path_to_repo}",
"rev-list",
"--max-count=1",
oldrev,
"^#{newrev}"]
end
def execute
Gitlab::Popen.popen(@args, nil, parse_environment_variables)
end
def valid?
environment_variables.all? do |(name, value)|
value.start_with?(project.repository.path_to_repo)
end
end
private
def parse_environment_variables
return {} unless valid?
environment_variables
end
def environment_variables
@environment_variables ||= env.slice(*ALLOWED_VARIABLES)
end
end
end
end
......@@ -17,12 +17,13 @@ module Gitlab
attr_reader :actor, :project, :protocol, :user_access, :authentication_abilities
def initialize(actor, project, protocol, authentication_abilities:)
def initialize(actor, project, protocol, authentication_abilities:, env: {})
@actor = actor
@project = project
@protocol = protocol
@authentication_abilities = authentication_abilities
@user_access = UserAccess.new(user, project: project)
@env = env
end
def check(cmd, changes)
......@@ -103,7 +104,7 @@ module Gitlab
end
def change_access_check(change)
Checks::ChangeAccess.new(change, user_access: user_access, project: project).exec
Checks::ChangeAccess.new(change, user_access: user_access, project: project, env: @env).exec
end
def protocol_allowed?
......
......@@ -5,13 +5,13 @@ module Gitlab
module Popen
extend self
def popen(cmd, path = nil)
def popen(cmd, path = nil, vars = {})
unless cmd.is_a?(Array)
raise "System commands must be given as an array of strings"
end
path ||= Dir.pwd
vars = { "PWD" => path }
vars['PWD'] = path
options = { chdir: path }
unless File.directory?(path)
......
module Gitlab
module Template
class DockerfileTemplate < BaseTemplate
def content
explanation = "# This file is a template, and might need editing before it works on your project."
[explanation, super].join("\n")
end
class << self
def extension
'Dockerfile'
end
def categories
{
"General" => ''
}
end
def base_dir
Rails.root.join('vendor/dockerfile')
end
def finder(project = nil)
Gitlab::Template::Finders::GlobalTemplateFinder.new(self.base_dir, self.extension, self.categories)
end
end
end
end
end
......@@ -20,6 +20,11 @@ upstream gitlab-workhorse {
server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
}
map $http_upgrade $connection_upgrade_gitlab {
default upgrade;
'' close;
}
## Normal HTTP host
server {
## Either remove "default_server" from the listen line below,
......@@ -53,6 +58,8 @@ server {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade_gitlab;
proxy_pass http://gitlab-workhorse;
}
......
......@@ -24,6 +24,11 @@ upstream gitlab-workhorse {
server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
}
map $http_upgrade $connection_upgrade_gitlab_ssl {
default upgrade;
'' close;
}
## Redirects all HTTP traffic to the HTTPS host
server {
## Either remove "default_server" from the listen line below,
......@@ -98,6 +103,9 @@ server {
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade_gitlab_ssl;
proxy_pass http://gitlab-workhorse;
}
......
class Spinach::Features::AdminDeployKeys < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedAdmin
require 'spec_helper'
step 'there are public deploy keys in system' do
create(:deploy_key, public: true)
create(:another_deploy_key, public: true)
end
RSpec.describe 'admin deploy keys', type: :feature do
let!(:deploy_key) { create(:deploy_key, public: true) }
let!(:another_deploy_key) { create(:another_deploy_key, public: true) }
step 'I should see all public deploy keys' do
DeployKey.are_public.each do |p|
expect(page).to have_content p.title
end
before do
login_as(:admin)
end
step 'I visit admin deploy key page' do
visit admin_deploy_key_path(deploy_key)
it 'show all public deploy keys' do
visit admin_deploy_keys_path
expect(page).to have_content(deploy_key.title)
expect(page).to have_content(another_deploy_key.title)
end
step 'I visit admin deploy keys page' do
it 'creates new deploy key' do
visit admin_deploy_keys_path
end
step 'I click \'New Deploy Key\'' do
click_link 'New Deploy Key'
end
fill_in 'deploy_key_title', with: 'laptop'
fill_in 'deploy_key_key', with: 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAzrEJUIR6Y03TCE9rIJ+GqTBvgb8t1jI9h5UBzCLuK4VawOmkLornPqLDrGbm6tcwM/wBrrLvVOqi2HwmkKEIecVO0a64A4rIYScVsXIniHRS6w5twyn1MD3sIbN+socBDcaldECQa2u1dI3tnNVcs8wi77fiRe7RSxePsJceGoheRQgC8AZ510UdIlO+9rjIHUdVN7LLyz512auAfYsgx1OfablkQ/XJcdEwDNgi9imI6nAXhmoKUm1IPLT2yKajTIC64AjLOnE0YyCh6+7RFMpiMyu1qiOCpdjYwTgBRiciNRZCH8xIedyCoAmiUgkUT40XYHwLuwiPJICpkAzp7Q== user@laptop'
click_button 'Create'
step 'I submit new deploy key' do
fill_in "deploy_key_title", with: "laptop"
fill_in "deploy_key_key", with: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAzrEJUIR6Y03TCE9rIJ+GqTBvgb8t1jI9h5UBzCLuK4VawOmkLornPqLDrGbm6tcwM/wBrrLvVOqi2HwmkKEIecVO0a64A4rIYScVsXIniHRS6w5twyn1MD3sIbN+socBDcaldECQa2u1dI3tnNVcs8wi77fiRe7RSxePsJceGoheRQgC8AZ510UdIlO+9rjIHUdVN7LLyz512auAfYsgx1OfablkQ/XJcdEwDNgi9imI6nAXhmoKUm1IPLT2yKajTIC64AjLOnE0YyCh6+7RFMpiMyu1qiOCpdjYwTgBRiciNRZCH8xIedyCoAmiUgkUT40XYHwLuwiPJICpkAzp7Q== user@laptop"
click_button "Create"
end
step 'I should be on admin deploy keys page' do
expect(current_path).to eq admin_deploy_keys_path
end
step 'I should see newly created deploy key' do
expect(page).to have_content(deploy_key.title)
end
def deploy_key
@deploy_key ||= DeployKey.are_public.first
expect(page).to have_content('laptop')
end
end
require 'spec_helper'
RSpec.describe 'admin manage applications', feature: true do
before do
login_as :admin
end
it do
visit admin_applications_path
click_on 'New Application'
expect(page).to have_content('New application')
fill_in :doorkeeper_application_name, with: 'test'
fill_in :doorkeeper_application_redirect_uri, with: 'https://test.com'
click_on 'Submit'
expect(page).to have_content('Application: test')
expect(page).to have_content('Application Id')
expect(page).to have_content('Secret')
click_on 'Edit'
expect(page).to have_content('Edit application')
fill_in :doorkeeper_application_name, with: 'test_changed'
click_on 'Submit'
expect(page).to have_content('test_changed')
expect(page).to have_content('Application Id')
expect(page).to have_content('Secret')
visit admin_applications_path
page.within '.oauth-applications' do
click_on 'Destroy'
end
expect(page.find('.oauth-applications')).not_to have_content('test_changed')
end
end
require 'spec_helper'
feature 'User wants to add a Dockerfile file', feature: true do
include WaitForAjax
before do
user = create(:user)
project = create(:project)
project.team << [user, :master]
login_as user
visit namespace_project_new_blob_path(project.namespace, project, 'master', file_name: 'Dockerfile')
end
scenario 'user can see Dockerfile dropdown' do
expect(page).to have_css('.dockerfile-selector')
end
scenario 'user can pick a Dockerfile file from the dropdown', js: true do
find('.js-dockerfile-selector').click
wait_for_ajax
within '.dockerfile-selector' do
find('.dropdown-input-field').set('HTTPd')
find('.dropdown-content li', text: 'HTTPd').click
end
wait_for_ajax
expect(page).to have_css('.dockerfile-selector .dropdown-toggle-text', text: 'HTTPd')
expect(page).to have_content('COPY ./ /usr/local/apache2/htdocs/')
end
end
......@@ -6,7 +6,7 @@ describe GroupsHelper do
it 'returns an url for the avatar' do
group = create(:group)
group.avatar = File.open(avatar_file_path)
group.avatar = fixture_file_upload(avatar_file_path)
group.save!
expect(group_icon(group.path).to_s).
to match("/uploads/group/avatar/#{group.id}/banana_sample.gif")
......
require 'spec_helper'
describe Gitlab::Checks::ChangeAccess, lib: true do
let(:project) { create(:project) }
context "exit code checking" do
it "does not raise a runtime error if the `popen` call to git returns a zero exit code" do
allow(Gitlab::Popen).to receive(:popen).and_return(['normal output', 0])
expect { Gitlab::Checks::ForcePush.force_push?(project, 'oldrev', 'newrev') }.not_to raise_error
end
it "raises a runtime error if the `popen` call to git returns a non-zero exit code" do
allow(Gitlab::Popen).to receive(:popen).and_return(['error', 1])
expect { Gitlab::Checks::ForcePush.force_push?(project, 'oldrev', 'newrev') }.to raise_error(RuntimeError)
end
end
end
require 'spec_helper'
describe Gitlab::Git::RevList, lib: true do
let(:project) { create(:project) }
context "validations" do
described_class::ALLOWED_VARIABLES.each do |var|
context var do
it "accepts values starting with the project repo path" do
env = { var => "#{project.repository.path_to_repo}/objects" }
rev_list = described_class.new('oldrev', 'newrev', project: project, env: env)
expect(rev_list).to be_valid
end
it "rejects values starting not with the project repo path" do
env = { var => "/some/other/path" }
rev_list = described_class.new('oldrev', 'newrev', project: project, env: env)
expect(rev_list).not_to be_valid
end
it "rejects values containing the project repo path but not starting with it" do
env = { var => "/some/other/path/#{project.repository.path_to_repo}" }
rev_list = described_class.new('oldrev', 'newrev', project: project, env: env)
expect(rev_list).not_to be_valid
end
end
end
end
context "#execute" do
let(:env) { { "GIT_OBJECT_DIRECTORY" => project.repository.path_to_repo } }
let(:rev_list) { Gitlab::Git::RevList.new('oldrev', 'newrev', project: project, env: env) }
it "calls out to `popen` without environment variables if the record is invalid" do
allow(rev_list).to receive(:valid?).and_return(false)
expect(Open3).to receive(:popen3).with(hash_excluding(env), any_args)
rev_list.execute
end
it "calls out to `popen` with environment variables if the record is valid" do
allow(rev_list).to receive(:valid?).and_return(true)
expect(Open3).to receive(:popen3).with(hash_including(env), any_args)
rev_list.execute
end
end
end
FROM httpd:alpine
COPY ./ /usr/local/apache2/htdocs/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment