Commit bb26c97a authored by Ruben Davila's avatar Ruben Davila

Merge branch 'master' into 8-12-stable

parents 649683c9 f3743798
...@@ -3,6 +3,7 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -3,6 +3,7 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.12.0 (unreleased) v 8.12.0 (unreleased)
- Update the rouge gem to 2.0.6, which adds highlighting support for JSX, Prometheus, and others. !6251 - Update the rouge gem to 2.0.6, which adds highlighting support for JSX, Prometheus, and others. !6251
- Only check :can_resolve permission if the note is resolvable - Only check :can_resolve permission if the note is resolvable
- Bump fog-aws to v0.11.0 to support ap-south-1 region
- Add ability to fork to a specific namespace using API. (ritave) - Add ability to fork to a specific namespace using API. (ritave)
- Cleanup misalignments in Issue list view !6206 - Cleanup misalignments in Issue list view !6206
- Prune events older than 12 months. (ritave) - Prune events older than 12 months. (ritave)
...@@ -29,6 +30,7 @@ v 8.12.0 (unreleased) ...@@ -29,6 +30,7 @@ v 8.12.0 (unreleased)
- Fix file permissions change when updating a file on the Gitlab UI !5979 - Fix file permissions change when updating a file on the Gitlab UI !5979
- Change merge_error column from string to text type - Change merge_error column from string to text type
- Reduce contributions calendar data payload (ClemMakesApps) - Reduce contributions calendar data payload (ClemMakesApps)
- Replace contributions calendar timezone payload with dates (ClemMakesApps)
- Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel) - Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel)
- Enable pipeline events by default !6278 - Enable pipeline events by default !6278
- Move parsing of sidekiq ps into helper !6245 (pascalbetz) - Move parsing of sidekiq ps into helper !6245 (pascalbetz)
...@@ -71,6 +73,7 @@ v 8.12.0 (unreleased) ...@@ -71,6 +73,7 @@ v 8.12.0 (unreleased)
- Show queued time when showing a pipeline !6084 - Show queued time when showing a pipeline !6084
- Remove unused mixins (ClemMakesApps) - Remove unused mixins (ClemMakesApps)
- Add search to all issue board lists - Add search to all issue board lists
- Scroll active tab into view on mobile
- Fix groups sort dropdown alignment (ClemMakesApps) - Fix groups sort dropdown alignment (ClemMakesApps)
- Add horizontal scrolling to all sub-navs on mobile viewports (ClemMakesApps) - Add horizontal scrolling to all sub-navs on mobile viewports (ClemMakesApps)
- Use JavaScript tooltips for mentions !5301 (winniehell) - Use JavaScript tooltips for mentions !5301 (winniehell)
...@@ -167,6 +170,7 @@ v 8.11.5 ...@@ -167,6 +170,7 @@ v 8.11.5
- Scope webhooks/services that will run for confidential issues - Scope webhooks/services that will run for confidential issues
- Remove gitorious from import_sources - Remove gitorious from import_sources
- Fix confidential issues being exposed as public using gitlab.com export - Fix confidential issues being exposed as public using gitlab.com export
- Use oj gem for faster JSON processing
v 8.11.4 v 8.11.4
- Fix resolving conflicts on forks. !6082 - Fix resolving conflicts on forks. !6082
......
...@@ -206,6 +206,9 @@ gem 'mousetrap-rails', '~> 1.4.6' ...@@ -206,6 +206,9 @@ gem 'mousetrap-rails', '~> 1.4.6'
# Detect and convert string character encoding # Detect and convert string character encoding
gem 'charlock_holmes', '~> 0.7.3' gem 'charlock_holmes', '~> 0.7.3'
# Faster JSON
gem 'oj', '~> 2.17.4'
# Parse time & duration # Parse time & duration
gem 'chronic', '~> 0.10.2' gem 'chronic', '~> 0.10.2'
gem 'chronic_duration', '~> 0.10.6' gem 'chronic_duration', '~> 0.10.6'
......
...@@ -189,7 +189,7 @@ GEM ...@@ -189,7 +189,7 @@ GEM
erubis (2.7.0) erubis (2.7.0)
escape_utils (1.1.1) escape_utils (1.1.1)
eventmachine (1.0.8) eventmachine (1.0.8)
excon (0.49.0) excon (0.52.0)
execjs (2.6.0) execjs (2.6.0)
expression_parser (0.9.0) expression_parser (0.9.0)
factory_girl (4.5.0) factory_girl (4.5.0)
...@@ -215,8 +215,8 @@ GEM ...@@ -215,8 +215,8 @@ GEM
flowdock (0.7.1) flowdock (0.7.1)
httparty (~> 0.7) httparty (~> 0.7)
multi_json multi_json
fog-aws (0.9.2) fog-aws (0.11.0)
fog-core (~> 1.27) fog-core (~> 1.38)
fog-json (~> 1.0) fog-json (~> 1.0)
fog-xml (~> 0.1) fog-xml (~> 0.1)
ipaddress (~> 0.8) ipaddress (~> 0.8)
...@@ -225,7 +225,7 @@ GEM ...@@ -225,7 +225,7 @@ GEM
fog-core (~> 1.27) fog-core (~> 1.27)
fog-json (~> 1.0) fog-json (~> 1.0)
fog-xml (~> 0.1) fog-xml (~> 0.1)
fog-core (1.40.0) fog-core (1.42.0)
builder builder
excon (~> 0.49) excon (~> 0.49)
formatador (~> 0.2) formatador (~> 0.2)
...@@ -427,6 +427,7 @@ GEM ...@@ -427,6 +427,7 @@ GEM
rack (>= 1.2, < 3) rack (>= 1.2, < 3)
octokit (4.3.0) octokit (4.3.0)
sawyer (~> 0.7.0, >= 0.5.3) sawyer (~> 0.7.0, >= 0.5.3)
oj (2.17.4)
omniauth (1.3.1) omniauth (1.3.1)
hashie (>= 1.2, < 4) hashie (>= 1.2, < 4)
rack (>= 1.0, < 3) rack (>= 1.0, < 3)
...@@ -904,6 +905,7 @@ DEPENDENCIES ...@@ -904,6 +905,7 @@ DEPENDENCIES
nokogiri (~> 1.6.7, >= 1.6.7.2) nokogiri (~> 1.6.7, >= 1.6.7.2)
oauth2 (~> 1.2.0) oauth2 (~> 1.2.0)
octokit (~> 4.3.0) octokit (~> 4.3.0)
oj (~> 2.17.4)
omniauth (~> 1.3.1) omniauth (~> 1.3.1)
omniauth-auth0 (~> 1.4.1) omniauth-auth0 (~> 1.4.1)
omniauth-azure-oauth2 (~> 0.0.6) omniauth-azure-oauth2 (~> 0.0.6)
......
...@@ -10,11 +10,13 @@ ...@@ -10,11 +10,13 @@
}; };
$(function() { $(function() {
hideEndFade($('.scrolling-tabs')); var $scrollingTabs = $('.scrolling-tabs');
hideEndFade($scrollingTabs);
$(window).off('resize.nav').on('resize.nav', function() { $(window).off('resize.nav').on('resize.nav', function() {
return hideEndFade($('.scrolling-tabs')); return hideEndFade($scrollingTabs);
}); });
return $('.scrolling-tabs').on('scroll', function(event) { $scrollingTabs.off('scroll').on('scroll', function(event) {
var $this, currentPosition, maxPosition; var $this, currentPosition, maxPosition;
$this = $(this); $this = $(this);
currentPosition = $this.scrollLeft(); currentPosition = $this.scrollLeft();
...@@ -22,6 +24,23 @@ ...@@ -22,6 +24,23 @@
$this.siblings('.fade-left').toggleClass('scrolling', currentPosition > 0); $this.siblings('.fade-left').toggleClass('scrolling', currentPosition > 0);
return $this.siblings('.fade-right').toggleClass('scrolling', currentPosition < maxPosition - 1); return $this.siblings('.fade-right').toggleClass('scrolling', currentPosition < maxPosition - 1);
}); });
$scrollingTabs.each(function () {
var $this = $(this),
scrollingTabWidth = $this.width(),
$active = $this.find('.active'),
activeWidth = $active.width();
if ($active.length) {
var offset = $active.offset().left + activeWidth;
if (offset > scrollingTabWidth - 30) {
var scrollLeft = scrollingTabWidth / 2;
scrollLeft = (offset - scrollLeft) - (activeWidth / 2);
$this.scrollLeft(scrollLeft);
}
}
});
}); });
}).call(this); }).call(this);
...@@ -232,10 +232,10 @@ ...@@ -232,10 +232,10 @@
$('.hll').removeClass('hll'); $('.hll').removeClass('hll');
locationHash = window.location.hash; locationHash = window.location.hash;
if (locationHash !== '') { if (locationHash !== '') {
hashClassString = "." + (locationHash.replace('#', '')); dataLineString = '[data-line-code="' + locationHash.replace('#', '') + '"]';
$diffLine = $(locationHash + ":not(.match)", $('#diffs')); $diffLine = $(locationHash + ":not(.match)", $('#diffs'));
if (!$diffLine.is('tr')) { if (!$diffLine.is('tr')) {
$diffLine = $('#diffs').find("td" + locationHash + ", td" + hashClassString); $diffLine = $('#diffs').find("td" + locationHash + ", td" + dataLineString);
} else { } else {
$diffLine = $diffLine.find('td'); $diffLine = $diffLine.find('td');
} }
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
date.setDate(date.getDate() + i); date.setDate(date.getDate() + i);
var day = date.getDay(); var day = date.getDay();
var count = timestamps[date.getTime() * 0.001]; var count = timestamps[dateFormat(date, 'yyyy-mm-dd')];
// Create a new group array if this is the first day of the week // Create a new group array if this is the first day of the week
// or if is first object // or if is first object
......
...@@ -164,7 +164,7 @@ ...@@ -164,7 +164,7 @@
text-decoration: none; text-decoration: none;
&:after { &:after {
content: url('icon_anchor.svg'); content: image-url('icon_anchor.svg');
visibility: hidden; visibility: hidden;
} }
} }
......
lex
[v-cloak] { [v-cloak] {
display: none; display: none;
} }
...@@ -18,6 +19,10 @@ ...@@ -18,6 +19,10 @@
} }
} }
.is-ghost {
opacity: 0.3;
}
.dropdown-menu-issues-board-new { .dropdown-menu-issues-board-new {
width: 320px; width: 320px;
...@@ -34,47 +39,13 @@ ...@@ -34,47 +39,13 @@
> p { > p {
margin: 0; margin: 0;
font-size: 14px; font-size: 14px;
color: #9c9c9c;
} }
} }
.issue-boards-page { .issue-boards-page {
.content-wrapper {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
}
.sub-nav,
.issues-filters {
-webkit-flex: none;
flex: none;
}
.page-with-sidebar { .page-with-sidebar {
display: -webkit-flex;
display: flex;
min-height: 100vh;
max-height: 100vh;
padding-bottom: 0; padding-bottom: 0;
} }
.issue-boards-content {
display: -webkit-flex;
display: flex;
-webkit-flex: 1;
flex: 1;
width: 100%;
.content {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
width: 100%;
}
}
} }
.boards-app-loading { .boards-app-loading {
...@@ -83,46 +54,38 @@ ...@@ -83,46 +54,38 @@
} }
.boards-list { .boards-list {
display: -webkit-flex; height: calc(100vh - 152px);
display: flex; width: 100%;
-webkit-flex: 1;
flex: 1;
-webkit-flex-basis: 0;
flex-basis: 0;
min-height: calc(100vh - 152px);
max-height: calc(100vh - 152px);
padding-top: 25px; padding-top: 25px;
padding-bottom: 25px;
padding-right: ($gl-padding / 2); padding-right: ($gl-padding / 2);
padding-left: ($gl-padding / 2); padding-left: ($gl-padding / 2);
overflow-x: scroll; overflow-x: scroll;
white-space: nowrap;
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
height: 475px; // Needed for PhantomJS
height: calc(100vh - 220px);
min-height: 475px; min-height: 475px;
max-height: none;
} }
} }
.board { .board {
display: -webkit-flex; display: inline-block;
display: flex; width: calc(85vw - 15px);
min-width: calc(85vw - 15px); height: 100%;
max-width: calc(85vw - 15px);
margin-bottom: 25px;
padding-right: ($gl-padding / 2); padding-right: ($gl-padding / 2);
padding-left: ($gl-padding / 2); padding-left: ($gl-padding / 2);
white-space: normal;
vertical-align: top;
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
min-width: 400px; width: 400px;
max-width: 400px;
} }
} }
.board-inner { .board-inner {
display: -webkit-flex; height: 100%;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
width: 100%;
font-size: $issue-boards-font-size; font-size: $issue-boards-font-size;
background: $background-color; background: $background-color;
border: 1px solid $border-color; border: 1px solid $border-color;
...@@ -193,45 +156,31 @@ ...@@ -193,45 +156,31 @@
} }
.board-list { .board-list {
-webkit-flex: 1; height: calc(100% - 49px);
flex: 1;
height: 400px;
margin-bottom: 0; margin-bottom: 0;
padding: 5px; padding: 5px;
list-style: none;
overflow-y: scroll; overflow-y: scroll;
overflow-x: hidden; overflow-x: hidden;
} }
.board-list-loading { .board-list-loading {
margin-top: 10px; margin-top: 10px;
font-size: 26px; font-size: (26px / $issue-boards-font-size) * 1em;
}
.is-ghost {
opacity: 0.3;
} }
.card { .card {
position: relative; position: relative;
width: 100%;
padding: 10px $gl-padding; padding: 10px $gl-padding;
background: #fff; background: #fff;
border-radius: $border-radius-default; border-radius: $border-radius-default;
box-shadow: 0 1px 2px rgba(186, 186, 186, 0.5); box-shadow: 0 1px 2px rgba(186, 186, 186, 0.5);
list-style: none; list-style: none;
&.user-can-drag {
padding-left: $gl-padding;
}
&:not(:last-child) { &:not(:last-child) {
margin-bottom: 5px; margin-bottom: 5px;
} }
a {
cursor: pointer;
}
.label { .label {
border: 0; border: 0;
outline: 0; outline: 0;
...@@ -256,14 +205,13 @@ ...@@ -256,14 +205,13 @@
line-height: 25px; line-height: 25px;
.label { .label {
margin-right: 4px; margin-right: 5px;
font-size: (14px / $issue-boards-font-size) * 1em; font-size: (14px / $issue-boards-font-size) * 1em;
} }
} }
.card-number { .card-number {
margin-right: 8px; margin-right: 5px;
font-weight: 500;
} }
.issue-boards-search { .issue-boards-search {
......
...@@ -73,7 +73,7 @@ class UsersController < ApplicationController ...@@ -73,7 +73,7 @@ class UsersController < ApplicationController
def calendar def calendar
calendar = contributions_calendar calendar = contributions_calendar
@timestamps = calendar.timestamps @activity_dates = calendar.activity_dates
render 'calendar', layout: false render 'calendar', layout: false
end end
......
...@@ -10,12 +10,16 @@ ...@@ -10,12 +10,16 @@
in group #{link_to @group.name, @group} in group #{link_to @group.name, @group}
.results.prepend-top-10 .results.prepend-top-10
.search-results - if @scope == 'commits'
- if @scope == 'projects' %ul.list-unstyled
.term = render partial: "search/results/commit", collection: @search_objects
= render 'shared/projects/list', projects: @search_objects - else
- else .search-results
= render partial: "search/results/#{@scope.singularize}", collection: @search_objects - if @scope == 'projects'
.term
= render 'shared/projects/list', projects: @search_objects
- else
= render partial: "search/results/#{@scope.singularize}", collection: @search_objects
- if @scope != 'projects' - if @scope != 'projects'
= paginate(@search_objects, theme: 'gitlab') = paginate(@search_objects, theme: 'gitlab')
.search-result-row = render 'projects/commits/commit', project: @project, commit: commit
= render 'projects/commits/commit', project: @project, commit: commit
...@@ -4,6 +4,6 @@ ...@@ -4,6 +4,6 @@
Summary of issues, merge requests, and push events Summary of issues, merge requests, and push events
:javascript :javascript
new Calendar( new Calendar(
#{@timestamps.to_json}, #{@activity_dates.to_json},
'#{user_calendar_activities_path}' '#{user_calendar_activities_path}'
); );
\ No newline at end of file
...@@ -78,7 +78,8 @@ Parameters: ...@@ -78,7 +78,8 @@ Parameters:
### Create new issue note ### Create new issue note
Creates a new note to a single project issue. Creates a new note to a single project issue. If you create a note where the body
only contains an Award Emoji, you'll receive this object back.
``` ```
POST /projects/:id/issues/:issue_id/notes POST /projects/:id/issues/:issue_id/notes
...@@ -204,6 +205,7 @@ Parameters: ...@@ -204,6 +205,7 @@ Parameters:
### Create new snippet note ### Create new snippet note
Creates a new note for a single snippet. Snippet notes are comments users can post to a snippet. Creates a new note for a single snippet. Snippet notes are comments users can post to a snippet.
If you create a note where the body only contains an Award Emoji, you'll receive this object back.
``` ```
POST /projects/:id/snippets/:snippet_id/notes POST /projects/:id/snippets/:snippet_id/notes
...@@ -332,6 +334,8 @@ Parameters: ...@@ -332,6 +334,8 @@ Parameters:
### Create new merge request note ### Create new merge request note
Creates a new note for a single merge request. Creates a new note for a single merge request.
If you create a note where the body only contains an Award Emoji, you'll receive
this object back.
``` ```
POST /projects/:id/merge_requests/:merge_request_id/notes POST /projects/:id/merge_requests/:merge_request_id/notes
......
...@@ -67,7 +67,7 @@ PUT /application/settings ...@@ -67,7 +67,7 @@ PUT /application/settings
| `default_snippet_visibility` | integer | no | What visibility level new snippets receive. Can take `0` _(Private)_, `1` _(Internal)_ and `2` _(Public)_ as a parameter. Default is `0`.| | `default_snippet_visibility` | integer | no | What visibility level new snippets receive. Can take `0` _(Private)_, `1` _(Internal)_ and `2` _(Public)_ as a parameter. Default is `0`.|
| `domain_whitelist` | array of strings | no | Force people to use only corporate emails for sign-up. Default is null, meaning there is no restriction. | | `domain_whitelist` | array of strings | no | Force people to use only corporate emails for sign-up. Default is null, meaning there is no restriction. |
| `domain_blacklist_enabled` | boolean | no | Enable/disable the `domain_blacklist` | | `domain_blacklist_enabled` | boolean | no | Enable/disable the `domain_blacklist` |
| `domain_blacklist` | array of strings | yes (if `domain_whitelist_enabled` is `true` | People trying to sign-up with emails from this domain will not be allowed to do so. | | `domain_blacklist` | array of strings | yes (if `domain_blacklist_enabled` is `true`) | People trying to sign-up with emails from this domain will not be allowed to do so. |
| `user_oauth_applications` | boolean | no | Allow users to register any application to use GitLab as an OAuth provider | | `user_oauth_applications` | boolean | no | Allow users to register any application to use GitLab as an OAuth provider |
| `after_sign_out_path` | string | no | Where to redirect users after logout | | `after_sign_out_path` | string | no | Where to redirect users after logout |
| `container_registry_token_expire_delay` | integer | no | Container Registry token duration in minutes | | `container_registry_token_expire_delay` | integer | no | Container Registry token duration in minutes |
......
...@@ -16,4 +16,4 @@ Apart from those, here is an collection of tutorials and guides on setting up yo ...@@ -16,4 +16,4 @@ Apart from those, here is an collection of tutorials and guides on setting up yo
- [Repo's with examples for various languages](https://gitlab.com/groups/gitlab-examples) - [Repo's with examples for various languages](https://gitlab.com/groups/gitlab-examples)
- [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml) - [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml)
[gitlab-ci-templates][https://gitlab.com/gitlab-org/gitlab-ci-yml] [gitlab-ci-templates]: https://gitlab.com/gitlab-org/gitlab-ci-yml
...@@ -78,9 +78,9 @@ delete them. ...@@ -78,9 +78,9 @@ delete them.
> **Note:** > **Note:**
This feature requires GitLab 8.8 and GitLab Runner 1.2. This feature requires GitLab 8.8 and GitLab Runner 1.2.
Make sure that your GitLab Runner is configured to allow building docker images. Make sure that your GitLab Runner is configured to allow building Docker images by
You have to check the [Using Docker Build documentation](../ci/docker/using_docker_build.md). following the [Using Docker Build](../ci/docker/using_docker_build.md)
Then see the CI documentation on [Using the GitLab Container Registry](../ci/docker/using_docker_build.md#using-the-gitlab-container-registry). and [Using the GitLab Container Registry documentation](../ci/docker/using_docker_build.md#using-the-gitlab-container-registry).
## Limitations ## Limitations
......
...@@ -79,6 +79,9 @@ gitlab_rails['backup_upload_connection'] = { ...@@ -79,6 +79,9 @@ gitlab_rails['backup_upload_connection'] = {
'region' => 'eu-west-1', 'region' => 'eu-west-1',
'aws_access_key_id' => 'AKIAKIAKI', 'aws_access_key_id' => 'AKIAKIAKI',
'aws_secret_access_key' => 'secret123' 'aws_secret_access_key' => 'secret123'
# If using an IAM Profile, leave aws_access_key_id & aws_secret_access_key empty
# ie. 'aws_access_key_id' => '',
# 'use_iam_profile' => 'true'
} }
gitlab_rails['backup_upload_remote_directory'] = 'my.s3.bucket' gitlab_rails['backup_upload_remote_directory'] = 'my.s3.bucket'
``` ```
...@@ -95,6 +98,9 @@ For installations from source: ...@@ -95,6 +98,9 @@ For installations from source:
region: eu-west-1 region: eu-west-1
aws_access_key_id: AKIAKIAKI aws_access_key_id: AKIAKIAKI
aws_secret_access_key: 'secret123' aws_secret_access_key: 'secret123'
# If using an IAM Profile, leave aws_access_key_id & aws_secret_access_key empty
# ie. aws_access_key_id: ''
# use_iam_profile: 'true'
# The remote 'directory' to store your backups. For S3, this would be the bucket name. # The remote 'directory' to store your backups. For S3, this would be the bucket name.
remote_directory: 'my.s3.bucket' remote_directory: 'my.s3.bucket'
# Turns on AWS Server-Side Encryption with Amazon S3-Managed Keys for backups, this is optional # Turns on AWS Server-Side Encryption with Amazon S3-Managed Keys for backups, this is optional
......
...@@ -101,4 +101,36 @@ inside GitLab that make that possible. ...@@ -101,4 +101,36 @@ inside GitLab that make that possible.
![Build artifacts browser](img/build_artifacts_browser.png) ![Build artifacts browser](img/build_artifacts_browser.png)
## Downloading the latest build artifacts
It is possible to download the latest artifacts of a build via a well known URL
so you can use it for scripting purposes.
The structure of the URL is the following:
```
https://example.com/<namespace>/<project>/builds/artifacts/<ref>/download?job=<job_name>
```
For example, to download the latest artifacts of the job named `rspec 6 20` of
the `master` branch of the `gitlab-ce` project that belongs to the `gitlab-org`
namespace, the URL would be:
```
https://gitlab.com/gitlab-org/gitlab-ce/builds/artifacts/master/download?job=rspec+6+20
```
The latest builds are also exposed in the UI in various places. Specifically,
look for the download button in:
- the main project's page
- the branches page
- the tags page
If the latest build has failed to upload the artifacts, you can see that
information in the UI.
![Latest artifacts button](img/build_latest_artifacts_browser.png)
[gitlab workhorse]: https://gitlab.com/gitlab-org/gitlab-workhorse "GitLab Workhorse repository" [gitlab workhorse]: https://gitlab.com/gitlab-org/gitlab-workhorse "GitLab Workhorse repository"
# Import your project from GitHub to GitLab # Import your project from GitHub to GitLab
Import your projects from GitHub to GitLab with minimal effort.
## Overview
>**Note:** >**Note:**
In order to enable the GitHub import setting, you may also want to If you are an administrator you can enable the [GitHub integration][gh-import]
enable the [GitHub integration][gh-import] in your GitLab instance. This in your GitLab instance sitewide. This configuration is optional, users will be
configuration is optional, you will be able import your GitHub repositories able import their GitHub repositories with a [personal access token][gh-token].
with a Personal Access Token.
At its current state, GitHub importer can import: - At its current state, GitHub importer can import:
- the repository description (GitLab 7.7+)
- the Git repository data (GitLab 7.7+)
- the issues (GitLab 7.7+)
- the pull requests (GitLab 8.4+)
- the wiki pages (GitLab 8.4+)
- the milestones (GitLab 8.7+)
- the labels (GitLab 8.7+)
- the release note descriptions (GitLab 8.12+)
- References to pull requests and issues are preserved (GitLab 8.7+)
- Repository public access is retained. If a repository is private in GitHub
it will be created as private in GitLab as well.
- the repository description (introduced in GitLab 7.7) ## How it works
- the git repository data (introduced in GitLab 7.7)
- the issues (introduced in GitLab 7.7)
- the pull requests (introduced in GitLab 8.4)
- the wiki pages (introduced in GitLab 8.4)
- the milestones (introduced in GitLab 8.7)
- the labels (introduced in GitLab 8.7)
- the release note descriptions (introduced in GitLab 8.12)
With GitLab 8.7+, references to pull requests and issues are preserved. When issues/pull requests are being imported, the GitHub importer tries to find
the GitHub author/assignee in GitLab's database using the GitHub ID. For this
to work, the GitHub author/assignee should have signed in beforehand in GitLab
and [**associated their GitHub account**][social sign-in]. If the user is not
found in GitLab's database, the project creator (most of the times the current
user that started the import process) is set as the author, but a reference on
the issue about the original GitHub author is kept.
The importer page is visible when you [create a new project][new-project]. The importer will create any new namespaces (groups) if they don't exist or in
Click on the **GitHub** link and, if you are logged in via the GitHub the case the namespace is taken, the repository will be imported under the user's
integration, you will be redirected to GitHub for permission to access your namespace that started the import process.
projects. After accepting, you'll be automatically redirected to the importer.
If you are not using the GitHub integration, you can still perform a one-off ## Importing your GitHub repositories
authorization with GitHub to access your projects.
Alternatively, you can also enter a GitHub Personal Access Token. Once you enter The importer page is visible when you create a new project.
your token, you'll be taken to the importer.
![New project page on GitLab](img/import_projects_from_github_new_project_page.png) ![New project page on GitLab](img/import_projects_from_github_new_project_page.png)
--- Click on the **GitHub** link and the import authorization process will start.
There are two ways to authorize access to your GitHub repositories:
While at the GitHub importer page, you can see the import statuses of your 1. [Using the GitHub integration][gh-integration] (if it's enabled by your
GitHub projects. Those that are being imported will show a _started_ status, GitLab administrator). This is the preferred way as it's possible to
those already imported will be green, whereas those that are not yet imported preserve the GitHub authors/assignees. Read more in the [How it works](#how-it-works)
have an **Import** button on the right side of the table. If you want, you can section.
import all your GitHub projects in one go by hitting **Import all projects** 1. [Using a personal access token][gh-token] provided by GitHub.
in the upper left corner.
![GitHub importer page](img/import_projects_from_github_importer.png) ![Select authentication method](img/import_projects_from_github_select_auth_method.png)
### Authorize access to your repositories using the GitHub integration
--- If the [GitHub integration][gh-import] is enabled by your GitLab administrator,
you can use it instead of the personal access token.
1. First you may want to connect your GitHub account to GitLab in order for
the username mapping to be correct. Follow the [social sign-in] documentation
on how to do so.
1. Once you connect GitHub, click the **List your GitHub repositories** button
and you will be redirected to GitHub for permission to access your projects.
1. After accepting, you'll be automatically redirected to the importer.
You can now go on and [select which repositories to import](#select-which-repositories-to-import).
### Authorize access to your repositories using a personal access token
>**Note:**
For a proper author/assignee mapping for issues and pull requests, the
[GitHub integration][gh-integration] should be used instead of the
[personal access token][gh-token]. If the GitHub integration is enabled by your
GitLab administrator, it should be the preferred method to import your repositories.
Read more in the [How it works](#how-it-works) section.
The importer will create any new namespaces if they don't exist or in the If you are not using the GitHub integration, you can still perform a one-off
case the namespace is taken, the project will be imported on the user's authorization with GitHub to grant GitLab access your repositories:
namespace.
1. Go to <https://github.com/settings/tokens/new>.
1. Enter a token description.
1. Check the `repo` scope.
1. Click **Generate token**.
1. Copy the token hash.
1. Go back to GitLab and provide the token to the GitHub importer.
1. Hit the **List your GitHub repositories** button and wait while GitLab reads
your repositories' information. Once done, you'll be taken to the importer
page to select the repositories to import.
### Select which repositories to import
After you've authorized access to your GitHub repositories, you will be
redirected to the GitHub importer page.
From there, you can see the import statuses of your GitHub repositories.
- Those that are being imported will show a _started_ status,
- those already successfully imported will be green with a _done_ status,
- whereas those that are not yet imported will 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)
[gh-import]: ../../integration/github.md "GitHub integration" [gh-import]: ../../integration/github.md "GitHub integration"
[ee-gh]: http://docs.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" [new-project]: ../../gitlab-basics/create-project.md "How to create a new project in GitLab"
[gh-integration]: #authorize-access-to-your-repositories-using-the-github-integration
[gh-token]: #authorize-access-to-your-repositories-using-a-personal-access-token
[social sign-in]: ../../profile/account/social_sign_in.md
...@@ -83,12 +83,12 @@ module API ...@@ -83,12 +83,12 @@ module API
opts[:created_at] = params[:created_at] opts[:created_at] = params[:created_at]
end end
@note = ::Notes::CreateService.new(user_project, current_user, opts).execute note = ::Notes::CreateService.new(user_project, current_user, opts).execute
if @note.valid? if note.valid?
present @note, with: Entities::Note present note, with: Entities::const_get(note.class.name)
else else
not_found!("Note #{@note.errors.messages}") not_found!("Note #{note.errors.messages}")
end end
end end
......
module Gitlab module Gitlab
class ContributionsCalendar class ContributionsCalendar
attr_reader :timestamps, :projects, :user attr_reader :activity_dates, :projects, :user
def initialize(projects, user) def initialize(projects, user)
@projects = projects @projects = projects
@user = user @user = user
end end
def timestamps def activity_dates
return @timestamps if @timestamps.present? return @activity_dates if @activity_dates.present?
@timestamps = {} @activity_dates = {}
date_from = 1.year.ago date_from = 1.year.ago
events = Event.reorder(nil).contributions.where(author_id: user.id). events = Event.reorder(nil).contributions.where(author_id: user.id).
...@@ -19,18 +19,17 @@ module Gitlab ...@@ -19,18 +19,17 @@ module Gitlab
select('date(created_at) as date, count(id) as total_amount'). select('date(created_at) as date, count(id) as total_amount').
map(&:attributes) map(&:attributes)
dates = (1.year.ago.to_date..Date.today).to_a activity_dates = (1.year.ago.to_date..Date.today).to_a
dates.each do |date| activity_dates.each do |date|
date_id = date.to_time.to_i.to_s
day_events = events.find { |day_events| day_events["date"] == date } day_events = events.find { |day_events| day_events["date"] == date }
if day_events if day_events
@timestamps[date_id] = day_events["total_amount"] @activity_dates[date] = day_events["total_amount"]
end end
end end
@timestamps @activity_dates
end end
def events_by_date(date) def events_by_date(date)
......
require 'spec_helper'
feature 'Contributions Calendar', js: true, feature: true do
include WaitForAjax
let(:contributed_project) { create(:project, :public) }
before do
login_as :user
issue_params = { title: 'Bug in old browser' }
Issues::CreateService.new(contributed_project, @user, issue_params).execute
# Push code contribution
push_params = {
project: contributed_project,
action: Event::PUSHED,
author_id: @user.id,
data: { commit_count: 3 }
}
Event.create(push_params)
visit @user.username
wait_for_ajax
end
it 'displays calendar', js: true do
expect(page).to have_css('.js-contrib-calendar')
end
it 'displays calendar activity log', js: true do
expect(find('.content_list .event-note')).to have_content "Bug in old browser"
end
it 'displays calendar activity square color', js: true do
expect(page).to have_selector('.user-contrib-cell[fill=\'#acd5f2\']', count: 1)
end
end
...@@ -220,6 +220,15 @@ describe API::API, api: true do ...@@ -220,6 +220,15 @@ describe API::API, api: true do
expect(Time.parse(json_response['created_at'])).to be_within(1.second).of(creation_time) expect(Time.parse(json_response['created_at'])).to be_within(1.second).of(creation_time)
end end
end end
context 'when the user is posting an award emoji' do
it 'returns an award emoji' do
post api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: ':+1:'
expect(response).to have_http_status(201)
expect(json_response['awardable_id']).to eq issue.id
end
end
end end
context "when noteable is a Snippet" do context "when noteable is a Snippet" do
......
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