Commit afda4835 authored by Robert Speicher's avatar Robert Speicher

Merge branch 'master' into 8-4-stable

parents 894cb7df d04eadf8
......@@ -17,8 +17,10 @@ v 8.4.0 (unreleased)
- Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu)
- Don't notify users twice if they are both project watchers and subscribers (Stan Hu)
- Remove gray background from layout in UI
- Fix signup for OAuth providers that don't provide a name
- Implement new UI for group page
- Implement search inside emoji picker
- Let the CI runner know about builds that this build depends on
- Add API support for looking up a user by username (Stan Hu)
- Add project permissions to all project API endpoints (Stan Hu)
- Link to milestone in "Milestone changed" system note
......@@ -54,6 +56,7 @@ v 8.4.0 (unreleased)
- Allow broadcast messages to be edited
- Autosize Markdown textareas
- Import GitHub wiki into GitLab
- Add reporters ability to download and browse build artifacts (Andrew Johnson)
v 8.3.4
- Use gitlab-workhorse 0.5.4 (fixes API routing bug)
......
......@@ -2,6 +2,6 @@
# https://gitlab.com/gitlab-org/omnibus-gitlab or the init scripts in
# lib/support/init.d, which call scripts in bin/ .
#
web: bundle exec unicorn_rails -p ${PORT:="3000"} -E ${RAILS_ENV:="development"} -c ${UNICORN_CONFIG:="config/unicorn.rb"}
worker: bundle exec sidekiq -q post_receive -q mailers -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q incoming_email -q runner -q common -q default
web: RAILS_ENV=development bin/web start_foreground
worker: RAILS_ENV=development bin/background_jobs start_foreground
# mail_room: bundle exec mail_room -q -c config/mail_room.yml
......@@ -355,7 +355,7 @@ class @Notes
$('.note[id="' + note_id + '"]').each ->
note = $(this)
notes = note.closest(".notes")
count = notes.closest(".notes_holder").find(".discussion-notes-count")
count = notes.closest(".issuable-details").find(".notes-tab .badge")
# check if this is the last note for this line
if notes.find(".note").length is 1
......@@ -365,9 +365,10 @@ class @Notes
# for diff lines
notes.closest("tr").remove()
else
# update notes count
count.get(0).lastChild.nodeValue = " #{notes.children().length - 1}"
# update notes count
oldNum = parseInt(count.text())
count.text(oldNum - 1)
note.remove()
......
......@@ -75,6 +75,8 @@ hr {
@include str-truncated;
}
.item-title { font-weight: 600; }
/** FLASH message **/
.author_link {
color: $gl-link-color;
......
......@@ -2,10 +2,6 @@
display: block;
}
.commit-row-title .commit-title {
font-weight: 600;
}
.commit-author, .commit-committer{
display: block;
color: #999;
......
......@@ -11,8 +11,3 @@
height: 42px;
}
}
.content-list .group-name {
font-weight: 600;
color: #4c4e54;
}
......@@ -115,7 +115,7 @@ class ApplicationController < ActionController::Base
# localhost/group/project
#
if id =~ /\.git\Z/
redirect_to request.original_url.gsub(/\.git\Z/, '') and return
redirect_to request.original_url.gsub(/\.git\/?\Z/, '') and return
end
project_path = "#{namespace}/#{id}"
......
......@@ -8,7 +8,7 @@ class Projects::ArtifactsController < Projects::ApplicationController
end
unless artifacts_file.exists?
return not_found!
return render_404
end
send_file artifacts_file.path, disposition: 'attachment'
......
......@@ -42,7 +42,7 @@ class Projects::BuildsController < Projects::ApplicationController
def retry
unless @build.retryable?
return page_404
return render_404
end
build = Ci::Build.retry(@build)
......@@ -72,7 +72,7 @@ class Projects::BuildsController < Projects::ApplicationController
def authorize_manage_builds!
unless can?(current_user, :manage_builds, project)
return page_404
return render_404
end
end
end
......@@ -79,7 +79,7 @@ class Projects::CommitController < Projects::ApplicationController
def authorize_manage_builds!
unless can?(current_user, :manage_builds, project)
return page_404
return render_404
end
end
end
......@@ -160,6 +160,7 @@ class Ability
@project_report_rules ||= project_guest_rules + [
:create_commit_status,
:read_commit_statuses,
:read_build_artifacts,
:download_code,
:fork_project,
:create_project_snippet,
......@@ -175,7 +176,6 @@ class Ability
:create_merge_request,
:create_wiki,
:manage_builds,
:read_build_artifacts,
:push_code
]
end
......
......@@ -128,6 +128,14 @@ module Ci
!self.commit.latest_builds_for_ref(self.ref).include?(self)
end
def depends_on_builds
# Get builds of the same type
latest_builds = self.commit.builds.similar(self).latest
# Return builds from previous stages
latest_builds.where('stage_idx < ?', stage_idx)
end
def trace_html
html = Ci::Ansi2html::convert(trace) if trace.present?
html || ''
......
......@@ -32,6 +32,10 @@ class ArtifactUploader < CarrierWave::Uploader::Base
self.class.storage == CarrierWave::Storage::File
end
def filename
file.try(:filename)
end
def exists?
file.try(:exists?)
end
......
- commit = @repository.commit(branch.target)
- bar_graph_width_factor = @max_commits > 0 ? 100.0/@max_commits : 0
- diverging_commit_counts = @repository.diverging_commit_counts(branch)
- diverging_commit_counts = @repository.diverging_commit_counts(branch)
- number_commits_behind = diverging_commit_counts[:behind]
- number_commits_ahead = diverging_commit_counts[:ahead]
%li(class="js-branch-#{branch.name}")
%div
= link_to namespace_project_tree_path(@project.namespace, @project, branch.name) do
.branch-name.str-truncated= branch.name
%span.item-title.str-truncated= branch.name
&nbsp;
- if branch.name == @repository.root_ref
%span.label.label-primary default
......
......@@ -11,7 +11,7 @@
= cache(cache_key) do
%li.commit.js-toggle-container{ id: "commit-#{commit.short_id}" }
.commit-row-title
.commit-title.str-truncated
%span.item-title.str-truncated
= link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message"
- if commit.description?
%a.text-expander.js-toggle-button ...
......
......@@ -3,7 +3,7 @@
%li
%div
= link_to namespace_project_tag_path(@project.namespace, @project, tag.name) do
.tag-name
%span.item-title
= icon('tag')
= tag.name
- if tag.message.present?
......
......@@ -17,8 +17,8 @@
.pull-right
= link_to namespace_project_tag_path(@project.namespace, @project, @tag.name), class: 'btn btn-remove remove-row grouped has_tooltip', title: "Delete tag", method: :delete, data: { confirm: "Deleting the '#{@tag.name}' tag cannot be undone. Are you sure?" } do
%i.fa.fa-trash-o
.tag-name.title
= @tag.name
.title
%span.item-title= @tag.name
- if @tag.message.present?
%span.light
&nbsp;
......
......@@ -10,7 +10,8 @@
%i.fa.fa-sign-out
= image_tag group_icon(group), class: "avatar s46 hidden-xs"
= link_to group.name, group, class: 'group-name'
= link_to group, class: 'group-name' do
%span.item-title= group.name
- if group_member
as
......@@ -18,4 +19,3 @@
%div.light
#{pluralize(group.projects.count, "project")}, #{pluralize(group.users.count, "user")}
......@@ -27,17 +27,17 @@ restart()
stop
fi
killall
start_sidekiq -d -L $sidekiq_logfile
start_sidekiq -d -L $sidekiq_logfile >> $sidekiq_logfile 2>&1
}
start_no_deamonize()
{
start_sidekiq
start_sidekiq >> $sidekiq_logfile 2>&1
}
start_sidekiq()
{
bundle exec sidekiq -q post_receive -q mailers -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q incoming_email -q runner -q common -q default -e $RAILS_ENV -P $sidekiq_pidfile $@ >> $sidekiq_logfile 2>&1
bundle exec sidekiq -q post_receive -q mailers -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q incoming_email -q runner -q common -q default -e $RAILS_ENV -P $sidekiq_pidfile "$@"
}
load_ok()
......@@ -66,6 +66,9 @@ case "$1" in
start_no_deamonize)
start_no_deamonize
;;
start_foreground)
start_sidekiq
;;
restart)
restart
;;
......
......@@ -5,6 +5,7 @@ app_root=$(pwd)
unicorn_pidfile="$app_root/tmp/pids/unicorn.pid"
unicorn_config="$app_root/config/unicorn.rb"
unicorn_cmd="bundle exec unicorn_rails -c $unicorn_config -E $RAILS_ENV"
get_unicorn_pid()
{
......@@ -18,7 +19,12 @@ get_unicorn_pid()
start()
{
bundle exec unicorn_rails -D -c $unicorn_config -E $RAILS_ENV
$unicorn_cmd -D
}
start_foreground()
{
$unicorn_cmd
}
stop()
......@@ -37,6 +43,9 @@ case "$1" in
start)
start
;;
start_foreground)
start_foreground
;;
stop)
stop
;;
......
......@@ -34,6 +34,8 @@ Rails.application.configure do
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
# Open sent mails in browser
config.action_mailer.delivery_method = :letter_opener
# Don't make a mess when bootstrapping a development environment
config.action_mailer.perform_deliveries = (ENV['BOOTSTRAP'] != '1')
config.eager_load = false
end
......@@ -18,18 +18,62 @@ Returns:
```json
{
"id" : 79,
"commands" : "",
"path" : "",
"ref" : "",
"sha" : "",
"project_id" : 6,
"repo_url" : "git@demo.gitlab.com:gitlab/gitlab-shell.git",
"before_sha" : ""
"id": 48584,
"ref": "0.1.1",
"tag": true,
"sha": "d63117656af6ff57d99e50cc270f854691f335ad",
"status": "success",
"name": "pages",
"token": "9dd60b4f1a439d1765357446c1084c",
"stage": "test",
"project_id": 479,
"project_name": "test",
"commands": "echo commands",
"repo_url": "http://gitlab-ci-token:token@gitlab.example/group/test.git",
"before_sha": "0000000000000000000000000000000000000000",
"allow_git_fetch": false,
"options": {
"image": "docker:image",
"artifacts": {
"paths": [
"public"
]
},
"cache": {
"paths": [
"vendor"
]
}
},
"timeout": 3600,
"variables": [
{
"key": "CI_BUILD_TAG",
"value": "0.1.1",
"public": true
}
],
"depends_on_builds": [
{
"id": 48584,
"ref": "0.1.1",
"tag": true,
"sha": "d63117656af6ff57d99e50cc270f854691f335ad",
"status": "success",
"name": "build",
"token": "9dd60b4f1a439d1765357446c1084c",
"stage": "build",
"project_id": 479,
"project_name": "test",
"artifacts_file": {
"filename": "artifacts.zip",
"size": 0
}
}
]
}
```
### Update details of an existing build
PUT /ci/builds/:id
......
# Import your project from GitHub to GitLab
It takes just a couple of steps to import your existing GitHub projects to GitLab. Keep in mind that it is possible only if
GitHub support is enabled on your GitLab instance. You can read more about GitHub support [here](http://doc.gitlab.com/ce/integration/github.html)
_**Note:** In order to enable the GitHub import setting, you should first
enable the [GitHub integration][gh-import] in your GitLab instance._
If you want to import from a GitHub Enterprise instance, you need to use GitLab Enterprise; please see the [EE docs for the GitHub integration](http://doc.gitlab.com/ee/integration/github.html).
At its current state, GitHub importer can import:
* Sign in to GitLab.com and go to your dashboard.
* To get to the importer page, you need to go to the "New project" page.
- the repository description
- the git repository data
- the issues
- the pull requests
- the wiki pages
![New project page](github_importer/new_project_page.png)
The importer page is visible when you [create a new project][new-project].
Click on the **GitHub** link and you will be redirected to GitHub for
permission to access your projects. After accepting, you'll be automatically
redirected to the importer.
* Click on the "Import project from GitHub" link and you will be redirected to GitHub for permission to access your projects. After accepting, you'll be automatically redirected to the importer.
![New project page on GitLab](img/import_projects_from_github_new_project_page.png)
![Importer page](github_importer/importer.png)
---
* To import a project, you can simple click "Add". The importer will import your repository, issues, and pull requests. Once the importer is done, a new GitLab project will be created with your imported data.
While at the GitHub importer page, you can see the import statuses of your
GitHub projects. Those that are being imported will show a _started_ status,
those already imported will be green, whereas those that are not yet imported
have an **Import** button on the right side of the table. If you want, you can
import all your GitHub projects in one go by hitting **Import all projects**
in the upper left corner.
![GitHub importer page](img/import_projects_from_github_importer.png)
---
The importer will create any new namespaces if they don't exist or in the
case the namespace is taken, the project will be imported on the user's
namespace.
### Note
When you import your projects from GitHub, it is not possible to keep your labels, milestones, and cross-repository pull requests. We are working on improving this in the near future.
When you import your projects from GitHub, it is not possible to keep your
labels, milestones, and cross-repository pull requests. We are working on
improving this in the near future.
[gh-import]: ../../integration/github.md "GitHub integration"
[ee-gh]: http://doc.gitlab.com/ee/integration/github.html "GitHub integration for GitLab EE"
[new-project]: ../../gitlab-basics/create-project.md "How to create a new project in GitLab"
Feature: Project Builds
Feature: Project Builds Artifacts
Background:
Given I sign in as a user
And I own a project
And CI is enabled
And I have recent build for my project
Scenario: I browse build summary page
When I visit recent build summary page
Then I see summary for build
And I see build trace
And project has CI enabled
And project has a recent build
Scenario: I download build artifacts
Given recent build has artifacts available
......
Feature: Project Builds Permissions
Background:
Given I sign in as a user
And project exists in some group namespace
And project has CI enabled
And project has a recent build
Scenario: I try to download build artifacts as guest
Given I am member of a project with a guest role
And recent build has artifacts available
When I access artifacts download page
Then page status code should be 404
Scenario: I try to download build artifacts as reporter
Given I am member of a project with a reporter role
And recent build has artifacts available
When I access artifacts download page
Then download of build artifacts archive starts
Feature: Project Builds Summary
Background:
Given I sign in as a user
And I own a project
And project has CI enabled
And project has a recent build
Scenario: I browse build summary page
When I visit recent build summary page
Then I see summary for build
And I see build trace
class Spinach::Features::ProjectBuilds < Spinach::FeatureSteps
class Spinach::Features::ProjectBuildsArtifacts < Spinach::FeatureSteps
include SharedAuthentication
include SharedProject
include SharedBuilds
include RepoHelpers
step 'I see summary for build' do
expect(page).to have_content "Build ##{@build.id}"
end
step 'I see build trace' do
expect(page).to have_css '#build-trace'
end
step 'I click artifacts download button' do
page.within('.artifacts') { click_link 'Download' }
end
step 'download of build artifacts archive starts' do
expect(page.response_headers['Content-Type']).to eq 'application/zip'
expect(page.response_headers['Content-Transfer-Encoding']).to eq 'binary'
end
step 'I click artifacts browse button' do
page.within('.artifacts') { click_link 'Browse' }
end
......
class Spinach::Features::ProjectBuildsPermissions < Spinach::FeatureSteps
include SharedAuthentication
include SharedProject
include SharedBuilds
include SharedPaths
include RepoHelpers
end
class Spinach::Features::ProjectBuildsSummary < Spinach::FeatureSteps
include SharedAuthentication
include SharedProject
include SharedBuilds
include RepoHelpers
step 'I see summary for build' do
expect(page).to have_content "Build ##{@build.id}"
end
step 'I see build trace' do
expect(page).to have_css '#build-trace'
end
end
module SharedBuilds
include Spinach::DSL
step 'CI is enabled' do
step 'project has CI enabled' do
@project.enable_ci
end
step 'I have recent build for my project' do
step 'project has a recent build' do
ci_commit = create :ci_commit, project: @project, sha: sample_commit.id
@build = create :ci_build, commit: ci_commit
end
......@@ -25,4 +25,13 @@ module SharedBuilds
gzip = fixture_file_upload(metadata, 'application/x-gzip')
@build.update_attributes(artifacts_metadata: gzip)
end
step 'download of build artifacts archive starts' do
expect(page.response_headers['Content-Type']).to eq 'application/zip'
expect(page.response_headers['Content-Transfer-Encoding']).to eq 'binary'
end
step 'I access artifacts download page' do
visit download_namespace_project_build_artifacts_path(@project.namespace, @project, @build)
end
end
......@@ -7,6 +7,11 @@ module SharedProject
@project.team << [@user, :master]
end
step "project exists in some group namespace" do
@group = create(:group, name: 'some group')
@project = create(:project, namespace: @group)
end
# Create a specific project called "Shop"
step 'I own project "Shop"' do
@project = Project.find_by(name: "Shop")
......@@ -97,6 +102,18 @@ module SharedProject
@project ||= Project.first
end
# ----------------------------------------
# Project permissions
# ----------------------------------------
step 'I am member of a project with a guest role' do
@project.team << [@user, Gitlab::Access::GUEST]
end
step 'I am member of a project with a reporter role' do
@project.team << [@user, Gitlab::Access::REPORTER]
end
# ----------------------------------------
# Visibility of archived project
# ----------------------------------------
......@@ -229,5 +246,4 @@ module SharedProject
project ||= create(:empty_project, visibility, name: project_name, namespace: user.namespace)
project.team << [user, :master]
end
end
......@@ -20,7 +20,7 @@ module Ci
if build
update_runner_info
present build, with: Entities::Build
present build, with: Entities::BuildDetails
else
not_found!
end
......@@ -111,7 +111,7 @@ module Ci
build.artifacts_metadata = metadata
if build.save
present(build, with: Entities::Build)
present(build, with: Entities::BuildDetails)
else
render_validation_error!(build)
end
......
......@@ -16,10 +16,19 @@ module Ci
end
class Build < Grape::Entity
expose :id, :commands, :ref, :sha, :status, :project_id, :repo_url,
:before_sha, :allow_git_fetch, :project_name
expose :id, :ref, :tag, :sha, :status
expose :name, :token, :stage
expose :project_id
expose :project_name
expose :artifacts_file, using: ArtifactFile, if: lambda { |build, opts| build.artifacts? }
end
class BuildDetails < Build
expose :commands
expose :repo_url
expose :before_sha
expose :allow_git_fetch
expose :token
expose :options do |model|
model.options
......@@ -30,7 +39,7 @@ module Ci
end
expose :variables
expose :artifacts_file, using: ArtifactFile
expose :depends_on_builds, using: Build
end
class Runner < Grape::Entity
......
......@@ -141,9 +141,12 @@ module Gitlab
username = auth_hash.username
email = auth_hash.email
end
name = auth_hash.name
name = ::Namespace.clean_path(username) if name.strip.empty?
{
name: auth_hash.name,
name: name,
username: ::Namespace.clean_path(username),
email: email,
password: auth_hash.password,
......
......@@ -426,6 +426,30 @@ describe Ci::Build, models: true do
it { is_expected.to include(project.web_url[7..-1]) }
end
describe :depends_on_builds do
let!(:build) { FactoryGirl.create :ci_build, commit: commit, name: 'build', stage_idx: 0, stage: 'build' }
let!(:rspec_test) { FactoryGirl.create :ci_build, commit: commit, name: 'rspec', stage_idx: 1, stage: 'test' }
let!(:rubocop_test) { FactoryGirl.create :ci_build, commit: commit, name: 'rubocop', stage_idx: 1, stage: 'test' }
let!(:staging) { FactoryGirl.create :ci_build, commit: commit, name: 'staging', stage_idx: 2, stage: 'deploy' }
it 'to have no dependents if this is first build' do
expect(build.depends_on_builds).to be_empty
end
it 'to have one dependent if this is test' do
expect(rspec_test.depends_on_builds.map(&:id)).to contain_exactly(build.id)
end
it 'to have all builds from build and test stage if this is last' do
expect(staging.depends_on_builds.map(&:id)).to contain_exactly(build.id, rspec_test.id, rubocop_test.id)
end
it 'to have retried builds instead the original ones' do
retried_rspec = Ci::Build.retry(rspec_test)
expect(staging.depends_on_builds.map(&:id)).to contain_exactly(build.id, retried_rspec.id, rubocop_test.id)
end
end
def create_mr(build, commit, factory: :merge_request, created_at: Time.now)
FactoryGirl.create(factory,
source_project_id: commit.gl_project_id,
......
......@@ -101,6 +101,18 @@ describe Ci::API::API do
{ "key" => "TRIGGER_KEY", "value" => "TRIGGER_VALUE", "public" => false },
])
end
it "returns dependent builds" do
commit = FactoryGirl.create(:ci_commit, project: project)
commit.create_builds('master', false, nil, nil)
commit.builds.where(stage: 'test').each(&:success)
post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
expect(response.status).to eq(201)
expect(json_response["depends_on_builds"].count).to eq(2)
expect(json_response["depends_on_builds"][0]["name"]).to eq("rspec")
end
end
describe "PUT /builds/:id" do
......
......@@ -36,8 +36,8 @@ staging:
script: "cap deploy stating"
type: deploy
tags:
- capistrano
- debian
- ruby
- mysql
except:
- stable
......@@ -47,8 +47,8 @@ production:
- cap deploy production
- cap notify
tags:
- capistrano
- debian
- ruby
- mysql
only:
- master
- /^deploy-.*$/
......
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