Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
8be0db711f
commit
fb8ebc84b8
|
|
@ -1,6 +1,5 @@
|
|||
For guidance on the overall deprecations, removals and breaking changes workflow, please visit [Breaking changes, deprecations, and removing features](https://about.gitlab.com/handbook/product/gitlab-the-product/#deprecations-removals-and-breaking-changes)
|
||||
|
||||
<!-- Use this template as a starting point for deprecations. -->
|
||||
<!-- For guidance on the overall deprecations, removals and breaking changes workflow, please visit [Breaking changes, deprecations, and removing features](https://handbook.gitlab.com/handbook/marketing/blog/release-posts/#deprecations-removals-and-breaking-changes). -->
|
||||
|
||||
### Deprecation Summary
|
||||
|
||||
|
|
@ -15,12 +14,17 @@ The description of the deprecation should state what actions the user should tak
|
|||
|
||||
-->
|
||||
|
||||
### Breaking Change
|
||||
### Breaking Change?
|
||||
|
||||
<!-- Does this MR contain a breaking change? If yes:
|
||||
- Add the ~"breaking change" label to this issue.
|
||||
- Add instructions for how users can update their workflow. -->
|
||||
|
||||
<!--
|
||||
/label ~"breaking change"
|
||||
-->
|
||||
|
||||
|
||||
### Affected Topology
|
||||
|
||||
<!--
|
||||
|
|
@ -37,41 +41,16 @@ Which tier is this feature available in?
|
|||
* Ultimate
|
||||
-->
|
||||
|
||||
### Checklists
|
||||
|
||||
**Labels**
|
||||
|
||||
- [ ] This issue is labeled ~deprecation, and with the relevant `~devops::`, `~group::`, and `~Category:` labels.
|
||||
- [ ] This issue is labeled ~"breaking change" if the removal of the deprecated item will be a [breaking change](https://about.gitlab.com/handbook/product/gitlab-the-product/#examples-of-breaking-changes).
|
||||
|
||||
**Timeline**
|
||||
|
||||
Please add links to the relevant merge requests.
|
||||
|
||||
- As soon as possible, but no later than the third milestone preceding the major release (for example, given the following release schedule: `14.8, 14.9, 14.10, 15.0` – `14.8` is the third milestone preceding the major release):
|
||||
- [ ] A [deprecation announcement entry](https://about.gitlab.com/handbook/marketing/blog/release-posts/#creating-the-announcement) has been created so the deprecation will appear in release posts and on the [general deprecation page](https://docs.gitlab.com/ee/update/deprecations).
|
||||
- [ ] Documentation has been updated to mark the feature as [deprecated](https://docs.gitlab.com/ee/development/documentation/versions.html#deprecations-and-removals).
|
||||
- [ ] On or before the major milestone: A [removal entry](https://about.gitlab.com/handbook/marketing/blog/release-posts/#creating-the-announcement-1) has been created so the removal will appear on the [removals by milestones](https://docs.gitlab.com/ee/update/removals) page and be announced in the release post.
|
||||
- On the major milestone:
|
||||
- [ ] The deprecated item has been removed.
|
||||
- [ ] If the removal of the deprecated item is a [breaking change](https://about.gitlab.com/handbook/product/gitlab-the-product/#examples-of-breaking-changes), the merge request is labeled ~"breaking change".
|
||||
|
||||
**Mentions**
|
||||
|
||||
- [ ] Your stage's stable counterparts have been `@mentioned` on this issue. For example, Customer Support, Customer Success (Technical Account Manager), Product Marketing Manager.
|
||||
- To see who the stable counterparts are for a product team visit [product categories](https://about.gitlab.com/handbook/product/categories/)
|
||||
- If there is no stable counterpart listed for Sales/CS please mention `@timtams`
|
||||
- If there is no stable counterpart listed for Support please mention `@gitlab-com/support/managers`
|
||||
- If there is no stable counterpart listed for Marketing please mention `@cfoster3`
|
||||
- [ ] Your GPM has been `@mentioned` so that they are aware of planned deprecations. The goal is to have reviews happen at least two releases before the final removal of the feature or introduction of a breaking change.
|
||||
<!-- Choose the Pricing Tier(s) -->
|
||||
/label ~"GitLab Free" ~"GitLab Premium" ~"GitLab Ultimate"
|
||||
|
||||
### Deprecation Milestone
|
||||
|
||||
<!-- In which milestone will this deprecation be announced ? -->
|
||||
<!-- In which milestone will this deprecation be announced? -->
|
||||
|
||||
### Planned Removal Milestone
|
||||
|
||||
<!-- In which milestone will the feature or functionality be removed and announced? -->
|
||||
<!-- In which milestone will the feature or functionality be removed? -->
|
||||
|
||||
### Links
|
||||
|
||||
|
|
@ -83,19 +62,47 @@ issues and MRs related to this deprecation/removal to this issue. This can inclu
|
|||
issues that were created ahead of time, and the MRs doing the actual deprecation/removal work.
|
||||
-->
|
||||
|
||||
### Checklists
|
||||
|
||||
<details><summary>Click to expand</summary>
|
||||
|
||||
**Labels**
|
||||
|
||||
<!-- Populate the Section, Group, and Category -->
|
||||
/label ~devops:: ~group: ~Category:
|
||||
|
||||
- [ ] This issue is labeled ~deprecation, and with the relevant `~devops::`, `~group::`, and `~Category:` labels.
|
||||
- [ ] This issue is labeled ~"breaking change" if the removal of the deprecated item will be a [breaking change](https://about.gitlab.com/handbook/product/gitlab-the-product/#examples-of-breaking-changes).
|
||||
|
||||
**Timeline**
|
||||
|
||||
Please add links to the relevant merge requests.
|
||||
|
||||
- As soon as possible, but no later than the third milestone preceding the major release (for example, given the following release schedule: `14.8, 14.9, 14.10, 15.0` – `14.8` is the third milestone preceding the major release):
|
||||
- [ ] A [deprecation announcement entry](https://about.gitlab.com/handbook/marketing/blog/release-posts/#creating-the-announcement) has been created so the deprecation will appear in release posts and on the [general deprecation page](https://docs.gitlab.com/ee/update/deprecations).
|
||||
- [ ] Documentation has been updated to mark the feature as [deprecated](https://docs.gitlab.com/ee/development/documentation/versions.html#deprecations-and-removals).
|
||||
- On the major milestone:
|
||||
- [ ] The deprecated item has been removed.
|
||||
- [ ] If the removal of the deprecated item is a [breaking change](https://about.gitlab.com/handbook/product/gitlab-the-product/#examples-of-breaking-changes), the merge request is labeled ~"breaking change".
|
||||
|
||||
**Mentions**
|
||||
|
||||
- [ ] Your stage's stable counterparts have been `@mentioned` on this issue. For example, Customer Support, Customer Success (Technical Account Manager), Product Marketing Manager.
|
||||
- To see who the stable counterparts are for a product team visit [product categories](https://handbook.gitlab.com/handbook/product/categories/)
|
||||
- If there is no stable counterpart listed for Sales/CS please mention `@timtams`
|
||||
- If there is no stable counterpart listed for Support please mention `@gitlab-com/support/managers`
|
||||
- If there is no stable counterpart listed for Marketing please mention `@cfoster3`
|
||||
- [ ] Your GPM or Director has been `@mentioned` so that they are aware of planned deprecations.
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
<!-- Label reminders - you should have one of each of the following labels.
|
||||
Use the following resources to find the appropriate labels:
|
||||
- https://gitlab.com/gitlab-org/gitlab/-/labels
|
||||
- https://about.gitlab.com/handbook/product/categories/features/
|
||||
-->
|
||||
|
||||
<!-- Populate the Section, Group, and Category -->
|
||||
/label ~devops:: ~group: ~Category:
|
||||
|
||||
<!-- Choose the Pricing Tier(s) -->
|
||||
/label ~"GitLab Free" ~"GitLab Premium" ~"GitLab Ultimate"
|
||||
|
||||
<!-- Identifies that this Issue is related to deprecating a feature -->
|
||||
/label ~"deprecation"
|
||||
|
||||
<!-- Add the ~"breaking change" label to this issue if necessary -->
|
||||
|
|
|
|||
|
|
@ -85,9 +85,9 @@ $avatar-sizes: (
|
|||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 0;
|
||||
background: $gray-10;
|
||||
background: var(--gl-background-color-subtle);
|
||||
overflow: hidden;
|
||||
box-shadow: inset 0 0 0 1px rgba($gray-950, $gl-avatar-border-opacity);
|
||||
box-shadow: inset 0 0 0 1px var(--gl-avatar-border-color-default);
|
||||
|
||||
&.avatar-inline {
|
||||
float: none;
|
||||
|
|
@ -116,8 +116,8 @@ $avatar-sizes: (
|
|||
.identicon {
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
color: $gray-900;
|
||||
background-color: $gray-50;
|
||||
color: var(--gl-text-color-strong);
|
||||
background-color: var(--gl-avatar-fallback-background-color-neutral);
|
||||
|
||||
// Sizes
|
||||
@each $size, $size-config in $avatar-sizes {
|
||||
|
|
@ -208,7 +208,7 @@ $avatar-sizes: (
|
|||
|
||||
&.user-popover-cannot-merge {
|
||||
.popover-header {
|
||||
background-color: $orange-50;
|
||||
background-color: var(--gl-feedback-warning-background-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ The following table lists the valid `objects` that can be used:
|
|||
| `dependency_proxy` | [Dependency Proxy](packages/dependency_proxy.md) |
|
||||
| `terraform_state` | [Terraform state files](terraform_state.md) |
|
||||
| `pages` | [Pages](pages/index.md) |
|
||||
| `ci_secure_files` | [Secure files](secure_files.md) |
|
||||
|
||||
Within each object type, three parameters can be defined:
|
||||
|
||||
|
|
@ -166,11 +167,11 @@ supported by the consolidated form, refer to the following guides:
|
|||
|
||||
| Object storage type | Supported by consolidated form? |
|
||||
|---------------------|------------------------------------------|
|
||||
| [Secure Files](secure_files.md#using-object-storage) | **{dotted-circle}** No |
|
||||
| [Backups](../administration/backup_restore/backup_gitlab.md#upload-backups-to-a-remote-cloud-storage) | **{dotted-circle}** No |
|
||||
| [Container registry](packages/container_registry.md#use-object-storage) (optional feature) | **{dotted-circle}** No |
|
||||
| [Mattermost](https://docs.mattermost.com/configure/file-storage-configuration-settings.html)| **{dotted-circle}** No |
|
||||
| [Autoscale runner caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) (optional for improved performance) | **{dotted-circle}** No |
|
||||
| [Secure Files](secure_files.md#using-object-storage) | **{check-circle}** Yes |
|
||||
| [Job artifacts](job_artifacts.md#using-object-storage) including archived job logs | **{check-circle}** Yes |
|
||||
| [LFS objects](lfs/index.md#storing-lfs-objects-in-remote-object-storage) | **{check-circle}** Yes |
|
||||
| [Uploads](uploads.md#using-object-storage) | **{check-circle}** Yes |
|
||||
|
|
@ -483,6 +484,7 @@ The following example uses AWS S3 to enable object storage for all supported ser
|
|||
gitlab_rails['object_store']['objects']['packages']['bucket'] = 'gitlab-packages'
|
||||
gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = 'gitlab-dependency-proxy'
|
||||
gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = 'gitlab-terraform-state'
|
||||
gitlab_rails['object_store']['objects']['ci_secure_files']['bucket'] = 'gitlab-ci-secure-files'
|
||||
gitlab_rails['object_store']['objects']['pages']['bucket'] = 'gitlab-pages'
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -97,13 +97,14 @@ DETAILS:
|
|||
Instead of storing Secure Files on disk, you should use [one of the supported object storage options](object_storage.md#supported-object-storage-providers).
|
||||
This configuration relies on valid credentials to be configured already.
|
||||
|
||||
[Read more about using object storage with GitLab](object_storage.md).
|
||||
### Consolidated object storage
|
||||
|
||||
NOTE:
|
||||
This feature is not supported by consolidated object storage configuration.
|
||||
Adding support is proposed in [issue 414673](https://gitlab.com/gitlab-org/gitlab/-/issues/414673).
|
||||
> - Support for consolidated object storage was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/149873) in GitLab 17.0.
|
||||
|
||||
### Object storage settings
|
||||
Using the [consolidated form](object_storage.md#configure-a-single-storage-connection-for-all-object-types-consolidated-form)
|
||||
of the object storage is recommended.
|
||||
|
||||
### Storage-specific object storage
|
||||
|
||||
The following settings are:
|
||||
|
||||
|
|
@ -120,7 +121,9 @@ The following settings are:
|
|||
|
||||
See [the available connection settings for different providers](object_storage.md#configure-the-connection-settings).
|
||||
|
||||
**For Linux package installations:**
|
||||
::Tabs
|
||||
|
||||
:::TabTitle Linux package (Omnibus)
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the following lines, but using
|
||||
the values you want:
|
||||
|
|
@ -147,10 +150,15 @@ See [the available connection settings for different providers](object_storage.m
|
|||
}
|
||||
```
|
||||
|
||||
1. Save the file and [reconfigure GitLab](restart_gitlab.md#reconfigure-a-linux-package-installation).
|
||||
1. Save the file and reconfigure GitLab:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl reconfigure
|
||||
```
|
||||
|
||||
1. [Migrate any existing local states to the object storage](#migrate-to-object-storage).
|
||||
|
||||
**For self-compiled installations**
|
||||
:::TabTitle Self-compiled (source)
|
||||
|
||||
1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following lines:
|
||||
|
||||
|
|
@ -167,9 +175,20 @@ See [the available connection settings for different providers](object_storage.m
|
|||
region: eu-central-1
|
||||
```
|
||||
|
||||
1. Save the file and [restart GitLab](restart_gitlab.md#self-compiled-installations) for the changes to take effect.
|
||||
1. Save the file and restart GitLab:
|
||||
|
||||
```shell
|
||||
# For systems running systemd
|
||||
sudo systemctl restart gitlab.target
|
||||
|
||||
# For systems running SysV init
|
||||
sudo service gitlab restart
|
||||
```
|
||||
|
||||
1. [Migrate any existing local states to the object storage](#migrate-to-object-storage).
|
||||
|
||||
::EndTabs
|
||||
|
||||
### Migrate to object storage
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/readme/-/issues/125) in GitLab 16.1.
|
||||
|
|
|
|||
|
|
@ -73,6 +73,10 @@ In each place, if you hover over the failed job you can see the reason it failed
|
|||
|
||||
You can also see the reason it failed on the Job detail page.
|
||||
|
||||
### Troubleshoot a failed job with root cause analysis
|
||||
|
||||
You can use root cause analysis in GitLab Duo Chat to [troubleshoot failed CI/CD jobs](../../user/gitlab_duo_chat/examples.md#troubleshoot-failed-cicd-jobs-with-root-cause-analysis).
|
||||
|
||||
## The order of jobs in a pipeline
|
||||
|
||||
The order of jobs in a pipeline depends on the type of pipeline graph.
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Prerequisites:
|
|||
- You must be an administrator.
|
||||
|
||||
1. Sign in to the [GitLab Customers Portal](https://customers.gitlab.com/).
|
||||
1. On the **GitLab Duo Pro** section of your subscription card click **Add seats** button.
|
||||
1. On the **GitLab Duo Pro** section of your subscription card select **Add seats**.
|
||||
1. Enter the number of seats. The amount cannot be higher than the number of seats in the subscription.
|
||||
1. Review the **Purchase summary** section.
|
||||
1. From the **Payment method** dropdown list, select your payment method.
|
||||
|
|
|
|||
|
|
@ -74,30 +74,6 @@ is displayed.
|
|||
|
||||
Provide feedback on this experimental feature in [issue 416833](https://gitlab.com/gitlab-org/gitlab/-/issues/416833).
|
||||
|
||||
## Troubleshoot failed CI/CD jobs with Root cause analysis
|
||||
|
||||
DETAILS:
|
||||
**Tier:** For a limited time, Ultimate. In the future, [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
|
||||
**Offering:** GitLab.com
|
||||
**Status:** Experiment
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123692) in GitLab 16.2 as an [experiment](../../policy/experiment-beta-support.md#experiment).
|
||||
|
||||
Determine the root cause of a CI/CD job failure by analyzing the logs.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must belong to at least one group with the [experiment and beta features setting](turn_on_off.md#turn-on-beta-and-experimental-features) enabled.
|
||||
- You must have permission to view the CI/CD job.
|
||||
|
||||
To view root cause analysis:
|
||||
|
||||
1. Open a merge request.
|
||||
1. On the **Pipelines** tab, select the failed CI/CD job.
|
||||
1. Above the job output, select **Troubleshoot**.
|
||||
|
||||
An analysis of the reasons for the failure is displayed.
|
||||
|
||||
## Summarize an issue with Issue description generation
|
||||
|
||||
DETAILS:
|
||||
|
|
|
|||
|
|
@ -43,6 +43,19 @@ the [Duo Chat examples](../gitlab_duo_chat_examples.md).
|
|||
For self-managed, the models also depend on your GitLab version.
|
||||
For the most benefit, use the latest GitLab version whenever possible.
|
||||
|
||||
#### Root cause analysis
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123692) in GitLab 16.2 as an [experiment](../../policy/experiment-beta-support.md#experiment) on GitLab.com.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/441681) and moved to GitLab Duo Chat in GitLab 17.3.
|
||||
|
||||
- Helps you determine the root cause for a CI/CD job failure by analyzing the logs.
|
||||
- LLM: Anthropic's [Claude 3.5 Sonnet](https://console.cloud.google.com/vertex-ai/publishers/anthropic/model-garden/claude-3-5-sonnet)
|
||||
- [View documentation](../gitlab_duo_chat/examples.md#troubleshoot-failed-cicd-jobs-with-root-cause-analysis)
|
||||
|
||||
### Code Suggestions
|
||||
|
||||
DETAILS:
|
||||
|
|
@ -190,7 +203,7 @@ DETAILS:
|
|||
|
||||
- Helps you determine the root cause for a CI/CD job failure by analyzing the logs.
|
||||
- LLM: Vertex AI Codey [`text-bison`](https://console.cloud.google.com/vertex-ai/publishers/google/model-garden/text-bison)
|
||||
- [View documentation](experiments.md#troubleshoot-failed-cicd-jobs-with-root-cause-analysis).
|
||||
- [View documentation](../gitlab_duo_chat/examples.md#troubleshoot-failed-cicd-jobs-with-root-cause-analysis).
|
||||
|
||||
### Vulnerability resolution
|
||||
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ you need to configure CI/CD.
|
|||
Please show a .gitignore and .gitlab-ci.yml configuration for a C# project.
|
||||
```
|
||||
|
||||
- If your CI/CD job fails, [Root Cause Analysis](../../user/gitlab_duo/experiments.md#troubleshoot-failed-cicd-jobs-with-root-cause-analysis)
|
||||
can help understand the problem. Alternatively, you can copy the error message into
|
||||
- If your CI/CD job fails, use root cause analysis to [troubleshoot failed CI/CD jobs](../gitlab_duo_chat/examples.md#troubleshoot-failed-cicd-jobs-with-root-cause-analysis).
|
||||
Alternatively, you can copy the error message into
|
||||
GitLab Duo Chat, and ask for help:
|
||||
|
||||
```markdown
|
||||
|
|
|
|||
|
|
@ -80,7 +80,35 @@ You can also ask to explain specific job errors by copy-pasting the error messag
|
|||
|
||||
- `Please explain this CI/CD job error message in the context of a Go project: build.sh: line 14: go command not found`
|
||||
|
||||
Alternatively, you can use [root cause analysis in CI/CD](../gitlab_duo/experiments.md#troubleshoot-failed-cicd-jobs-with-root-cause-analysis).
|
||||
Alternatively, you can use root cause analysis to [troubleshoot failed CI/CD jobs](#troubleshoot-failed-cicd-jobs-with-root-cause-analysis).
|
||||
|
||||
## Troubleshoot failed CI/CD jobs with root cause analysis
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123692) in GitLab 16.2 as an [experiment](../../policy/experiment-beta-support.md#experiment) on GitLab.com.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/441681) and moved to GitLab Duo Chat in GitLab 17.3.
|
||||
|
||||
You can ask GitLab Duo Chat to determine the root cause of a CI/CD job failure by analyzing the logs.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- Have permission to view the CI/CD job.
|
||||
- Have a paid GitLab Duo Enterprise seat.
|
||||
|
||||
To troubleshoot a failed CI/CD job:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Build > Jobs**.
|
||||
1. Select the failed CI/CD job.
|
||||
1. From the job log page, do one of the following:
|
||||
|
||||
- Above the job log, select **Troubleshoot**.
|
||||
- Open GitLab Duo Chat and type `/troubleshoot`.
|
||||
|
||||
An analysis of the reasons for the failure and an example fix is displayed.
|
||||
|
||||
## Explain a vulnerability
|
||||
|
||||
|
|
@ -276,4 +304,5 @@ Use the following commands to quickly accomplish specific tasks.
|
|||
| /explain | [Explain code](../gitlab_duo_chat/examples.md#explain-code-in-the-ide) |
|
||||
| /vulnerability_explain | [Explain current vulnerability](../gitlab_duo/index.md#vulnerability-explanation) |
|
||||
| /refactor | [Refactor the code](../gitlab_duo_chat/examples.md#refactor-code-in-the-ide) |
|
||||
| /troubleshoot | [Troubleshoot failed CI/CD jobs with root cause analysis](#troubleshoot-failed-cicd-jobs-with-root-cause-analysis) |
|
||||
| /fix | [Fix the code](../gitlab_duo_chat/examples.md#fix-code-in-the-ide) |
|
||||
|
|
|
|||
|
|
@ -28,11 +28,17 @@ module CsvBuilder
|
|||
# * +collection+ - The data collection to be used
|
||||
# * +header_to_value_hash+ - A hash of 'Column Heading' => 'value_method'.
|
||||
# * +associations_to_preload+ - An array of records to preload with a batch of records.
|
||||
# * +replace_newlines+ - default: false - If true, replaces newline characters with a literal "\n"
|
||||
#
|
||||
# The value method will be called once for each object in the collection, to
|
||||
# determine the value for that row. It can either be the name of a method on
|
||||
# the object, or a lamda to call passing in the object.
|
||||
def self.new(collection, header_to_value_hash, associations_to_preload = [])
|
||||
CsvBuilder::Builder.new(collection, header_to_value_hash, associations_to_preload)
|
||||
def self.new(collection, header_to_value_hash, associations_to_preload = [], replace_newlines: false)
|
||||
CsvBuilder::Builder.new(
|
||||
collection,
|
||||
header_to_value_hash,
|
||||
associations_to_preload,
|
||||
replace_newlines: replace_newlines
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,12 +6,13 @@ module CsvBuilder
|
|||
|
||||
attr_reader :rows_written
|
||||
|
||||
def initialize(collection, header_to_value_hash, associations_to_preload = [])
|
||||
def initialize(collection, header_to_value_hash, associations_to_preload = [], replace_newlines: false)
|
||||
@header_to_value_hash = header_to_value_hash
|
||||
@collection = collection
|
||||
@truncated = false
|
||||
@rows_written = 0
|
||||
@associations_to_preload = associations_to_preload
|
||||
@replace_newlines = replace_newlines
|
||||
end
|
||||
|
||||
# Renders the csv to a string
|
||||
|
|
@ -78,13 +79,19 @@ module CsvBuilder
|
|||
|
||||
def row(object)
|
||||
attributes.map do |attribute|
|
||||
if attribute.respond_to?(:call)
|
||||
excel_sanitize(attribute.call(object))
|
||||
elsif object.is_a?(Hash)
|
||||
excel_sanitize(object[attribute])
|
||||
else
|
||||
excel_sanitize(object.public_send(attribute)) # rubocop:disable GitlabSecurity/PublicSend
|
||||
end
|
||||
data = if attribute.respond_to?(:call)
|
||||
attribute.call(object)
|
||||
elsif object.is_a?(Hash)
|
||||
object[attribute]
|
||||
else
|
||||
object.public_send(attribute) # rubocop:disable GitlabSecurity/PublicSend -- Not user input
|
||||
end
|
||||
|
||||
next if data.nil?
|
||||
|
||||
data = data.gsub("\n", '\n') if data.is_a?(String) && @replace_newlines
|
||||
|
||||
excel_sanitize(data)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -104,7 +111,6 @@ module CsvBuilder
|
|||
end
|
||||
|
||||
def excel_sanitize(line)
|
||||
return if line.nil?
|
||||
return line unless line.is_a?(String) && line.match?(UNSAFE_EXCEL_PREFIX)
|
||||
|
||||
["'", line].join
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ RSpec.describe CsvBuilder::Gzip do
|
|||
let(:event_2) { double(title: 'Added sugar', description: 'Just a pinch') }
|
||||
let(:items) { [event_1, event_2] }
|
||||
|
||||
subject(:builder) { described_class.new(items, 'Title' => 'title', 'Description' => 'description') }
|
||||
subject(:builder) { described_class.new(items, { 'Title' => 'title', 'Description' => 'description' }) }
|
||||
|
||||
describe '#render' do
|
||||
it 'returns yields a tempfile' do
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ RSpec.describe CsvBuilder::Stream do
|
|||
let(:event_2) { double(title: 'Added sugar', description: 'Just a pinch') }
|
||||
let(:fake_relation) { described_class::FakeRelation.new([event_1, event_2]) }
|
||||
|
||||
subject(:builder) { described_class.new(fake_relation, 'Title' => 'title', 'Description' => 'description') }
|
||||
subject(:builder) { described_class.new(fake_relation, { 'Title' => 'title', 'Description' => 'description' }) }
|
||||
|
||||
describe '#render' do
|
||||
before do
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ RSpec.describe CsvBuilder do
|
|||
end
|
||||
|
||||
let(:subject) do
|
||||
described_class.new(enumerable, **header_to_value_hash)
|
||||
described_class.new(enumerable, header_to_value_hash)
|
||||
end
|
||||
|
||||
shared_examples 'csv builder examples' do
|
||||
|
|
@ -113,6 +113,41 @@ RSpec.describe CsvBuilder do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'builder that replaces newlines' do
|
||||
let(:object) { double(title: "title", description: "Line 1\n\nLine 2") }
|
||||
let(:header_to_value_hash) { { 'Title' => 'title', 'Description' => 'description' } }
|
||||
let(:items) { [object] }
|
||||
|
||||
it 'does not replace newlines by default' do
|
||||
expect(csv_data).to eq("Title,Description\ntitle,\"Line 1\n\nLine 2\"\n")
|
||||
end
|
||||
|
||||
context 'when replace_newlines is set to true' do
|
||||
let(:subject) { described_class.new(enumerable, header_to_value_hash, replace_newlines: true) }
|
||||
|
||||
it 'replaces newlines with a literal "\n"' do
|
||||
expect(csv_data).to eq("Title,Description\ntitle,Line 1\\n\\nLine 2\n")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when line is nil' do
|
||||
let(:object) { double(title: "title", description: nil) }
|
||||
|
||||
it 'gracefully generates CSV' do
|
||||
expect(csv_data).to eq("Title,Description\ntitle,\n")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when data is not a string' do
|
||||
let(:object) { double(title: "title", created_at: Date.new(2001, 2, 3)) }
|
||||
let(:header_to_value_hash) { { 'Title' => 'title', 'Created At' => 'created_at' } }
|
||||
|
||||
it 'gracefully generates CSV' do
|
||||
expect(csv_data).to eq("Title,Created At\ntitle,2001-02-03\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ActiveRecord::Relation like object is given' do
|
||||
let(:object) { double(question: :answer) }
|
||||
let(:enumerable) { described_class::FakeRelation.new(items) }
|
||||
|
|
@ -129,6 +164,7 @@ RSpec.describe CsvBuilder do
|
|||
|
||||
it_behaves_like 'csv builder examples'
|
||||
it_behaves_like 'excel sanitization'
|
||||
it_behaves_like 'builder that replaces newlines'
|
||||
it_behaves_like 'csv builder with truncation ability' do
|
||||
let(:big_object) { double(question: 'Long' * 1024) }
|
||||
let(:question_value) { big_object.question }
|
||||
|
|
@ -141,6 +177,7 @@ RSpec.describe CsvBuilder do
|
|||
|
||||
it_behaves_like 'csv builder examples'
|
||||
it_behaves_like 'excel sanitization'
|
||||
it_behaves_like 'builder that replaces newlines'
|
||||
it_behaves_like 'csv builder with truncation ability' do
|
||||
let(:big_object) { double(question: 'Long' * 1024) }
|
||||
let(:question_value) { big_object.question }
|
||||
|
|
@ -155,6 +192,7 @@ RSpec.describe CsvBuilder do
|
|||
end
|
||||
|
||||
it_behaves_like 'csv builder examples'
|
||||
it_behaves_like 'builder that replaces newlines'
|
||||
|
||||
it_behaves_like 'excel sanitization' do
|
||||
let(:dangerous_title) { { title: "=cmd|' /C calc'!A0 title", description: "*safe_desc" } }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
variables:
|
||||
DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.99.0'
|
||||
DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.100.0'
|
||||
|
||||
.dast-auto-deploy:
|
||||
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${DAST_AUTO_DEPLOY_IMAGE_VERSION}"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
variables:
|
||||
AUTO_DEPLOY_IMAGE_VERSION: 'v2.99.0'
|
||||
AUTO_DEPLOY_IMAGE_VERSION: 'v2.100.0'
|
||||
|
||||
.auto-deploy:
|
||||
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
variables:
|
||||
AUTO_DEPLOY_IMAGE_VERSION: 'v2.99.0'
|
||||
AUTO_DEPLOY_IMAGE_VERSION: 'v2.100.0'
|
||||
|
||||
.auto-deploy:
|
||||
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
|
||||
|
|
|
|||
|
|
@ -13,6 +13,19 @@ module Gitlab
|
|||
MANAGEMENT_LEASE_KEY = 'database_partition_management_%s'
|
||||
RETAIN_DETACHED_PARTITIONS_FOR = 1.week
|
||||
|
||||
LOCK_RETRIES_TIMING_CONFIGURATION = [
|
||||
[0.1.seconds, 0.05.seconds],
|
||||
[0.1.seconds, 0.05.seconds],
|
||||
[0.2.seconds, 0.05.seconds],
|
||||
[0.3.seconds, 0.10.seconds],
|
||||
[0.4.seconds, 0.15.seconds],
|
||||
[0.5.seconds, 2.seconds],
|
||||
[0.5.seconds, 2.seconds],
|
||||
[0.5.seconds, 2.seconds],
|
||||
[0.5.seconds, 2.seconds],
|
||||
[1.second, 5.seconds]
|
||||
].freeze
|
||||
|
||||
def initialize(model, connection: nil)
|
||||
@model = model
|
||||
@connection = connection || model.connection
|
||||
|
|
@ -135,6 +148,7 @@ module Gitlab
|
|||
|
||||
def with_lock_retries(&block)
|
||||
Gitlab::Database::WithLockRetries.new(
|
||||
timing_configuration: LOCK_RETRIES_TIMING_CONFIGURATION * 2,
|
||||
klass: self.class,
|
||||
logger: Gitlab::AppLogger,
|
||||
connection: connection
|
||||
|
|
|
|||
|
|
@ -70,10 +70,12 @@ module Gitlab
|
|||
finder.execute(gitaly_pagination: true).tap do |records|
|
||||
total = finder.total
|
||||
per_page = params[:per_page].presence || Kaminari.config.default_per_page
|
||||
total_pages = (total / per_page.to_f).ceil
|
||||
next_page = total_pages > 1 ? 2 : nil
|
||||
|
||||
Gitlab::Pagination::OffsetHeaderBuilder.new(
|
||||
request_context: request_context, per_page: per_page, page: 1, next_page: 2,
|
||||
total: total, total_pages: (total / per_page) + 1
|
||||
request_context: request_context, per_page: per_page, page: 1, next_page: next_page,
|
||||
total: total, total_pages: total_pages
|
||||
).execute
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,18 +2,21 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::Groups::Update do
|
||||
RSpec.describe Mutations::Groups::Update, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be_with_reload(:group) { create(:group) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
let(:params) { { full_path: group.full_path } }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:admin_group) }
|
||||
|
||||
describe '#resolve' do
|
||||
subject { described_class.new(object: group, context: { current_user: user }, field: nil).resolve(**params) }
|
||||
subject { described_class.new(object: group, context: context, field: nil).resolve(**params) }
|
||||
|
||||
shared_examples 'updating the group shared runners setting' do
|
||||
it 'updates the group shared runners setting' do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::IncidentManagement::TimelineEvent::Create do
|
||||
RSpec.describe Mutations::IncidentManagement::TimelineEvent::Create, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:incident) { create(:incident, project: project) }
|
||||
|
|
@ -11,6 +13,8 @@ RSpec.describe Mutations::IncidentManagement::TimelineEvent::Create do
|
|||
end
|
||||
|
||||
let(:args) { { note: 'note', occurred_at: Time.current } }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: current_user }) }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:admin_incident_management_timeline_event) }
|
||||
|
||||
|
|
@ -147,7 +151,7 @@ RSpec.describe Mutations::IncidentManagement::TimelineEvent::Create do
|
|||
|
||||
private
|
||||
|
||||
def mutation_for(project, user)
|
||||
described_class.new(object: project, context: { current_user: user }, field: nil)
|
||||
def mutation_for(project, _user)
|
||||
described_class.new(object: project, context: context, field: nil)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,13 +2,16 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::IncidentManagement::TimelineEvent::Destroy do
|
||||
RSpec.describe Mutations::IncidentManagement::TimelineEvent::Destroy, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:incident) { create(:incident, project: project) }
|
||||
|
||||
let(:timeline_event) { create(:incident_management_timeline_event, incident: incident, project: project) }
|
||||
let(:args) { { id: timeline_event.to_global_id } }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: current_user }) }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:admin_incident_management_timeline_event) }
|
||||
|
||||
|
|
@ -60,7 +63,7 @@ RSpec.describe Mutations::IncidentManagement::TimelineEvent::Destroy do
|
|||
|
||||
private
|
||||
|
||||
def mutation_for(project, user)
|
||||
described_class.new(object: project, context: { current_user: user }, field: nil)
|
||||
def mutation_for(project, _user)
|
||||
described_class.new(object: project, context: context, field: nil)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::IncidentManagement::TimelineEvent::PromoteFromNote do
|
||||
RSpec.describe Mutations::IncidentManagement::TimelineEvent::PromoteFromNote, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
include NotesHelper
|
||||
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
|
|
@ -15,6 +16,8 @@ RSpec.describe Mutations::IncidentManagement::TimelineEvent::PromoteFromNote do
|
|||
let_it_be(:alert_comment) { create(:note, project: project, noteable: alert) }
|
||||
|
||||
let(:args) { { note_id: comment.to_global_id.to_s } }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: current_user }) }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:admin_incident_management_timeline_event) }
|
||||
|
||||
|
|
@ -82,7 +85,7 @@ RSpec.describe Mutations::IncidentManagement::TimelineEvent::PromoteFromNote do
|
|||
|
||||
private
|
||||
|
||||
def mutation_for(project, user)
|
||||
described_class.new(object: project, context: { current_user: user }, field: nil)
|
||||
def mutation_for(project, _user)
|
||||
described_class.new(object: project, context: context, field: nil)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::IncidentManagement::TimelineEvent::Update do
|
||||
RSpec.describe Mutations::IncidentManagement::TimelineEvent::Update, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:developer) { create(:user) }
|
||||
let_it_be(:reporter) { create(:user) }
|
||||
let_it_be(:project) { create(:project, developers: developer, reporters: reporter) }
|
||||
|
|
@ -30,6 +32,9 @@ RSpec.describe Mutations::IncidentManagement::TimelineEvent::Update do
|
|||
}
|
||||
end
|
||||
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: current_user }) }
|
||||
|
||||
let(:note) { 'Updated Note' }
|
||||
let(:timeline_event_id) { GitlabSchema.id_from_object(timeline_event).to_s }
|
||||
let(:occurred_at) { 1.minute.ago }
|
||||
|
|
@ -154,7 +159,7 @@ RSpec.describe Mutations::IncidentManagement::TimelineEvent::Update do
|
|||
|
||||
private
|
||||
|
||||
def mutation_for(user)
|
||||
described_class.new(object: nil, context: { current_user: user }, field: nil)
|
||||
def mutation_for(_user)
|
||||
described_class.new(object: nil, context: context, field: nil)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::IncidentManagement::TimelineEventTag::Create do
|
||||
RSpec.describe Mutations::IncidentManagement::TimelineEventTag::Create, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
let_it_be_with_reload(:project) { create(:project, maintainers: current_user) }
|
||||
|
||||
let(:args) { { name: 'Test tag 1' } }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: current_user }) }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:admin_incident_management_timeline_event_tag) }
|
||||
|
||||
|
|
@ -42,7 +45,7 @@ RSpec.describe Mutations::IncidentManagement::TimelineEventTag::Create do
|
|||
|
||||
private
|
||||
|
||||
def mutation_for(project, user)
|
||||
described_class.new(object: project, context: { current_user: user }, field: nil)
|
||||
def mutation_for(project, _user)
|
||||
described_class.new(object: project, context: context, field: nil)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::Issues::Create do
|
||||
RSpec.describe Mutations::Issues::Create, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:assignee1) { create(:user) }
|
||||
|
|
@ -40,7 +42,9 @@ RSpec.describe Mutations::Issues::Create do
|
|||
}
|
||||
end
|
||||
|
||||
let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
let(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
let(:mutated_issue) { subject[:issue] }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:create_issue) }
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::Issues::LinkAlerts, feature_category: :incident_management do
|
||||
include GraphqlHelpers
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:guest) { create(:user, guest_of: project) }
|
||||
let_it_be(:developer) { create(:user, developer_of: project) }
|
||||
|
|
@ -10,7 +11,9 @@ RSpec.describe Mutations::Issues::LinkAlerts, feature_category: :incident_manage
|
|||
let_it_be(:alert1) { create(:alert_management_alert, project: project) }
|
||||
let_it_be(:alert2) { create(:alert_management_alert, project: project) }
|
||||
|
||||
let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
let(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:update_issue, :admin_issue) }
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,17 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::Issues::Move do
|
||||
RSpec.describe Mutations::Issues::Move, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:issue) { create(:issue) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:target_project) { create(:project) }
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
describe '#resolve' do
|
||||
subject(:resolve) { mutation.resolve(project_path: issue.project.full_path, iid: issue.iid, target_project_path: target_project.full_path) }
|
||||
|
|
|
|||
|
|
@ -2,13 +2,17 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::Issues::SetAssignees do
|
||||
RSpec.describe Mutations::Issues::SetAssignees, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
context 'when the user does not have permissions' do
|
||||
let_it_be(:issue) { create(:issue) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:assignee) { create(:user) }
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
describe '#resolve' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -2,12 +2,15 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::Issues::SetConfidential do
|
||||
RSpec.describe Mutations::Issues::SetConfidential, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
let(:project) { create(:project, :private) }
|
||||
let(:issue) { create(:issue, project: project, assignees: [user]) }
|
||||
let(:user) { create(:user) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:update_issue) }
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,16 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::Issues::SetDueDate do
|
||||
RSpec.describe Mutations::Issues::SetDueDate, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
|
||||
let(:issue) { create(:issue, due_date: '2021-05-01') }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:update_issue) }
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,18 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::Issues::SetEscalationStatus do
|
||||
RSpec.describe Mutations::Issues::SetEscalationStatus, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:issue, reload: true) { create(:incident, project: project) }
|
||||
let_it_be(:escalation_status, reload: true) { create(:incident_management_issuable_escalation_status, issue: issue) }
|
||||
|
||||
let(:status) { :acknowledged }
|
||||
let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
let(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
describe '#resolve' do
|
||||
let(:args) { { status: status } }
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::Issues::SetLocked do
|
||||
RSpec.describe Mutations::Issues::SetLocked, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:issue) { create(:issue) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:update_issue) }
|
||||
|
||||
|
|
|
|||
|
|
@ -2,13 +2,17 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::Issues::SetSeverity do
|
||||
RSpec.describe Mutations::Issues::SetSeverity, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:guest) { create(:user, guest_of: project) }
|
||||
let_it_be(:reporter) { create(:user, reporter_of: project) }
|
||||
let_it_be(:issue) { create(:incident, project: project) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
let(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:update_issue, :admin_issue) }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::Issues::UnlinkAlert, feature_category: :incident_management do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:another_project) { create(:project) }
|
||||
let_it_be(:guest) { create(:user, guest_of: project) }
|
||||
|
|
@ -11,7 +13,9 @@ RSpec.describe Mutations::Issues::UnlinkAlert, feature_category: :incident_manag
|
|||
let_it_be(:external_alert) { create(:alert_management_alert, project: another_project) }
|
||||
let_it_be(:issue) { create(:incident, project: project, alert_management_alerts: [internal_alert, external_alert]) }
|
||||
|
||||
let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
let(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:update_issue, :admin_issue) }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::Issues::Update, feature_category: :team_planning do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project_label) { create(:label, project: project) }
|
||||
|
|
@ -20,7 +22,9 @@ RSpec.describe Mutations::Issues::Update, feature_category: :team_planning do
|
|||
}
|
||||
end
|
||||
|
||||
let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
let(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
let(:mutated_issue) { subject[:issue] }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:update_issue) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::Labels::Create do
|
||||
RSpec.describe Mutations::Labels::Create, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
let(:attributes) do
|
||||
|
|
@ -12,7 +14,9 @@ RSpec.describe Mutations::Labels::Create do
|
|||
}
|
||||
end
|
||||
|
||||
let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
let(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
let(:mutated_label) { subject[:label] }
|
||||
|
||||
shared_examples 'create labels mutation' do
|
||||
|
|
|
|||
|
|
@ -7,9 +7,11 @@ RSpec.describe Mutations::Members::BulkUpdateBase, feature_category: :groups_and
|
|||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:group) { create(:group, owners: user) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
it 'raises a NotImplementedError error if the source_type method is called on the base class' do
|
||||
mutation = described_class.new(context: { current_user: user }, object: nil, field: nil)
|
||||
mutation = described_class.new(context: context, object: nil, field: nil)
|
||||
|
||||
expect { mutation.resolve(group_id: group.to_gid.to_s) }.to raise_error(NotImplementedError)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,21 +2,16 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::MergeRequests::Accept do
|
||||
RSpec.describe Mutations::MergeRequests::Accept, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
include AfterNextHelpers
|
||||
|
||||
subject(:mutation) { described_class.new(context: context, object: nil, field: nil) }
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
let(:context) do
|
||||
GraphQL::Query::Context.new(
|
||||
query: query_double(schema: GitlabSchema),
|
||||
values: { current_user: user }
|
||||
)
|
||||
end
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
subject(:mutation) { described_class.new(context: context, object: nil, field: nil) }
|
||||
|
||||
before do
|
||||
project.repository.expire_all_method_caches
|
||||
|
|
|
|||
|
|
@ -2,19 +2,14 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::MergeRequests::Create do
|
||||
RSpec.describe Mutations::MergeRequests::Create, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
let(:user) { create(:user) }
|
||||
|
||||
let(:context) do
|
||||
GraphQL::Query::Context.new(
|
||||
query: query_double(schema: nil),
|
||||
values: { current_user: user }
|
||||
)
|
||||
end
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
describe '#resolve' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -2,13 +2,16 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::MergeRequests::SetAssignees do
|
||||
RSpec.describe Mutations::MergeRequests::SetAssignees, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
context 'when the user does not have permissions' do
|
||||
let_it_be(:merge_request) { create(:merge_request) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:assignee) { create(:user) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
describe '#resolve' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::MergeRequests::SetDraft do
|
||||
RSpec.describe Mutations::MergeRequests::SetDraft, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
let_it_be(:merge_request) { create(:merge_request) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:update_merge_request) }
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::MergeRequests::SetLabels do
|
||||
RSpec.describe Mutations::MergeRequests::SetLabels, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
|
||||
let(:merge_request) { create(:merge_request) }
|
||||
let(:user) { create(:user) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:update_merge_request) }
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::MergeRequests::SetLocked do
|
||||
RSpec.describe Mutations::MergeRequests::SetLocked, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
|
||||
let(:merge_request) { create(:merge_request) }
|
||||
let(:user) { create(:user) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:update_merge_request) }
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::MergeRequests::SetMilestone do
|
||||
RSpec.describe Mutations::MergeRequests::SetMilestone, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project, :private) }
|
||||
let(:merge_request) { create(:merge_request, source_project: project, target_project: project, assignees: [user]) }
|
||||
let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
let(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
let(:milestone) { create(:milestone, project: project) }
|
||||
|
||||
subject { mutation.resolve(project_path: project.full_path, iid: merge_request.iid, milestone: milestone) }
|
||||
|
|
|
|||
|
|
@ -2,13 +2,17 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::MergeRequests::SetReviewers do
|
||||
RSpec.describe Mutations::MergeRequests::SetReviewers, feature_category: :api do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:merge_request, reload: true) { create(:merge_request) }
|
||||
let_it_be(:reviewer) { create(:user) }
|
||||
let_it_be(:reviewer2) { create(:user) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
describe '#resolve' do
|
||||
let(:reviewer_usernames) { [reviewer.username] }
|
||||
|
|
|
|||
|
|
@ -3,10 +3,14 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::MergeRequests::Update, feature_category: :team_planning do
|
||||
include GraphqlHelpers
|
||||
|
||||
let(:merge_request) { create(:merge_request) }
|
||||
let(:user) { create(:user) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:update_merge_request) }
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,11 @@ RSpec.describe Gitlab::Pagination::GitalyKeysetPager, feature_category: :source_
|
|||
context 'when first page is requested' do
|
||||
let(:branches) { [branch1, branch2, branch3] }
|
||||
|
||||
before do
|
||||
allow(BranchesFinder).to receive(:===).with(finder).and_return(true)
|
||||
allow(finder).to receive(:total).and_return(branches.size)
|
||||
end
|
||||
|
||||
it 'keyset pagination is used with offset headers' do
|
||||
allow(request_context).to receive(:request).and_return(fake_request)
|
||||
allow(project.repository).to receive(:branch_count).and_return(branches.size)
|
||||
|
|
@ -85,6 +90,26 @@ RSpec.describe Gitlab::Pagination::GitalyKeysetPager, feature_category: :source_
|
|||
|
||||
pager.paginate(finder)
|
||||
end
|
||||
|
||||
context 'when second page does not exist' do
|
||||
let(:base_query) { { per_page: 3 } }
|
||||
|
||||
it 'does not set an invalid X-Next-Page header' do
|
||||
allow(request_context).to receive(:request).and_return(fake_request)
|
||||
allow(project.repository).to receive(:branch_count).and_return(branches.size)
|
||||
|
||||
expect(finder).to receive(:execute).and_return(branches)
|
||||
expect(request_context).to receive(:header).with('X-Per-Page', '3')
|
||||
expect(request_context).to receive(:header).with('X-Page', '1')
|
||||
expect(request_context).to receive(:header).with('X-Next-Page', '')
|
||||
expect(request_context).to receive(:header).with('X-Prev-Page', '')
|
||||
expect(request_context).to receive(:header).with('Link', kind_of(String))
|
||||
expect(request_context).to receive(:header).with('X-Total', '3')
|
||||
expect(request_context).to receive(:header).with('X-Total-Pages', '1')
|
||||
|
||||
pager.paginate(finder)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when second page is requested' do
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.shared_examples 'a subscribeable not accessible graphql resource' do
|
||||
let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
include GraphqlHelpers
|
||||
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
let(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
subject { mutation.resolve(project_path: resource.project.full_path, iid: resource.iid, subscribed_state: true) }
|
||||
|
||||
|
|
@ -13,8 +17,12 @@ RSpec.shared_examples 'a subscribeable not accessible graphql resource' do
|
|||
end
|
||||
|
||||
RSpec.shared_examples 'a subscribeable graphql resource' do
|
||||
include GraphqlHelpers
|
||||
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
let(:mutated_resource) { subject[resource.class.name.underscore.to_sym] }
|
||||
let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
let(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
let(:subscribe) { true }
|
||||
|
||||
subject { mutation.resolve(project_path: resource.project.full_path, iid: resource.iid, subscribed_state: subscribe) }
|
||||
|
|
|
|||
|
|
@ -3,9 +3,13 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.shared_examples 'an assignable resource' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
include GraphqlHelpers
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let(:query) { GraphQL::Query.new(empty_schema, document: nil, context: {}, variables: {}) }
|
||||
let(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: user }) }
|
||||
|
||||
subject(:mutation) { described_class.new(object: nil, context: context, field: nil) }
|
||||
|
||||
describe '#resolve' do
|
||||
let_it_be(:assignee) { create(:user) }
|
||||
|
|
|
|||
|
|
@ -41,6 +41,25 @@ RSpec.shared_examples 'a correct instrumented metric query' do |params|
|
|||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'a correct instrumented database query execution value' do |params|
|
||||
let(:time_frame) { params[:time_frame] }
|
||||
let(:options) { params[:options] }
|
||||
let(:metric) { described_class.new(time_frame: time_frame, options: options) }
|
||||
|
||||
around do |example|
|
||||
freeze_time { example.run }
|
||||
end
|
||||
|
||||
before do
|
||||
allow(metric.relation).to receive(:transaction_open?).and_return(false)
|
||||
end
|
||||
|
||||
it 'returns correct value' do
|
||||
query_result = metric.relation.connection.execute(metric.instrumentation).to_a.first.each_value.first
|
||||
expect(query_result).to eq(expected_value)
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'a correct instrumented metric value and query' do |params|
|
||||
it_behaves_like 'a correct instrumented metric value', params
|
||||
it_behaves_like 'a correct instrumented metric query', params
|
||||
|
|
|
|||
Loading…
Reference in New Issue