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: - ![Job artifacts in Pipelines page](img/job_artifacts_pipelines_page.png) + ![Job artifacts in Pipelines page](img/job_artifacts_pipelines_page_v13_11.png) - On the **Jobs** page, to the right of the job: - ![Job artifacts in Builds page](img/job_artifacts_builds_page.png) + ![Job artifacts in Jobs page](img/job_artifacts_jobs_page_v13_11.png) - On a job's detail page. The **Keep** button indicates an `expire_in` value was set: - ![Job artifacts browser button](img/job_artifacts_browser_button.png) + ![Job artifacts browser button](img/job_artifacts_browser_button_v13_11.png) - On a merge request, by the pipeline details: - ![Job artifacts in Merge Request](img/job_artifacts_merge_request.png) + ![Job artifacts in merge request](img/job_artifacts_merge_request_v13_11.png) - When browsing an archive: - ![Job artifacts browser](img/job_artifacts_browser.png) + ![Job artifacts browser](img/job_artifacts_browser_v13_11.png) 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. ![Latest artifacts button](img/job_latest_artifacts_browser.png) -## 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