Commit e0665e66 authored by Valery Sizov's avatar Valery Sizov

Merge branch 'ce_upstream' into 'master'

CE upstream

See merge request !996
parents cdb51842 0e569f2c
...@@ -4,8 +4,7 @@ entry. ...@@ -4,8 +4,7 @@ entry.
## 8.15.0 (2017-01-22) ## 8.15.0 (2017-01-22)
- Add shortcuts for adding users to a project team with a specific role. (Nikolay Ponomarev and Dino M) - Whitelist next project names: notes, services.
- Ensure nil User-Agent doesn't break the CI API.
- Use Grape's new Route methods. - Use Grape's new Route methods.
- Fixed issue boards scrolling with a lot of lists & issues. - Fixed issue boards scrolling with a lot of lists & issues.
- Remove unnecessary sentences for status codes in the API documentation. (Luis Alonso Chavez Armendariz) - Remove unnecessary sentences for status codes in the API documentation. (Luis Alonso Chavez Armendariz)
...@@ -28,11 +27,11 @@ entry. ...@@ -28,11 +27,11 @@ entry.
- Use authorized projects in ProjectTeam. - Use authorized projects in ProjectTeam.
- Destroy a user's session when they delete their own account. - Destroy a user's session when they delete their own account.
- Edit help text to clarify annotated tag creation. (Liz Lam) - Edit help text to clarify annotated tag creation. (Liz Lam)
- Fixed file template dropdown for the "New File" editor for smaller/zoomed screens.
- Fix Route#rename_children behavior. - Fix Route#rename_children behavior.
- Add nested groups support on data level. - Add nested groups support on data level.
- Fixed file template dropdown for the "New File" editor for smaller/zoomed screens.
- Allow projects with 'dashboard' as path. - Allow projects with 'dashboard' as path.
- Whitelist next project names: notes, services. - Disabled emoji buttons when user is not logged in.
- Remove unused and void services from the database. - Remove unused and void services from the database.
- Add issue search slash command. - Add issue search slash command.
- Accept issue new as command to create an issue. - Accept issue new as command to create an issue.
...@@ -46,7 +45,7 @@ entry. ...@@ -46,7 +45,7 @@ entry.
- Fixed timeago re-rendering every timeago. - Fixed timeago re-rendering every timeago.
- Enable ColorVariable in scss-lint. (Sam Rose) - Enable ColorVariable in scss-lint. (Sam Rose)
- Various small emoji positioning adjustments. - Various small emoji positioning adjustments.
- Disabled emoji buttons when user is not logged in. - Add shortcuts for adding users to a project team with a specific role. (Nikolay Ponomarev and Dino M)
- Additional rounded label fixes. - Additional rounded label fixes.
- Remove unnecessary database indices. - Remove unnecessary database indices.
- 24726 Remove Across GitLab from side navigation. - 24726 Remove Across GitLab from side navigation.
...@@ -85,7 +84,7 @@ entry. ...@@ -85,7 +84,7 @@ entry.
- 25617 Fix placeholder color of todo filters. - 25617 Fix placeholder color of todo filters.
- Made the padding on the plus button in the breadcrumb menu even. (Ryan Harris) - Made the padding on the plus button in the breadcrumb menu even. (Ryan Harris)
- Allow to delete tag release note. - Allow to delete tag release note.
- Don't delete branches/tags that contains changes only in the remote mirror. !968 - Ensure nil User-Agent doesn't break the CI API.
- Replace Rack::Multipart with GitLab-Workhorse based solution. !5867 - Replace Rack::Multipart with GitLab-Workhorse based solution. !5867
- Add scopes for personal access tokens and OAuth tokens. !5951 - Add scopes for personal access tokens and OAuth tokens. !5951
- API: Endpoint to expose personal snippets as /snippets. !6373 (Bernard Guyzmo Pratz) - API: Endpoint to expose personal snippets as /snippets. !6373 (Bernard Guyzmo Pratz)
...@@ -182,7 +181,7 @@ entry. ...@@ -182,7 +181,7 @@ entry.
- Allow all alphanumeric characters in file names. !8002 (winniehell) - Allow all alphanumeric characters in file names. !8002 (winniehell)
- Added support for math rendering, using KaTeX, in Markdown and asciidoc. !8003 (Munken) - Added support for math rendering, using KaTeX, in Markdown and asciidoc. !8003 (Munken)
- Remove unnecessary commits order message. !8004 - Remove unnecessary commits order message. !8004
- API: Memoize the current_user so that the sudo can work properly. !8017 - API: Memoize the current_user so that sudo can work properly. !8017
- group authors in contribution graph with case insensitive email handle comparison. !8021 - group authors in contribution graph with case insensitive email handle comparison. !8021
- Move admin active tab spinach tests to rspec. !8037 (Semyon Pupkov) - Move admin active tab spinach tests to rspec. !8037 (Semyon Pupkov)
- Add Authentiq as Oauth provider. !8038 (Alexandros Keramidas) - Add Authentiq as Oauth provider. !8038 (Alexandros Keramidas)
......
8.14.0-ee-pre 8.16.0-ee-pre
...@@ -143,11 +143,6 @@ ...@@ -143,11 +143,6 @@
case 'projects:merge_requests:commits': case 'projects:merge_requests:commits':
new MergedButtons(); new MergedButtons();
break; break;
case 'projects:merge_requests:pipelines':
new gl.MiniPipelineGraph({
container: '.js-pipeline-table',
});
break;
case "projects:merge_requests:diffs": case "projects:merge_requests:diffs":
new gl.Diff(); new gl.Diff();
new ZenMode(); new ZenMode();
......
...@@ -74,15 +74,16 @@ ...@@ -74,15 +74,16 @@
// The below is taken from At.js source // The below is taken from At.js source
// Tweaked to commands to start without a space only if char before is a non-word character // Tweaked to commands to start without a space only if char before is a non-word character
// https://github.com/ichord/At.js // https://github.com/ichord/At.js
var _a, _y, regexp, match, atSymbols; var _a, _y, regexp, match, atSymbolsWithBar, atSymbolsWithoutBar;
atSymbols = Object.keys(this.app.controllers).join('|'); atSymbolsWithBar = Object.keys(this.app.controllers).join('|');
atSymbolsWithoutBar = Object.keys(this.app.controllers).join('');
subtext = subtext.split(' ').pop(); subtext = subtext.split(' ').pop();
flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
_a = decodeURI("%C3%80"); _a = decodeURI("%C3%80");
_y = decodeURI("%C3%BF"); _y = decodeURI("%C3%BF");
regexp = new RegExp("(?:\\B|\\W|\\s)" + flag + "(?![" + atSymbols + "])([A-Za-z" + _a + "-" + _y + "0-9_\'\.\+\-]*)$", 'gi'); regexp = new RegExp("^(?:\\B|[^a-zA-Z0-9_" + atSymbolsWithoutBar + "]|\\s)" + flag + "(?![" + atSymbolsWithBar + "])([A-Za-z" + _a + "-" + _y + "0-9_\'\.\+\-]*)$", 'gi');
match = regexp.exec(subtext); match = regexp.exec(subtext);
......
...@@ -259,6 +259,10 @@ ...@@ -259,6 +259,10 @@
gl.utils.localTimeAgo($('.js-timeago', '#pipelines')); gl.utils.localTimeAgo($('.js-timeago', '#pipelines'));
this.pipelinesLoaded = true; this.pipelinesLoaded = true;
this.scrollToElement('#pipelines'); this.scrollToElement('#pipelines');
new gl.MiniPipelineGraph({
container: '.js-pipeline-table',
});
}, },
}); });
} }
......
...@@ -98,7 +98,7 @@ ...@@ -98,7 +98,7 @@
} }
.label { .label {
padding: 8px 9px 9px; padding: 8px 9px 9px $gl-padding;
font-size: 14px; font-size: 14px;
} }
} }
......
...@@ -25,12 +25,6 @@ ...@@ -25,12 +25,6 @@
} }
.issuable-row { .issuable-row {
.color-label {
border-radius: 2px;
padding: 3px !important;
margin-right: 7px;
}
span a { span a {
color: $gl-text-color; color: $gl-text-color;
word-wrap: break-word; word-wrap: break-word;
......
...@@ -52,6 +52,10 @@ ...@@ -52,6 +52,10 @@
} }
} }
.content-list.pipelines .table-holder {
min-height: 300px;
}
.pipeline-holder { .pipeline-holder {
width: 100%; width: 100%;
overflow: auto; overflow: auto;
...@@ -593,6 +597,27 @@ ...@@ -593,6 +597,27 @@
} }
} }
} }
.grouped-pipeline-dropdown {
.dropdown-build {
.build-content {
width: 100%;
&:hover {
background-color: $stage-hover-bg;
color: $gl-text-color;
}
}
.ci-action-icon-container {
padding: 0;
font-size: 11px;
position: absolute;
top: 1px;
right: 8px;
}
}
}
} }
.dropdown-counter-badge { .dropdown-counter-badge {
...@@ -603,9 +628,11 @@ ...@@ -603,9 +628,11 @@
margin-right: 2px; margin-right: 2px;
} }
.grouped-pipeline-dropdown { .grouped-pipeline-dropdown {
padding: 0; padding: 0;
width: 191px; width: 191px;
min-width: 191px;
left: auto; left: auto;
right: -195px; right: -195px;
top: -4px; top: -4px;
...@@ -615,11 +642,22 @@ ...@@ -615,11 +642,22 @@
display: inline-block; display: inline-block;
} }
.build-content { .dropdown-build {
width: 138px; .build-content {
width: 100%;
&:hover { &:hover {
background-color: $stage-hover-bg; background-color: $stage-hover-bg;
color: $gl-text-color;
}
}
.ci-action-icon-container {
padding: 0;
font-size: 11px;
position: absolute;
margin-top: 3px;
right: 7px;
} }
} }
...@@ -629,12 +667,10 @@ ...@@ -629,12 +667,10 @@
margin: 3px 0; margin: 3px 0;
li { li {
padding-top: 2px; margin: 4px 8px 4px 9px;
margin: 4px 7px; padding: 0;
padding: 0 3px; line-height: 1.1;
padding-left: 0; position: relative;
padding-bottom: 0;
line-height: 0;
.ci-action-icon-container:hover { .ci-action-icon-container:hover {
background-color: transparent; background-color: transparent;
...@@ -648,6 +684,11 @@ ...@@ -648,6 +684,11 @@
} }
} }
.pipeline-graph .dropdown-build .ci-status-icon svg {
width: 18px;
height: 18px;
}
.ci-status-text { .ci-status-text {
max-width: 110px; max-width: 110px;
white-space: nowrap; white-space: nowrap;
...@@ -656,7 +697,7 @@ ...@@ -656,7 +697,7 @@
vertical-align: bottom; vertical-align: bottom;
display: inline-block; display: inline-block;
position: relative; position: relative;
font-weight: 100; font-weight: 200;
} }
// Action Icons // Action Icons
...@@ -693,7 +734,7 @@ ...@@ -693,7 +734,7 @@
color: $gl-text-color-light; color: $gl-text-color-light;
.build-content { .build-content {
padding: 3px 7px 6px; padding: 4px 7px 8px;
} }
.ci-action-icon-container { .ci-action-icon-container {
......
...@@ -105,8 +105,8 @@ module IssuablesHelper ...@@ -105,8 +105,8 @@ module IssuablesHelper
if issuable.tasks? if issuable.tasks?
output << "&ensp;".html_safe output << "&ensp;".html_safe
output << content_tag(:span, issuable.task_status, id: "task_status", class: "hidden-xs") output << content_tag(:span, issuable.task_status, id: "task_status", class: "hidden-xs hidden-sm")
output << content_tag(:span, issuable.task_status_short, id: "task_status_short", class: "hidden-sm hidden-md hidden-lg") output << content_tag(:span, issuable.task_status_short, id: "task_status_short", class: "hidden-md hidden-lg")
end end
output output
......
...@@ -35,7 +35,7 @@ module TodosHelper ...@@ -35,7 +35,7 @@ module TodosHelper
else else
path = [todo.project.namespace.becomes(Namespace), todo.project, todo.target] path = [todo.project.namespace.becomes(Namespace), todo.project, todo.target]
path.unshift(:builds) if todo.build_failed? path.unshift(:pipelines) if todo.build_failed?
polymorphic_path(path, anchor: anchor) polymorphic_path(path, anchor: anchor)
end end
......
...@@ -46,6 +46,6 @@ class MattermostSlashCommandsService < ChatSlashCommandsService ...@@ -46,6 +46,6 @@ class MattermostSlashCommandsService < ChatSlashCommandsService
description: "Perform common operations on: #{pretty_project_name}", description: "Perform common operations on: #{pretty_project_name}",
display_name: "GitLab / #{pretty_project_name}", display_name: "GitLab / #{pretty_project_name}",
method: 'P', method: 'P',
user_name: 'GitLab') username: 'GitLab')
end end
end end
...@@ -16,7 +16,7 @@ class SlackSlashCommandsService < ChatSlashCommandsService ...@@ -16,7 +16,7 @@ class SlackSlashCommandsService < ChatSlashCommandsService
def trigger(params) def trigger(params)
# Format messages to be Slack-compatible # Format messages to be Slack-compatible
super.tap do |result| super.tap do |result|
result[:text] = format(result[:text]) result[:text] = format(result[:text]) if result.is_a?(Hash)
end end
end end
......
...@@ -710,8 +710,7 @@ class Repository ...@@ -710,8 +710,7 @@ class Repository
end end
def last_commit_for_path(sha, path) def last_commit_for_path(sha, path)
args = %W(#{Gitlab.config.git.bin_path} rev-list --max-count=1 #{sha} -- #{path}) sha = last_commit_id_for_path(sha, path)
sha = Gitlab::Popen.popen(args, path_to_repo).first.strip
commit(sha) commit(sha)
end end
...@@ -724,6 +723,15 @@ class Repository ...@@ -724,6 +723,15 @@ class Repository
end end
end end
def last_commit_id_for_path(sha, path)
key = path.blank? ? "last_commit_id_for_path:#{sha}" : "last_commit_id_for_path:#{sha}:#{Digest::SHA1.hexdigest(path)}"
cache.fetch(key) do
args = %W(#{Gitlab.config.git.bin_path} rev-list --max-count=1 #{sha} -- #{path})
Gitlab::Popen.popen(args, path_to_repo).first.strip
end
end
def next_branch(name, opts = {}) def next_branch(name, opts = {})
branch_ids = self.branch_names.map do |n| branch_ids = self.branch_names.map do |n|
next 1 if n == name next 1 if n == name
......
%ul %ul
- @stage.statuses.each do |status| - @stage.statuses.latest.each do |status|
%li.dropdown-build %li.dropdown-build
= render 'ci/status/graph_badge', subject: status = render 'ci/status/graph_badge', subject: status
- group_status = CommitStatus.where(id: subject).status - group_status = CommitStatus.where(id: subject).status
%button.dropdown-menu-toggle.build-content.has-tooltip{ type: 'button', data: { toggle: 'dropdown'} } %button.dropdown-menu-toggle.build-content.has-tooltip{ type: 'button', data: { toggle: 'dropdown', title: "#{name} - #{group_status}" } }
%span{class: "ci-status-icon ci-status-icon-#{group_status}"} %span{class: "ci-status-icon ci-status-icon-#{group_status}"}
= ci_icon_for_status(group_status) = ci_icon_for_status(group_status)
%span.ci-status-text{ 'data-toggle' => 'tooltip', 'data-title' => "#{name} - #{group_status}" } %span.ci-status-text
= name = name
%span.dropdown-counter-badge= subject.size %span.dropdown-counter-badge= subject.size
.dropdown-menu.grouped-pipeline-dropdown .dropdown-menu.grouped-pipeline-dropdown
......
---
title: Change earlier to task_status_short to avoid titlebar line wraps
merge_request:
author:
---
title: Fix Pipeline builds list blank on MR
merge_request: 8255
author:
---
title: Do not show retried builds in pipeline stage dropdown
merge_request: 8260
author:
---
title: Fix Mattermost command creation by specifying username
merge_request:
author:
---
title: Add Gitaly to the architecture documentation
merge_request: 8264
author: Pablo Carranza <pablo@gitlab.com>
...@@ -20,9 +20,10 @@ The list of supported autodeploy templates is available [here][autodeploy-templa ...@@ -20,9 +20,10 @@ The list of supported autodeploy templates is available [here][autodeploy-templa
## Configuration ## Configuration
1. Enable a deployment [project service][project-services] to store your 1. Enable a deployment [project service][project-services] to store your
credentials. For example, if you want to deploy to a Kubernetes cluster credentials. For example, if you want to deploy to OpenShift you have to
you have to enable [Kubernetes service][kubernetes-service]. enable [Kubernetes service][kubernetes-service].
1. Configure GitLab Runner to use [docker-in-docker executor][docker-in-docker]. 1. Configure GitLab Runner to use Docker or Kubernetes executor with
[privileged mode enabled][docker-in-docker].
1. Navigate to the "Project" tab and click "Set up autodeploy" button. 1. Navigate to the "Project" tab and click "Set up autodeploy" button.
![Autodeploy button](img/autodeploy_button.png) ![Autodeploy button](img/autodeploy_button.png)
1. Select a template. 1. Select a template.
......
...@@ -34,7 +34,7 @@ production: ...@@ -34,7 +34,7 @@ production:
This project has three jobs: This project has three jobs:
1. `test` - used to test Rails application, 1. `test` - used to test Rails application,
2. `staging` - used to automatically deploy staging environment every push to `master` branch 2. `staging` - used to automatically deploy staging environment every push to `master` branch
3. `production` - used to automatically deploy production environmnet for every created tag 3. `production` - used to automatically deploy production environment for every created tag
### Store API keys ### Store API keys
You'll need to create two variables in `Project > Variables`: You'll need to create two variables in `Project > Variables`:
......
...@@ -6,7 +6,7 @@ There are two editions of GitLab: [Enterprise Edition](https://about.gitlab.com/ ...@@ -6,7 +6,7 @@ There are two editions of GitLab: [Enterprise Edition](https://about.gitlab.com/
EE releases are available not long after CE releases. To obtain GitLab EE there is a [repository at gitlab.com](https://gitlab.com/gitlab-org/gitlab-ee). For more information about the release process see the section 'New versions and upgrading' in the readme. EE releases are available not long after CE releases. To obtain GitLab EE there is a [repository at gitlab.com](https://gitlab.com/gitlab-org/gitlab-ee). For more information about the release process see the section 'New versions and upgrading' in the readme.
Both EE and CE require an add-on component called gitlab-shell. It is obtained from the [gitlab-shell repository](https://gitlab.com/gitlab-org/gitlab-shell/tree/master). New versions are usually tags but staying on the master branch will give you the latest stable version. New releases are generally around the same time as GitLab CE releases with exception for informal security updates deemed critical. Both EE and CE require some add-on components called gitlab-shell and Gitaly. These components are available from the [gitlab-shell](https://gitlab.com/gitlab-org/gitlab-shell/tree/master) and [gitaly](https://gitlab.com/gitlab-org/gitaly/tree/master) repositories respectively. New versions are usually tags but staying on the master branch will give you the latest stable version. New releases are generally around the same time as GitLab CE releases with exception for informal security updates deemed critical.
## Physical office analogy ## Physical office analogy
...@@ -35,8 +35,10 @@ Their job description: ...@@ -35,8 +35,10 @@ Their job description:
- make tasks for Sidekiq; - make tasks for Sidekiq;
- fetch stuff from the warehouse or move things around in there; - fetch stuff from the warehouse or move things around in there;
**Gitlab-shell** is a third kind of worker that takes orders from a fax machine (SSH) instead of the front desk (HTTP). **GitLab-shell** is a third kind of worker that takes orders from a fax machine (SSH) instead of the front desk (HTTP).
Gitlab-shell communicates with Sidekiq via the “communication board” (Redis), and asks quick questions of the Unicorn workers either directly or via the front desk. GitLab-shell communicates with Sidekiq via the “communication board” (Redis), and asks quick questions of the Unicorn workers either directly or via the front desk.
**Gitaly** is a back desk that is specialized on reaching the disks to perform git operations efficiently and keep a copy of the result of costly operations. All git operations go through Gitaly.
**GitLab Enterprise Edition (the application)** is the collection of processes and business practices that the office is run by. **GitLab Enterprise Edition (the application)** is the collection of processes and business practices that the office is run by.
...@@ -53,7 +55,7 @@ To serve repositories over SSH there's an add-on application called gitlab-shell ...@@ -53,7 +55,7 @@ To serve repositories over SSH there's an add-on application called gitlab-shell
### Components ### Components
![GitLab Diagram Overview](gitlab_architecture_diagram.png) ![GitLab Diagram Overview](gitlab_architecture_diagram.png)
_[edit diagram (for GitLab team members only)](https://docs.google.com/drawings/d/1fBzAyklyveF-i-2q-OHUIqDkYfjjxC4mq5shwKSZHLs/edit)_ _[edit diagram (for GitLab team members only)](https://docs.google.com/drawings/d/1fBzAyklyveF-i-2q-OHUIqDkYfjjxC4mq5shwKSZHLs/edit)_
A typical install of GitLab will be on GNU/Linux. It uses Nginx or Apache as a web front end to proxypass the Unicorn web server. By default, communication between Unicorn and the front end is via a Unix domain socket but forwarding requests via TCP is also supported. The web front end accesses `/home/git/gitlab/public` bypassing the Unicorn server to serve static pages, uploads (e.g. avatar images or attachments), and precompiled assets. GitLab serves web pages and a [GitLab API](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/api) using the Unicorn web server. It uses Sidekiq as a job queue which, in turn, uses redis as a non-persistent database backend for job information, meta data, and incoming jobs. A typical install of GitLab will be on GNU/Linux. It uses Nginx or Apache as a web front end to proxypass the Unicorn web server. By default, communication between Unicorn and the front end is via a Unix domain socket but forwarding requests via TCP is also supported. The web front end accesses `/home/git/gitlab/public` bypassing the Unicorn server to serve static pages, uploads (e.g. avatar images or attachments), and precompiled assets. GitLab serves web pages and a [GitLab API](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/api) using the Unicorn web server. It uses Sidekiq as a job queue which, in turn, uses redis as a non-persistent database backend for job information, meta data, and incoming jobs.
...@@ -62,7 +64,9 @@ The GitLab web app uses MySQL or PostgreSQL for persistent database information ...@@ -62,7 +64,9 @@ The GitLab web app uses MySQL or PostgreSQL for persistent database information
When serving repositories over HTTP/HTTPS GitLab utilizes the GitLab API to resolve authorization and access as well as serving git objects. When serving repositories over HTTP/HTTPS GitLab utilizes the GitLab API to resolve authorization and access as well as serving git objects.
The add-on component gitlab-shell serves repositories over SSH. It manages the SSH keys within `/home/git/.ssh/authorized_keys` which should not be manually edited. gitlab-shell accesses the bare repositories directly to serve git objects and communicates with redis to submit jobs to Sidekiq for GitLab to process. gitlab-shell queries the GitLab API to determine authorization and access. The add-on component gitlab-shell serves repositories over SSH. It manages the SSH keys within `/home/git/.ssh/authorized_keys` which should not be manually edited. gitlab-shell accesses the bare repositories through Gitaly to serve git objects and communicates with redis to submit jobs to Sidekiq for GitLab to process. gitlab-shell queries the GitLab API to determine authorization and access.
Gitaly executes git operations from gitlab-shell and Workhorse, and provides an API to the GitLab web app to get attributes from git (e.g. title, branches, tags, other meta data), and to get blobs (e.g. diffs, commits, files)
### Installation Folder Summary ### Installation Folder Summary
......
# Chat Commands
Chat commands allow user to perform common operations on GitLab right from there chat client.
Right now both Mattermost and Slack are supported.
## Available commands
The trigger is configurable, but for the sake of this example, we'll use `/trigger`
* `/trigger help` - Displays all available commands for this user
* `/trigger issue new <title> <shift+return> <description>` - creates a new issue on the project
* `/trigger issue show <id>` - Shows the issue with the given ID, if you've got access
* `/trigger issue search <query>` - Shows a maximum of 5 items matching the query
* `/trigger deploy <from> to <to>` - Deploy from an environment to another
...@@ -14,12 +14,18 @@ If you have the Omnibus GitLab package installed, Mattermost is already bundled ...@@ -14,12 +14,18 @@ If you have the Omnibus GitLab package installed, Mattermost is already bundled
in it. All you have to do is configure it. Read more in the in it. All you have to do is configure it. Read more in the
[Omnibus GitLab Mattermost documentation][omnimmdocs]. [Omnibus GitLab Mattermost documentation][omnimmdocs].
## Configuration ## Automated Configuration
If Mattermost is installed on the same server as GitLab, the configuration process can be
done for you by GitLab.
Go to the Mattermost Slash Command service on your project and click the 'Add to Mattermost' button.
## Manual Configuration
The configuration consists of two parts. First you need to enable the slash The configuration consists of two parts. First you need to enable the slash
commands in Mattermost and then enable the service in GitLab. commands in Mattermost and then enable the service in GitLab.
### Step 1. Enable custom slash commands in Mattermost ### Step 1. Enable custom slash commands in Mattermost
This step is only required when using a source install, omnibus installs will be This step is only required when using a source install, omnibus installs will be
......
# Slack slash commands
> Introduced in GitLab 8.15
Slack commands give users an extra interface to perform common operations
from the chat environment. This allows one to, for example, create an issue as
soon as the idea was discussed in chat.
For all available commands try the help subcommand, for example: `/gitlab help`,
all review the [full list of commands](../integrations/chat_commands.md).
## Prerequisites
A [team](https://get.slack.help/hc/en-us/articles/217608418-Creating-a-team) in Slack should be created beforehand, GitLab cannot create it for you.
## Configuration
First, navigate to the Slack Slash commands service page, found at your project's
**Settings** > **Services**, and you find the instructions there:
![Slack setup instructions](img/slack_setup.png)
Once you've followed the instructions, mark the service as active and insert the token
you've received from Slack. After saving the service you are good to go!
...@@ -51,13 +51,15 @@ are resolved. ...@@ -51,13 +51,15 @@ are resolved.
![Only allow merge if all the discussions are resolved message](img/only_allow_merge_if_all_discussions_are_resolved_msg.png) ![Only allow merge if all the discussions are resolved message](img/only_allow_merge_if_all_discussions_are_resolved_msg.png)
### Move all unresolved discussions in a merge request to an issue ## Move all unresolved discussions in a merge request to an issue
> [Introduced][ce-7180] (Currently on Backlog) > [Introduced][ce-7180] in GitLab 8.15.
To delegate unresolved discussions to a new issue you can click the link **open To delegate unresolved discussions to a new issue you can click the link **open
an issue to resolve them later**. an issue to resolve them later**.
![Open new issue from unresolved discussions](img/resolve_discussion_open_issue.png)
This will prepare an issue with content referring to the merge request and This will prepare an issue with content referring to the merge request and
discussions. discussions.
...@@ -66,6 +68,8 @@ discussions. ...@@ -66,6 +68,8 @@ discussions.
Hitting **Submit issue** will cause all discussions to be marked as resolved and Hitting **Submit issue** will cause all discussions to be marked as resolved and
add a note referring to the newly created issue. add a note referring to the newly created issue.
![Mark discussions as resolved notice](img/resolve_discussion_issue_notice.png)
You can now proceed to merge the merge request from the UI. You can now proceed to merge the merge request from the UI.
[ce-5022]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5022 [ce-5022]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5022
......
...@@ -68,7 +68,7 @@ module API ...@@ -68,7 +68,7 @@ module API
ref: params[:ref], ref: params[:ref],
blob_id: blob.id, blob_id: blob.id,
commit_id: commit.id, commit_id: commit.id,
last_commit_id: repo.last_commit_for_path(commit.sha, params[:file_path]).id last_commit_id: repo.last_commit_id_for_path(commit.sha, params[:file_path])
} }
end end
......
...@@ -37,8 +37,6 @@ module API ...@@ -37,8 +37,6 @@ module API
optional :labels, type: String, desc: 'Comma-separated list of label names' optional :labels, type: String, desc: 'Comma-separated list of label names'
optional :due_date, type: String, desc: 'Date string in the format YEAR-MONTH-DAY' optional :due_date, type: String, desc: 'Date string in the format YEAR-MONTH-DAY'
optional :confidential, type: Boolean, desc: 'Boolean parameter if the issue should be confidential' optional :confidential, type: Boolean, desc: 'Boolean parameter if the issue should be confidential'
optional :state_event, type: String, values: %w[open close],
desc: 'State of the issue'
end end
end end
...@@ -172,6 +170,7 @@ module API ...@@ -172,6 +170,7 @@ module API
optional :title, type: String, desc: 'The title of an issue' optional :title, type: String, desc: 'The title of an issue'
optional :updated_at, type: DateTime, optional :updated_at, type: DateTime,
desc: 'Date time when the issue was updated. Available only for admins and project owners.' desc: 'Date time when the issue was updated. Available only for admins and project owners.'
optional :state_event, type: String, values: %w[reopen close], desc: 'State of the issue'
use :issue_params use :issue_params
at_least_one_of :title, :description, :assignee_id, :milestone_id, at_least_one_of :title, :description, :assignee_id, :milestone_id,
:labels, :created_at, :due_date, :confidential, :state_event :labels, :created_at, :due_date, :confidential, :state_event
......
...@@ -5,12 +5,6 @@ module Banzai ...@@ -5,12 +5,6 @@ module Banzai
# HTML filter that adds class="code math" and removes the dollar sign in $`2+2`$. # HTML filter that adds class="code math" and removes the dollar sign in $`2+2`$.
# #
class MathFilter < HTML::Pipeline::Filter class MathFilter < HTML::Pipeline::Filter
# This picks out <code>...</code>.
INLINE_MATH = 'descendant-or-self::code'.freeze
# Pick out a code block which is declared math
DISPLAY_MATH = "descendant-or-self::pre[contains(@class, 'math') and contains(@class, 'code')]".freeze
# Attribute indicating inline or display math. # Attribute indicating inline or display math.
STYLE_ATTRIBUTE = 'data-math-style'.freeze STYLE_ATTRIBUTE = 'data-math-style'.freeze
...@@ -22,13 +16,14 @@ module Banzai ...@@ -22,13 +16,14 @@ module Banzai
DOLLAR_SIGN = '$'.freeze DOLLAR_SIGN = '$'.freeze
def call def call
doc.xpath(INLINE_MATH).each do |code| doc.css('code').each do |code|
closing = code.next closing = code.next
opening = code.previous opening = code.previous
# We need a sibling before and after. # We need a sibling before and after.
# They should end and start with $ respectively. # They should end and start with $ respectively.
if closing && opening && if closing && opening &&
closing.text? && opening.text? &&
closing.content.first == DOLLAR_SIGN && closing.content.first == DOLLAR_SIGN &&
opening.content.last == DOLLAR_SIGN opening.content.last == DOLLAR_SIGN
...@@ -39,7 +34,7 @@ module Banzai ...@@ -39,7 +34,7 @@ module Banzai
end end
end end
doc.xpath(DISPLAY_MATH).each do |el| doc.css('pre.code.math').each do |el|
el[STYLE_ATTRIBUTE] = 'display' el[STYLE_ATTRIBUTE] = 'display'
el[:class] += " #{TAG_CLASS}" el[:class] += " #{TAG_CLASS}"
end end
......
...@@ -21,6 +21,7 @@ FactoryGirl.define do ...@@ -21,6 +21,7 @@ FactoryGirl.define do
trait :build_failed do trait :build_failed do
action { Todo::BUILD_FAILED } action { Todo::BUILD_FAILED }
target factory: :merge_request
end end
trait :approval_required do trait :approval_required do
......
...@@ -47,6 +47,24 @@ feature 'GFM autocomplete', feature: true, js: true do ...@@ -47,6 +47,24 @@ feature 'GFM autocomplete', feature: true, js: true do
expect_to_wrap(true, label_item, note, label.title) expect_to_wrap(true, label_item, note, label.title)
end end
it "does not show drpdown when preceded with a special character" do
note = find('#note_note')
page.within '.timeline-content-form' do
note.native.send_keys('')
note.native.send_keys("@")
note.click
end
expect(page).to have_selector('.atwho-container')
page.within '.timeline-content-form' do
note.native.send_keys("@")
note.click
end
expect(page).to have_selector('.atwho-container', visible: false)
end
it 'doesn\'t wrap for assignee values' do it 'doesn\'t wrap for assignee values' do
note = find('#note_note') note = find('#note_note')
page.within '.timeline-content-form' do page.within '.timeline-content-form' do
......
...@@ -155,5 +155,24 @@ describe 'Dashboard Todos', feature: true do ...@@ -155,5 +155,24 @@ describe 'Dashboard Todos', feature: true do
expect(page).to have_selector('.todos-all-done', count: 1) expect(page).to have_selector('.todos-all-done', count: 1)
end end
end end
context 'User has a Build Failed todo' do
let!(:todo) { create(:todo, :build_failed, user: user, project: project, author: author) }
before do
login_as user
visit dashboard_todos_path
end
it 'shows the todo' do
expect(page).to have_content 'The build failed for your merge request'
end
it 'links to the pipelines for the merge request' do
href = pipelines_namespace_project_merge_request_path(project.namespace, project, todo.target)
expect(page).to have_link "merge request #{todo.target.to_reference}", href
end
end
end end
end end
...@@ -79,6 +79,13 @@ describe Banzai::Filter::MathFilter, lib: true do ...@@ -79,6 +79,13 @@ describe Banzai::Filter::MathFilter, lib: true do
expect(doc.to_s).to eq input expect(doc.to_s).to eq input
end end
it 'ignores dollar signs if they are inside another element' do
input = '<p>We check strictly <em>$</em><code>2+2</code><em>$</em></p>'
doc = filter(input)
expect(doc.to_s).to eq input
end
# Display math # Display math
it 'adds data-math-style display attribute to display math' do it 'adds data-math-style display attribute to display math' do
......
...@@ -36,7 +36,7 @@ describe MattermostSlashCommandsService, :models do ...@@ -36,7 +36,7 @@ describe MattermostSlashCommandsService, :models do
description: "Perform common operations on: #{project.name_with_namespace}", description: "Perform common operations on: #{project.name_with_namespace}",
display_name: "GitLab / #{project.name_with_namespace}", display_name: "GitLab / #{project.name_with_namespace}",
method: 'P', method: 'P',
user_name: 'GitLab' }.to_json). username: 'GitLab' }.to_json).
to_return( to_return(
status: 200, status: 200,
headers: { 'Content-Type' => 'application/json' }, headers: { 'Content-Type' => 'application/json' },
......
...@@ -18,7 +18,8 @@ describe SlackSlashCommandsService, :models do ...@@ -18,7 +18,8 @@ describe SlackSlashCommandsService, :models do
let(:service) do let(:service) do
project.create_slack_slash_commands_service( project.create_slack_slash_commands_service(
properties: { token: 'token' } properties: { token: 'token' },
active: true
) )
end end
......
...@@ -139,6 +139,22 @@ describe Repository, models: true do ...@@ -139,6 +139,22 @@ describe Repository, models: true do
it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') } it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') }
end end
describe '#last_commit_id_for_path' do
subject { repository.last_commit_id_for_path(sample_commit.id, '.gitignore') }
it "returns last commit id for a given path" do
is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8')
end
it "caches last commit id for a given path" do
cache = repository.send(:cache)
key = "last_commit_id_for_path:#{sample_commit.id}:#{Digest::SHA1.hexdigest('.gitignore')}"
expect(cache).to receive(:fetch).with(key).and_return('c1acaa5')
is_expected.to eq('c1acaa5')
end
end
describe '#find_commits_by_message' do describe '#find_commits_by_message' do
it 'returns commits with messages containing a given string' do it 'returns commits with messages containing a given string' do
commit_ids = repository.find_commits_by_message('submodule').map(&:id) commit_ids = repository.find_commits_by_message('submodule').map(&:id)
......
...@@ -932,6 +932,13 @@ describe API::Issues, api: true do ...@@ -932,6 +932,13 @@ describe API::Issues, api: true do
expect(json_response['state']).to eq "closed" expect(json_response['state']).to eq "closed"
end end
it 'reopens a project isssue' do
put api("/projects/#{project.id}/issues/#{closed_issue.id}", user), state_event: 'reopen'
expect(response).to have_http_status(200)
expect(json_response['state']).to eq 'reopened'
end
context 'when an admin or owner makes the request' do context 'when an admin or owner makes the request' do
it 'accepts the update date to be set' do it 'accepts the update date to be set' do
update_time = 2.weeks.ago update_time = 2.weeks.ago
......
...@@ -7,15 +7,47 @@ describe 'projects/pipelines/_stage', :view do ...@@ -7,15 +7,47 @@ describe 'projects/pipelines/_stage', :view do
before do before do
assign :stage, stage assign :stage, stage
end
context 'when there are only latest builds present' do
before do
create(:ci_build, name: 'test:build',
stage: stage.name,
pipeline: pipeline)
end
it 'shows the builds in the stage' do
render
expect(rendered).to have_text 'test:build'
end
end
context 'when build belongs to different stage' do
before do
create(:ci_build, name: 'test:build',
stage: 'other:stage',
pipeline: pipeline)
end
create(:ci_build, name: 'test:build', it 'does not render build' do
stage: stage.name, render
pipeline: pipeline)
expect(rendered).not_to have_text 'test:build'
end
end end
it 'shows the builds in the stage' do context 'when there are retried builds present' do
render before do
create_list(:ci_build, 2, name: 'test:build',
stage: stage.name,
pipeline: pipeline)
end
it 'shows only latest builds' do
render
expect(rendered).to have_text 'test:build' expect(rendered).to have_text 'test:build', count: 1
end
end end
end end
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