Skip to content
Snippets Groups Projects
Commit 5e11c9b7 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 97d4d926
No related branches found
No related tags found
No related merge requests found
Showing
with 574 additions and 19 deletions
.notify:
image: alpine
image: ruby:2.6-alpine
stage: notification
dependencies: []
cache: {}
before_script:
- apk update && apk add git curl bash
- source scripts/utils.sh
- source scripts/notifications.sh
- install_gitlab_gem
variables:
COMMIT_NOTES_URL: "https://$CI_SERVER_HOST/$CI_PROJECT_PATH/commit/$CI_COMMIT_SHA#notes-list"
COMMIT_NOTES_URL: "https://${CI_SERVER_HOST}/${CI_PROJECT_PATH}/commit/${CI_COMMIT_SHA}#notes-list"
 
schedule:package-and-qa:notify-failure:
extends:
- .only:variables_refs-canonical-dot-com-schedules
- .notify
script:
- 'scripts/notify-slack qa-master ":skull_and_crossbones: Scheduled QA against master failed! :skull_and_crossbones: See $CI_PIPELINE_URL. For downstream pipelines, see $COMMIT_NOTES_URL" ci_failing'
- 'export NOTIFICATION_MESSAGE=":skull_and_crossbones: Scheduled QA against master failed! :skull_and_crossbones: See ${CI_PIPELINE_URL}. For downstream pipelines, see ${COMMIT_NOTES_URL}"'
- 'notify_on_job_failure schedule:package-and-qa qa-master "${NOTIFICATION_MESSAGE}" ci_failing'
needs: ["schedule:package-and-qa"]
when: on_failure
allow_failure: true
when: always
## What is the productivity problem to solve?
<!--
Please describe the productivity problem that needs to be solved backed by charts from
https://about.gitlab.com/handbook/engineering/quality/engineering-productivity-team/#engineering-productivity-team-metrics.
-->
### Problem identification checklist
- [ ] The root cause of the problem is identified.
- [ ] The surface of the problem is as small as possible.
## What are the potential solutions?
<!--
Please provide potential solutions here. Example solutions could be:
- Dogfood a feature.
- Refactor/improve some workflow code.
- Throw more money at the problem.
Please provide pros/cons and a weight estimate for each solution.
-->
- [ ] All potential solutions are listed.
- [ ] A solution has been chosen for the first iteration: `PUT THE CHOSEN SOLUTION HERE`
## Who and when will the solution be implemented?
<!--
For history reason, please list the person that will implement the solution and
the planned milestone/date.
-->
## Verify that the solution has improved the situation
<!--
Ideally, looking at the charts from the first part, we should see an improvement
after the implementation is merged/deployed/released.
-->
- [ ] The solution improved the situation.
- If yes, check this box and close the issue. Well done! :tada:
- Otherwise, create a new "Productivity Improvement" issue. You can re-use the description from this issue, but obviously another solution should be chosen this time.
/label ~"Engineering Productivity" ~meta
/cc @gl-quality/eng-prod
Loading
Loading
@@ -127,9 +127,11 @@ export default {
<input name="issue[description]" :value="issueDescription" type="hidden" />
<gl-form-input :value="csrfToken" class="hidden" name="authenticity_token" />
<loading-button
v-if="!error.gitlab_issue"
class="btn-success"
:label="__('Create issue')"
:loading="issueCreationInProgress"
data-qa-selector="create_issue_button"
@click="createIssue"
/>
</form>
Loading
Loading
@@ -140,6 +142,12 @@ export default {
</tooltip-on-truncate>
<h3>{{ __('Error details') }}</h3>
<ul>
<li v-if="error.gitlab_issue">
<span class="bold">{{ __('GitLab Issue') }}:</span>
<gl-link :href="error.gitlab_issue">
<span>{{ error.gitlab_issue }}</span>
</gl-link>
</li>
<li>
<span class="bold">{{ __('Sentry event') }}:</span>
<gl-link
Loading
Loading
Loading
Loading
@@ -42,6 +42,7 @@ class Issue < ApplicationRecord
has_many :issue_assignees
has_many :assignees, class_name: "User", through: :issue_assignees
has_many :zoom_meetings
has_one :sentry_issue
 
validates :project, presence: true
 
Loading
Loading
# frozen_string_literal: true
class SentryIssue < ApplicationRecord
belongs_to :issue
validates :issue, uniqueness: true, presence: true
validates :sentry_issue_identifier, presence: true
end
Loading
Loading
@@ -8,6 +8,18 @@ class Timelog < ApplicationRecord
belongs_to :merge_request, touch: true
belongs_to :user
 
scope :for_issues_in_group, -> (group) do
joins(:issue).where(
'EXISTS (?)',
Project.select(1).where(namespace: group.self_and_descendants)
.where('issues.project_id = projects.id')
)
end
scope :between_dates, -> (start_date, end_date) do
where('spent_at BETWEEN ? AND ?', start_date, end_date)
end
def issuable
issue || merge_request
end
Loading
Loading
Loading
Loading
@@ -10,6 +10,7 @@ module ErrorTracking
:first_release_short_version,
:first_seen,
:frequency,
:gitlab_issue,
:id,
:last_release_last_commit,
:last_release_short_version,
Loading
Loading
---
title: Add SentryIssue table to store a link between issue and sentry issue
merge_request: 37026
author:
type: added
---
title: Increase lower DAG `needs` limit from five to ten
merge_request: 21237
author:
type: changed
---
title: Fix misaligned approval tr
merge_request: 21368
author: Lee Tickett
type: fixed
---
title: Surface GitLab issue in error detail page
merge_request: 21019
author:
type: added
Loading
Loading
@@ -29,8 +29,8 @@ def ce_port_changelog?(changelog_path)
helper.ee? && !ee_changelog?(changelog_path)
end
 
def docs_only_change?
helper.changes_by_category.keys == [:docs]
def categories_need_changelog?
(helper.changes_by_category.keys - %i[docs none]).any?
end
 
def check_changelog(path)
Loading
Loading
@@ -59,7 +59,7 @@ def sanitized_mr_title
gitlab.mr_json["title"].gsub(/^WIP: */, '').gsub(/`/, '\\\`')
end
 
changelog_needed = !docs_only_change? && (gitlab.mr_labels & NO_CHANGELOG_LABELS).empty?
changelog_needed = categories_need_changelog? && (gitlab.mr_labels & NO_CHANGELOG_LABELS).empty?
changelog_found = git.added_files.find { |path| path =~ %r{\A(ee/)?(changelogs/unreleased)(-ee)?/} }
 
if git.modified_files.include?("CHANGELOG.md")
Loading
Loading
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddTimelogSpentAtIndex < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :timelogs, :spent_at, where: 'spent_at IS NOT NULL'
end
def down
remove_concurrent_index :timelogs, :spent_at, where: 'spent_at IS NOT NULL'
end
end
# frozen_string_literal: true
class CreateSentryIssuesTable < ActiveRecord::Migration[5.2]
DOWNTIME = false
def change
create_table :sentry_issues do |t|
t.references :issue,
foreign_key: { on_delete: :cascade },
index: { unique: true },
null: false
t.bigint :sentry_issue_identifier, null: false
end
end
end
Loading
Loading
@@ -3607,6 +3607,12 @@ ActiveRecord::Schema.define(version: 2019_12_06_122926) do
t.index ["reply_key"], name: "index_sent_notifications_on_reply_key", unique: true
end
 
create_table "sentry_issues", force: :cascade do |t|
t.bigint "issue_id", null: false
t.bigint "sentry_issue_identifier", null: false
t.index ["issue_id"], name: "index_sentry_issues_on_issue_id", unique: true
end
create_table "service_desk_settings", primary_key: "project_id", id: :bigint, default: nil, force: :cascade do |t|
t.string "issue_template_key", limit: 255
end
Loading
Loading
@@ -3812,6 +3818,7 @@ ActiveRecord::Schema.define(version: 2019_12_06_122926) do
t.datetime "spent_at"
t.index ["issue_id"], name: "index_timelogs_on_issue_id"
t.index ["merge_request_id"], name: "index_timelogs_on_merge_request_id"
t.index ["spent_at"], name: "index_timelogs_on_spent_at", where: "(spent_at IS NOT NULL)"
t.index ["user_id"], name: "index_timelogs_on_user_id"
end
 
Loading
Loading
@@ -4660,6 +4667,7 @@ ActiveRecord::Schema.define(version: 2019_12_06_122926) do
add_foreign_key "scim_oauth_access_tokens", "namespaces", column: "group_id", on_delete: :cascade
add_foreign_key "self_managed_prometheus_alert_events", "environments", on_delete: :cascade
add_foreign_key "self_managed_prometheus_alert_events", "projects", on_delete: :cascade
add_foreign_key "sentry_issues", "issues", on_delete: :cascade
add_foreign_key "service_desk_settings", "projects", on_delete: :cascade
add_foreign_key "services", "projects", name: "fk_71cce407f9", on_delete: :cascade
add_foreign_key "slack_integrations", "services", on_delete: :cascade
Loading
Loading
Loading
Loading
@@ -2156,6 +2156,10 @@ type Group {
"""
state: EpicState
): EpicConnection
"""
Indicates if Epics are enabled for namespace
"""
epicsEnabled: Boolean
 
"""
Loading
Loading
@@ -2168,6 +2172,11 @@ type Group {
"""
fullPath: ID!
 
"""
Indicates if Group timelogs are enabled for namespace
"""
groupTimelogsEnabled: Boolean
"""
ID of the namespace
"""
Loading
Loading
@@ -2233,6 +2242,41 @@ type Group {
"""
rootStorageStatistics: RootStorageStatistics
 
"""
Time logged in issues by group members
"""
timelogs(
"""
Returns the elements in the list that come after the specified cursor.
"""
after: String
"""
Returns the elements in the list that come before the specified cursor.
"""
before: String
"""
List time logs within a time range where the logged date is before end_date parameter.
"""
endDate: Time!
"""
Returns the first _n_ elements from the list.
"""
first: Int
"""
Returns the last _n_ elements from the list.
"""
last: Int
"""
List time logs within a time range where the logged date is after start_date parameter.
"""
startDate: Time!
): TimelogConnection!
"""
Permissions for the current user on the resource
"""
Loading
Loading
@@ -5484,6 +5528,63 @@ Time represented in ISO 8601
"""
scalar Time
 
type Timelog {
"""
The date when the time tracked was spent at
"""
date: Time!
"""
The issue that logged time was added to
"""
issue: Issue
"""
The time spent displayed in seconds
"""
timeSpent: Int!
"""
The user that logged the time
"""
user: User!
}
"""
The connection type for Timelog.
"""
type TimelogConnection {
"""
A list of edges.
"""
edges: [TimelogEdge]
"""
A list of nodes.
"""
nodes: [Timelog]
"""
Information to aid in pagination.
"""
pageInfo: PageInfo!
}
"""
An edge in a connection.
"""
type TimelogEdge {
"""
A cursor for use in pagination.
"""
cursor: String!
"""
The item at the end of the edge.
"""
node: Timelog
}
"""
Representing a todo entry
"""
Loading
Loading
Loading
Loading
@@ -3223,7 +3223,7 @@
},
{
"name": "epicsEnabled",
"description": null,
"description": "Indicates if Epics are enabled for namespace",
"args": [
 
],
Loading
Loading
@@ -3271,6 +3271,20 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "groupTimelogsEnabled",
"description": "Indicates if Group timelogs are enabled for namespace",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "id",
"description": "ID of the namespace",
Loading
Loading
@@ -3448,6 +3462,91 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "timelogs",
"description": "Time logged in issues by group members",
"args": [
{
"name": "startDate",
"description": "List time logs within a time range where the logged date is after start_date parameter.",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "endDate",
"description": "List time logs within a time range where the logged date is before end_date parameter.",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "before",
"description": "Returns the elements in the list that come before the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "first",
"description": "Returns the first _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
},
{
"name": "last",
"description": "Returns the last _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
}
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "TimelogConnection",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "userPermissions",
"description": "Permissions for the current user on the resource",
Loading
Loading
@@ -10813,6 +10912,199 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "TimelogConnection",
"description": "The connection type for Timelog.",
"fields": [
{
"name": "edges",
"description": "A list of edges.",
"args": [
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "TimelogEdge",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "nodes",
"description": "A list of nodes.",
"args": [
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "Timelog",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "pageInfo",
"description": "Information to aid in pagination.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "PageInfo",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "TimelogEdge",
"description": "An edge in a connection.",
"fields": [
{
"name": "cursor",
"description": "A cursor for use in pagination.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "node",
"description": "The item at the end of the edge.",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "Timelog",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "Timelog",
"description": null,
"fields": [
{
"name": "date",
"description": "The date when the time tracked was spent at",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "issue",
"description": "The issue that logged time was added to",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "Issue",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "timeSpent",
"description": "The time spent displayed in seconds",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "user",
"description": "The user that logged the time",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "User",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "ProjectStatistics",
Loading
Loading
Loading
Loading
@@ -320,7 +320,8 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `webUrl` | String! | Web URL of the group |
| `avatarUrl` | String | Avatar URL of the group |
| `parent` | Group | Parent group |
| `epicsEnabled` | Boolean | |
| `epicsEnabled` | Boolean | Indicates if Epics are enabled for namespace |
| `groupTimelogsEnabled` | Boolean | Indicates if Group timelogs are enabled for namespace |
| `epic` | Epic | |
 
### GroupPermissions
Loading
Loading
@@ -836,6 +837,15 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `count` | Int! | Number of total tasks |
| `completedCount` | Int! | Number of completed tasks |
 
### Timelog
| Name | Type | Description |
| --- | ---- | ---------- |
| `date` | Time! | The date when the time tracked was spent at |
| `timeSpent` | Int! | The time spent displayed in seconds |
| `user` | User! | The user that logged the time |
| `issue` | Issue | The issue that logged time was added to |
### Todo
 
| Name | Type | Description |
Loading
Loading
Loading
Loading
@@ -2256,11 +2256,11 @@ This example creates three paths of execution:
pipeline will be created with YAML error.
- We are temporarily limiting the maximum number of jobs that a single job can
need in the `needs:` array:
- For GitLab.com, the limit is five. For more information, see our
- For GitLab.com, the limit is ten. For more information, see our
[infrastructure issue](https://gitlab.com/gitlab-com/gl-infra/infrastructure/issues/7541).
- For self-managed instances, the limit is:
- Five by default (`ci_dag_limit_needs` feature flag is enabled).
- 50 if the `ci_dag_limit_needs` feature flag is disabled.
- 10, if the `ci_dag_limit_needs` feature flag is enabled (default).
- 50, if the `ci_dag_limit_needs` feature flag is disabled.
- It is impossible for now to have `needs: []` (empty needs), the job always needs to
depend on something, unless this is the job in the first stage. However, support for
an empty needs array [is planned](https://gitlab.com/gitlab-org/gitlab/issues/30631).
Loading
Loading
Loading
Loading
@@ -38,7 +38,7 @@ Feature.enabled?(:feature_flag, project, default_enabled: true)
The [`Project#feature_available?`][project-fa],
[`Namespace#feature_available?`][namespace-fa] (EE), and
[`License.feature_available?`][license-fa] (EE) methods all implicitly check for
a feature flag by the same name as the provided argument.
a by default enabled feature flag with the same name as the provided argument.
 
For example if a feature is license-gated, there's no need to add an additional
explicit feature flag check since the flag will be checked as part of the
Loading
Loading
@@ -56,12 +56,19 @@ isn't gated by a License or Plan.
unless the feature is explicitly disabled or limited to a percentage of users,
the feature flag check will default to `true`.**
 
As an example, if you were to ship the backend half of a feature behind a flag,
you'd want to explicitly disable that flag until the frontend half is also ready
to be shipped. To make sure this feature is disabled for both GitLab.com and
self-managed instances you'd need to explicitly call `Feature.enabled?` method
before the `feature_available` method. This ensures the feature_flag is defaulting
to `false`.
This is relevant when developing the feature using
[several smaller merge requests](https://about.gitlab.com/handbook/values/#make-small-merge-requests), or when the feature is considered to be an
[alpha or beta](https://about.gitlab.com/handbook/product/#alpha-beta-ga), and
should not be available by default.
As an example, if you were to ship the frontend half of a feature without the
backend, you'd want to disable the feature entirely until the backend half is
also ready to be shipped. To make sure this feature is disabled for both
GitLab.com and self-managed instances, you should use the
[`Namespace#alpha_feature_available?`](https://gitlab.com/gitlab-org/gitlab/blob/458749872f4a8f27abe8add930dbb958044cb926/ee/app/models/ee/namespace.rb#L113) or
[`Namespace#beta_feature_available?`](https://gitlab.com/gitlab-org/gitlab/blob/458749872f4a8f27abe8add930dbb958044cb926/ee/app/models/ee/namespace.rb#L100-112)
method, according to our [definitions](https://about.gitlab.com/handbook/product/#alpha-beta-ga). This ensures the feature is disabled unless the feature flag is
_explicitly_ enabled.
 
## Feature groups
 
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment