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

Add latest changes from gitlab-org/gitlab@master

parent 3f3e4bcc
No related branches found
No related tags found
No related merge requests found
Showing
with 325 additions and 158 deletions
Loading
Loading
@@ -5186,6 +5186,20 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "healthStatus",
"description": "Current health status of the epic",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "EpicHealthStatus",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "id",
"description": "ID of the epic",
Loading
Loading
@@ -13084,6 +13098,61 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "EpicHealthStatus",
"description": "Health status of child issues",
"fields": [
{
"name": "issuesAtRisk",
"description": "Number of issues at risk",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "issuesNeedingAttention",
"description": "Number of issues that need attention",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "issuesOnTrack",
"description": "Number of issues on track",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "TimelogConnection",
Loading
Loading
Loading
Loading
@@ -327,6 +327,7 @@ Represents an epic.
| `group` | Group! | Group to which the epic belongs |
| `hasChildren` | Boolean! | Indicates if the epic has children |
| `hasIssues` | Boolean! | Indicates if the epic has direct issues |
| `healthStatus` | EpicHealthStatus | Current health status of the epic |
| `id` | ID! | ID of the epic |
| `iid` | ID! | Internal ID of the epic |
| `parent` | Epic | Parent epic of the epic |
Loading
Loading
@@ -377,6 +378,16 @@ Total weight of open and closed descendant issues
| `closedIssues` | Int | Total weight of completed (closed) issues in this epic, including epic descendants |
| `openedIssues` | Int | Total weight of opened issues in this epic, including epic descendants |
 
## EpicHealthStatus
Health status of child issues
| Name | Type | Description |
| --- | ---- | ---------- |
| `issuesAtRisk` | Int | Number of issues at risk |
| `issuesNeedingAttention` | Int | Number of issues that need attention |
| `issuesOnTrack` | Int | Number of issues on track |
## EpicIssue
 
Relationship between an epic and an issue
Loading
Loading
Loading
Loading
@@ -261,15 +261,6 @@ Do not include the same information in multiple places. [Link to a SSOT instead.
Some features are also objects. For example, "GitLab's Merge Requests support X" and
"Create a new merge request for Z."
 
- Use common contractions when it helps create a friendly and informal tone, especially in tutorials and [UIs](https://design.gitlab.com/content/punctuation/#contractions).
- Do use contractions like: _it's_, _can't_, _wouldn't_, _you're_, _you've_, _haven't_, don't, _we're_, _that's_, and _won't_. Contractions in instructional documentation such as tutorials can help create a friendly and informal tone.
- Avoid less common contractions such as: _he'd_, _it'll_, _should've_, and _there'd_.
- Do not use contractions in reference documentation. Examples:
- You cannot set a limit higher than 1000.
- For `parameter1`, the default is 10.
- Do not use contractions with a proper noun and a verb, such as _GitLab's creating X_.
- Avoid using contractions when you need to emphasize a negative, such as "Do **not** install X with Y."
- Avoid use of the future tense:
- Instead of "after you execute this command, GitLab will display the result", use "after you execute this command, GitLab displays the result".
- Only use the future tense to convey when the action or result will actually occur at a future time.
Loading
Loading
@@ -286,6 +277,58 @@ as even native users of English might misunderstand them.
- Instead of "e.g.", use "for example," "such as," "for instance," or "like."
- Instead of "etc.", either use "and so on" or consider editing it out, since it can be vague.
 
### Contractions
- Use common contractions when it helps create a friendly and informal tone, especially in tutorials, instructional documentation, and [UIs](https://design.gitlab.com/content/punctuation/#contractions).
| Do | Don't |
|----------|-----------|
| it's | it is |
| can't | cannot |
| wouldn't | would not |
| you're | you are |
| you've | you have |
| haven't | have not |
| don't | do not |
| we're | we are |
| that's' | that is |
| won't | will not |
- Avoid less common contractions:
| Do | Don't |
|--------------|-------------|
| he would | he'd |
| it will | it'll |
| should have | should've |
| there would | there'd |
- Do not use contractions with a proper noun and a verb. For example:
| Do | Don't |
|----------------------|---------------------|
| GitLab is creating X | GitLab's creating X |
- Do not use contractions when you need to emphasize a negative. For example:
| Do | Don't |
|-----------------------------|----------------------------|
| Do **not** install X with Y | **Don't** install X with Y |
- Do not use contractions in reference documentation. For example:
| Do | Don't |
|------------------------------------------|----------------------------|
| Do **not** set a limit greater than 1000 | **Don't** set a limit greater than 1000 |
| For `parameter1`, the default is 10 | For `parameter1`, the default's 10 |
- Avoid contractions in error messages. Examples:
| Do | Don't |
|------------------------------------------|----------------------------|
| Requests to localhost are not allowed | Requests to localhost aren't allowed |
| Specified URL cannot be used | Specified URL can't be used |
## Text
 
- [Write in Markdown](#markdown).
Loading
Loading
doc/user/group/epics/img/epic_view_roadmap_v12.3.png

49.3 KiB

doc/user/group/epics/img/epic_view_roadmap_v12_9.png

425 KiB

Loading
Loading
@@ -182,7 +182,7 @@ If your epic contains one or more [child epics](#multi-level-child-epics-ultimat
have a [start or due date](#start-date-and-due-date), a
[roadmap](../roadmap/index.md) view of the child epics is listed under the parent epic.
 
![Child epics roadmap](img/epic_view_roadmap_v12.3.png)
![Child epics roadmap](img/epic_view_roadmap_v12_9.png)
 
## Reordering issues and child epics
 
Loading
Loading
doc/user/group/roadmap/img/roadmap_view.png

48.6 KiB

doc/user/group/roadmap/img/roadmap_view_v12_9.png

405 KiB

Loading
Loading
@@ -10,7 +10,12 @@ An Epic within a group containing **Start date** and/or **Due date**
can be visualized in a form of a timeline (e.g. a Gantt chart). The Epics Roadmap page
shows such a visualization for all the epics which are under a group and/or its subgroups.
 
![roadmap view](img/roadmap_view.png)
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/5164) in GitLab 12.9.
On the epic bars, you can see their title, progress, and completed weight percentage.
When you hover over an epic bar, a popover appears with its description, start and due dates, and weight completed.
![roadmap view](img/roadmap_view_v12_9.png)
 
A dropdown allows you to show only open or closed epics. By default, all epics are shown.
 
Loading
Loading
@@ -68,11 +73,7 @@ the timeline header represent the days of the week.
 
## Timeline bar for an epic
 
The timeline bar indicates the approximate position of an epic based on its start
and due date. If an epic doesn't have a due date, the timeline bar fades
away towards the future. Similarly, if an epic doesn't have a start date, the
timeline bar becomes more visible as it approaches the epic's due date on the
timeline.
The timeline bar indicates the approximate position of an epic based on its start and due date.
 
<!-- ## Troubleshooting
 
Loading
Loading
Loading
Loading
@@ -820,7 +820,7 @@ Prerequisites for embedding from a Grafana instance:
![Grafana Metric Panel](img/grafana_panel_v12_5.png)
1. In the upper-left corner of the page, select a specific value for each variable required for the queries in the chart.
![Select Query Variables](img/select_query_variables_v12_5.png)
1. In Grafana, click on a panel's title, then click **Share** to open the panel's sharing dialog to the **Link** tab.
1. In Grafana, click on a panel's title, then click **Share** to open the panel's sharing dialog to the **Link** tab. If you click the _dashboard's_ share panel instead, GitLab will attempt to embed the first supported panel on the dashboard (if available).
1. If your Prometheus queries use Grafana's custom template variables, ensure that "Template variables" option is toggled to **On**. Of Grafana global template variables, only `$__interval`, `$__from`, and `$__to` are currently supported. Toggle **On** the "Current time range" option to specify the time range of the chart. Otherwise, the default range will be the last 8 hours.
![Grafana Sharing Dialog](img/grafana_sharing_dialog_v12_5.png)
1. Click **Copy** to copy the URL to the clipboard.
Loading
Loading
Loading
Loading
@@ -17,8 +17,6 @@ module Banzai
def embed_params(node)
query_params = Gitlab::Metrics::Dashboard::Url.parse_query(node['href'])
 
return unless query_params.include?(:panelId)
time_window = Grafana::TimeWindow.new(query_params[:from], query_params[:to])
url = url_with_window(node['href'], query_params, time_window.in_milliseconds)
 
Loading
Loading
apply:
stage: deploy
image: "registry.gitlab.com/gitlab-org/cluster-integration/cluster-applications:v0.9.0"
image: "registry.gitlab.com/gitlab-org/cluster-integration/cluster-applications:v0.11.0"
environment:
name: production
variables:
Loading
Loading
@@ -15,6 +15,7 @@ apply:
JUPYTERHUB_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/jupyterhub/values.yaml
PROMETHEUS_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/prometheus/values.yaml
ELASTIC_STACK_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/elastic-stack/values.yaml
VAULT_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/vault/values.yaml
script:
- gitlab-managed-apps /usr/local/share/gitlab-managed-apps/helmfile.yaml
only:
Loading
Loading
Loading
Loading
@@ -248,6 +248,7 @@ excluded_attributes:
- :token_encrypted
services:
- :template
- :instance
error_tracking_setting:
- :encrypted_token
- :encrypted_token_iv
Loading
Loading
Loading
Loading
@@ -13,12 +13,7 @@ module Gitlab
# Reformats the specified panel in the Gitlab
# dashboard-yml format
def transform!
InputFormatValidator.new(
grafana_dashboard,
datasource,
panel,
query_params
).validate!
validate_input!
 
new_dashboard = formatted_dashboard
 
Loading
Loading
@@ -28,6 +23,17 @@ module Gitlab
 
private
 
def validate_input!
::Grafana::Validator.new(
grafana_dashboard,
datasource,
panel,
query_params
).validate!
rescue ::Grafana::Validator::Error => e
raise ::Gitlab::Metrics::Dashboard::Errors::DashboardProcessingError, e.message
end
def formatted_dashboard
{ panel_groups: [{ panels: [formatted_panel] }] }
end
Loading
Loading
@@ -56,11 +62,25 @@ module Gitlab
def panel
strong_memoize(:panel) do
grafana_dashboard[:dashboard][:panels].find do |panel|
panel[:id].to_s == query_params[:panelId]
query_params[:panelId] ? matching_panel?(panel) : valid_panel?(panel)
end
end
end
 
# Determines whether a given panel is the one
# specified by the linked grafana url
def matching_panel?(panel)
panel[:id].to_s == query_params[:panelId]
end
# Determines whether any given panel has the potenial
# to return valid results from grafana/prometheus
def valid_panel?(panel)
::Grafana::Validator
.new(grafana_dashboard, datasource, panel, query_params)
.valid?
end
# Grafana url query parameters. Includes information
# on which panel to select and time range.
def query_params
Loading
Loading
@@ -141,83 +161,6 @@ module Gitlab
params[:grafana_url]
end
end
class InputFormatValidator
include ::Gitlab::Metrics::Dashboard::Errors
attr_reader :grafana_dashboard, :datasource, :panel, :query_params
UNSUPPORTED_GRAFANA_GLOBAL_VARS = %w(
$__interval_ms
$__timeFilter
$__name
$timeFilter
$interval
).freeze
def initialize(grafana_dashboard, datasource, panel, query_params)
@grafana_dashboard = grafana_dashboard
@datasource = datasource
@panel = panel
@query_params = query_params
end
def validate!
validate_query_params!
validate_datasource!
validate_panel_type!
validate_variable_definitions!
validate_global_variables!
end
private
def validate_datasource!
return if datasource[:access] == 'proxy' && datasource[:type] == 'prometheus'
raise_error 'Only Prometheus datasources with proxy access in Grafana are supported.'
end
def validate_query_params!
return if [:panelId, :from, :to].all? { |param| query_params.include?(param) }
raise_error 'Grafana query parameters must include panelId, from, and to.'
end
def validate_panel_type!
return if panel[:type] == 'graph' && panel[:lines]
raise_error 'Panel type must be a line graph.'
end
def validate_variable_definitions!
return unless grafana_dashboard[:dashboard][:templating]
return if grafana_dashboard[:dashboard][:templating][:list].all? do |variable|
query_params[:"var-#{variable[:name]}"].present?
end
raise_error 'All Grafana variables must be defined in the query parameters.'
end
def validate_global_variables!
return unless panel_contains_unsupported_vars?
raise_error 'Prometheus must not include'
end
def panel_contains_unsupported_vars?
panel[:targets].any? do |target|
UNSUPPORTED_GRAFANA_GLOBAL_VARS.any? do |variable|
target[:expr].include?(variable)
end
end
end
def raise_error(message)
raise DashboardProcessingError.new(message)
end
end
end
end
end
Loading
Loading
# frozen_string_literal: true
# Performs checks on whether resources from Grafana can be handled
# We have certain restrictions on which formats we accept.
# Some are technical requirements, others are simplifications.
module Grafana
class Validator
Error = Class.new(StandardError)
attr_reader :grafana_dashboard, :datasource, :panel, :query_params
UNSUPPORTED_GRAFANA_GLOBAL_VARS = %w(
$__interval_ms
$__timeFilter
$__name
$timeFilter
$interval
).freeze
def initialize(grafana_dashboard, datasource, panel, query_params)
@grafana_dashboard = grafana_dashboard
@datasource = datasource
@panel = panel
@query_params = query_params
end
def validate!
validate_query_params!
validate_panel_type!
validate_variable_definitions!
validate_global_variables!
validate_datasource! if datasource
end
def valid?
validate!
true
rescue ::Grafana::Validator::Error
false
end
private
# See defaults in Banzai::Filter::InlineGrafanaMetricsFilter.
def validate_query_params!
return if [:from, :to].all? { |param| query_params.include?(param) }
raise_error 'Grafana query parameters must include from and to.'
end
# We may choose to support other panel types in future.
def validate_panel_type!
return if panel && panel[:type] == 'graph' && panel[:lines]
raise_error 'Panel type must be a line graph.'
end
# We must require variable definitions to create valid prometheus queries.
def validate_variable_definitions!
return unless grafana_dashboard[:dashboard][:templating]
return if grafana_dashboard[:dashboard][:templating][:list].all? do |variable|
query_params[:"var-#{variable[:name]}"].present?
end
raise_error 'All Grafana variables must be defined in the query parameters.'
end
# We may choose to support further Grafana variables in future.
def validate_global_variables!
return unless panel_contains_unsupported_vars?
raise_error "Prometheus must not include #{UNSUPPORTED_GRAFANA_GLOBAL_VARS}"
end
# We may choose to support additional datasources in future.
def validate_datasource!
return if datasource[:access] == 'proxy' && datasource[:type] == 'prometheus'
raise_error 'Only Prometheus datasources with proxy access in Grafana are supported.'
end
def panel_contains_unsupported_vars?
panel[:targets].any? do |target|
UNSUPPORTED_GRAFANA_GLOBAL_VARS.any? do |variable|
target[:expr].include?(variable)
end
end
end
def raise_error(message)
raise Validator::Error, message
end
end
end
Loading
Loading
@@ -220,6 +220,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
 
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
msgid "%{cores} cores"
msgstr ""
 
Loading
Loading
@@ -600,6 +603,9 @@ msgid_plural "- Users"
msgstr[0] ""
msgstr[1] ""
 
msgid "- of - weight completed"
msgstr ""
msgid "- show less"
msgstr ""
 
Loading
Loading
@@ -7795,6 +7801,9 @@ msgstr ""
msgid "Epics|An error occurred while saving the %{epicDateType} date"
msgstr ""
 
msgid "Epics|An error occurred while updating labels."
msgstr ""
msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
 
Loading
Loading
@@ -9925,10 +9934,13 @@ msgstr ""
msgid "Group: %{name}"
msgstr ""
 
msgid "GroupRoadmap|%{startDateInWords} &ndash; %{endDateInWords}"
msgid "GroupRoadmap|%{dateWord} – No end date"
msgstr ""
msgid "GroupRoadmap|%{startDateInWords} – %{endDateInWords}"
msgstr ""
 
msgid "GroupRoadmap|From %{dateWord}"
msgid "GroupRoadmap|No start date – %{dateWord}"
msgstr ""
 
msgid "GroupRoadmap|Something went wrong while fetching epics"
Loading
Loading
@@ -9949,9 +9961,6 @@ msgstr ""
msgid "GroupRoadmap|To widen your search, change or remove filters; from %{startDate} to %{endDate}."
msgstr ""
 
msgid "GroupRoadmap|Until %{dateWord}"
msgstr ""
msgid "GroupSAML|Certificate fingerprint"
msgstr ""
 
Loading
Loading
Loading
Loading
@@ -57,6 +57,18 @@ describe Boards::IssuesController do
expect(development.issues.map(&:relative_position)).not_to include(nil)
end
 
it 'returns issues by closed_at in descending order in closed list' do
create(:closed_issue, project: project, title: 'New Issue 1', closed_at: 1.day.ago)
create(:closed_issue, project: project, title: 'New Issue 2', closed_at: 1.week.ago)
list_issues user: user, board: board, list: board.lists.last.id
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['issues'].length).to eq(2)
expect(json_response['issues'][0]['title']).to eq('New Issue 1')
expect(json_response['issues'][1]['title']).to eq('New Issue 2')
end
it 'avoids N+1 database queries' do
create(:labeled_issue, project: project, labels: [development])
control_count = ActiveRecord::QueryRecorder.new { list_issues(user: user, board: board, list: list2) }.count
Loading
Loading
Loading
Loading
@@ -86,58 +86,11 @@ describe Dashboard::ProjectsController do
end
 
describe 'GET /starred.json' do
subject { get :starred, format: :json }
let(:projects) { create_list(:project, 2, creator: user) }
before do
allow(Kaminari.config).to receive(:default_per_page).and_return(1)
projects.each do |project|
project.add_developer(user)
create(:users_star_project, project_id: project.id, user_id: user.id)
end
end
it 'returns success' do
subject
expect(response).to have_gitlab_http_status(:ok)
get :starred, format: :json
end
 
it 'paginates the records' do
subject
expect(assigns(:projects).count).to eq(1)
end
end
end
context 'atom requests' do
let(:user) { create(:user) }
before do
sign_in(user)
end
describe '#index' do
context 'project pagination' do
let(:projects) { create_list(:project, 2, creator: user) }
before do
allow(Kaminari.config).to receive(:default_per_page).and_return(1)
projects.each do |project|
project.add_developer(user)
end
end
it 'does not paginate projects, even if page number is passed' do
get :index, format: :atom
expect(assigns(:events).count).to eq(2)
end
end
it { is_expected.to respond_with(:success) }
end
end
end
Loading
Loading
@@ -4,6 +4,11 @@ FactoryBot.define do
factory :service do
project
type { 'Service' }
trait :instance do
project { nil }
instance { true }
end
end
 
factory :custom_issue_tracker_service, class: 'CustomIssueTrackerService' do
Loading
Loading
Loading
Loading
@@ -47,6 +47,31 @@ describe 'Issue Boards', :js do
end
end
 
context 'closed issues' do
let!(:issue7) { create(:closed_issue, project: project, title: 'Closed issue 1', closed_at: 1.day.ago) }
let!(:issue8) { create(:closed_issue, project: project, title: 'Closed issue 2', closed_at: 1.week.ago) }
let!(:issue9) { create(:closed_issue, project: project, title: 'Closed issue 3', closed_at: 2.weeks.ago) }
before do
visit project_board_path(project, board)
wait_for_requests
expect(page).to have_selector('.board', count: 3)
end
it 'orders issues by closed_at' do
wait_for_requests
page.within(find('.board:nth-child(3)')) do
first, second, third = all('.board-card').to_a
expect(first).to have_content(issue7.title)
expect(second).to have_content(issue8.title)
expect(third).to have_content(issue9.title)
end
end
end
context 'ordering in list' do
before do
visit project_board_path(project, board)
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