diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 1963fca425f..f9b425ecaab 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-0f93ceb8a8ccfe38ee3fde399efcb49aa91cbedd
+61404ee4997721100430c6acf4586ec3d85b15da
diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js
index 8d2d9d1d9f6..39f66063cfb 100644
--- a/app/assets/javascripts/notes/stores/getters.js
+++ b/app/assets/javascripts/notes/stores/getters.js
@@ -8,7 +8,7 @@ const getDraftComments = (state) => {
}
return state.batchComments.drafts
- .filter((draft) => !draft.line_code && !draft.discussion_id)
+ .filter((draft) => !draft.file_path && !draft.discussion_id)
.map((x) => ({
...x,
// Treat a top-level draft note as individual_note so it's not included in
diff --git a/app/assets/javascripts/performance/constants.js b/app/assets/javascripts/performance/constants.js
index 4ac758550e0..98b2e4238c1 100644
--- a/app/assets/javascripts/performance/constants.js
+++ b/app/assets/javascripts/performance/constants.js
@@ -74,4 +74,4 @@ export const PIPELINES_DETAIL_LINKS_MEASURE_CALCULATION =
// (defined in: app/services/ci/prometheus_metrics/observe_histograms_service.rb)
export const PIPELINES_DETAIL_LINK_DURATION = 'pipeline_graph_link_calculation_duration_seconds';
export const PIPELINES_DETAIL_LINKS_TOTAL = 'pipeline_graph_links_total';
-export const PIPELINES_DETAIL_LINKS_JOB_RATIO = 'pipeline_graph_link_per_job_ratio';
+export const PIPELINES_DETAIL_LINKS_JOB_RATIO = 'pipeline_graph_links_per_job_ratio';
diff --git a/app/services/issuable/destroy_service.rb b/app/services/issuable/destroy_service.rb
index bdbd814435e..d5aa84d8d6c 100644
--- a/app/services/issuable/destroy_service.rb
+++ b/app/services/issuable/destroy_service.rb
@@ -17,13 +17,13 @@ module Issuable
end
def group_for(issuable)
- issuable.resource_parent
+ issuable.resource_parent.group
end
def delete_todos(issuable)
- group = group_for(issuable)
+ actor = group_for(issuable)
- if Feature.enabled?(:destroy_issuable_todos_async, group, default_enabled: :yaml)
+ if Feature.enabled?(:destroy_issuable_todos_async, actor, default_enabled: :yaml)
TodosDestroyer::DestroyedIssuableWorker
.perform_async(issuable.id, issuable.class.name)
else
diff --git a/doc/administration/auth/atlassian.md b/doc/administration/auth/atlassian.md
index 78fb709886f..9c5da558b0d 100644
--- a/doc/administration/auth/atlassian.md
+++ b/doc/administration/auth/atlassian.md
@@ -12,7 +12,7 @@ To enable the Atlassian OmniAuth provider for passwordless authentication you mu
## Atlassian application registration
1. Go to and sign-in with the Atlassian
- account to administer the application with.
+ account that will administer the application.
1. Click **Create a new app**.
diff --git a/doc/administration/auth/authentiq.md b/doc/administration/auth/authentiq.md
index 3a3b81fc263..dbc5e446287 100644
--- a/doc/administration/auth/authentiq.md
+++ b/doc/administration/auth/authentiq.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
To enable the Authentiq OmniAuth provider for passwordless authentication you must register an application with Authentiq.
-Authentiq generates a Client ID and the accompanying Client Secret for you to use.
+Authentiq will generate a Client ID and the accompanying Client Secret for you to use.
1. Get your Client credentials (Client ID and Client Secret) at [Authentiq](https://www.authentiq.com/developers).
diff --git a/doc/ci/pipelines/img/job_artifacts_browser.png b/doc/ci/pipelines/img/job_artifacts_browser.png
deleted file mode 100644
index d3d8de5ac60..00000000000
Binary files a/doc/ci/pipelines/img/job_artifacts_browser.png and /dev/null differ
diff --git a/doc/ci/pipelines/img/job_artifacts_browser_button.png b/doc/ci/pipelines/img/job_artifacts_browser_button.png
deleted file mode 100644
index 21072ce1248..00000000000
Binary files a/doc/ci/pipelines/img/job_artifacts_browser_button.png and /dev/null differ
diff --git a/doc/ci/pipelines/img/job_artifacts_browser_button_v13_11.png b/doc/ci/pipelines/img/job_artifacts_browser_button_v13_11.png
new file mode 100644
index 00000000000..710a82075ce
Binary files /dev/null and b/doc/ci/pipelines/img/job_artifacts_browser_button_v13_11.png differ
diff --git a/doc/ci/pipelines/img/job_artifacts_browser_v13_11.png b/doc/ci/pipelines/img/job_artifacts_browser_v13_11.png
new file mode 100644
index 00000000000..6a8ea49b833
Binary files /dev/null and b/doc/ci/pipelines/img/job_artifacts_browser_v13_11.png differ
diff --git a/doc/ci/pipelines/img/job_artifacts_builds_page.png b/doc/ci/pipelines/img/job_artifacts_builds_page.png
deleted file mode 100644
index 13e039ba934..00000000000
Binary files a/doc/ci/pipelines/img/job_artifacts_builds_page.png and /dev/null differ
diff --git a/doc/ci/pipelines/img/job_artifacts_jobs_page_v13_11.png b/doc/ci/pipelines/img/job_artifacts_jobs_page_v13_11.png
new file mode 100644
index 00000000000..9f09e36b927
Binary files /dev/null and b/doc/ci/pipelines/img/job_artifacts_jobs_page_v13_11.png differ
diff --git a/doc/ci/pipelines/img/job_artifacts_merge_request.png b/doc/ci/pipelines/img/job_artifacts_merge_request.png
deleted file mode 100644
index e87839ceeca..00000000000
Binary files a/doc/ci/pipelines/img/job_artifacts_merge_request.png and /dev/null differ
diff --git a/doc/ci/pipelines/img/job_artifacts_merge_request_v13_11.png b/doc/ci/pipelines/img/job_artifacts_merge_request_v13_11.png
new file mode 100644
index 00000000000..f4b875de471
Binary files /dev/null and b/doc/ci/pipelines/img/job_artifacts_merge_request_v13_11.png differ
diff --git a/doc/ci/pipelines/img/job_artifacts_pipelines_page.png b/doc/ci/pipelines/img/job_artifacts_pipelines_page.png
deleted file mode 100644
index 983f903ca72..00000000000
Binary files a/doc/ci/pipelines/img/job_artifacts_pipelines_page.png and /dev/null differ
diff --git a/doc/ci/pipelines/img/job_artifacts_pipelines_page_v13_11.png b/doc/ci/pipelines/img/job_artifacts_pipelines_page_v13_11.png
new file mode 100644
index 00000000000..c7b0b91d488
Binary files /dev/null and b/doc/ci/pipelines/img/job_artifacts_pipelines_page_v13_11.png differ
diff --git a/doc/ci/pipelines/job_artifacts.md b/doc/ci/pipelines/job_artifacts.md
index ebf4dffcf89..fa97f9bd75d 100644
--- a/doc/ci/pipelines/job_artifacts.md
+++ b/doc/ci/pipelines/job_artifacts.md
@@ -15,14 +15,14 @@ Jobs can output an archive of files and directories. This output is known as a j
You can download job artifacts by using the GitLab UI or the [API](../../api/job_artifacts.md#get-job-artifacts).
-For an overview, watch the video [GitLab CI Pipeline, Artifacts, and Environments](https://www.youtube.com/watch?v=PCKDICEe10s).
-Watch also [GitLab CI pipeline tutorial for beginners](https://www.youtube.com/watch?v=Jav4vbUrqII).
+For an overview of job artifacts, watch the video [GitLab CI pipelines, artifacts, and environments](https://www.youtube.com/watch?v=PCKDICEe10s).
+Or, for an introduction, watch [GitLab CI pipeline tutorial for beginners](https://www.youtube.com/watch?v=Jav4vbUrqII).
-Administrators should review our [job artifacts administration](../../administration/job_artifacts.md) documentation.
+For administrator information about job artifact storage, see [administering job artifacts](../../administration/job_artifacts.md).
-## Define artifacts in the `.gitlab-ci.yml` file
+## Create job artifacts
-This example shows how to configure your `.gitlab-ci.yml` file to create job artifacts:
+To create job artifacts, use the `artifacts` keyword in your `.gitlab-ci.yml` file:
```yaml
pdf:
@@ -33,7 +33,7 @@ pdf:
expire_in: 1 week
```
-A job named `pdf` calls the `xelatex` command to build a PDF file from the
+In this example, a job named `pdf` calls the `xelatex` command to build a PDF file from the
LaTeX source file, `mycv.tex`.
The `paths` keyword determines which files to add to the job artifacts.
@@ -45,6 +45,9 @@ If `expire_in` is not defined, the
[instance-wide setting](../../user/admin_area/settings/continuous_integration.md#default-artifacts-expiration)
is used.
+If you run two types of pipelines (like branch and scheduled) for the same ref,
+the pipeline that finishes later creates the job artifact.
+
For more examples, view the [keyword reference for the `.gitlab-ci.yml` file](../yaml/README.md#artifacts).
## Download job artifacts
@@ -53,23 +56,23 @@ You can download job artifacts or view the job archive:
- On the **Pipelines** page, to the right of the pipeline:
- 
+ 
- On the **Jobs** page, to the right of the job:
- 
+ 
- On a job's detail page. The **Keep** button indicates an `expire_in` value was set:
- 
+ 
- On a merge request, by the pipeline details:
- 
+ 
- When browsing an archive:
- 
+ 
If [GitLab Pages](../../administration/pages/index.md) is enabled in the project, you can preview
HTML files in the artifacts directly in your browser. If the project is internal or private, you must
@@ -83,44 +86,37 @@ information in the UI.

-## Erase job artifacts
+## Delete job artifacts
WARNING:
This is a destructive action that leads to data loss. Use with caution.
-You can erase a single job, which also removes the job's
+You can delete a single job, which also removes the job's
artifacts and log. You must be:
- The owner of the job.
-- A [Maintainer](../../user/permissions.md#gitlab-cicd-permissions) of the project.
+- A [maintainer](../../user/permissions.md#gitlab-cicd-permissions) of the project.
-To erase a job:
+To delete a job:
1. Go to a job's detail page.
1. At the top right of the job's log, select the trash icon.
1. Confirm the deletion.
-## Retrieve job artifacts for private projects
+## Retrieve job artifacts for other projects
To retrieve a job artifact from a different project, you might need to use a
private token to [authenticate and download](../../api/job_artifacts.md#get-job-artifacts)
the artifact.
-## The latest job artifacts
-
-Job artifacts created in the most recent successful pipeline for a specific ref
-are considered the latest artifacts. If you run two types of pipelines for the same ref,
-timing determines which artifacts are the latest.
-
-For example, if a merge request creates a branch pipeline at the same time as
-a scheduled pipeline, the pipeline that finished most recently creates the latest job artifact.
+## How searching for job artifacts works
In [GitLab 13.5](https://gitlab.com/gitlab-org/gitlab/-/issues/201784) and later, artifacts
for [parent and child pipelines](../parent_child_pipelines.md) are searched in hierarchical
order from parent to child. For example, if both parent and child pipelines have a
job with the same name, the job artifact from the parent pipeline is returned.
-### Access the latest job artifacts by URL
+## Access the latest job artifacts by URL
You can download the latest job artifacts by using a URL.
@@ -136,12 +132,12 @@ To download a single file from the artifacts:
https://example.com///-/jobs/artifacts/[/raw/?job=
```
-For example, to download the latest artifacts of the job named `coverage` of
-the `master` branch of the `gitlab` project that belongs to the `gitlab-org`
+For example, to download the latest artifacts of the job named `coverage` in
+the `main` branch of the `gitlab` project in the `gitlab-org`
namespace:
```plaintext
-https://gitlab.com/gitlab-org/gitlab/-/jobs/artifacts/master/download?job=coverage
+https://gitlab.com/gitlab-org/gitlab/-/jobs/artifacts/main/download?job=coverage
```
To download the file `coverage/index.html` from the same artifacts:
@@ -162,7 +158,7 @@ For example:
https://gitlab.com/gitlab-org/gitlab/-/jobs/artifacts/master/browse?job=coverage
```
-There is also a URL for specific files, including HTML files that
+To download specific files, including HTML files that
are shown in [GitLab Pages](../../administration/pages/index.md):
```plaintext
@@ -175,16 +171,18 @@ For example, when a job `coverage` creates the artifact `htmlcov/index.html`:
https://gitlab.com/gitlab-org/gitlab/-/jobs/artifacts/master/file/htmlcov/index.html?job=coverage
```
+## When job artifacts are deleted
+
+By default, the latest job artifacts from the most recent successful jobs are never deleted.
+If a job is configured with [`expire_in`](../yaml/README.md#artifactsexpire_in),
+its artifacts only expire if a more recent artifact exists.
+
### Keep artifacts from most recent successful jobs
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16267) in GitLab 13.0.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/229936) in GitLab 13.4.
> - [Made optional with a CI/CD setting](https://gitlab.com/gitlab-org/gitlab/-/issues/241026) in GitLab 13.8.
-By default, the latest job artifacts from the most recent successful jobs are never deleted.
-If a job is configured with [`expire_in`](../yaml/README.md#artifactsexpire_in),
-its artifacts only expire if a more recent artifact exists.
-
Keeping the latest artifacts can use a large amount of storage space in projects
with a lot of jobs or large artifacts. If the latest artifacts are not needed in
a project, you can disable this behavior to save space:
@@ -202,21 +200,9 @@ A new pipeline must run before the latest artifacts can expire and be deleted.
### Error message `No files to upload`
-This is often preceded by other errors or warnings that specify the filename and why it wasn't
-generated in the first place. Please check the entire job log for such messages.
+This message is often preceded by other errors or warnings that specify the filename and why it wasn't
+generated. Check the job log for these messages.
-If you find no helpful messages, please retry the failed job after activating
+If you find no helpful messages, retry the failed job after activating
[CI/CD debug logging](../variables/README.md#debug-logging).
-This provides useful information to investigate further.
-
-
+This logging should provide information to help you investigate further.
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index ef201887ef1..49daa2b17fb 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -3270,7 +3270,7 @@ deploy:
If the artifacts of the job that is set as a dependency are
[expired](#artifactsexpire_in) or
-[erased](../pipelines/job_artifacts.md#erase-job-artifacts), then
+[deleted](../pipelines/job_artifacts.md#delete-job-artifacts), then
the dependent job fails.
You can ask your administrator to
diff --git a/doc/development/contributing/style_guides.md b/doc/development/contributing/style_guides.md
index 0f4b69d3daf..444a067a780 100644
--- a/doc/development/contributing/style_guides.md
+++ b/doc/development/contributing/style_guides.md
@@ -62,7 +62,6 @@ Before you push your changes, Lefthook automatically runs the following checks:
- SCSS lint: Run `yarn lint:stylelint` checks (with the [`.stylelintrc`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.stylelintrc) configuration) on the modified `*.scss{,.css}` files. Tags: `stylesheet`, `css`, `style`.
- RuboCop: Run `bundle exec rubocop` checks (with the [`.rubocop.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.rubocop.yml) configuration) on the modified `*.rb` files. Tags: `backend`, `style`.
- Vale: Run `vale` checks (with the [`.vale.ini`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.vale.ini) configuration) on the modified `*.md` files. Tags: `documentation`, `style`.
-- Documentation metadata: Run checks for the absence of [documentation metadata](../documentation/index.md#metadata).
In addition to the default configuration, you can define a [local configuration](https://github.com/Arkweid/lefthook/blob/master/docs/full_guide.md#local-config).
diff --git a/doc/development/elasticsearch.md b/doc/development/elasticsearch.md
index ba977b28247..705a69765f7 100644
--- a/doc/development/elasticsearch.md
+++ b/doc/development/elasticsearch.md
@@ -241,6 +241,10 @@ cron worker runs. Default value is 5 minutes.
- `pause_indexing!` - Pause indexing while the migration runs. This setting will record the indexing setting before
the migration runs and set it back to that value when the migration is completed.
+- `space_requirements!` - Verify that enough free space is available in the cluster when the migration runs. This setting
+ will halt the migration if the storage required is not available when the migration runs. The migration must provide
+ the space required in bytes by defining a `space_required_bytes` method.
+
```ruby
# frozen_string_literal: true
@@ -248,7 +252,9 @@ class BatchedMigrationName < Elastic::Migration
# Declares a migration should be run in batches
batched!
throttle_delay 10.minutes
-
+ pause_indexing!
+ space_requirements!
+
# ...
end
```
diff --git a/lefthook.yml b/lefthook.yml
index d29dce157db..daab6e7f4a0 100644
--- a/lefthook.yml
+++ b/lefthook.yml
@@ -38,8 +38,3 @@ pre-push:
files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
glob: 'doc/*.md'
run: if command -v vale 2> /dev/null; then vale --config .vale.ini --minAlertLevel error {files}; else echo "Vale not found. Install Vale"; fi
- docs-metadata: # https://docs.gitlab.com/ee/development/documentation/#metadata
- tags: documentation style
- files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
- glob: '*.md'
- run: scripts/lint-docs-metadata.sh "{files}"
diff --git a/lib/gitlab/gitaly_client/blob_service.rb b/lib/gitlab/gitaly_client/blob_service.rb
index 669fb1c0a31..19a473e4785 100644
--- a/lib/gitlab/gitaly_client/blob_service.rb
+++ b/lib/gitlab/gitaly_client/blob_service.rb
@@ -98,11 +98,12 @@ module Gitlab
end
def get_all_lfs_pointers
- request = Gitaly::GetAllLFSPointersRequest.new(
- repository: @gitaly_repo
+ request = Gitaly::ListLFSPointersRequest.new(
+ repository: @gitaly_repo,
+ revisions: [encode_binary("--all")]
)
- response = GitalyClient.call(@gitaly_repo.storage_name, :blob_service, :get_all_lfs_pointers, request, timeout: GitalyClient.medium_timeout)
+ response = GitalyClient.call(@gitaly_repo.storage_name, :blob_service, :list_lfs_pointers, request, timeout: GitalyClient.medium_timeout)
map_lfs_pointers(response)
end
@@ -125,19 +126,20 @@ module Gitlab
[request, :list_all_lfs_pointers]
else
- request = Gitaly::GetNewLFSPointersRequest.new(
+ revisions = [revision]
+ revisions += if not_in.nil? || not_in == :all
+ ["--not", "--all"]
+ else
+ not_in.prepend "--not"
+ end
+
+ request = Gitaly::ListLFSPointersRequest.new(
repository: @gitaly_repo,
- revision: encode_binary(revision),
- limit: limit || 0
+ limit: limit || 0,
+ revisions: revisions.map { |rev| encode_binary(rev) }
)
- if not_in.nil? || not_in == :all
- request.not_in_all = true
- else
- request.not_in_refs += not_in
- end
-
- [request, :get_new_lfs_pointers]
+ [request, :list_lfs_pointers]
end
end
diff --git a/lib/gitlab/pages/settings.rb b/lib/gitlab/pages/settings.rb
index 0e77259a0de..be71018e851 100644
--- a/lib/gitlab/pages/settings.rb
+++ b/lib/gitlab/pages/settings.rb
@@ -6,7 +6,7 @@ module Gitlab
DiskAccessDenied = Class.new(StandardError)
def path
- ::Gitlab::ErrorTracking.track_exception(DiskAccessDenied.new) if disk_access_denied?
+ report_denied_disk_access
super
end
@@ -22,6 +22,12 @@ module Gitlab
::Gitlab::Runtime.web_server? && !::Gitlab::Runtime.test_suite?
end
+
+ def report_denied_disk_access
+ raise DiskAccessDenied if disk_access_denied?
+ rescue => e
+ ::Gitlab::ErrorTracking.track_exception(e)
+ end
end
end
end
diff --git a/scripts/lint-doc.sh b/scripts/lint-doc.sh
index e11ce60c17f..4d0c1ba99d2 100755
--- a/scripts/lint-doc.sh
+++ b/scripts/lint-doc.sh
@@ -19,7 +19,6 @@ then
fi
# Documentation pages need front matter for tracking purposes.
-# See also lint-docs-metadata.sh
echo '=> Checking documentation for front matter...'
echo
no_frontmatter=$(find doc -name "*.md" -exec head -n1 {} \; | grep -v --count -- ---)
diff --git a/scripts/lint-docs-metadata.sh b/scripts/lint-docs-metadata.sh
deleted file mode 100755
index 75e4b9c2418..00000000000
--- a/scripts/lint-docs-metadata.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env bash
-
-# Used in `lefthook.yml`
-(( counter=0 ))
-
-for file in $1
-do
- if [ "$(head -n1 "$file")" != "---" ]
- then
- printf "%sDocumentation metadata missing in %s%s\n" "$(tput setaf 1)" "$file" "$(tput sgr0)"
- (( counter++ ))
- else
- printf "Documentation metadata found in %s.\n" "$file"
- fi
-done
-
-if [ "$counter" -gt 0 ]
-then
- printf "\n%sDocumentation metadata is missing in changed documentation files.%s For more information, see https://docs.gitlab.com/ee/development/documentation/#metadata.\n" "$(tput setaf 1)" "$(tput sgr0)"
- false
-else
- printf "\n%sDocumentation metadata found in all changed documentation files.%s\n" "$(tput setaf 2)" "$(tput sgr0)"
- true
-fi
diff --git a/spec/factories/draft_note.rb b/spec/factories/draft_note.rb
index 67a3377a39f..cde8831f169 100644
--- a/spec/factories/draft_note.rb
+++ b/spec/factories/draft_note.rb
@@ -9,17 +9,30 @@ FactoryBot.define do
transient do
line_number { 14 }
diff_refs { merge_request.try(:diff_refs) }
+ path { "files/ruby/popen.rb" }
end
position do
Gitlab::Diff::Position.new(
- old_path: "files/ruby/popen.rb",
- new_path: "files/ruby/popen.rb",
+ old_path: path,
+ new_path: path,
old_line: nil,
new_line: line_number,
diff_refs: diff_refs
)
end
+
+ factory :draft_note_on_image_diff do
+ transient do
+ path { "files/images/any_image.png" }
+ end
+
+ position do
+ association(:image_diff_position,
+ file: path,
+ diff_refs: diff_refs)
+ end
+ end
end
factory :draft_note_on_discussion, traits: [:on_discussion]
diff --git a/spec/features/merge_request/batch_comments_spec.rb b/spec/features/merge_request/batch_comments_spec.rb
index d3e32ecff28..19680a827bf 100644
--- a/spec/features/merge_request/batch_comments_spec.rb
+++ b/spec/features/merge_request/batch_comments_spec.rb
@@ -86,6 +86,19 @@ RSpec.describe 'Merge request > Batch comments', :js do
expect(page).to have_selector('.draft-note-component', text: 'Testing update')
end
+ context 'with image and file draft note' do
+ let(:merge_request) { create(:merge_request_with_diffs, :with_image_diffs, source_project: project) }
+ let!(:draft_on_text) { create(:draft_note_on_text_diff, merge_request: merge_request, author: user, path: 'README.md', note: 'Lorem ipsum on text...') }
+ let!(:draft_on_image) { create(:draft_note_on_image_diff, merge_request: merge_request, author: user, path: 'files/images/ee_repo_logo.png', note: 'Lorem ipsum on an image...') }
+
+ it 'does not show in overview' do
+ visit_overview
+
+ expect(page).to have_no_text(draft_on_text.note)
+ expect(page).to have_no_text(draft_on_image.note)
+ end
+ end
+
context 'adding single comment to review' do
before do
visit_overview
diff --git a/spec/frontend/notes/components/notes_app_spec.js b/spec/frontend/notes/components/notes_app_spec.js
index 727e24b6bd9..241a89b2218 100644
--- a/spec/frontend/notes/components/notes_app_spec.js
+++ b/spec/frontend/notes/components/notes_app_spec.js
@@ -408,10 +408,9 @@ describe('note_app', () => {
store = createStore();
store.registerModule('batchComments', batchComments());
store.state.batchComments.drafts = [
- { line_code: 1, isDraft: true },
- { discussion_id: 1, isDraft: true },
- { note: 'A', isDraft: true },
- { note: 'B', isDraft: true },
+ mockData.draftDiffDiscussion,
+ mockData.draftReply,
+ ...mockData.draftComments,
];
store.state.isLoading = false;
wrapper = shallowMount(NotesApp, {
@@ -426,10 +425,9 @@ describe('note_app', () => {
it('correctly finds only draft comments', () => {
const drafts = wrapper.findAll(DraftNote).wrappers;
- expect(drafts.map((x) => x.props('draft'))).toEqual([
- expect.objectContaining({ note: 'A' }),
- expect.objectContaining({ note: 'B' }),
- ]);
+ expect(drafts.map((x) => x.props('draft'))).toEqual(
+ mockData.draftComments.map(({ note }) => expect.objectContaining({ note })),
+ );
});
});
});
diff --git a/spec/frontend/notes/mock_data.js b/spec/frontend/notes/mock_data.js
index 44bb87d7736..a4aeeda48d8 100644
--- a/spec/frontend/notes/mock_data.js
+++ b/spec/frontend/notes/mock_data.js
@@ -1273,10 +1273,16 @@ export const batchSuggestionsInfoMock = [
];
export const draftComments = [
- { id: 7, note: 'test draft note' },
- { id: 9, note: 'draft note 2' },
+ { id: 7, note: 'test draft note', isDraft: true },
+ { id: 9, note: 'draft note 2', isDraft: true },
];
-export const draftReply = { id: 8, note: 'draft reply', discussion_id: 1 };
+export const draftReply = { id: 8, note: 'draft reply', discussion_id: 1, isDraft: true };
-export const draftDiffDiscussion = { id: 6, note: 'draft diff discussion', line_code: 1 };
+export const draftDiffDiscussion = {
+ id: 6,
+ note: 'draft diff discussion',
+ line_code: 1,
+ file_path: 'lib/foo.rb',
+ isDraft: true,
+};
diff --git a/spec/lib/gitlab/gitaly_client/blob_service_spec.rb b/spec/lib/gitlab/gitaly_client/blob_service_spec.rb
index e35f541f5c8..f0ec58f3c2d 100644
--- a/spec/lib/gitlab/gitaly_client/blob_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/blob_service_spec.rb
@@ -14,14 +14,14 @@ RSpec.describe Gitlab::GitalyClient::BlobService do
let(:limit) { 5 }
let(:not_in) { %w[branch-a branch-b] }
let(:expected_params) do
- { revision: revision, limit: limit, not_in_refs: not_in, not_in_all: false }
+ { revisions: ["master", "--not", "branch-a", "branch-b"], limit: limit }
end
subject { client.get_new_lfs_pointers(revision, limit, not_in) }
it 'sends a get_new_lfs_pointers message' do
expect_any_instance_of(Gitaly::BlobService::Stub)
- .to receive(:get_new_lfs_pointers)
+ .to receive(:list_lfs_pointers)
.with(gitaly_request_with_params(expected_params), kind_of(Hash))
.and_return([])
@@ -31,12 +31,12 @@ RSpec.describe Gitlab::GitalyClient::BlobService do
context 'with not_in = :all' do
let(:not_in) { :all }
let(:expected_params) do
- { revision: revision, limit: limit, not_in_refs: [], not_in_all: true }
+ { revisions: ["master", "--not", "--all"], limit: limit }
end
it 'sends the correct message' do
expect_any_instance_of(Gitaly::BlobService::Stub)
- .to receive(:get_new_lfs_pointers)
+ .to receive(:list_lfs_pointers)
.with(gitaly_request_with_params(expected_params), kind_of(Hash))
.and_return([])
@@ -73,12 +73,16 @@ RSpec.describe Gitlab::GitalyClient::BlobService do
end
describe '#get_all_lfs_pointers' do
+ let(:expected_params) do
+ { revisions: ["--all"], limit: 0 }
+ end
+
subject { client.get_all_lfs_pointers }
it 'sends a get_all_lfs_pointers message' do
expect_any_instance_of(Gitaly::BlobService::Stub)
- .to receive(:get_all_lfs_pointers)
- .with(gitaly_request_with_params({}), kind_of(Hash))
+ .to receive(:list_lfs_pointers)
+ .with(gitaly_request_with_params(expected_params), kind_of(Hash))
.and_return([])
subject
diff --git a/spec/mailers/devise_mailer_spec.rb b/spec/mailers/devise_mailer_spec.rb
index c9dfee8255d..2634d7c722b 100644
--- a/spec/mailers/devise_mailer_spec.rb
+++ b/spec/mailers/devise_mailer_spec.rb
@@ -94,4 +94,36 @@ RSpec.describe DeviseMailer do
is_expected.to have_link(Gitlab.config.gitlab.url)
end
end
+
+ describe '#reset_password_instructions' do
+ subject { described_class.reset_password_instructions(user, 'faketoken') }
+
+ let_it_be(:user) { create(:user) }
+
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like 'a user cannot unsubscribe through footer link'
+
+ it 'is sent to the user' do
+ is_expected.to deliver_to user.email
+ end
+
+ it 'has the correct subject' do
+ is_expected.to have_subject 'Reset password instructions'
+ end
+
+ it 'greets the user' do
+ is_expected.to have_body_text /Hello, #{user.name}!/
+ end
+
+ it 'includes the correct content' do
+ is_expected.to have_text /Someone, hopefully you, has requested to reset the password for your GitLab account on #{Gitlab.config.gitlab.url}/
+ is_expected.to have_body_text /If you did not perform this request, you can safely ignore this email./
+ is_expected.to have_body_text /Otherwise, click the link below to complete the process./
+ end
+
+ it 'includes a link to reset the password' do
+ is_expected.to have_link("Reset password", href: "#{Gitlab.config.gitlab.url}/users/password/edit?reset_password_token=faketoken")
+ end
+ end
end
diff --git a/spec/services/issuable/destroy_service_spec.rb b/spec/services/issuable/destroy_service_spec.rb
index fadab77a043..fa4902e5237 100644
--- a/spec/services/issuable/destroy_service_spec.rb
+++ b/spec/services/issuable/destroy_service_spec.rb
@@ -4,37 +4,12 @@ require 'spec_helper'
RSpec.describe Issuable::DestroyService do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:group) { create(:group, :public) }
+ let(:project) { create(:project, :public, group: group) }
subject(:service) { described_class.new(project, user) }
describe '#execute' do
- shared_examples_for 'service deleting todos' do
- it 'destroys associated todos asynchronously' do
- expect(TodosDestroyer::DestroyedIssuableWorker)
- .to receive(:perform_async)
- .with(issuable.id, issuable.class.name)
-
- subject.execute(issuable)
- end
-
- context 'when destroy_issuable_todos_async feature is disabled' do
- before do
- stub_feature_flags(destroy_issuable_todos_async: false)
- end
-
- it 'destroy associated todos synchronously' do
- expect_next_instance_of(TodosDestroyer::DestroyedIssuableWorker) do |worker|
- expect(worker)
- .to receive(:perform)
- .with(issuable.id, issuable.class.name)
- end
-
- subject.execute(issuable)
- end
- end
- end
-
context 'when issuable is an issue' do
let!(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
diff --git a/spec/support/shared_examples/models/packages/debian/architecture_shared_examples.rb b/spec/support/shared_examples/models/packages/debian/architecture_shared_examples.rb
index b73ff516670..fbb94b4f5c1 100644
--- a/spec/support/shared_examples/models/packages/debian/architecture_shared_examples.rb
+++ b/spec/support/shared_examples/models/packages/debian/architecture_shared_examples.rb
@@ -34,7 +34,7 @@ RSpec.shared_examples 'Debian Distribution Architecture' do |factory, container,
subject { described_class.with_distribution(architecture.distribution) }
it 'does not return other distributions' do
- expect(subject.to_a).to eq([architecture, architecture_same_distribution])
+ expect(subject.to_a).to match_array([architecture, architecture_same_distribution])
end
end
@@ -42,7 +42,7 @@ RSpec.shared_examples 'Debian Distribution Architecture' do |factory, container,
subject { described_class.with_name(architecture.name) }
it 'does not return other distributions' do
- expect(subject.to_a).to eq([architecture, architecture_same_name])
+ expect(subject.to_a).to match_array([architecture, architecture_same_name])
end
end
end
diff --git a/spec/support/shared_examples/models/packages/debian/component_shared_examples.rb b/spec/support/shared_examples/models/packages/debian/component_shared_examples.rb
index bf6fc23116c..23e76d32fb0 100644
--- a/spec/support/shared_examples/models/packages/debian/component_shared_examples.rb
+++ b/spec/support/shared_examples/models/packages/debian/component_shared_examples.rb
@@ -36,7 +36,7 @@ RSpec.shared_examples 'Debian Distribution Component' do |factory, container, ca
subject { described_class.with_distribution(component.distribution) }
it 'does not return other distributions' do
- expect(subject.to_a).to eq([component, component_same_distribution])
+ expect(subject.to_a).to match_array([component, component_same_distribution])
end
end
@@ -44,7 +44,7 @@ RSpec.shared_examples 'Debian Distribution Component' do |factory, container, ca
subject { described_class.with_name(component.name) }
it 'does not return other distributions' do
- expect(subject.to_a).to eq([component, component_same_name])
+ expect(subject.to_a).to match_array([component, component_same_name])
end
end
end
diff --git a/spec/support/shared_examples/services/issuable/destroy_service_shared_examples.rb b/spec/support/shared_examples/services/issuable/destroy_service_shared_examples.rb
new file mode 100644
index 00000000000..ccc287c10de
--- /dev/null
+++ b/spec/support/shared_examples/services/issuable/destroy_service_shared_examples.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+shared_examples_for 'service deleting todos' do
+ before do
+ stub_feature_flags(destroy_issuable_todos_async: group)
+ end
+
+ it 'destroys associated todos asynchronously' do
+ expect(TodosDestroyer::DestroyedIssuableWorker)
+ .to receive(:perform_async)
+ .with(issuable.id, issuable.class.name)
+
+ subject.execute(issuable)
+ end
+
+ context 'when destroy_issuable_todos_async feature is disabled for group' do
+ before do
+ stub_feature_flags(destroy_issuable_todos_async: false)
+ end
+
+ it 'destroy associated todos synchronously' do
+ expect_next_instance_of(TodosDestroyer::DestroyedIssuableWorker) do |worker|
+ expect(worker)
+ .to receive(:perform)
+ .with(issuable.id, issuable.class.name)
+ end
+
+ subject.execute(issuable)
+ end
+ end
+end
]