Commit b7dc48a4 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'master' into ee-fl-prettify

* master: (52 commits)
  Add 2FA filter to users API for admins only
  Remove Web IDE feature flag from docs
  Removes 'no job log' from trace action
  Resolve conflicts in app/models/milestone.rb
  Resolve conflicts in db/schema.rb
  "Geo: schedule a git repack after initial clone"
  It is stable since it works.
  Add docs for background verification
  Lock mysql image to 5.7 for `use-mysql-with-elasticsearch`
  Dedupe yarn dependencies
  Merge branch 'sh-downgrade-mysql-ci' into 'master'
  Fix conflict related to LfsFileLock block
  Resolve CHANGELOG.md by using CE's version
  Downgrade MySQL CI service from 8.0 to 5.7
  CE->EE: Fix conflicts relating to project snapshots
  Warn admin 60 may be removed from protected branch levels
  Fix conflict: app/assets/javascripts/boards/models/list.js
  Atomic internal ids for all models
  EE-port for "Atomic internal ids for all models"
  Fix conflicts in db/schema.rb
  ...
parents a580d399 16eb5607
......@@ -80,7 +80,7 @@ stages:
.use-mysql: &use-mysql
services:
- mysql:latest
- mysql:5.7
- redis:alpine
# BEGIN EE-only service helpers
......@@ -103,7 +103,7 @@ stages:
.use-mysql-with-elasticsearch: &use-mysql-with-elasticsearch
services:
- mysql:latest
- mysql:5.7
- redis:alpine
- docker.elastic.co/elasticsearch/elasticsearch:5.5.2
......
......@@ -13,8 +13,9 @@ entry.
- Fix XSS on diff view stored on filenames.
- Fix GitLab Auth0 integration signing in the wrong user.
### Fixed (63 changes, 20 of them are from the community)
### Fixed (65 changes, 20 of them are from the community)
- File uploads in remote storage now support project renaming. !4597
- Fixed bug in dropdown selector when selecting the same selection again. !14631 (bitsapien)
- Fixed group deletion linked to Mattermost. !16209 (Julien Millau)
- Create commit API and Web IDE obey LFS filters. !16718
......@@ -55,9 +56,9 @@ entry.
- Work around Prometheus Helm chart name changes to fix integration. !18206 (joshlambert)
- Prioritize weight over title when sorting charts. !18233
- Verify that deploy token has valid access when pulling container registry image. !18260
- Ensure hooks run when a deploy key without a user pushes.
- Stop redirecting the page in pipeline main actions.
- Fixed IDE button opening the wrong URL in tree list.
- Ensure hooks run when a deploy key without a user pushes.
- Fix 404 in group boards when moving issue between lists.
- Display state indicator for issuable references in non-project scope (e.g. when referencing issuables from group scope).
- Add missing port to artifact links.
......@@ -66,12 +67,13 @@ entry.
- Don't show Jump to Discussion button on Issues.
- Fix bug rendering group icons when forking.
- Automatically cleanup stale worktrees and lock files upon a push.
- Use the GitLab version as part of the appearances cache key.
- Fix Firefox stealing formatting characters on issue notes.
- Include matching branches and tags in protected branches / tags count. (Jan Beckmann)
- Fix relative uri when "#" is in branch name. (Jan)
- Test if remote repository exists when importing wikis.
- Fix 500 error when a merge request from a fork has conflicts and has not yet been updated.
- Test if remote repository exists when importing wikis.
- Hide emoji popup after multiple spaces. (Jan Beckmann)
- Fix relative uri when "#" is in branch name. (Jan)
- Escape Markdown characters properly when using autocomplete.
- Ignore project internal references in group context.
- Fix finding wiki file when Gitaly is enabled.
......@@ -108,7 +110,7 @@ entry.
- Fixes remove source branch checkbox being visible when user cannot remove the branch.
- Make /-/ delimiter optional for search endpoints.
### Performance (25 changes, 11 of them are from the community)
### Performance (24 changes, 11 of them are from the community)
- Move AssigneeTitle vue component. !17397 (George Tsiolis)
- Move TimeTrackingCollapsedState vue component. !17399 (George Tsiolis)
......@@ -128,7 +130,6 @@ entry.
- Cache personal projects count. !18197
- Reduce complexity of issuable finder query. !18219
- Reduce number of queries when viewing a merge request.
- Support Markdown rendering using multiple projects.
- Free open file descriptors and libgit2 buffers in UpdatePagesService.
- Memoize Git::Repository#has_visible_content?.
- Require at least one filter when listing issues or merge requests on dashboard page.
......@@ -136,7 +137,7 @@ entry.
- Bulk deleting refs is handled by Gitaly by default.
- ListCommitsByOid is executed by Gitaly by default.
### Added (37 changes, 7 of them are from the community)
### Added (38 changes, 7 of them are from the community)
- Add HTTPS-only pages. !16273 (rfwatson)
- adds closed by informations in issue api. !17042 (haseebeqx)
......@@ -144,6 +145,7 @@ entry.
- Add per-runner configured job timeout. !17221
- Add alternate archive route for simplified packaging. !17225
- Add support for pipeline variables expressions in only/except. !17316
- Add object storage support for LFS objects, CI artifacts, and uploads. !17358
- Added confirmation modal for changing username. !17405
- Implement foreground verification of CI artifacts. !17578
- Extend API for exporting a project with direct upload URL. !17686
......@@ -164,9 +166,9 @@ entry.
- Support LFS objects when importing/exporting GitLab project archives. !18115
- Store sha256 checksum of artifact metadata. !18149
- Limit the number of failed logins when using LDAP for authentication. !43525
- Allow to store uploads by default on Object Storage.
- Allow assigning and filtering issuables by ancestor group labels.
- Include subgroup issues when searching for group issues using the API.
- Allow to store uploads by default on Object Storage.
- Add slash command for moving issues. (Adam Pahlevi)
- Render MR commit SHA instead "diffs" when viable.
- Send @mention notifications even if a user has explicitly unsubscribed from item.
......@@ -209,7 +211,7 @@ entry.
## 10.6.4 (2018-04-09)
### Fixed (9 changes, 1 of them is from the community)
### Fixed (8 changes, 1 of them is from the community)
- Correct copy text for the promote milestone and label modals. !17726
- Avoid validation errors when running the Pages domain verification service. !17992
......@@ -217,7 +219,6 @@ entry.
- Fix exceptions raised when migrating pipeline stages in the background. !18076
- Work around Prometheus Helm chart name changes to fix integration. !18206 (joshlambert)
- Don't show Jump to Discussion button on Issues.
- Fix data race between ObjectStorage background_upload and Pages publishing.
- Fix listing commit branch/tags that contain special characters.
- Fix 404 in group boards when moving issue between lists.
......@@ -248,11 +249,10 @@ entry.
- Bump rails-html-sanitizer to 1.0.4.
### Fixed (3 changes)
### Fixed (2 changes)
- Prevent auto-retry AccessDenied error from stopping transition to failed. !17862
- Fix 500 error when trying to resolve non-ASCII conflicts in the editor. !17962
- Don't capture trailing punctuation when autolinking. !17965
### Performance (1 change)
......
......@@ -127,7 +127,7 @@ Most issues will have labels for at least one of the following:
- Type: ~"feature proposal", ~bug, ~customer, etc.
- Subject: ~wiki, ~"container registry", ~ldap, ~api, ~frontend, etc.
- Team: ~"CI/CD", ~Discussion, ~Edge, ~Platform, etc.
- Priority: ~Deliverable, ~Stretch, ~"Next Patch Release"
- Milestone: ~Deliverable, ~Stretch, ~"Next Patch Release"
All labels, their meaning and priority are defined on the
[labels page][labels-page].
......@@ -186,10 +186,10 @@ indicate if an issue needs backend work, frontend work, or both.
Team labels are always capitalized so that they show up as the first label for
any issue.
### Priority labels (~Deliverable, ~Stretch, ~"Next Patch Release")
### Milestone labels (~Deliverable, ~Stretch, ~"Next Patch Release")
Priority labels help us clearly communicate expectations of the work for the
release. There are two levels of priority labels:
Milestone labels help us clearly communicate expectations of the work for the
release. There are three levels of Milestone labels:
- ~Deliverable: Issues that are expected to be delivered in the current
milestone.
......@@ -204,16 +204,46 @@ Each issue scheduled for the current milestone should be labeled ~Deliverable
or ~"Stretch". Any open issue for a previous milestone should be labeled
~"Next Patch Release", or otherwise rescheduled to a different milestone.
### Severity labels (~S1, ~S2, etc.)
### Bug Priority labels (~P1, ~P2, ~P3 & etc.)
Severity labels help us clearly communicate the impact of a ~bug on users.
Bug Priority labels help us define the time a ~bug fix should be completed. Priority determines how quickly the defect turnaround time must be. If there are multiple defects, the priority decides which defect has to be fixed immediately versus later.
This label documents the planned timeline & urgency which is used to measure against our actual SLA on delivering ~bug fixes.
| Label | Meaning | Example |
|-------|------------------------------------------|---------|
| ~S1 | Feature broken, no workaround | Unable to create an issue |
| ~S2 | Feature broken, workaround unacceptable | Can push commits, but only via the command line |
| ~S3 | Feature broken, workaround acceptable | Can create merge requests only from the Merge Requests page, not through the Issue |
| ~S4 | Cosmetic issue | Label colors are incorrect / not being displayed |
| Label | Meaning | Estimate time to fix | Guidance |
|-------|-----------------|------------------------------------------------------------------|----------|
| ~P1 | Urgent Priority | The current release | |
| ~P2 | High Priority | The next release | |
| ~P3 | Medium Priority | Within the next 3 releases (approx one quarter) | |
| ~P4 | Low Priority | Anything outside the next 3 releases (approx beyond one quarter) | The issue is prominent but does not impact user workflow and a workaround is documented |
#### Specific Priority guidance
| Label | Availability / Performance |
|-------|--------------------------------------------------------------|
| ~P1 | |
| ~P2 | The issue is (almost) guaranteed to occur in the near future |
| ~P3 | The issue is likely to occur in the near future |
| ~P4 | The issue _may_ occur but it's not likely |
### Bug Severity labels (~S1, ~S2, ~S3 & etc.)
Severity labels help us clearly communicate the impact of a ~bug on users.
| Label | Meaning | Impact of the defect | Example |
|-------|-------------------|-------------------------------------------------------|---------|
| ~S1 | Blocker | Outage, broken feature with no workaround | Unable to create an issue. Data corruption/loss. Security breach. |
| ~S2 | Critical Severity | Broken Feature, workaround too complex & unacceptable | Can push commits, but only via the command line. |
| ~S3 | Major Severity | Broken Feature, workaround acceptable | Can create merge requests only from the Merge Requests page, not through the Issue. |
| ~S4 | Low Severity | Functionality inconvenience or cosmetic issue | Label colors are incorrect / not being displayed. |
#### Specific Severity guidance
| Label | Security Impact |
|-------|-------------------------------------------------------------------|
| ~S1 | >50% customers impacted (possible company extinction level event) |
| ~S2 | Multiple customers impacted (but not apocalyptic) |
| ~S3 | A single customer impacted |
| ~S4 | No customer impact, or expected impact within 30 days |
### Label for community contributors (~"Accepting Merge Requests")
......
......@@ -97,6 +97,12 @@ You can access a new installation with the login **`root`** and password **`5ive
GitLab is an open source project and we are very happy to accept community contributions. Please refer to [CONTRIBUTING.md](/CONTRIBUTING.md) for details.
## Licensing
GitLab Community Edition (CE) is available freely under the MIT Expat license.
All third party components incorporated into the GitLab Software are licensed under the original license provided by the owner of the applicable component.
## Install a development environment
To work on GitLab itself, we recommend setting up your development environment with [the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit).
......
......@@ -1427,7 +1427,7 @@ export default class Notes {
const { discussion_html } = data;
const lines = $(discussion_html).find('.line_holder');
lines.addClass('fade-in');
$container.find('tbody').prepend(lines);
$container.find('.diff-content > table > tbody').prepend(lines);
const fileHolder = $container.find('.file-holder');
$container.find('.line-holder-placeholder').remove();
syntaxHighlight(fileHolder);
......
......@@ -19,7 +19,7 @@ function getSystemDate(systemUtcOffsetSeconds) {
const date = new Date();
const localUtcOffsetMinutes = 0 - date.getTimezoneOffset();
const systemUtcOffsetMinutes = systemUtcOffsetSeconds / 60;
date.setMinutes((date.getMinutes() - localUtcOffsetMinutes) + systemUtcOffsetMinutes);
date.setMinutes(date.getMinutes() - localUtcOffsetMinutes + systemUtcOffsetMinutes);
return date;
}
......@@ -35,18 +35,36 @@ function formatTooltipText({ date, count }) {
return `${contribText}<br />${dateDayName} ${dateText}`;
}
const initColorKey = () => d3.scaleLinear().range(['#acd5f2', '#254e77']).domain([0, 3]);
const initColorKey = () =>
d3
.scaleLinear()
.range(['#acd5f2', '#254e77'])
.domain([0, 3]);
export default class ActivityCalendar {
constructor(container, timestamps, calendarActivitiesPath, utcOffset = 0) {
constructor(container, timestamps, calendarActivitiesPath, utcOffset = 0, firstDayOfWeek = 0) {
this.calendarActivitiesPath = calendarActivitiesPath;
this.clickDay = this.clickDay.bind(this);
this.currentSelectedDate = '';
this.daySpace = 1;
this.daySize = 15;
this.daySizeWithSpace = this.daySize + (this.daySpace * 2);
this.monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
this.daySizeWithSpace = this.daySize + this.daySpace * 2;
this.monthNames = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
];
this.months = [];
this.firstDayOfWeek = firstDayOfWeek;
// Loop through the timestamps to create a group of objects
// The group of objects will be grouped based on the day of the week they are
......@@ -70,7 +88,7 @@ export default class ActivityCalendar {
// Create a new group array if this is the first day of the week
// or if is first object
if ((day === 0 && i !== 0) || i === 0) {
if ((day === this.firstDayOfWeek && i !== 0) || i === 0) {
this.timestampsTmp.push([]);
group += 1;
}
......@@ -109,21 +127,30 @@ export default class ActivityCalendar {
}
renderSvg(container, group) {
const width = ((group + 1) * this.daySizeWithSpace) + this.getExtraWidthPadding(group);
return d3.select(container)
const width = (group + 1) * this.daySizeWithSpace + this.getExtraWidthPadding(group);
return d3
.select(container)
.append('svg')
.attr('width', width)
.attr('height', 167)
.attr('class', 'contrib-calendar');
.attr('width', width)
.attr('height', 167)
.attr('class', 'contrib-calendar');
}
dayYPos(day) {
return this.daySizeWithSpace * ((day + 7 - this.firstDayOfWeek) % 7);
}
renderDays() {
this.svg.selectAll('g').data(this.timestampsTmp).enter().append('g')
this.svg
.selectAll('g')
.data(this.timestampsTmp)
.enter()
.append('g')
.attr('transform', (group, i) => {
_.each(group, (stamp, a) => {
if (a === 0 && stamp.day === 0) {
const month = stamp.date.getMonth();
const x = (this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace;
const x = this.daySizeWithSpace * i + 1 + this.daySizeWithSpace;
const lastMonth = _.last(this.months);
if (
lastMonth == null ||
......@@ -133,86 +160,113 @@ export default class ActivityCalendar {
}
}
});
return `translate(${(this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace}, 18)`;
return `translate(${this.daySizeWithSpace * i + 1 + this.daySizeWithSpace}, 18)`;
})
.selectAll('rect')
.data(stamp => stamp)
.enter()
.append('rect')
.attr('x', '0')
.attr('y', stamp => this.daySizeWithSpace * stamp.day)
.attr('width', this.daySize)
.attr('height', this.daySize)
.attr('fill', stamp => (
stamp.count !== 0 ? this.color(Math.min(stamp.count, 40)) : '#ededed'
))
.attr('title', stamp => formatTooltipText(stamp))
.attr('class', 'user-contrib-cell js-tooltip')
.attr('data-container', 'body')
.on('click', this.clickDay);
.data(stamp => stamp)
.enter()
.append('rect')
.attr('x', '0')
.attr('y', stamp => this.dayYPos(stamp.day))
.attr('width', this.daySize)
.attr('height', this.daySize)
.attr(
'fill',
stamp => (stamp.count !== 0 ? this.color(Math.min(stamp.count, 40)) : '#ededed'),
)
.attr('title', stamp => formatTooltipText(stamp))
.attr('class', 'user-contrib-cell js-tooltip')
.attr('data-container', 'body')
.on('click', this.clickDay);
}
renderDayTitles() {
const days = [
{
text: 'M',
y: 29 + (this.daySizeWithSpace * 1),
}, {
y: 29 + this.dayYPos(1),
},
{
text: 'W',
y: 29 + (this.daySizeWithSpace * 3),
}, {
y: 29 + this.dayYPos(2),
},
{
text: 'F',
y: 29 + (this.daySizeWithSpace * 5),
y: 29 + this.dayYPos(3),
},
];
this.svg.append('g')
this.svg
.append('g')
.selectAll('text')
.data(days)
.enter()
.append('text')
.attr('text-anchor', 'middle')
.attr('x', 8)
.attr('y', day => day.y)
.text(day => day.text)
.attr('class', 'user-contrib-text');
.data(days)
.enter()
.append('text')
.attr('text-anchor', 'middle')
.attr('x', 8)
.attr('y', day => day.y)
.text(day => day.text)
.attr('class', 'user-contrib-text');
}
renderMonths() {
this.svg.append('g')
this.svg
.append('g')
.attr('direction', 'ltr')
.selectAll('text')
.data(this.months)
.enter()
.append('text')
.attr('x', date => date.x)
.attr('y', 10)
.attr('class', 'user-contrib-text')
.text(date => this.monthNames[date.month]);
.data(this.months)
.enter()
.append('text')
.attr('x', date => date.x)
.attr('y', 10)
.attr('class', 'user-contrib-text')
.text(date => this.monthNames[date.month]);
}
renderKey() {
const keyValues = ['no contributions', '1-9 contributions', '10-19 contributions', '20-29 contributions', '30+ contributions'];
const keyColors = ['#ededed', this.colorKey(0), this.colorKey(1), this.colorKey(2), this.colorKey(3)];
const keyValues = [
'no contributions',
'1-9 contributions',
'10-19 contributions',
'20-29 contributions',
'30+ contributions',
];
const keyColors = [
'#ededed',
this.colorKey(0),
this.colorKey(1),
this.colorKey(2),
this.colorKey(3),
];
this.svg.append('g')
.attr('transform', `translate(18, ${(this.daySizeWithSpace * 8) + 16})`)
this.svg
.append('g')
.attr('transform', `translate(18, ${this.daySizeWithSpace * 8 + 16})`)
.selectAll('rect')
.data(keyColors)
.enter()
.append('rect')
.attr('width', this.daySize)
.attr('height', this.daySize)
.attr('x', (color, i) => this.daySizeWithSpace * i)
.attr('y', 0)
.attr('fill', color => color)
.attr('class', 'js-tooltip')
.attr('title', (color, i) => keyValues[i])
.attr('data-container', 'body');
.data(keyColors)
.enter()
.append('rect')
.attr('width', this.daySize)
.attr('height', this.daySize)
.attr('x', (color, i) => this.daySizeWithSpace * i)
.attr('y', 0)
.attr('fill', color => color)
.attr('class', 'js-tooltip')
.attr('title', (color, i) => keyValues[i])
.attr('data-container', 'body');
}
initColor() {
const colorRange = ['#ededed', this.colorKey(0), this.colorKey(1), this.colorKey(2), this.colorKey(3)];
return d3.scaleThreshold().domain([0, 10, 20, 30]).range(colorRange);
const colorRange = [
'#ededed',
this.colorKey(0),
this.colorKey(1),
this.colorKey(2),
this.colorKey(3),
];
return d3
.scaleThreshold()
.domain([0, 10, 20, 30])
.range(colorRange);
}
clickDay(stamp) {
......@@ -227,14 +281,15 @@ export default class ActivityCalendar {
$('.user-calendar-activities').html(LOADING_HTML);
axios.get(this.calendarActivitiesPath, {
params: {
date,
},
responseType: 'text',
})
.then(({ data }) => $('.user-calendar-activities').html(data))
.catch(() => flash(__('An error occurred while retrieving calendar activity')));
axios
.get(this.calendarActivitiesPath, {
params: {
date,
},
responseType: 'text',
})
.then(({ data }) => $('.user-calendar-activities').html(data))
.catch(() => flash(__('An error occurred while retrieving calendar activity')));
} else {
this.currentSelectedDate = '';
$('.user-calendar-activities').html('');
......
......@@ -78,8 +78,6 @@ class Projects::JobsController < Projects::ApplicationController
result.merge!(trace.to_h)
end
result[:html] = result[:html].presence || 'No job log'
render json: result
end
end
......
......@@ -28,11 +28,12 @@ class Projects::RepositoriesController < Projects::ApplicationController
end
def assign_archive_vars
@id = params[:id]
return unless @id
@ref, @filename = extract_ref(@id)
if params[:id]
@ref, @filename = extract_ref(params[:id])
else
@ref = params[:ref]
@filename = nil
end
rescue InvalidPathError
render_404
end
......
......@@ -33,6 +33,7 @@ class UsersFinder
users = by_active(users)
users = by_external_identity(users)
users = by_external(users)
users = by_2fa(users)
users = by_created_at(users)
users = by_custom_attributes(users)
users = by_non_ldap(users)
......@@ -84,4 +85,15 @@ class UsersFinder
users.non_ldap
end
def by_2fa(users)
case params[:two_factor]
when 'enabled'
users.with_two_factor
when 'disabled'
users.without_two_factor
else
users
end
end
end
......@@ -27,8 +27,9 @@ module AtomicInternalId
module ClassMethods
def has_internal_id(column, scope:, init:) # rubocop:disable Naming/PredicateName
before_validation(on: :create) do
if read_attribute(column).blank?
scope_attrs = { scope => association(scope).reader }
scope_value = association(scope).reader
if read_attribute(column).blank? && scope_value
scope_attrs = { scope_value.class.table_name.singularize.to_sym => scope_value }
usage = self.class.table_name.to_sym
new_iid = InternalId.generate_next(self, scope_attrs, usage, init)
......
module NonatomicInternalId
extend ActiveSupport::Concern
included do
validate :set_iid, on: :create
validates :iid, presence: true, numericality: true
end
def set_iid
if iid.blank?
parent = project || group
records = parent.public_send(self.class.name.tableize) # rubocop:disable GitlabSecurity/PublicSend
max_iid = records.maximum(:iid)
self.iid = max_iid.to_i + 1
end
end
def to_param
iid.to_s
end
end
class Deployment < ActiveRecord::Base
include NonatomicInternalId
include AtomicInternalId
belongs_to :project, required: true
belongs_to :environment, required: true
belongs_to :user
belongs_to :deployable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
has_internal_id :iid, scope: :project, init: ->(s) { s&.project&.deployments&.maximum(:iid) }
validates :sha, presence: true
validates :ref, presence: true
......
......@@ -12,8 +12,9 @@
# * (Optionally) add columns to `internal_ids` if needed for scope.
class InternalId < ActiveRecord::Base
belongs_to :project
belongs_to :namespace
enum usage: { issues: 0 }
enum usage: { issues: 0, merge_requests: 1, deployments: 2, milestones: 3, epics: 4 }
validates :usage, presence: true
......
class MergeRequest < ActiveRecord::Base
include NonatomicInternalId
include AtomicInternalId
include Issuable
include Noteable
include Referable
......@@ -22,6 +22,8 @@ class MergeRequest < ActiveRecord::Base
belongs_to :source_project, class_name: "Project"
belongs_to :merge_user, class_name: "User"
has_internal_id :iid, scope: :target_project, init: ->(s) { s&.target_project&.merge_requests&.maximum(:iid) }
has_many :merge_request_diffs
has_one :merge_request_diff,
......
......@@ -8,7 +8,7 @@ class Milestone < ActiveRecord::Base
Started = MilestoneStruct.new('Started', '#started', -3)
include CacheMarkdownField
include NonatomicInternalId
include AtomicInternalId
include Sortable
include Referable
include StripAttribute
......@@ -24,6 +24,9 @@ class Milestone < ActiveRecord::Base
belongs_to :project
belongs_to :group
has_internal_id :iid, scope: :project, init: ->(s) { s&.project&.milestones&.maximum(:iid) }
has_internal_id :iid, scope: :group, init: ->(s) { s&.group&.milestones&.maximum(:iid) }
has_many :boards
has_many :issues
has_many :labels, -> { distinct.reorder('labels.title') }, through: :issues
......
......@@ -8,9 +8,10 @@ module Projects
template_name = params.delete(:template_name)
file = Gitlab::ProjectTemplate.find(template_name).file
override_params = params.dup
params[:file] = file
GitlabProjectsImportService.new(current_user, params).execute
GitlabProjectsImportService.new(current_user, params, override_params).execute
ensure
file&.close
......
---
title: Improve tooltips in collapsed right sidebar
merge_request: 17714
author:
type: changed
---
title: Add index to file_store on ci_job_artifacts
merge_request: 18444
author:
type: performance
---
title: Fix specifying a non-default ref when requesting an archive using the legacy
URL
merge_request: 18468
author:
type: fixed
---
title: Removes 'No Job log' message from build trace
merge_request: 18523
author:
type: fixed
---
title: Transition to atomic internal ids for all models.
merge_request: 44259
author:
type: other
---
title: Respect visibility options and description when importing project from template
merge_request: 18473
author:
type: fixed
---
title: Refactored activity calendar
merge_request: 18469
author: Enrico Scholz
type: changed
---
title: Don't include lfs_file_locks data in export bundle
merge_request: 18495
author:
type: fixed
---
title: Use the GitLab version as part of the appearances cache key
merge_request:
author:
type: fixed
class AddFurtherScopeColumnsToInternalIdTable < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
change_column_null :internal_ids, :project_id, true
add_column :internal_ids, :namespace_id, :integer, null: true
end
def down
change_column_null :internal_ids, :project_id, false
remove_column :internal_ids, :namespace_id
end
end
class AddIndexConstraintsToInternalIdTable < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :internal_ids, [:usage, :namespace_id], unique: true, where: 'namespace_id IS NOT NULL'
replace_index(:internal_ids, [:usage, :project_id], name: 'index_internal_ids_on_usage_and_project_id') do
add_concurrent_index :internal_ids, [:usage, :project_id], unique: true, where: 'project_id IS NOT NULL'
end
add_concurrent_foreign_key :internal_ids, :namespaces, column: :namespace_id, on_delete: :cascade
end
def down
remove_concurrent_index :internal_ids, [:usage, :namespace_id]
replace_index(:internal_ids, [:usage, :project_id], name: 'index_internal_ids_on_usage_and_project_id') do
add_concurrent_index :internal_ids, [:usage, :project_id], unique: true
end
remove_foreign_key :internal_ids, column: :namespace_id
end
private
def replace_index(table, columns, name:)
temporary_name = "#{name}_old"
if index_exists?(table, columns, name: name)
rename_index table, name, temporary_name
end
yield
remove_concurrent_index_by_name table, temporary_name
end
end
class AddIndexToCiJobArtifactsFileStore < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :ci_job_artifacts, :file_store
end
def down
remove_index :ci_job_artifacts, :file_store if index_exists?(:ci_job_artifacts, :file_store)
end
end
......@@ -456,6 +456,7 @@ ActiveRecord::Schema.define(version: 20180419031622) do
end
add_index "ci_job_artifacts", ["expire_at", "job_id"], name: "index_ci_job_artifacts_on_expire_at_and_job_id", using: :btree
add_index "ci_job_artifacts", ["file_store"], name: "index_ci_job_artifacts_on_file_store", using: :btree
add_index "ci_job_artifacts", ["job_id", "file_type"], name: "index_ci_job_artifacts_on_job_id_and_file_type", unique: true, using: :btree
add_index "ci_job_artifacts", ["project_id"], name: "index_ci_job_artifacts_on_project_id", using: :btree
......@@ -1264,12 +1265,14 @@ ActiveRecord::Schema.define(version: 20180419031622) do
add_index "index_statuses", ["project_id"], name: "index_index_statuses_on_project_id", unique: true, using: :btree
create_table "internal_ids", id: :bigserial, force: :cascade do |t|
t.integer "project_id", null: false
t.integer "project_id"
t.integer "usage", null: false
t.integer "last_value", null: false
t.integer "namespace_id"
end
add_index "internal_ids", ["usage", "project_id"], name: "index_internal_ids_on_usage_and_project_id", unique: true, using: :btree
add_index "internal_ids", ["usage", "namespace_id"], name: "index_internal_ids_on_usage_and_namespace_id", unique: true, where: "(namespace_id IS NOT NULL)", using: :btree
add_index "internal_ids", ["usage", "project_id"], name: "index_internal_ids_on_usage_and_project_id", unique: true, where: "(project_id IS NOT NULL)", using: :btree
create_table "issue_assignees", id: false, force: :cascade do |t|
t.integer "user_id", null: false
......@@ -2753,6 +2756,7 @@ ActiveRecord::Schema.define(version: 20180419031622) do
add_foreign_key "gpg_signatures", "projects", on_delete: :cascade
add_foreign_key "group_custom_attributes", "namespaces", column: "group_id", on_delete: :cascade
add_foreign_key "index_statuses", "projects", name: "fk_74b2492545", on_delete: :cascade
add_foreign_key "internal_ids", "namespaces", name: "fk_162941d509", on_delete: :cascade
add_foreign_key "internal_ids", "projects", on_delete: :cascade
add_foreign_key "issue_assignees", "issues", name: "fk_b7d881734a", on_delete: :cascade
add_foreign_key "issue_assignees", "users", name: "fk_5e0c8d9154", on_delete: :cascade
......
# Automatic background verification **[PREMIUM ONLY]**
NOTE: **Note:**
Automatic background verification of repositories and wikis was added in GitLab
EE 10.6, but is disabled by default. To enable it, run
`sudo gitlab-rails runner 'Feature.enable(:geo_repository_verification)'` on
the **primary**. Until [issue #5699][ee-5699] is completed, we need to reset
the cache for this feature flag on each **secondary**, to do this run
`sudo gitlab-rails runner 'Rails.cache.expire('flipper/v1/feature/geo_repository_verification', 0)'`.
Automatic backgorund verification ensures that the transferred data matches a
calculated checksum, proving that the content on the **secondary** matches that
on the **primary**. Following a planned failover, any corrupted data may be
**lost**, depending on the extent of the corruption.
If verification fails on the **primary**, this indicates that Geo is
successfully replicating a corrupted object; restore it from backup or remove it
it from the primary to resolve the issue.
If verification succeeds on the **primary** but fails on the **secondary**, this
indicates that the object was corrupted during the replication process. Until
[issue #5195][ee-5195] is implemented, Geo won't automatically resolve
verification failures of this kind, so you should remove the registry entries to
force Geo to re-replicate the files:
```
sudo gitlab-rails runner 'Geo::ProjectRegistry.verification_failed.delete_all'
```
If verification is lagging significantly behind replication, consider giving
the node more time before scheduling a planned failover.
# Repository verification
Visit the **Admin Area ➔ Geo nodes** dashboard on the **primary** and expand
the **Verification information** tab for that node to view automatic checksumming
status for repositories and wikis. Successes are shown in green, pending work
in grey, and failures in red.
![Verification status](img/verification-status-primary.png)
Visit the **Admin Area ➔ Geo nodes** dashboard on the **secondary** and expand
the **Verification information** tab for that node to view automatic verifcation
status for repositories and wikis. As with checksumming, successes are shown in
green, pending work in grey, and failures in red.
![Verification status](img/verification-status-secondary.png)
# Using checksums to compare Geo nodes
To check the health of Geo secondary nodes, we use a checksum over the list of
Git references and theirs values. Right now the checksum only includes `heads`
and `tags`. We should include all references ([issue #5196][ee-5196]), including
GitLab-specific references to ensure true consistency. If two nodes have the
same checksum, then they definitely hold the same data. We compute the checksuym
for every node after every update to make sure that they are all in sync.
# Current limitations
Until [issue #5064][ee-5064] is completed, background verification doesn't cover
CI job artifacts and traces, LFS objects, or user uploads in file storage.
Verifytheir integrity manually by following [these instructions][foreground-verification]
on both nodes, and comparing the output between them.
Data in object storage is **not verified**, as the object store is responsible
for ensuring the integrity of the data.
[disaster-recovery]: index.md
[foreground-verification]: ../../raketasks/check.md
[ee-5699]: https://gitlab.com/gitlab-org/gitlab-ee/issues/5699
[ee-5195]: https://gitlab.com/gitlab-org/gitlab-ee/issues/5195
[ee-5196]: https://gitlab.com/gitlab-org/gitlab-ee/issues/5196
......@@ -188,7 +188,7 @@ and after that you also need two extra steps.
### Step 1. Prepare the new primary to serve one or more secondaries
1. SSH into your **secondary** and login as root:
1. SSH into your new **primary** and login as root:
```bash
sudo -i
......@@ -197,6 +197,9 @@ and after that you also need two extra steps.
1. Edit `/etc/gitlab/gitlab.rb`
```ruby
## Enable a Geo Primary role (if you haven't yet)
geo_primary_role['enable'] = true
##
# Primary and Secondary addresses
# - replace '1.2.3.4' with the primary public or VPC address
......
......@@ -122,48 +122,7 @@ or removing references to the missing data.
### Verify the integrity of replicated data
NOTE: **Note:**
Automatic background verification of repositories and wikis was added in GitLab
EE 10.6, but is disabled by default. To enable it, run
`sudo gitlab-rails runner 'Feature.enable(:geo_repository_verification)'` on
the **primary**.
Visit the **Admin Area ➔ Geo nodes** dashboard on the **secondary** and expand
the **Advanced** tab for that node to view automatic checksumming status for
repositories and wikis. As with replication, successes are shown in green,
pending work in grey, and failures in red.
![Verification status](img/verification-status.png)
Until [issue #5064][ee-5064] is completed, background verification doesn't cover
CI job artifacts and traces, LFS objects, or user uploads in file storage.
Verifytheir integrity manually by following [these instructions][foreground-verification]
on both nodes, and comparing the output between them.
Verification ensures that the transferred data matches a calculated checksum,
proving that the content on the **secondary** matches that on the **primary**.
Following a planned failover, any corrupted data may be **lost**, depending on
the extent of the corruption.
Data in object storage is **not verified**, as the object store is responsible
for ensuring the integrity of the data.
If verification is lagging significantly behind replication, consider giving
the node more time before scheduling a planned failover.
If verification fails on the **primary**, this indicates that Geo is
successfully replicating a corrupted object; restore it from backup or remove it
it from the primary to resolve the issue.
If verification succeeds on the **primary** but fails on the **secondary**, this
indicates that the object was corrupted during the replication process. Until
[issue #5195][ee-5195] is implemented, Geo won't automatically resolve
verification failures of this kind, so you should remove the registry entries to
force Geo to re-replicate the files:
```
sudo gitlab-rails runner 'Geo::ProjectRegistry.verification_failed.delete_all'
```
This [content was moved to another location][background-verification].
### Notify users of scheduled maintenance
......@@ -183,7 +142,7 @@ access to the primary for the duration of the maintenance window.
1. At the scheduled time, using your cloud provider or your node's firewall, block
all HTTP, HTTPS and SSH traffic to/from the primary, **except** for your IP and
the secondary's IP.
For instance, if your secondary originates all its traffic from `5.6.7.8` and
your IP is `100.0.0.1`, you might run the following commands on the server(s)
making up your primary node:
......@@ -263,8 +222,8 @@ Don't forget to remove the broadcast message after failover is complete.
[disaster-recovery]: index.md
[ee-4930]: https://gitlab.com/gitlab-org/gitlab-ee/issues/4930
[ee-5064]: https://gitlab.com/gitlab-org/gitlab-ee/issues/5064
[ee-5195]: https://gitlab.com/gitlab-org/gitlab-ee/issues/5195
[foreground-verification]: ../../raketasks/check.md
[background-verification]: background_verification.md
[geo-status-api]: ../../../api/geo_nodes.html#retrieve-project-sync-failures-ocurred-on-the-current-node
[limitations]: ../replication/index.md#current-limitations
[moving-repositories]: ../../operations/moving_repositories.md
......
......@@ -651,6 +651,47 @@ gitlab_rails['redis_sentinels'] = [
Omnibus GitLab configures some things behind the curtains to make the sysadmins'
lives easier. If you want to know what happens underneath keep reading.
### Running multiple Redis clusters
GitLab supports running [separate Redis clusters for different persistent
classes](https://docs.gitlab.com/omnibus/settings/redis.html#running-with-multiple-redis-instances):
cache, queues, and shared_state. To make this work with Sentinel:
1. Set the appropriate variable in `/etc/gitlab/gitlab.rb` for each instance you are using:
```ruby
gitlab_rails['redis_cache_instance'] = REDIS_CACHE_URL
gitlab_rails['redis_queues_instance'] = REDIS_QUEUES_URL
gitlab_rails['redis_shared_state_instance'] = REDIS_SHARED_STATE_URL
```
**Note**: Redis URLs should be in the format: `redis://:PASSWORD@SENTINEL_MASTER_NAME`
1. PASSWORD is the plaintext password for the Redis instance
2. SENTINEL_MASTER_NAME is the Sentinel master name (e.g. `gitlab-redis-cache`)
1. Include an array of hashes with host/port combinations, such as the following:
```ruby
gitlab_rails['redis_cache_sentinels'] = [
{ host: REDIS_CACHE_SENTINEL_HOST, port: PORT1 },
{ host: REDIS_CACHE_SENTINEL_HOST2, port: PORT2 }
]
gitlab_rails['redis_queues_sentinels'] = [
{ host: REDIS_QUEUES_SENTINEL_HOST, port: PORT1 },
{ host: REDIS_QUEUES_SENTINEL_HOST2, port: PORT2 }
]
gitlab_rails['redis_shared_state_sentinels'] = [
{ host: SHARED_STATE_SENTINEL_HOST, port: PORT1 },
{ host: SHARED_STATE_SENTINEL_HOST2, port: PORT2 }
]
```
1. Note that for each persistence class, GitLab will default to using the
configuration specified in `gitlab_rails['redis_sentinels']` unless
overriden by the settings above.
1. Be sure to include BOTH configuration options for each persistent classes. For example,
if you choose to configure a cache instance, you must specify both `gitlab_rails['redis_cache_instance']`
and `gitlab_rails['redis_cache_sentinels']` for GitLab to generate the proper configuration files.
1. Run `gitlab-ctl reconfigure`
### Control running services
In the previous example, we've used `redis_sentinel_role` and
......
......@@ -119,11 +119,17 @@ The Pages daemon doesn't listen to the outside world.
1. Set the external URL for GitLab Pages in `/etc/gitlab/gitlab.rb`:
```ruby
```shell
pages_external_url 'http://example.io'
```
1. [Reconfigure GitLab][reconfigure]
1. Restart gitlab-pages by running the following command:
```shell
sudo gitlab-ctl restart gitlab-pages
```
Watch the [video tutorial][video-admin] for this configuration.
......@@ -143,7 +149,7 @@ outside world.
1. Place the certificate and key inside `/etc/gitlab/ssl`
1. In `/etc/gitlab/gitlab.rb` specify the following configuration:
```ruby
```shell
pages_external_url 'https://example.io'
pages_nginx['redirect_http_to_https'] = true
......@@ -155,6 +161,11 @@ outside world.
respectively.
1. [Reconfigure GitLab][reconfigure]
1. Restart gitlab-pages by running the following command:
```shell
sudo gitlab-ctl restart gitlab-pages
```
## Advanced configuration
......@@ -180,7 +191,7 @@ world. Custom domains are supported, but no TLS.
1. Edit `/etc/gitlab/gitlab.rb`:
```ruby
```shell
pages_external_url "http://example.io"
nginx['listen_addresses'] = ['1.1.1.1']
pages_nginx['enable'] = false
......@@ -192,6 +203,11 @@ world. Custom domains are supported, but no TLS.
listens on. If you don't have IPv6, you can omit the IPv6 address.
1. [Reconfigure GitLab][reconfigure]
1. Restart gitlab-pages by running the following command:
```shell
sudo gitlab-ctl restart gitlab-pages
```
### Custom domains with TLS support
......@@ -210,7 +226,7 @@ world. Custom domains and TLS are supported.
1. Edit `/etc/gitlab/gitlab.rb`:
```ruby
```shell
pages_external_url "https://example.io"
nginx['listen_addresses'] = ['1.1.1.1']
pages_nginx['enable'] = false
......@@ -225,6 +241,11 @@ world. Custom domains and TLS are supported.
listens on. If you don't have IPv6, you can omit the IPv6 address.
1. [Reconfigure GitLab][reconfigure]
1. Restart gitlab-pages by running the following command:
```shell
sudo gitlab-ctl restart gitlab-pages
```
### Custom domain verification
......@@ -247,11 +268,16 @@ are stored.
If you wish to store them in another location you must set it up in
`/etc/gitlab/gitlab.rb`:
```ruby
```shell
gitlab_rails['pages_path'] = "/mnt/storage/pages"
```
1. [Reconfigure GitLab][reconfigure]
1. Restart gitlab-pages by running the following command:
```shell
sudo gitlab-ctl restart gitlab-pages
```
## Set maximum pages size
......
......@@ -12,6 +12,9 @@ The access levels are defined in the `ProtectedRefAccess::ALLOWED_ACCESS_LEVELS`
60 => Admin access
```
**Note:** The admin access level (`60`) may be removed in GitLab 11.0. We are currently evaluating restrictions to
the Owner role as an alternative.
## List protected branches
Gets a list of protected branches from a project.
......
......@@ -57,6 +57,7 @@ GET /users
| --------- | ---- | -------- | ----------- |
| `order_by` | string | no | Return projects ordered by `id`, `name`, `username`, `created_at`, or `updated_at` fields. Default is `id` |
| `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
| `two_factor` | string | no | Filter users by Two-factor authentication. Filter values are `enabled` or `disabled`. By default it returns all users |
```json
[
......
......@@ -31,6 +31,9 @@ container_scanning:
- chmod +x clair-scanner
- touch clair-whitelist.yml
- while( ! wget -q -O /dev/null http://docker:6060/v1/namespaces ) ; do sleep 1 ; done
- retries=0
- echo "Waiting for clair daemon to start"
- while( ! wget -T 10 -q -O /dev/null http://docker:6060/v1/namespaces ) ; do sleep 1 ; echo -n "." ; if [ $retries -eq 10 ] ; then echo " Timeout, aborting." ; exit 1 ; fi ; retries=$(($retries+1)) ; done
- ./clair-scanner -c http://docker:6060 --ip $(hostname -i) -r gl-sast-container-report.json -l clair.log -w clair-whitelist.yml ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} || true
artifacts:
paths: [gl-sast-container-report.json]
......
# Frontend Development Process
You can find more about the organization of the frontend team in the [handbook](https://about.gitlab.com/handbook/frontend/).
## Development Checklist
The idea is to remind us about specific topics during the time we build a new feature or start something. This is a common practice in other industries (like pilots) that also use standardised checklists to reduce problems early on.
Copy the content over to your issue or merge request and if something doesn't apply simply remove it from your current list.
This checklist is intended to help us during development of bigger features/refactorings, it's not a "use it always and every point always matches" list.
Please use your best judgement when to use it and please contribute new points through merge requests if something comes to your mind.
---
### Frontend development
#### Planning development
- [ ] Check the current set weight of the issue, does it fit your estimate?
- [ ] Are all [departments](https://about.gitlab.com/handbook/engineering/#engineering-teams) that are needed from your perspective already involved in the issue? (For example is UX missing?)
- [ ] Is the specification complete? Are you missing decisions? How about error handling/defaults/edge cases? Take your time to understand the needed implementation and go through its flow.
- [ ] Are all necessary UX specifications available that you will need in order to implement? Are there new UX components/patterns in the designs? Then contact the UI component team early on. How should error messages or validation be handled?
- [ ] **Library usage** Use Vuex as soon as you have even a medium state to manage, use Vue router if you need to have different views internally and want to link from the outside. Check what libraries we already have for which occassions.
- [ ] **Plan your implementation:**
- [ ] **Architecture plan:** Create a plan aligned with GitLab's architecture, how you are going to do the implementation, for example Vue application setup and its components (through [onion skinning](https://gitlab.com/gitlab-org/gitlab-ce/issues/35873#note_39994091)), Store structure and data flow, which existing Vue components can you reuse. Its a good idea to go through your plan with another engineer to refine it.
- [ ] **Backend:** The best way is to kickoff the implementation in a call and discuss with the assigned Backend engineer what you will need from the backend and also when. Can you reuse existing API's? How is the performance with the planned architecture? Maybe create together a JSON mock object to already start with development.
- [ ] **Communication:** It also makes sense to have for bigger features an own slack channel (normally called #f_{feature_name}) and even weekly demo calls with all people involved.
- [ ] **Dependency Plan:** Are there big dependencies in the plan between you and others, then maybe create an execution diagram to show what is blocking which part and the order of the different parts.
- [ ] **Task list:** Create a simple checklist of the subtasks that are needed for the implementation, also consider creating even sub issues. (for example show a comment, delete a comment, update a comment, etc.). This helps you and also everyone else following the implementation
- [ ] **Keep it small** To make it easier for you and also all reviewers try to keep merge requests small and merge into a feature branch if needed. To accomplish that you need to plan that from the start. Different methods are:
- [ ] **Skeleton based plan** Start with an MR that has the skeleton of the components with placeholder content. In following MRs you can fill the components with interactivity. This also makes it easier to spread out development on multiple people.
- [ ] **Cookie Mode** Think about hiding the feature behind a cookie flag if the implementation is on top of existing features
- [ ] **New route** Are you refactoring something big then you might consider adding a new route where you implement the new feature and when finished delete the current route and rename the new one. (for example 'merge_request' and 'new_merge_request')
- [ ] **Setup** Is there any specific setup needed for your implementation (for example a kubernetes cluster)? Then let everyone know if it is not already mentioned where they can find documentation (if it doesn't exist - create it)
- [ ] **Security** Are there any new security relevant implementations? Then please contact the security team for an app security review. If you are not sure ask our [domain expert](https://about.gitlab.com/handbook/frontend/#frontend-domain-experts)
#### During development
- [ ] Check off tasks on your created task list to keep everyone updated on the progress
- [ ] [Share your work early with reviewers/maintainers](#share-your-work-early)
- [ ] Share your work with UXer and Product Manager with Screenshots and/or [GIF's](https://about.gitlab.com/handbook/product/making-gifs/). They are easy to create for you and keep them up to date.
- [ ] If you are blocked on something let everyone on the issue know through a comment.
- [ ] Are you unable to work on this issue for a longer period of time, also let everyone know.
- [ ] **Documentation** Update/add docs for the new feature, see `docs/`. Ping one of the documentation experts/reviewers
#### Finishing development + Review
- [ ] **Keep it in the scope** Try to focus on the actual scope and avoid a scope creep during review and keep new things to new issues.
- [ ] **Performance** Have you checked performance? For example do the same thing with 500 comments instead of 1. Document the tests and possible findings in the MR so a reviewer can directly see it.
- [ ] Have you tested with a variety of our [supported browsers](../../install/requirements.md#supported-web-browsers)? You can use [browserstack](https://www.browserstack.com/) to be able to access a wide variety of browsers and operating systems.
- [ ] Did you check the mobile view?
- [ ] Check the built webpack bundle (For the report run `WEBPACK_REPORT=true gdk run`, then open `webpack-report/index.html`) if we have unnecessary bloat due to wrong references, including libraries multiple times, etc.. If you need help contact the webpack [domain expert](https://about.gitlab.com/handbook/frontend/#frontend-domain-experts)
- [ ] **Tests** Not only greenfield tests - Test also all bad cases that come to your mind.
- [ ] If you have multiple MR's then also smoke test against the final merge.
- [ ] Are there any big changes on how and especially how frequently we use the API then let production know about it
- [ ] Smoke test of the RC on dev., staging., canary deployments and .com
- [ ] Follow up on issues that came out of the review. Create isssues for discovered edge cases that should be covered in future iterations.
---
### Share your work early
1. Before writing code, ensure your vision of the architecture is aligned with
GitLab's architecture.
1. Add a diagram to the issue and ask a frontend architect in the slack channel `#fe_architectural` about it.
![Diagram of Issue Boards Architecture](img/boards_diagram.png)
1. Don't take more than one week between starting work on a feature and
sharing a Merge Request with a reviewer or a maintainer.
### Vue features
1. Follow the steps in [Vue.js Best Practices](vue.md)
1. Follow the style guide.
1. Only a handful of people are allowed to merge Vue related features.
Reach out to one of Vue experts early in this process.
......@@ -5,11 +5,15 @@ across GitLab's frontend team.
## Overview
GitLab is built on top of [Ruby on Rails][rails] using [Haml][haml] with
[Hamlit][hamlit]. Be wary of [the limitations that come with using
Hamlit][hamlit-limits]. We also use [SCSS][scss] and plain JavaScript with
modern ECMAScript standards supported through [Babel][babel] and ES module
support through [webpack][webpack].
GitLab is built on top of [Ruby on Rails][rails] using [Haml][haml] and also a JavaScript based Frontend with [Vue.js][vue].
Be wary of [the limitations that come with using Hamlit][hamlit-limits]. We also use [SCSS][scss] and plain JavaScript with
modern ECMAScript standards supported through [Babel][babel] and ES module support through [webpack][webpack].
### Javascript development
[Vue.js][vue] is used for particularly advanced, dynamic elements and based on previous iterations [jQuery][jquery] is used in lot of places through the application's JavaScript.
We also use [Axios][axios] to handle all of our network requests.
We also utilize [webpack][webpack] to handle the bundling, minification, and
compression of our assets.
......@@ -18,61 +22,29 @@ Working with our frontend assets requires Node (v6.0 or greater) and Yarn
(v1.2 or greater). You can find information on how to install these on our
[installation guide][install].
[jQuery][jquery] is used throughout the application's JavaScript, with
[Vue.js][vue] for particularly advanced, dynamic elements.
We also use [Axios][axios] to handle all of our network requests.
### Browser Support
For our currently-supported browsers, see our [requirements][requirements].
---
## Development Process
### Share your work early
1. Before writing code guarantee your vision of the architecture is aligned with
GitLab's architecture.
1. Add a diagram to the issue and ask a Frontend Architecture about it.
![Diagram of Issue Boards Architecture](img/boards_diagram.png)
1. Don't take more than one week between starting work on a feature and
sharing a Merge Request with a reviewer or a maintainer.
### Vue features
1. Follow the steps in [Vue.js Best Practices](vue.md)
1. Follow the style guide.
1. Only a handful of people are allowed to merge Vue related features.
Reach out to one of Vue experts early in this process.
---
## [Development Process](development_process.md)
How we plan and execute the work on the frontend.
## [Architecture](architecture.md)
How we go about making fundamental design decisions in GitLab's frontend team
or make changes to our frontend development guidelines.
---
## [Testing](../testing_guide/frontend_testing.md)
How we write frontend tests, run the GitLab test suite, and debug test related
issues.
---
## [Design Patterns](design_patterns.md)
Common JavaScript design patterns in GitLab's codebase.
---
## [Vue.js Best Practices](vue.md)
Vue specific design patterns and practices.
---
## [Axios](axios.md)
Axios specific practices and gotchas.
......
......@@ -67,9 +67,9 @@ and examples in [the `qa/` directory][instance-qa-examples].
## Where can I ask for help?
You can ask question in the `#qa` channel on Slack (GitLab internal) or you can
find an issue you would like to work on in [the issue tracker][gitlab-qa-issues]
and start a new discussion there.
You can ask question in the `#quality` channel on Slack (GitLab internal) or
you can find an issue you would like to work on in
[the issue tracker][gitlab-qa-issues] and start a new discussion there.
[omnibus-gitlab]: https://gitlab.com/gitlab-org/omnibus-gitlab
[gitlab-qa]: https://gitlab.com/gitlab-org/gitlab-qa
......
......@@ -70,7 +70,7 @@ In case you want to point a root domain (`example.com`) to your
GitLab Pages site, deployed to `namespace.gitlab.io`, you need to
log into your domain's admin control panel and add a DNS `A` record
pointing your domain to Pages' server IP address. For projects on
GitLab.com, this IP is `52.167.214.135`. For projects leaving in
GitLab.com, this IP is `52.167.214.135`. For projects living in
other GitLab instances (CE or EE), please contact your sysadmin
asking for this information (which IP address is Pages server
running on your instance).
......
......@@ -6,15 +6,6 @@
The Web IDE editor makes it faster and easier to contribute changes to your
projects by providing an advanced editor with commit staging.
## Enable the Web IDE
While in the early stages of the Beta, access to the Web IDE is by opting in.
To enable the Web IDE, click on your profile image in the top right corner and
navigate to **Settings > Preferences**, check **Enable Web IDE** and save.
![Enable Web IDE](img/enable_web_ide.png)
## Open the Web IDE
The Web IDE can be opened when viewing a file, from the repository file list,
......
......@@ -3,7 +3,7 @@ module EE
extend ActiveSupport::Concern
prepended do
include NonatomicInternalId
include AtomicInternalId
include Issuable
include Noteable
include Referable
......@@ -12,6 +12,8 @@ module EE
belongs_to :assignee, class_name: "User"
belongs_to :group
has_internal_id :iid, scope: :group, init: ->(s) { s&.group&.epics&.maximum(:iid) }
has_many :epic_issues
validates :group, presence: true
......
......@@ -61,12 +61,20 @@ module Geo
if redownload
redownload_repository
set_temp_repository_as_main
schedule_repack
elsif repository.exists?
fetch_geo_mirror(repository)
else
ensure_repository
fetch_geo_mirror(repository)
schedule_repack
end
end
def schedule_repack
raise NotImplementedError
end
def redownload_repository
log_info("Redownloading #{type}")
......
......@@ -62,5 +62,9 @@ module Geo
repository.copy_gitattributes(project.default_branch)
end
def schedule_repack
GitGarbageCollectWorker.perform_async(@project.id, :full_repack, lease_key)
end
end
end
......@@ -51,5 +51,10 @@ module Geo
update_delay_s: update_delay_in_seconds,
download_time_s: download_time_in_seconds)
end
def schedule_repack
# No-op: we currently don't schedule wiki repository to repack
# TODO: https://gitlab.com/gitlab-org/gitlab-ce/issues/45523
end
end
end
---
title: 'Geo: schedule a git repack after initial clone'
merge_request: 4266
author:
type: added
......@@ -20,7 +20,12 @@ describe Epic do
describe 'modules' do
subject { described_class }
it { is_expected.to include_module(NonatomicInternalId) }
it_behaves_like 'AtomicInternalId' do
let(:internal_id_attribute) { :iid }
let(:instance) { build(:epic) }
let(:scope_attrs) { { namespace: instance.group } }
let(:usage) { :epics }
end
end
describe '.order_start_or_end_date_asc' do
......
......@@ -7,6 +7,8 @@ describe Geo::RepositorySyncService do
set(:secondary) { create(:geo_node) }
let(:lease) { double(try_obtain: true) }
let(:project) { create(:project_empty_repo) }
let(:repository) { project.repository }
subject { described_class.new(project) }
......@@ -15,16 +17,13 @@ describe Geo::RepositorySyncService do
end
it_behaves_like 'geo base sync execution'
it_behaves_like 'geo base sync fetch and repack'
describe '#execute' do
let(:project) { create(:project_empty_repo) }
let(:repository) { project.repository }
let(:url_to_repo) { "#{primary.url}#{project.full_path}.git" }
before do
allow(Gitlab::ExclusiveLease).to receive(:new)
.with(subject.lease_key, anything)
.and_return(lease)
allow(subject).to receive(:exclusive_lease).and_return(lease)
allow_any_instance_of(Repository).to receive(:fetch_as_mirror)
.and_return(true)
......@@ -340,4 +339,12 @@ describe Geo::RepositorySyncService do
let(:repository) { project.repository }
end
end
describe '#schedule_repack' do
it 'schedule GitGarbageCollectWorker for full repack' do
Sidekiq::Testing.fake! do
expect { subject.send(:schedule_repack) }.to change { GitGarbageCollectWorker.jobs.count }.by(1)
end
end
end
end
......@@ -6,7 +6,9 @@ RSpec.describe Geo::WikiSyncService do
set(:primary) { create(:geo_node, :primary) }
set(:secondary) { create(:geo_node) }
let(:lease) { double(try_obtain: true) }
let(:lease) { double(try_obtain: true, lease_key: anything ) }
let(:project) { create(:project_empty_repo) }
let(:repository) { project.wiki.repository }
subject { described_class.new(project) }
......@@ -15,16 +17,13 @@ RSpec.describe Geo::WikiSyncService do
end
it_behaves_like 'geo base sync execution'
it_behaves_like 'geo base sync fetch and repack'
describe '#execute' do
let(:project) { create(:project_empty_repo) }
let(:repository) { project.wiki.repository }
let(:url_to_repo) { "#{primary.url}#{project.full_path}.wiki.git" }
before do
allow(Gitlab::ExclusiveLease).to receive(:new)
.with(subject.lease_key, anything)
.and_return(lease)
allow(subject).to receive(:exclusive_lease).and_return(lease)
allow_any_instance_of(Repository).to receive(:fetch_as_mirror)
.and_return(true)
......@@ -40,7 +39,7 @@ RSpec.describe Geo::WikiSyncService do
end
it 'releases lease' do
expect(Gitlab::ExclusiveLease).to receive(:cancel).once.with(
expect(Gitlab::ExclusiveLease).to receive(:cancel).at_least(:once).with(
subject.__send__(:lease_key), anything).and_call_original
subject.execute
......@@ -49,7 +48,7 @@ RSpec.describe Geo::WikiSyncService do
it 'voids the failure message when it succeeds after an error' do
registry = create(:geo_project_registry, project: project, last_wiki_sync_failure: 'error')
expect { subject.execute }.to change { registry.reload.last_wiki_sync_failure}.to(nil)
expect { subject.execute }.to change { registry.reload.last_wiki_sync_failure }.to(nil)
end
it 'does not fetch wiki repository if cannot obtain a lease' do
......
......@@ -48,6 +48,76 @@ shared_examples 'cleans temporary repositories' do
end
end
shared_examples 'geo base sync fetch and repack' do
describe '#fetch_repository' do
let(:fetch_repository) { subject.send(:fetch_repository, false) }
before do
allow(subject).to receive(:fetch_geo_mirror).and_return(true)
end
it 'cleans up temporary repository' do
is_expected.to receive(:clean_up_temporary_repository)
fetch_repository
end
it 'updates registry' do
is_expected.to receive(:update_registry!)
fetch_repository
end
it 'fetches repository from geo node' do
is_expected.to receive(:fetch_geo_mirror).with(subject.send(:repository))
fetch_repository
end
context 'redownload' do
let(:fetch_repository) { subject.send(:fetch_repository, true) }
before do
stub_feature_flags(geo_redownload_with_snapshot: false)
end
it 'fetches repository from geo node into temporary location' do
temporary_repository = instance_double('Repository')
is_expected.to receive(:temp_repo) { temporary_repository }
is_expected.to receive(:fetch_geo_mirror).with(temporary_repository)
is_expected.to receive(:set_temp_repository_as_main)
fetch_repository
end
it 'schedule git repack' do
is_expected.to receive(:schedule_repack)
fetch_repository
end
end
context 'repository does not exist' do
before do
allow_any_instance_of(Repository).to receive(:exists?) { false }
end
it 'ensures repository is created' do
is_expected.to receive(:ensure_repository)
fetch_repository
end
it 'schedule git repack' do
is_expected.to receive(:schedule_repack)
fetch_repository
end
end
end
end
shared_examples 'sync retries use the snapshot RPC' do
let(:retry_count) { Geo::BaseSyncService::RETRY_BEFORE_REDOWNLOAD }
......
......@@ -83,7 +83,7 @@ module API
authenticated_as_admin! if params[:external].present? || (params[:extern_uid].present? && params[:provider].present?)
unless current_user&.admin?
params.except!(:created_after, :created_before, :order_by, :sort)
params.except!(:created_after, :created_before, :order_by, :sort, :two_factor)
end
users = UsersFinder.new(current_user, params).execute
......
......@@ -27,8 +27,6 @@ project_tree:
- :releases
- project_members:
- :user
- lfs_file_locks:
- :user
- merge_requests:
- notes:
- :author
......
namespace :gitlab do
desc "GitLab | Setup production application"
task setup: :gitlab_environment do
check_gitaly_connection
setup_db
end
def check_gitaly_connection
Gitlab.config.repositories.storages.each do |name, _details|
Gitlab::GitalyClient::ServerService.new(name).info
end
rescue GRPC::Unavailable => ex
puts "Failed to connect to Gitaly...".color(:red)
puts "Error: #{ex}"
exit 1
end
def setup_db
warn_user_is_not_gitlab
......
......@@ -115,8 +115,8 @@ from within the `qa` directory.
## Where to ask for help?
If you need more information, ask for help on `#qa` channel on Slack (GitLab
Team only).
If you need more information, ask for help on `#quality` channel on Slack
(internal, GitLab Team only).
If you are not a Team Member, and you still need help to contribute, please
open an issue in GitLab QA issue tracker.
......@@ -31,7 +31,7 @@ module QA
current changes in this merge request.
For more help see documentation in `qa/page/README.md` file or
ask for help on #qa channel on Slack (GitLab Team only).
ask for help on #quality channel on Slack (GitLab Team only).
If you are not a Team Member, and you still need help to
contribute, please open an issue in GitLab QA issue tracker.
......
......@@ -190,10 +190,7 @@ describe Projects::JobsController do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['id']).to eq job.id
expect(json_response['status']).to eq job.status
end
it 'returns no job log message' do
expect(json_response['html']).to eq('No job log')
expect(json_response['html']).to be_nil
end
end
......
......@@ -40,6 +40,30 @@ describe Projects::RepositoriesController do
expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with("git-archive:")
end
it 'handles legacy queries with the ref specified as ref in params' do
get :archive, namespace_id: project.namespace, project_id: project, ref: 'feature', format: 'zip'
expect(response).to have_gitlab_http_status(200)
expect(assigns(:ref)).to eq('feature')
expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with("git-archive:")
end
it 'handles legacy queries with the ref specified as id in params' do
get :archive, namespace_id: project.namespace, project_id: project, id: 'feature', format: 'zip'
expect(response).to have_gitlab_http_status(200)
expect(assigns(:ref)).to eq('feature')
expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with("git-archive:")
end
it 'prioritizes the id param over the ref param when both are specified' do
get :archive, namespace_id: project.namespace, project_id: project, id: 'feature', ref: 'feature_conflict', format: 'zip'
expect(response).to have_gitlab_http_status(200)
expect(assigns(:ref)).to eq('feature')
expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with("git-archive:")
end
context "when the service raises an error" do
before do
allow(Gitlab::Workhorse).to receive(:send_git_archive).and_raise("Archive failed")
......
......@@ -5,7 +5,7 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
let(:user) { project.creator }
let(:guest) { create(:user) }
let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user, title: "Bug NS-04") }
let!(:note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request) }
let!(:note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request, note: "| Markdown | Table |\n|-------|---------|\n| first | second |") }
let(:path) { "files/ruby/popen.rb" }
let(:position) do
Gitlab::Diff::Position.new(
......@@ -111,6 +111,15 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
expect(page.find(".line-holder-placeholder")).to be_visible
expect(page.find(".timeline-content #note_#{note.id}")).to be_visible
end
it 'renders tables in lazy-loaded resolved diff dicussions' do
find(".timeline-content .discussion[data-discussion-id='#{note.discussion_id}'] .discussion-toggle-button").click
wait_for_requests
expect(page.find(".timeline-content #note_#{note.id}")).not_to have_css(".line_holder")
expect(page.find(".timeline-content #note_#{note.id}")).to have_css("tr", count: 2)
end
end
describe 'side-by-side view' do
......
......@@ -576,12 +576,6 @@ PrometheusMetric:
- title
- query
- group
LfsFileLock:
- id
- path
- user_id
- project_id
- created_at
Badge:
- id
- link_url
......
......@@ -16,6 +16,15 @@ describe Deployment do
it { is_expected.to validate_presence_of(:ref) }
it { is_expected.to validate_presence_of(:sha) }
describe 'modules' do
it_behaves_like 'AtomicInternalId' do
let(:internal_id_attribute) { :iid }
let(:instance) { build(:deployment) }
let(:scope_attrs) { { project: instance.project } }
let(:usage) { :deployments }
end
end
describe 'after_create callbacks' do
let(:environment) { create(:environment) }
let(:store) { Gitlab::EtagCaching::Store.new }
......
......@@ -17,11 +17,17 @@ describe MergeRequest do
describe 'modules' do
subject { described_class }
it { is_expected.to include_module(NonatomicInternalId) }
it { is_expected.to include_module(Issuable) }
it { is_expected.to include_module(Referable) }
it { is_expected.to include_module(Sortable) }
it { is_expected.to include_module(Taskable) }
it_behaves_like 'AtomicInternalId' do
let(:internal_id_attribute) { :iid }
let(:instance) { build(:merge_request) }
let(:scope_attrs) { { project: instance.target_project } }
let(:usage) { :merge_requests }
end
end
describe 'validation' do
......
require 'spec_helper'
describe Milestone do
describe 'modules' do
context 'with a project' do
it_behaves_like 'AtomicInternalId' do
let(:internal_id_attribute) { :iid }
let(:instance) { build(:milestone, project: build(:project), group: nil) }
let(:scope_attrs) { { project: instance.project } }
let(:usage) { :milestones }
end
end
context 'with a group' do
it_behaves_like 'AtomicInternalId' do
let(:internal_id_attribute) { :iid }
let(:instance) { build(:milestone, project: nil, group: build(:group)) }
let(:scope_attrs) { { namespace: instance.group } }
let(:usage) { :milestones }
end
end
end
describe "Validation" do
before do
allow(subject).to receive(:set_iid).and_return(false)
......
......@@ -212,6 +212,18 @@ describe API::Users do
expect(json_response.last['id']).to eq(user.id)
end
it 'returns users with 2fa enabled' do
admin
user
user_with_2fa = create(:user, :two_factor_via_otp)
get api('/users', admin), { two_factor: 'enabled' }
expect(response).to match_response_schema('public_api/v4/user/admins')
expect(json_response.size).to eq(1)
expect(json_response.first['id']).to eq(user_with_2fa.id)
end
it 'returns 400 when provided incorrect sort params' do
get api('/users', admin), { order_by: 'magic', sort: 'asc' }
......
......@@ -32,6 +32,7 @@ describe EntityDateHelper do
end
it 'converts 86560 seconds' do
Rails.logger.debug date_helper_class.inspect
expect(date_helper_class.distance_of_time_as_hash(86560)).to eq(days: 1, mins: 2, seconds: 40)
end
......
......@@ -7,7 +7,7 @@ describe Projects::CreateFromTemplateService do
path: user.to_param,
template_name: 'rails',
description: 'project description',
visibility_level: Gitlab::VisibilityLevel::PRIVATE
visibility_level: Gitlab::VisibilityLevel::PUBLIC
}
end
......@@ -24,7 +24,23 @@ describe Projects::CreateFromTemplateService do
expect(project).to be_saved
expect(project.scheduled?).to be(true)
expect(project.description).to match('project description')
expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE)
end
context 'the result project' do
before do
Sidekiq::Testing.inline! do
@project = subject.execute
end
@project.reload
end
it 'overrides template description' do
expect(@project.description).to match('project description')
end
it 'overrides template visibility_level' do
expect(@project.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC)
end
end
end
......@@ -19,6 +19,14 @@ shared_examples_for 'AtomicInternalId' do
it { is_expected.to validate_numericality_of(internal_id_attribute) }
end
describe 'Creating an instance' do
subject { instance.save! }
it 'saves a new instance properly' do
expect { subject }.not_to raise_error
end
end
describe 'internal id generation' do
subject { instance.save! }
......
This diff is collapsed.
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