提交 8e812185 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 2f47b6d8
......@@ -75,7 +75,11 @@ export default {
name="eye-slash"
class="suggestion-help-hover mr-1 suggestion-confidential"
/>
<gl-link :href="suggestion.webUrl" target="_blank" class="suggestion bold str-truncated-100">
<gl-link
:href="suggestion.webUrl"
target="_blank"
class="suggestion bold str-truncated-100 gl-text-gray-900!"
>
{{ suggestion.title }}
</gl-link>
</div>
......
......@@ -257,15 +257,6 @@ export default {
{{ __('Copy link') }}
</button>
</li>
<li v-if="canEdit">
<button
class="btn btn-transparent js-note-delete js-note-delete"
type="button"
@click.prevent="onDelete"
>
<span class="text-danger">{{ __('Delete comment') }}</span>
</button>
</li>
<li v-if="isIssue">
<button
class="btn-default btn-transparent"
......@@ -276,6 +267,15 @@ export default {
{{ displayAssignUserText }}
</button>
</li>
<li v-if="canEdit">
<button
class="btn btn-transparent js-note-delete js-note-delete"
type="button"
@click.prevent="onDelete"
>
<span class="text-danger">{{ __('Delete comment') }}</span>
</button>
</li>
</ul>
</div>
</div>
......
......@@ -18,17 +18,21 @@ export default class PersistentUserCallout {
init() {
const closeButton = this.container.querySelector('.js-close');
const followLink = this.container.querySelector('.js-follow-link');
if (!closeButton) {
return;
if (closeButton) {
this.handleCloseButtonCallout(closeButton);
} else if (followLink) {
this.handleFollowLinkCallout(followLink);
}
}
handleCloseButtonCallout(closeButton) {
closeButton.addEventListener('click', event => this.dismiss(event));
if (this.deferLinks) {
this.container.addEventListener('click', event => {
const isDeferredLink = event.target.classList.contains(DEFERRED_LINK_CLASS);
if (isDeferredLink) {
const { href, target } = event.target;
......@@ -38,6 +42,10 @@ export default class PersistentUserCallout {
}
}
handleFollowLinkCallout(followLink) {
followLink.addEventListener('click', event => this.registerCalloutWithLink(event));
}
dismiss(event, deferredLinkOptions = null) {
event.preventDefault();
......@@ -58,6 +66,27 @@ export default class PersistentUserCallout {
});
}
registerCalloutWithLink(event) {
event.preventDefault();
const { href } = event.currentTarget;
axios
.post(this.dismissEndpoint, {
feature_name: this.featureId,
})
.then(() => {
window.location.assign(href);
})
.catch(() => {
Flash(
__(
'An error occurred while acknowledging the notification. Refresh the page and try again.',
),
);
});
}
static factory(container, options) {
if (!container) {
return undefined;
......
......@@ -4,6 +4,7 @@ const PERSISTENT_USER_CALLOUTS = [
'.js-recovery-settings-callout',
'.js-users-over-license-callout',
'.js-admin-licensed-user-count-threshold',
'.js-buy-pipeline-minutes-notification-callout',
];
const initCallouts = () => {
......
......@@ -5,7 +5,7 @@
font-size: 13px;
word-break: break-all;
word-wrap: break-word;
color: $gl-text-color-inverted;
color: color-yiq($builds-trace-bg);
border-radius: $border-radius-small;
min-height: 42px;
background-color: $builds-trace-bg;
......
......@@ -969,10 +969,6 @@
vertical-align: sub;
}
.suggestion-item a {
color: initial;
}
.suggestion-confidential {
color: $orange-600;
}
......
......@@ -115,6 +115,9 @@ $secondary: $gray-600;
$issues-today-bg: #333838;
$issues-today-border: #333a40;
$yiq-text-dark: $gray-50;
$yiq-text-light: $gray-950;
.gl-label {
filter: brightness(0.9) contrast(1.1);
}
......
......@@ -19,7 +19,11 @@ module WikiActions
end
before_action only: [:edit, :update], unless: :valid_encoding? do
redirect_to wiki_page_path(wiki, page)
if params[:id].present?
redirect_to wiki_page_path(wiki, page || params[:id])
else
redirect_to wiki_path(wiki)
end
end
end
......
......@@ -226,6 +226,11 @@ class Environment < ApplicationRecord
available? && stop_action.present?
end
def cancel_deployment_jobs!
jobs = all_deployments.active.with_deployable
jobs.each { |deployment| deployment.deployable.cancel! }
end
def stop_with_action!(current_user)
return unless available?
......
......@@ -93,7 +93,7 @@ class Iteration < ApplicationRecord
# ensure dates do not overlap with other Iterations in the same group/project
def dates_do_not_overlap
return unless resource_parent.iterations.within_timeframe(start_date, due_date).exists?
return unless resource_parent.iterations.where.not(id: self.id).within_timeframe(start_date, due_date).exists?
errors.add(:base, s_("Iteration|Dates cannot overlap with other existing Iterations"))
end
......
......@@ -29,6 +29,11 @@ module MergeRequests
.execute_for_merge_request(merge_request)
end
def cancel_review_app_jobs!(merge_request)
environments = merge_request.environments.in_review_folder.available
environments.each { |environment| environment.cancel_deployment_jobs! }
end
def source_project
@source_project ||= merge_request.source_project
end
......
......@@ -18,6 +18,7 @@ module MergeRequests
invalidate_cache_counts(merge_request, users: merge_request.assignees)
merge_request.update_project_counter_caches
delete_non_latest_diffs(merge_request)
cancel_review_app_jobs!(merge_request)
cleanup_environments(merge_request)
end
......
---
title: Cancel review app deployment when MR is merged
merge_request: 34960
author:
type: fixed
---
title: Move 'Delete comment' button to bottom of 'More actions' list
merge_request: 35237
author:
type: fixed
---
title: Fix issue suggestion text color on dark mode
merge_request: 34899
author:
type: fixed
---
title: Fix job log text color in dark mode
merge_request: 35387
author:
type: fixed
---
title: Redirect wiki edit actions for missing pages
merge_request: 35350
author:
type: fixed
......@@ -21,7 +21,7 @@ end
scope path: '-' do
get '/snippets/:snippet_id/raw/:ref/*path',
to: 'snippets/blobs#raw',
as: :snippet_raw,
as: :snippet_blob_raw,
format: false,
constraints: { snippet_id: /\d+/ }
end
......
......@@ -24,6 +24,7 @@ exceptions:
- CSV
- DNS
- EKS
- FAQ
- GDK
- GET
- GNU
......@@ -34,11 +35,14 @@ exceptions:
- HTTPS
- IAM
- IDE
- IRC
- IBM
- JSON
- LDAP
- LDAPS
- LESS
- LFS
- LRU
- NFS
- NGINX
- NOTE
......@@ -48,6 +52,7 @@ exceptions:
- POST
- PUT
- RPC
- RAM
- RSA
- RSS
- SAML
......@@ -58,11 +63,13 @@ exceptions:
- SSH
- SSL
- SSO
- TCP
- TIP
- TLS
- TODO
- TOML
- UNIX
- USB
- URI
- URL
- VPC
......
......@@ -248,6 +248,7 @@ memoization
memoize
memoized
memoizing
Memorystore
mergeable
Microsoft
middleware
......@@ -335,6 +336,7 @@ Puma
Python
Qualys
Rackspace
Raspbian
reachability
rebase
rebased
......@@ -422,6 +424,7 @@ storages
strace
strikethrough
strikethroughs
stunnel
subpath
subfolder
subfolders
......
......@@ -7944,6 +7944,7 @@ type Mutation {
"""
updateImageDiffNote(input: UpdateImageDiffNoteInput!): UpdateImageDiffNotePayload
updateIssue(input: UpdateIssueInput!): UpdateIssuePayload
updateIteration(input: UpdateIterationInput!): UpdateIterationPayload
"""
Updates a Note. If the body of the Note contains only quick actions, the Note
......@@ -13257,6 +13258,66 @@ type UpdateIssuePayload {
issue: Issue
}
"""
Autogenerated input type of UpdateIteration
"""
input UpdateIterationInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
The description of the iteration
"""
description: String
"""
The end date of the iteration
"""
dueDate: String
"""
The group of the iteration
"""
groupPath: ID!
"""
The id of the iteration
"""
id: ID!
"""
The start date of the iteration
"""
startDate: String
"""
The title of the iteration
"""
title: String
}
"""
Autogenerated return type of UpdateIteration
"""
type UpdateIterationPayload {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
Errors encountered during execution of the mutation.
"""
errors: [String!]!
"""
The updated iteration
"""
iteration: Iteration
}
"""
Autogenerated input type of UpdateNote
"""
......
......@@ -23646,6 +23646,33 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "updateIteration",
"description": null,
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "UpdateIterationInput",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "UpdateIterationPayload",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "updateNote",
"description": "Updates a Note. If the body of the Note contains only quick actions, the Note will be destroyed during the update, and no Note will be returned",
......@@ -39167,6 +39194,162 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "UpdateIterationInput",
"description": "Autogenerated input type of UpdateIteration",
"fields": null,
"inputFields": [
{
"name": "groupPath",
"description": "The group of the iteration",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "id",
"description": "The id of the iteration",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "title",
"description": "The title of the iteration",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "description",
"description": "The description of the iteration",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "startDate",
"description": "The start date of the iteration",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "dueDate",
"description": "The end date of the iteration",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
}
],
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "UpdateIterationPayload",
"description": "Autogenerated return type of UpdateIteration",
"fields": [
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "errors",
"description": "Errors encountered during execution of the mutation.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "iteration",
"description": "The updated iteration",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "Iteration",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "UpdateNoteInput",
......@@ -2019,6 +2019,16 @@ Autogenerated return type of UpdateIssue
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `issue` | Issue | The issue after mutation |
## UpdateIterationPayload
Autogenerated return type of UpdateIteration
| Name | Type | Description |
| --- | ---- | ---------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `iteration` | Iteration | The updated iteration |
## UpdateNotePayload
Autogenerated return type of UpdateNote
......
......@@ -283,7 +283,7 @@ Markdown code will embed the test coverage report badge of the `coverage` job
into your `README.md`:
```markdown
![coverage](https://gitlab.com/gitlab-org/gitlab-foss/badges/master/coverage.svg?job=coverage)
![coverage](https://gitlab.com/gitlab-org/gitlab/badges/master/coverage.svg?job=coverage)
```
### Badge styles
......@@ -296,7 +296,7 @@ Pipeline badges can be rendered in different styles by adding the `style=style_n
https://example.gitlab.com/<namespace>/<project>/badges/<branch>/coverage.svg?style=flat
```
![Badge flat style](https://gitlab.com/gitlab-org/gitlab-foss/badges/master/coverage.svg?job=coverage&style=flat)
![Badge flat style](https://gitlab.com/gitlab-org/gitlab/badges/master/coverage.svg?job=coverage&style=flat)
#### Flat square
......@@ -306,17 +306,17 @@ https://example.gitlab.com/<namespace>/<project>/badges/<branch>/coverage.svg?st
https://example.gitlab.com/<namespace>/<project>/badges/<branch>/coverage.svg?style=flat-square
```
![Badge flat square style](https://gitlab.com/gitlab-org/gitlab-foss/badges/master/coverage.svg?job=coverage&style=flat-square)
![Badge flat square style](https://gitlab.com/gitlab-org/gitlab/badges/master/coverage.svg?job=coverage&style=flat-square)
### Custom badge text
The text for a badge can be customized. This can be useful to differentiate between multiple coverage jobs that run in the same pipeline. Customize the badge text and width by adding the `key_text=custom_text` and `key_width=custom_key_width` parameters to the URL:
```plaintext
https://gitlab.com/gitlab-org/gitlab-foss/badges/master/coverage.svg?job=karma&key_text=Frontend+Coverage&key_width=100
https://gitlab.com/gitlab-org/gitlab/badges/master/coverage.svg?job=karma&key_text=Frontend+Coverage&key_width=100
```
![Badge with custom text and width](https://gitlab.com/gitlab-org/gitlab-foss/badges/master/coverage.svg?job=karma&key_text=Frontend+Coverage&key_width=100)
![Badge with custom text and width](https://gitlab.com/gitlab-org/gitlab/badges/master/coverage.svg?job=karma&key_text=Frontend+Coverage&key_width=100)
## Environment Variables
......
......@@ -412,7 +412,7 @@ are *explicitly not supported* and may stop working at any time.
### Options for Microsoft Windows
If you're running Windows 10, the [Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/install-win10), and its latest [WSL 2](https://docs.microsoft.com/en-us/install-win10) version,
If you're running Windows 10, the [Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/install-win10), and its latest [WSL 2](https://docs.microsoft.com/en-us/windows/wsl/install-win10#update-to-wsl-2) version,
support the installation of different Linux distributions, which include the Git and SSH clients.
For current versions of Windows, you can also install the Git and SSH clients with
......
......@@ -72,7 +72,7 @@ The GitLab University curriculum is composed of GitLab videos, screencasts, pres
1. [Getting Help](https://about.gitlab.com/get-help/)
- Proposing Features and Reporting and Tracking bugs for GitLab
- The GitLab IRC channel, Gitter Chat Room, Community Forum and Mailing List
- The GitLab IRC channel, Gitter Chat Room, Community Forum, and Mailing List
- Getting Technical Support
- Being part of our Great Community and Contributing to GitLab
1. [Getting Started with the GitLab Development Kit (GDK)](https://about.gitlab.com/blog/2016/06/08/getting-started-with-gitlab-development-kit/)
......@@ -140,11 +140,11 @@ The GitLab University curriculum is composed of GitLab videos, screencasts, pres
## 3. GitLab Advanced
### 3.1. Dev Ops
### 3.1. DevOps
1. [Xebia Labs: Dev Ops Terminology](https://xebialabs.com/glossary/)
1. [Xebia Labs: Periodic Table of DevOps Tools](https://xebialabs.com/periodic-table-of-devops-tools/)
1. [Puppet Labs: State of Dev Ops 2016 - Book](https://puppet.com/resources/report/2016-state-devops-report/)
1. [XebiaLabs: DevOps Terminology](https://xebialabs.com/glossary/)
1. [XebiaLabs: Periodic Table of DevOps Tools](https://digital.ai/periodic-table-of-devops-tools)
1. [Puppet Labs: State of DevOps 2016 - Book](https://puppet.com/resources/report/2016-state-devops-report/)
### 3.2. Installing GitLab with Omnibus
......
......@@ -15,7 +15,7 @@ See the [book list](booklist.md) for additional recommendations.
1. **Remote: Office not required**
David Heinemeier Hansson and Jason Fried, 2013
([amazon](https://www.amazon.co.uk/Remote-Required-David-Heinemeier-Hansson/dp/0091954673))
([Amazon](https://www.amazon.co.uk/dp/0091954673/ref=cm_sw_r_tw_dp_x_0yy9EbZ2WXJ6Y))
1. **The Year Without Pants**
......
......@@ -72,7 +72,7 @@ Plans are underway for supporting the following languages, dependency managers,
| Language (package managers) | Supported files | Scan tool(s) | Issue |
|----------------------------- | --------------- | ------------ | ----- |
| Python ([Poetry](http://python-poetry.org/)) | `poetry.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | [GitLab#7006](https://gitlab.com/gitlab-org/gitlab/-/issues/7006) |
| Python ([Poetry](https://python-poetry.org/)) | `poetry.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | [GitLab#7006](https://gitlab.com/gitlab-org/gitlab/-/issues/7006) |
| Python ([Pipenv](https://pipenv.pypa.io/en/latest/)) | `Pipfile.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | [GitLab#11756](https://gitlab.com/gitlab-org/gitlab/-/issues/11756) |
## Contribute your scanner
......
......@@ -1084,8 +1084,8 @@ customRules:
```
By default, Falco only outputs security events to logs as JSON objects. To set it to output to an
[external API](https://falco.org/docs/alerts#https-output-send-alerts-to-an-https-end-point)
or [application](https://falco.org/docs/alerts#program-output),
[external API](https://falco.org/docs/alerts/#https-output-send-alerts-to-an-https-end-point)
or [application](https://falco.org/docs/alerts/#program-output),
add the following to `.gitlab/managed-apps/falco/values.yaml`:
```yaml
......
......@@ -64,7 +64,7 @@ The following languages and package managers are supported.
| Go | [Godep](https://github.com/tools/godep), [go mod](https://github.com/golang/go/wiki/Modules) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| Java | [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| .NET | [Nuget](https://www.nuget.org/) (.NET Framework is supported via the [mono project](https://www.mono-project.com/). Windows specific dependencies are not supported at this time.) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| Python | [pip](https://pip.pypa.io/en/stable/) (Python is supported through [requirements.txt](https://pip.pypa.io/en/1.1/requirements/) and [Pipfile.lock](https://github.com/pypa/pipfile#pipfilelock).) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| Python | [pip](https://pip.pypa.io/en/stable/) (Python is supported through [requirements.txt](https://pip.pypa.io/en/stable/user_guide/#requirements-files) and [Pipfile.lock](https://github.com/pypa/pipfile#pipfilelock).) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| Ruby | [gem](https://rubygems.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| Objective-C, Swift | [Carthage](https://github.com/Carthage/Carthage) |[License Finder](https://github.com/pivotal/LicenseFinder)|
......@@ -339,7 +339,7 @@ strict-ssl = false
### Configuring Yarn projects
You can configure Yarn projects by using a [`.yarnrc.yml`](https://yarnpkg.com/configuration/yarnrc/)
You can configure Yarn projects by using a [`.yarnrc.yml`](https://yarnpkg.com/configuration/yarnrc)
file.
#### Using private Yarn registries
......
......@@ -38,7 +38,7 @@ From there you can create a new iteration or click an iteration to get a more de
## Create an iteration
NOTE: **Note:**
A permission level of [Developer or higher](../../permissions.md) is required to create iterations.
You need Developer [permissions](../../permissions.md) or higher to create an iteration.
To create an iteration:
......@@ -47,7 +47,16 @@ To create an iteration:
1. Enter the title, a description (optional), a start date, and a due date.
1. Click **Create iteration**. The iteration details page opens.
### Enable Iterations **(CORE ONLY)**
## Edit an iteration
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218277) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.2.
NOTE: **Note:**
You need Developer [permissions](../../permissions.md) or higher to edit an iteration.
To edit an iteration, click the three-dot menu (**{ellipsis_v}**) > **Edit iteration**.
## Enable Iterations **(CORE ONLY)**
GitLab Iterations feature is under development and not ready for production use.
It is deployed behind a feature flag that is **disabled by default**.
......
......@@ -75,7 +75,7 @@ This is a [Closed Beta](https://about.gitlab.com/handbook/product/#closed-beta)
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/709) in GitLab 12.1.
> - It's deployed behind a feature flag, disabled by default.
> - It's disabled on GitLab.com. If you want to enable it for your subscription, contact Product Management through [GitLab Support](https://support.gitlab.com/hc).
> - It's disabled on GitLab.com. If you want to enable it for your subscription, contact Product Management through [GitLab Support](https://support.gitlab.com/hc/en-us).
When SSO is being enforced, groups can enable an additional level of protection by enforcing the creation of dedicated user accounts to access the group.
......
......@@ -54,7 +54,7 @@ repository that were written using some of the nuances of GitLab's RedCarpet ver
of Markdown. Since CommonMark uses slightly stricter syntax, these documents
might now appear a little differently since we have transitioned to CommonMark.
It's usually quite easy to fix. For example, numbered lists with nested lists may
For example, numbered lists with nested lists may
render incorrectly:
```markdown
......@@ -63,8 +63,8 @@ render incorrectly:
- milk
```
Simply add a space to each nested item to align the `-` with the first character of
the top list item (`C` in this case):
To correct their rendering, add a space to each nested item to align the `-` with the first
character of the top list item (`C` in this case):
```markdown
1. Chocolate
......@@ -241,7 +241,7 @@ Sometimes you want to :monkey: around a bit and add some :star2: to your :speech
You can use it to point out a :bug: or warn about :speak_no_evil: patches. And if someone improves your really :snail: code, send them some :birthday:. People will :heart: you for that.
If you're new to this, don't be :fearful:. You can easily join the emoji :family:. All you need to do is to look up one of the supported codes.
If you're new to this, don't be :fearful:. You can join the emoji :family:. All you need to do is to look up one of the supported codes.
Consult the [Emoji Cheat Sheet](https://www.emojicopy.com) for a list of all supported emoji codes. :thumbsup:
```
......@@ -252,7 +252,7 @@ Sometimes you want to <img src="https://gitlab.com/gitlab-org/gitlab-foss/raw/ma
You can use it to point out a <img src="https://gitlab.com/gitlab-org/gitlab-foss/raw/master/app/assets/images/emoji/bug.png" width="20px" height="20px" style="display:inline;margin:0"> or warn about <img src="https://gitlab.com/gitlab-org/gitlab-foss/raw/master/app/assets/images/emoji/speak_no_evil.png" width="20px" height="20px" style="display:inline;margin:0"> patches. And if someone improves your really <img src="https://gitlab.com/gitlab-org/gitlab-foss/raw/master/app/assets/images/emoji/snail.png" width="20px" height="20px" style="display:inline;margin:0"> code, send them some <img src="https://gitlab.com/gitlab-org/gitlab-foss/raw/master/app/assets/images/emoji/birthday.png" width="20px" height="20px" style="display:inline;margin:0">. People will <img src="https://gitlab.com/gitlab-org/gitlab-foss/raw/master/app/assets/images/emoji/heart.png" width="20px" height="20px" style="display:inline;margin:0"> you for that.
If you're new to this, don't be <img src="https://gitlab.com/gitlab-org/gitlab-foss/raw/master/app/assets/images/emoji/fearful.png" width="20px" height="20px" style="display:inline;margin:0">. You can easily join the emoji <img src="https://gitlab.com/gitlab-org/gitlab-foss/raw/master/app/assets/images/emoji/family.png" width="20px" height="20px" style="display:inline;margin:0">. All you need to do is to look up one of the supported codes.
If you're new to this, don't be <img src="https://gitlab.com/gitlab-org/gitlab-foss/raw/master/app/assets/images/emoji/fearful.png" width="20px" height="20px" style="display:inline;margin:0">. You can join the emoji <img src="https://gitlab.com/gitlab-org/gitlab-foss/raw/master/app/assets/images/emoji/family.png" width="20px" height="20px" style="display:inline;margin:0">. All you need to do is to look up one of the supported codes.
Consult the [Emoji Cheat Sheet](https://www.webfx.com/tools/emoji-cheat-sheet/) for a list of all supported emoji codes. <img src="https://gitlab.com/gitlab-org/gitlab-foss/raw/master/app/assets/images/emoji/thumbsup.png" width="20px" height="20px" style="display:inline;margin:0">
......@@ -407,9 +407,9 @@ the [Asciidoctor user manual](https://asciidoctor.org/docs/user-manual/#activati
### Special GitLab references
GFM recognizes special GitLab related references. For example, you can easily reference
GFM recognizes special GitLab related references. For example, you can reference
an issue, a commit, a team member, or even the whole team within a project. GFM will turn
that reference into a link so you can navigate between them easily.
that reference into a link so you can navigate between them.
Additionally, GFM recognizes certain cross-project references and also has a shorthand
version to reference other projects from the same namespace.
......@@ -589,7 +589,7 @@ If a functionality is extended, the new option will be listed as a sub-section.
### Blockquotes
Blockquotes are an easy way to highlight information, such as a side-note. It's generated
Blockquotes are useful to highlight information, such as a side-note. It's generated
by starting the lines of the blockquote with `>`:
```markdown
......@@ -635,9 +635,9 @@ you can quote that without having to manually prepend `>` to every line!
### Code spans and blocks
You can easily highlight anything that should be viewed as code and not simple text.
You can highlight anything that should be viewed as code and not simple text.
Simple inline code is easily highlighted with single backticks `` ` ``:
Simple inline code is highlighted with single backticks `` ` ``:
```markdown
Inline `code` has `back-ticks around` it.
......@@ -1148,7 +1148,7 @@ A line break will be inserted (a new paragraph will start) if the previous text
ended with two newlines, like when you hit <kbd>Enter</kbd> twice in a row. If you only
use one newline (hit <kbd>Enter</kbd> once), the next sentence will be part of the
same paragraph. This is useful if you want to keep long lines from wrapping, and keep
them easily editable:
them editable:
```markdown
Here's a line for us to start with.
......@@ -1273,7 +1273,7 @@ GFM will auto-link almost any URL you put into your text:
### Lists
Ordered and unordered lists can be easily created.
Ordered and unordered lists can be created.
For an ordered list, add the number you want the list
to start with, like `1.`, followed by a space, at the start of each line for ordered lists.
......
......@@ -247,6 +247,7 @@ group.
| Create project in group | | | ✓ (3) | ✓ (3) | ✓ (3) |
| Share (invite) groups with groups | | | | | ✓ |
| Create/edit/delete group milestones | | | ✓ | ✓ | ✓ |
| Create/edit/delete iterations | | | ✓ | ✓ | ✓ |
| Enable/disable a dependency proxy **(PREMIUM)** | | | ✓ | ✓ | ✓ |
| Use security dashboard **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
| Create/edit/delete metrics dashboard annotations | | | ✓ | ✓ | ✓ |
......
......@@ -1050,8 +1050,7 @@ Alerts can be used to trigger actions, like opening an issue automatically (disa
1. Optionally, select whether to send an email notification to the developers of the project.
1. Click **Save changes**.
Once enabled, an issue will be opened automatically when an alert is triggered which contains values extracted from [alert's payload](https://prometheus.io/docs/alerting/configuration/#webhook_config
):
Once enabled, an issue will be opened automatically when an alert is triggered which contains values extracted from [alert's payload](https://prometheus.io/docs/alerting/latest/configuration/#webhook_config):
- Issue author: `GitLab Alert Bot`
- Issue title: Extract from `annotations/title`, `annotations/summary` or `labels/alertname`
......
# Publishes a tag/branch to Composer Packages of the current project
publish:
image: curlimages/curl:latest
stage: build
variables:
URL: "$CI_SERVER_PROTOCOL://$CI_SERVER_HOST:$CI_SERVER_PORT/api/v4/projects/$CI_PROJECT_ID/packages/composer?job_token=$CI_JOB_TOKEN"
script:
- version=$([[ -z "$CI_COMMIT_TAG" ]] && echo "branch=$CI_COMMIT_REF_NAME" || echo "tag=$CI_COMMIT_TAG")
- insecure=$([ "$CI_SERVER_PROTOCOL" = "http" ] && echo "--insecure" || echo "")
- response=$(curl -s -w "\n%{http_code}" $insecure --data $version $URL)
- code=$(echo "$response" | tail -n 1)
- body=$(echo "$response" | head -n 1)
# Output state information
- if [ $code -eq 201 ]; then
echo "Package created - Code $code - $body";
else
echo "Could not create package - Code $code - $body";
exit 1;
fi
......@@ -1233,6 +1233,9 @@ msgstr ""
msgid "Action to take when receiving an alert."
msgstr ""
msgid "Actions"
msgstr ""
msgid "Activate"
msgstr ""
......@@ -2254,6 +2257,9 @@ msgstr ""
msgid "An error occurred when updating the issue weight"
msgstr ""
msgid "An error occurred while acknowledging the notification. Refresh the page and try again."
msgstr ""
msgid "An error occurred while adding formatted title for epic"
msgstr ""
......@@ -8231,6 +8237,9 @@ msgstr ""
msgid "Edit issues"
msgstr ""
msgid "Edit iteration"
msgstr ""
msgid "Edit public deploy key"
msgstr ""
......@@ -9509,6 +9518,12 @@ msgstr ""
msgid "Failed to install."
msgstr ""
msgid "Failed to load assignees. Please try again."
msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
msgid "Failed to load emoji list."
msgstr ""
......@@ -12662,6 +12677,9 @@ msgstr ""
msgid "Iteration removed"
msgstr ""
msgid "Iteration updated"
msgstr ""
msgid "Iterations"
msgstr ""
......@@ -14885,9 +14903,6 @@ msgid_plural "New Issues"
msgstr[0] ""
msgstr[1] ""
msgid "New Iteration"
msgstr ""
msgid "New Jira import"
msgstr ""
......@@ -24515,6 +24530,9 @@ msgstr ""
msgid "Update it"
msgstr ""
msgid "Update iteration"
msgstr ""
msgid "Update now"
msgstr ""
......
......@@ -43,6 +43,23 @@ describe('PersistentUserCallout', () => {
return fixture;
}
function createFollowLinkFixture() {
const fixture = document.createElement('div');
fixture.innerHTML = `
<ul>
<li
class="container"
data-dismiss-endpoint="${dismissEndpoint}"
data-feature-id="${featureName}"
>
<a class="js-follow-link" href="/somewhere-pleasant">A Link</a>
</li>
</ul>
`;
return fixture;
}
describe('dismiss', () => {
let button;
let mockAxios;
......@@ -144,6 +161,55 @@ describe('PersistentUserCallout', () => {
});
});
describe('follow links', () => {
let link;
let mockAxios;
let persistentUserCallout;
beforeEach(() => {
const fixture = createFollowLinkFixture();
const container = fixture.querySelector('.container');
link = fixture.querySelector('.js-follow-link');
mockAxios = new MockAdapter(axios);
persistentUserCallout = new PersistentUserCallout(container);
jest.spyOn(persistentUserCallout.container, 'remove').mockImplementation(() => {});
delete window.location;
window.location = { assign: jest.fn() };
});
afterEach(() => {
mockAxios.restore();
});
it('uses a link to trigger callout and defers following until callout is finished', () => {
const { href } = link;
mockAxios.onPost(dismissEndpoint).replyOnce(200);
link.click();
return waitForPromises().then(() => {
expect(window.location.assign).toBeCalledWith(href);
expect(mockAxios.history.post[0].data).toBe(JSON.stringify({ feature_name: featureName }));
expect(persistentUserCallout.container.remove).not.toHaveBeenCalled();
});
});
it('invokes Flash when the dismiss request fails', () => {
mockAxios.onPost(dismissEndpoint).replyOnce(500);
link.click();
return waitForPromises().then(() => {
expect(window.location.assign).not.toHaveBeenCalled();
expect(Flash).toHaveBeenCalledWith(
'An error occurred while acknowledging the notification. Refresh the page and try again.',
);
});
});
});
describe('factory', () => {
it('returns an instance of PersistentUserCallout with the provided container property', () => {
const fixture = createFixture();
......
......@@ -45,6 +45,14 @@ RSpec.describe Iteration do
it { is_expected.to be_valid }
end
context 'when updated iteration dates overlap with its own dates' do
it 'is valid' do
existing_iteration.start_date = 5.days.from_now
expect(existing_iteration).to be_valid
end
end
context 'when dates overlap' do
context 'same group' do
context 'when start_date is in range' do
......
......@@ -7,6 +7,8 @@ RSpec.describe MergeRequests::PostMergeService do
let(:merge_request) { create(:merge_request, assignees: [user]) }
let(:project) { merge_request.project }
subject { described_class.new(project, user).execute(merge_request) }
before do
project.add_maintainer(user)
end
......@@ -19,10 +21,7 @@ RSpec.describe MergeRequests::PostMergeService do
project.open_merge_requests_count
merge_request.update!(state: 'merged')
service = described_class.new(project, user, {})
expect { service.execute(merge_request) }
.to change { project.open_merge_requests_count }.from(1).to(0)
expect { subject }.to change { project.open_merge_requests_count }.from(1).to(0)
end
it 'updates metrics' do
......@@ -35,7 +34,7 @@ RSpec.describe MergeRequests::PostMergeService do
expect(metrics_service).to receive(:merge)
described_class.new(project, user, {}).execute(merge_request)
subject
end
it 'deletes non-latest diffs' do
......@@ -45,7 +44,7 @@ RSpec.describe MergeRequests::PostMergeService do
.to receive(:new).with(merge_request)
.and_return(diff_removal_service)
described_class.new(project, user, {}).execute(merge_request)
subject
expect(diff_removal_service).to have_received(:execute)
end
......@@ -56,21 +55,59 @@ RSpec.describe MergeRequests::PostMergeService do
issue = create(:issue, project: project)
allow(merge_request).to receive(:visible_closing_issues_for).and_return([issue])
expect_next_instance_of(Issues::CloseService) do |service|
allow(service).to receive(:execute).with(issue, commit: merge_request).and_raise(RuntimeError)
expect_next_instance_of(Issues::CloseService) do |close_service|
allow(close_service).to receive(:execute).with(issue, commit: merge_request).and_raise(RuntimeError)
end
expect { described_class.new(project, user).execute(merge_request) }.to raise_error(RuntimeError)
expect { subject }.to raise_error(RuntimeError)
expect(merge_request.reload).to be_merged
end
it 'clean up environments for the merge request' do
expect_next_instance_of(Ci::StopEnvironmentsService) do |service|
expect(service).to receive(:execute_for_merge_request).with(merge_request)
expect_next_instance_of(Ci::StopEnvironmentsService) do |stop_environment_service|
expect(stop_environment_service).to receive(:execute_for_merge_request).with(merge_request)
end
described_class.new(project, user).execute(merge_request)
subject
end
context 'when the merge request has review apps' do
it 'cancels all review app deployments' do
pipeline = create(:ci_pipeline,
source: :merge_request_event,
merge_request: merge_request,
project: project,
sha: merge_request.diff_head_sha,
merge_requests_as_head_pipeline: [merge_request])
review_env_a = create(:environment, project: project, state: :available, name: 'review/a')
review_env_b = create(:environment, project: project, state: :available, name: 'review/b')
review_env_c = create(:environment, project: project, state: :stopped, name: 'review/c')
deploy_env = create(:environment, project: project, state: :available, name: 'deploy')
review_job_a1 = create(:ci_build, :with_deployment, :start_review_app,
pipeline: pipeline, project: project, environment: review_env_a.name)
review_job_a2 = create(:ci_build, :with_deployment, :start_review_app,
pipeline: pipeline, project: project, environment: review_env_a.name)
review_job_b1 = create(:ci_build, :with_deployment, :start_review_app,
pipeline: pipeline, project: project, environment: review_env_b.name)
review_job_b2 = create(:ci_build, :start_review_app,
pipeline: pipeline, project: project, environment: review_env_b.name)
review_job_c1 = create(:ci_build, :with_deployment, :start_review_app,
pipeline: pipeline, project: project, environment: review_env_c.name)
deploy_job = create(:ci_build, :with_deployment, :deploy_to_production,
pipeline: pipeline, project: project, environment: deploy_env.name)
subject
expect(review_job_a1.reload.canceled?).to be true
expect(review_job_a2.reload.canceled?).to be true
expect(review_job_b1.reload.canceled?).to be true
expect(review_job_b2.reload.canceled?).to be false
expect(review_job_c1.reload.canceled?).to be false
expect(deploy_job.reload.canceled?).to be false
end
end
end
end
......@@ -211,8 +211,26 @@ RSpec.shared_examples 'wiki controller actions' do
end
end
describe 'GET #edit' do
subject { get(:edit, params: routing_params.merge(id: wiki_title)) }
shared_examples 'edit action' do
context 'when the page does not exist' do
let(:id_param) { 'invalid' }
it 'redirects to show' do
subject
expect(response).to redirect_to_wiki(wiki, 'invalid')
end
end
context 'when id param is blank' do
let(:id_param) { ' ' }
it 'redirects to the home page' do
subject
expect(response).to redirect_to_wiki(wiki, 'home')
end
end
context 'when page content encoding is invalid' do
it 'redirects to show' do
......@@ -236,6 +254,14 @@ RSpec.shared_examples 'wiki controller actions' do
expect(response).to redirect_to_wiki(wiki, page)
end
end
end
describe 'GET #edit' do
let(:id_param) { wiki_title }
subject { get(:edit, params: routing_params.merge(id: id_param)) }
it_behaves_like 'edit action'
context 'when page content encoding is valid' do
render_views
......@@ -252,23 +278,17 @@ RSpec.shared_examples 'wiki controller actions' do
describe 'PATCH #update' do
let(:new_title) { 'New title' }
let(:new_content) { 'New content' }
let(:id_param) { wiki_title }
subject do
patch(:update,
params: routing_params.merge(
id: wiki_title,
id: id_param,
wiki: { title: new_title, content: new_content }
))
end
context 'when page content encoding is invalid' do
it 'redirects to show' do
allow(controller).to receive(:valid_encoding?).and_return(false)
subject
expect(response).to redirect_to_wiki(wiki, wiki.list_pages.first)
end
end
it_behaves_like 'edit action'
context 'when page content encoding is valid' do
render_views
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册