diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-20 00:23:20 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-20 00:23:20 +0300 |
commit | ec2d2ecdf734e48f6603c90aea01abc67c6bb293 (patch) | |
tree | dffc3ea9b5e771785f4e9cc712a68aff76b9079e | |
parent | 39406b41a6f3178feea7153bb2ce7343bc193e93 (diff) |
Add latest changes from gitlab-org/gitlab@master
29 files changed, 504 insertions, 161 deletions
@@ -406,7 +406,7 @@ group :development do gem 'listen', '~> 3.7' # rubocop:todo Gemfile/MissingFeatureCategory - gem 'ruby-lsp', "~> 0.13.1", require: false, feature_category: :tooling + gem 'ruby-lsp', "~> 0.13.2", require: false, feature_category: :tooling gem 'ruby-lsp-rails', "~> 0.2.8", feature_category: :tooling diff --git a/Gemfile.checksum b/Gemfile.checksum index 1403fe315ed..e545531d857 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -455,7 +455,7 @@ {"name":"premailer","version":"1.16.0","platform":"ruby","checksum":"03e4402c448e6bae13fb5f6301a8bde4f3508e1bff90ae7c0972c7be94694786"}, {"name":"premailer-rails","version":"1.10.3","platform":"ruby","checksum":"7cdcb97027866f7a81c490c6d15ada7f39666b5f6375f0821b7e97e0483b112f"}, {"name":"prime","version":"0.1.2","platform":"ruby","checksum":"d4e956cadfaf04de036dc7dc74f95bf6a285a62cc509b28b7a66b245d19fe3a4"}, -{"name":"prism","version":"0.18.0","platform":"ruby","checksum":"bae73ccaed950e830e136be38cdb9461f9f645f8ef306217ff1d66ff83eb589c"}, +{"name":"prism","version":"0.19.0","platform":"ruby","checksum":"47f17ea8c0b35d051de183608f9bb7e29fa0ced37f3fcc5550542896734c3b62"}, {"name":"proc_to_ast","version":"0.1.0","platform":"ruby","checksum":"92a73fa66e2250a83f8589f818b0751bcf227c68f85916202df7af85082f8691"}, {"name":"prometheus-client-mmap","version":"1.0.2","platform":"aarch64-linux","checksum":"1cec0954f54e47760f56c4fb9cf98de30e5a80f1a803726239590d008c976847"}, {"name":"prometheus-client-mmap","version":"1.0.2","platform":"arm64-darwin","checksum":"a9911e1963bbdb170f07af125efa2f1fb38aa6f49b442ac31abd2e13cf3599b4"}, @@ -556,7 +556,7 @@ {"name":"rubocop-rails","version":"2.22.1","platform":"ruby","checksum":"db673cdb6321d8bb7627cd6cfb2cb36114acaa0e89581e4694b7304ce2acbd46"}, {"name":"rubocop-rspec","version":"2.25.0","platform":"ruby","checksum":"083f8a0481dbb9969b2a9eae85670a454fe91d46812e6ec97b34e7f6227b99f3"}, {"name":"ruby-fogbugz","version":"0.3.0","platform":"ruby","checksum":"5e04cde474648f498a71cf1e1a7ab42c66b953862fbe224f793ec0a7a1d5f657"}, -{"name":"ruby-lsp","version":"0.13.1","platform":"ruby","checksum":"8f1243beb92a49e24447edbd0c31a7ee3a400376757dea60f068fe4eba4a4dff"}, +{"name":"ruby-lsp","version":"0.13.2","platform":"ruby","checksum":"99db45e35fb1e6ffa04e8f65665797c4c5efdd925dde2b33353b8794b46a3bbc"}, {"name":"ruby-lsp-rails","version":"0.2.8","platform":"ruby","checksum":"1730cafa65c04c9bc3b6e28b3454afb561ae71859be1f26f36b065975a5a57c8"}, {"name":"ruby-lsp-rspec","version":"0.1.8","platform":"ruby","checksum":"21db2255bad7ecf7297945c453d8e84af167d01776853f47aacb3bb50caa0ea3"}, {"name":"ruby-magic","version":"0.6.0","platform":"ruby","checksum":"7b2138877b7d23aff812c95564eba6473b74b815ef85beb0eb792e729a2b6101"}, diff --git a/Gemfile.lock b/Gemfile.lock index e106367ae95..77c866875b2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1253,7 +1253,7 @@ GEM prime (0.1.2) forwardable singleton - prism (0.18.0) + prism (0.19.0) proc_to_ast (0.1.0) coderay parser @@ -1469,9 +1469,9 @@ GEM ruby-fogbugz (0.3.0) crack (~> 0.4) multipart-post (~> 2.0) - ruby-lsp (0.13.1) + ruby-lsp (0.13.2) language_server-protocol (~> 3.17.0) - prism (>= 0.18.0, < 0.19) + prism (>= 0.19.0, < 0.20) sorbet-runtime (>= 0.5.5685) ruby-lsp-rails (0.2.8) actionpack (>= 6.0) @@ -2051,7 +2051,7 @@ DEPENDENCIES rspec_profiling (~> 0.0.6) rubocop ruby-fogbugz (~> 0.3.0) - ruby-lsp (~> 0.13.1) + ruby-lsp (~> 0.13.2) ruby-lsp-rails (~> 0.2.8) ruby-lsp-rspec (~> 0.1.8) ruby-magic (~> 0.6) diff --git a/app/views/projects/_readme.html.haml b/app/views/projects/_readme.html.haml index c3d66396256..fc9ddb650e9 100644 --- a/app/views/projects/_readme.html.haml +++ b/app/views/projects/_readme.html.haml @@ -1,5 +1,5 @@ - if (readme = @repository.readme) && readme.rich_viewer - .tree-holder + .tree-holder.gl-mt-5 .nav-block.mt-0 = render 'projects/tree/tree_header', tree: @tree %article.file-holder.readme-holder{ id: 'readme', class: ("limited-width-container" unless fluid_layout) } diff --git a/app/views/projects/mirrors/_mirror_repos_list.html.haml b/app/views/projects/mirrors/_mirror_repos_list.html.haml index 5e3c4889d1d..ab0786a6f5b 100644 --- a/app/views/projects/mirrors/_mirror_repos_list.html.haml +++ b/app/views/projects/mirrors/_mirror_repos_list.html.haml @@ -29,7 +29,7 @@ - if mirror.disabled? = render 'projects/mirrors/disabled_mirror_badge' - if mirror.last_error.present? - = gl_badge_tag _('Error'), { variant: :danger }, { data: { toggle: 'tooltip', html: 'true', testid: 'mirror-error-badge-content' }, title: html_escape(mirror.last_error.try(:strip)) } + = gl_badge_tag _('Error'), { variant: :danger }, { data: { toggle: 'tooltip', html: 'true', testid: 'mirror-error-badge-content' }, title: html_escape(mirror.last_error.try(:strip)), tabindex: 0 } %td - if mirror_settings_enabled .btn-group.mirror-actions-group{ role: 'group' } diff --git a/app/views/shared/groups/_group.html.haml b/app/views/shared/groups/_group.html.haml index 375e10de065..38189786c24 100644 --- a/app/views/shared/groups/_group.html.haml +++ b/app/views/shared/groups/_group.html.haml @@ -2,9 +2,8 @@ - access = user&.max_member_access_for_group(group.id) %li.group-row.py-3.gl-align-items-center{ class: "gl-display-flex!" } - .avatar-container.rect-avatar.s48.gl-flex-shrink-0 - = link_to group do - = render Pajamas::AvatarComponent.new(group, alt: group.name, size: 48) + = link_to group do + = render Pajamas::AvatarComponent.new(group, alt: group.name, size: 48, class: 'gl-mr-5') .gl-min-w-0.gl-flex-grow-1 .title = link_to group.full_name, group, class: 'group-name' diff --git a/db/migrate/20231214222351_drop_index_users_forbidden_state.rb b/db/migrate/20231214222351_drop_index_users_forbidden_state.rb new file mode 100644 index 00000000000..aa51702c93e --- /dev/null +++ b/db/migrate/20231214222351_drop_index_users_forbidden_state.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class DropIndexUsersForbiddenState < Gitlab::Database::Migration[2.2] + milestone '16.8' + disable_ddl_transaction! + + INDEX_NAME = :users_forbidden_state_idx + TABLE_NAME = :users + + def up + remove_concurrent_index_by_name(TABLE_NAME, INDEX_NAME) + end + + def down + add_concurrent_index TABLE_NAME, :id, + name: INDEX_NAME, + where: "confirmed_at IS NOT NULL AND (state <> ALL (ARRAY['blocked', 'banned', 'ldap_blocked']))" + end +end diff --git a/db/schema_migrations/20231214222351 b/db/schema_migrations/20231214222351 new file mode 100644 index 00000000000..ba699f1b541 --- /dev/null +++ b/db/schema_migrations/20231214222351 @@ -0,0 +1 @@ +ccfa73743ce6ebc37f661f9286912a3c635a068ff374d0bb1859f74609b84674
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 7c2df067b18..16ca18337fd 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -35566,8 +35566,6 @@ CREATE UNIQUE INDEX unique_zoekt_shards_uuid ON zoekt_shards USING btree (uuid); CREATE INDEX user_follow_users_followee_id_idx ON user_follow_users USING btree (followee_id); -CREATE INDEX users_forbidden_state_idx ON users USING btree (id) WHERE ((confirmed_at IS NOT NULL) AND ((state)::text <> ALL (ARRAY['blocked'::text, 'banned'::text, 'ldap_blocked'::text]))); - CREATE UNIQUE INDEX vulnerability_occurrence_pipelines_on_unique_keys ON vulnerability_occurrence_pipelines USING btree (occurrence_id, pipeline_id); CREATE INDEX wi_datessources_due_date_sourcing_milestone_id_index ON work_item_dates_sources USING btree (due_date_sourcing_milestone_id); diff --git a/doc/ci/cloud_services/azure/index.md b/doc/ci/cloud_services/azure/index.md index d3bd8e187ba..b3fcaabfdde 100644 --- a/doc/ci/cloud_services/azure/index.md +++ b/doc/ci/cloud_services/azure/index.md @@ -153,7 +153,7 @@ you should verify: - For the `gitlab-group/gitlab-project` project and `main` branch it would be: `project_path:gitlab-group/gitlab-project:ref_type:branch:ref:main`. - The correct values of `mygroup` and `myproject` can be retrieved by checking the URL - when accessing your GitLab project or by selecting the **Clone** option in the project. + when accessing your GitLab project or, in the upper-right corner of the project's overview page, selecting **Code**. - The `Audience` defined in the Azure AD federated identity credentials, for example `https://gitlab.com` or your own GitLab URL. diff --git a/doc/ci/quick_start/tutorial.md b/doc/ci/quick_start/tutorial.md index 389309538e9..413eb0f16ee 100644 --- a/doc/ci/quick_start/tutorial.md +++ b/doc/ci/quick_start/tutorial.md @@ -45,7 +45,7 @@ on GitLab.com: - In the **Project name** field, enter the name of your project, for example `My Pipeline Tutorial Project`. - Select **Initialize repository with a README**. 1. Select **Create project**. -1. On the right of the **Project Overview** page for your project, select **Clone** +1. On the project's overview page, in the upper-right corner, select **Code** to find the clone paths for your project. Copy the SSH or HTTP path and use the path to clone the project locally. diff --git a/doc/development/internal_analytics/internal_event_instrumentation/migration.md b/doc/development/internal_analytics/internal_event_instrumentation/migration.md index 2ef439e21e9..79ca45ed84c 100644 --- a/doc/development/internal_analytics/internal_event_instrumentation/migration.md +++ b/doc/development/internal_analytics/internal_event_instrumentation/migration.md @@ -125,6 +125,7 @@ To start using Internal Events Tracking, follow these steps: 1. Create an event definition that describes `git_write_action` ([guide](event_definition_guide.md)). 1. Find metric definitions that list `git_write_action` in the events section (`20210216182041_action_monthly_active_users_git_write.yml` and `20210216184045_git_write_action_weekly.yml`). 1. Change the `data_source` from `redis_hll` to `internal_events` in the metric definition files. +1. Remove the `instrumentation_class` property. It's not used for Internal Events metrics. 1. Add an `events` section to both metric definition files. ```yaml diff --git a/doc/gitlab-basics/start-using-git.md b/doc/gitlab-basics/start-using-git.md index ecdc4aeed06..a1dd99d811f 100644 --- a/doc/gitlab-basics/start-using-git.md +++ b/doc/gitlab-basics/start-using-git.md @@ -117,7 +117,7 @@ Clone with SSH when you want to authenticate only one time. 1. Authenticate with GitLab by following the instructions in the [SSH documentation](../user/ssh.md). 1. On the left sidebar, select **Search or go to** and find the project you want to clone. -1. On the right-hand side of the page, select **Clone**, then copy the URL for **Clone with SSH**. +1. On the project's overview page, in the upper-right corner, select **Code**, then copy the URL for **Clone with SSH**. 1. Open a terminal and go to the directory where you want to clone the files. Git automatically creates a folder with the repository name and downloads the files there. 1. Run this command: @@ -142,7 +142,7 @@ between your computer and GitLab. [OAuth credential helpers](../user/profile/account/two_factor_authentication.md#oauth-credential-helpers) can decrease the number of times you must manually authenticate, making HTTPS a seamless experience. 1. On the left sidebar, select **Search or go to** and find the project you want to clone. -1. On the right-hand side of the page, select **Clone**, then copy the URL for **Clone with HTTPS**. +1. On the project's overview page, in the upper-right corner, select **Code**, then copy the URL for **Clone with HTTPS**. 1. Open a terminal and go to the directory where you want to clone the files. 1. Run the following command. Git automatically creates a folder with the repository name and downloads the files there. @@ -255,6 +255,47 @@ existing branch. You can create additional named remotes and branches as necessa You can learn more on how Git manages remote repositories in the [Git Remote documentation](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes). +## Add another URL to a remote + +Add another URL to a remote, so both remotes get updated on each push: + +```shell +git remote set-url --add <remote_name> <remote_url> +``` + +## Show the log of reference changes to HEAD + +```shell +git reflog +``` + +## Check the Git history of a file + +The basic command to check the Git history of a file: + +```shell +git log <file> +``` + +If you get this error message: + +```plaintext +fatal: ambiguous argument <file_name>: unknown revision or path not in the working tree. +Use '--' to separate paths from revisions, like this: +``` + +Use this to check the Git history of the file: + +```shell +git log -- <file> +``` + +## Check the content of each change to a file + +```shell +gitk <file> +``` + ## Branches A **branch** is a copy of the files in the repository at the time you create the branch. @@ -423,6 +464,20 @@ In GitLab, you typically use a [merge request](../user/project/merge_requests/in To create a merge request from a fork to an upstream repository, see the [forking workflow](../user/project/repository/forking_workflow.md). +## Reuse recorded resolutions + +To _reuse_ recorded resolutions: + +```shell +git rerere +``` + +To enable `rerere` functionality: + +```shell +git config --global rerere.enabled true +``` + ## Advanced use of Git through the command line For an introduction of more advanced Git techniques, see [Git rebase, force-push, and merge conflicts](../topics/git/git_rebase.md). @@ -439,15 +494,3 @@ changes from the original repository. It is common to call this remote repositor You can now use the `upstream` as a [`<remote>` to `pull` new updates](#download-the-latest-changes-in-the-project) from the original repository, and use the `origin` to [push local changes](#send-changes-to-gitlab) and create merge requests. - -<!-- ## Troubleshooting - -Include any troubleshooting steps that you can foresee. If you know beforehand what issues -one might have when setting this up, or when something is changed, or on upgrading, it's -important to describe those, too. Think of things that may go wrong and include them here. -This is important to minimize requests for support, and to avoid doc comments with -questions that you know someone might ask. - -Each scenario can be a third-level heading, for example `### Getting error message X`. -If you have none to add when creating a doc, leave this section in place -but commented out to help encourage others to add to it in the future. --> diff --git a/doc/topics/git/useful_git_commands.md b/doc/topics/git/useful_git_commands.md index a397ec749d0..54a877bd974 100644 --- a/doc/topics/git/useful_git_commands.md +++ b/doc/topics/git/useful_git_commands.md @@ -1,101 +1,11 @@ --- -stage: Create -group: Source Code -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments" +redirect_to: 'index.md' +remove_date: '2024-03-19' --- -# Frequently used Git commands **(FREE ALL)** +This document was moved to [another location](index.md). -The following commands are frequently used. - -## Add another URL to a remote - -Add another URL to a remote, so both remotes get updated on each push: - -```shell -git remote set-url --add <remote_name> <remote_url> -``` - -## Refs and Log - -### Use reflog to show the log of reference changes to HEAD - -```shell -git reflog -``` - -### Check the Git history of a file - -The basic command to check the Git history of a file: - -```shell -git log <file> -``` - -If you get this error message: - -```plaintext -fatal: ambiguous argument <file_name>: unknown revision or path not in the working tree. -Use '--' to separate paths from revisions, like this: -``` - -Use this to check the Git history of the file: - -```shell -git log -- <file> -``` - -### Check the content of each change to a file - -```shell -gitk <file> -``` - -### Check the content of each change to a file, follows it past file renames - -```shell -gitk --follow <file> -``` - -## Rebasing - -### Rebase your branch onto the default - -The `-i` flag stands for 'interactive'. Replace `<default-branch>` with the name -of your [default branch](../../user/project/repository/branches/default.md): - -```shell -git rebase -i <default-branch> -``` - -### Continue the rebase if paused - -```shell -git rebase --continue -``` - -### Use `git rerere` - -To _reuse_ recorded solutions to the same problems when repeated: - -```shell -git rerere -``` - -To enable `rerere` functionality: - -```shell -git config --global rerere.enabled true -``` - -<!-- ## Troubleshooting - -Include any troubleshooting steps that you can foresee. If you know beforehand what issues -one might have when setting this up, or when something is changed, or on upgrading, it's -important to describe those, too. Think of things that may go wrong and include them here. -This is important to minimize requests for support, and to avoid doc comments with -questions that you know someone might ask. - -Each scenario can be a third-level heading, for example `### Getting error message X`. -If you have none to add when creating a doc, leave this section in place -but commented out to help encourage others to add to it in the future. --> +<!-- This redirect file can be deleted after <2024-03-19>. --> +<!-- Redirects that point to other docs in the same project expire in three months. --> +<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. --> +<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html --> diff --git a/doc/tutorials/make_first_git_commit/index.md b/doc/tutorials/make_first_git_commit/index.md index 1663fa08ad6..e80cd6770d0 100644 --- a/doc/tutorials/make_first_git_commit/index.md +++ b/doc/tutorials/make_first_git_commit/index.md @@ -93,7 +93,7 @@ To start, create a sample project in GitLab. Now you can clone the repository in your project. *Cloning* a repository means you're creating a copy on your computer, or wherever you want to store and work with the files. -1. On your project page, select **Clone**. Copy the URL for **Clone with SSH**. +1. On your project's overview page, in the upper-right corner, select **Code**, then copy the URL for **Clone with SSH**. ![Clone a project with SSH](img/clone_project_v14_9.png) diff --git a/doc/tutorials/update_commit_messages/index.md b/doc/tutorials/update_commit_messages/index.md index 0228b33e3de..36106dd4f98 100644 --- a/doc/tutorials/update_commit_messages/index.md +++ b/doc/tutorials/update_commit_messages/index.md @@ -53,7 +53,7 @@ disabled to authenticate from the CLI. Alternatively, you can [use an SSH key to The first step is to get a clone of the repository on your local machine: -1. In GitLab, on your project's overview page, on the top right, select **Clone**. +1. In GitLab, on your project's overview page, in the upper-right corner, select **Code**. 1. In the dropdown list, copy the URL for your repository by selecting **{copy-to-clipboard}** next to: - **Clone with HTTPS** if your GitLab account uses basic username and password authentication. - **Clone with SSH** if you use SSH to authenticate with GitLab. diff --git a/doc/user/project/repository/code_suggestions/index.md b/doc/user/project/repository/code_suggestions/index.md index 785c82d96fc..61b6d3724cd 100644 --- a/doc/user/project/repository/code_suggestions/index.md +++ b/doc/user/project/repository/code_suggestions/index.md @@ -4,7 +4,7 @@ group: Code Creation info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments --- -# Code Suggestions **(FREE ALL BETA)** +# Code Suggestions **(FREE ALL)** > - [Introduced support for Google Vertex AI Codey APIs](https://gitlab.com/groups/gitlab-org/-/epics/10562) in GitLab 16.1. > - [Removed support for GitLab native model](https://gitlab.com/groups/gitlab-org/-/epics/10752) in GitLab 16.2. diff --git a/doc/user/project/repository/code_suggestions/saas.md b/doc/user/project/repository/code_suggestions/saas.md index 1af5eef585c..52b023445d5 100644 --- a/doc/user/project/repository/code_suggestions/saas.md +++ b/doc/user/project/repository/code_suggestions/saas.md @@ -4,7 +4,7 @@ group: Code Creation info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments --- -# Code Suggestions on GitLab SaaS **(FREE SAAS BETA)** +# Code Suggestions on GitLab SaaS **(FREE SAAS)** > - [Introduced](https://about.gitlab.com/releases/2023/02/22/gitlab-15-9-released/#code-suggestions-available-in-closed-beta) in GitLab 15.9 as [Beta](../../../../policy/experiment-beta-support.md#beta) for early access Ultimate customers on GitLab.com. > - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/408104) as opt-in with GitLab 15.11 as [Beta](../../../../policy/experiment-beta-support.md#beta). diff --git a/doc/user/project/repository/code_suggestions/self_managed.md b/doc/user/project/repository/code_suggestions/self_managed.md index 26850bc8b5f..8c3c4aadc71 100644 --- a/doc/user/project/repository/code_suggestions/self_managed.md +++ b/doc/user/project/repository/code_suggestions/self_managed.md @@ -4,7 +4,7 @@ group: Code Creation info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments --- -# Code Suggestions on self-managed GitLab **(SELF BETA)** +# Code Suggestions on self-managed GitLab **(SELF)** > - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10653) in GitLab 16.1 as [Beta](../../../../policy/experiment-beta-support.md#beta) on self-managed GitLab. > - [Introduced support for Google Vertex AI Codey APIs](https://gitlab.com/groups/gitlab-org/-/epics/10562) in GitLab 16.1. diff --git a/doc/user/project/repository/code_suggestions/troubleshooting.md b/doc/user/project/repository/code_suggestions/troubleshooting.md index c18ea2dd26b..22398395c2c 100644 --- a/doc/user/project/repository/code_suggestions/troubleshooting.md +++ b/doc/user/project/repository/code_suggestions/troubleshooting.md @@ -4,7 +4,7 @@ group: Code Creation info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments --- -# Troubleshooting Code Suggestions **(FREE ALL BETA)** +# Troubleshooting Code Suggestions **(FREE ALL)** When working with GitLab Duo Code Suggestions, you might encounter the following issues. diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md index dd8ee61f6ae..b2a14dcc3cf 100644 --- a/doc/user/project/repository/index.md +++ b/doc/user/project/repository/index.md @@ -85,7 +85,7 @@ Projects that contain a `.xcodeproj` or `.xcworkspace` directory can be cloned into Xcode on macOS. 1. From the GitLab UI, go to the project's overview page. -1. Select **Clone**. +1. In the upper-right corner, select **Code**. 1. Select **Xcode**. The project is cloned onto your computer and you are @@ -101,7 +101,7 @@ Visual Studio Code: - From the GitLab interface: 1. Go to the project's overview page. - 1. Select **Clone**. + 1. In the upper-right corner, select **Code**. 1. Under **Open in your IDE**, select **Visual Studio Code (SSH)** or **Visual Studio Code (HTTPS)**. 1. Select a folder to clone the project into. @@ -121,7 +121,7 @@ Prerequisites: To do this: 1. Go to the project's overview page. -1. Select **Clone**. +1. In the upper-right corner, select **Code**. 1. Under **Open in your IDE**, select **IntelliJ IDEA (SSH)** or **IntelliJ IDEA (HTTPS)**. ## Download the code in a repository diff --git a/doc/user/project/repository/mirror/push.md b/doc/user/project/repository/mirror/push.md index 3aa4c768ebe..babe99441ef 100644 --- a/doc/user/project/repository/mirror/push.md +++ b/doc/user/project/repository/mirror/push.md @@ -161,7 +161,7 @@ To set up a mirror from GitLab to AWS CodeCommit: 1. Copy or download the special Git HTTPS user ID and password. 1. In the AWS CodeCommit console, create a new repository to mirror from your GitLab repository. -1. Open your new repository, and then select **Clone URL > Clone HTTPS** (not **Clone HTTPS (GRC)**). +1. Open your new repository, in the upper-right corner, select **Code > Clone HTTPS** (not **Clone HTTPS (GRC)**). 1. In GitLab, open the repository to be push-mirrored. 1. Select **Settings > Repository**, and then expand **Mirroring repositories**. 1. Fill in the **Git repository URL** field using this format, replacing diff --git a/gems/gem-pg.gitlab-ci.yml b/gems/gem-pg.gitlab-ci.yml index c48e18fa297..2806437e15b 100644 --- a/gems/gem-pg.gitlab-ci.yml +++ b/gems/gem-pg.gitlab-ci.yml @@ -63,6 +63,7 @@ rubocop: rules: - exists: ["$[[inputs.gem_path_prefix]]$[[inputs.gem_name]]/.rubocop.yml"] script: + - $CI_PROJECT_DIR/scripts/validate-monorepo-gem "$[[inputs.gem_name]]" - bundle exec rubocop rspec: diff --git a/gems/gem.gitlab-ci.yml b/gems/gem.gitlab-ci.yml index a379a887bdd..3ced4b5e364 100644 --- a/gems/gem.gitlab-ci.yml +++ b/gems/gem.gitlab-ci.yml @@ -50,6 +50,7 @@ rubocop: rules: - exists: ["$[[inputs.gem_path_prefix]]$[[inputs.gem_name]]/.rubocop.yml"] script: + - $CI_PROJECT_DIR/scripts/validate-monorepo-gem "$[[inputs.gem_name]]" - bundle exec rubocop rspec: diff --git a/gems/gitlab-housekeeper/lib/gitlab/housekeeper/gitlab_client.rb b/gems/gitlab-housekeeper/lib/gitlab/housekeeper/gitlab_client.rb index b28d44195cb..e23dbe46cae 100644 --- a/gems/gitlab-housekeeper/lib/gitlab/housekeeper/gitlab_client.rb +++ b/gems/gitlab-housekeeper/lib/gitlab/housekeeper/gitlab_client.rb @@ -13,13 +13,50 @@ module Gitlab @base_uri = 'https://gitlab.com/api/v4' end + # This looks at the system notes of the merge request to detect if it has been updated by anyone other than the + # current housekeeper user. If it has then it assumes that they did this for a reason and we can skip updating + # this detail of the merge request. Otherwise we assume we should generate it again using the latest output. + def non_housekeeper_changes( + source_project_id:, + source_branch:, + target_branch:, + target_project_id: + ) + + iid = get_existing_merge_request( + source_project_id: source_project_id, + source_branch: source_branch, + target_branch: target_branch, + target_project_id: target_project_id + ) + + return [] if iid.nil? + + merge_request_notes = get_merge_request_notes(target_project_id: target_project_id, iid: iid) + + changes = Set.new + + merge_request_notes.each do |note| + next false unless note["system"] + next false if note["author"]["id"] == current_user_id + + changes << :title if note['body'].start_with?("changed title from") + changes << :description if note['body'] == "changed the description" + changes << :code if note['body'].match?(/added \d+ commit/) + end + + changes.to_a + end + def create_or_update_merge_request( source_project_id:, title:, description:, source_branch:, target_branch:, - target_project_id: + target_project_id:, + update_title:, + update_description: ) existing_iid = get_existing_merge_request( source_project_id: source_project_id, @@ -33,7 +70,9 @@ module Gitlab existing_iid: existing_iid, title: title, description: description, - target_project_id: target_project_id + target_project_id: target_project_id, + update_title:, + update_description: ) else create_merge_request( @@ -49,6 +88,39 @@ module Gitlab private + def get_merge_request_notes(target_project_id:, iid:) + response = HTTParty.get( + "#{@base_uri}/projects/#{target_project_id}/merge_requests/#{iid}/notes", + query: { + per_page: 100 + }, + headers: { + "Private-Token" => @token + } + ) + + unless (200..299).cover?(response.code) + raise Error, + "Failed to get merge request notes with response code: #{response.code} and body:\n#{response.body}" + end + + JSON.parse(response.body) + end + + def current_user_id + @current_user_id = begin + response = HTTParty.get("#{@base_uri}/user") + + unless (200..299).cover?(response.code) + raise Error, + "Failed with response code: #{response.code} and body:\n#{response.body}" + end + + data = JSON.parse(response.body) + data['id'] + end + end + def get_existing_merge_request(source_project_id:, source_branch:, target_branch:, target_project_id:) response = HTTParty.get("#{@base_uri}/projects/#{target_project_id}/merge_requests", query: { @@ -78,8 +150,13 @@ module Gitlab end def create_merge_request( - source_project_id:, title:, description:, source_branch:, target_branch:, - target_project_id:) + source_project_id:, + title:, + description:, + source_branch:, + target_branch:, + target_project_id: + ) response = HTTParty.post("#{@base_uri}/projects/#{source_project_id}/merge_requests", body: { title: title, description: description, @@ -98,11 +175,23 @@ module Gitlab "Failed with response code: #{response.code} and body:\n#{response.body}" end - def update_existing_merge_request(existing_iid:, title:, description:, target_project_id:) - response = HTTParty.put("#{@base_uri}/projects/#{target_project_id}/merge_requests/#{existing_iid}", body: { - title: title, - description: description - }.to_json, + def update_existing_merge_request( + existing_iid:, + title:, + description:, + target_project_id:, + update_title:, + update_description: + ) + body = {} + + body[:title] = title if update_title + body[:description] = description if update_description + + return if body.empty? + + response = HTTParty.put("#{@base_uri}/projects/#{target_project_id}/merge_requests/#{existing_iid}", + body: body.to_json, headers: { 'Private-Token' => @token, 'Content-Type' => 'application/json' diff --git a/gems/gitlab-housekeeper/lib/gitlab/housekeeper/runner.rb b/gems/gitlab-housekeeper/lib/gitlab/housekeeper/runner.rb index 76d629e29a3..ad43ec014f5 100644 --- a/gems/gitlab-housekeeper/lib/gitlab/housekeeper/runner.rb +++ b/gems/gitlab-housekeeper/lib/gitlab/housekeeper/runner.rb @@ -70,7 +70,16 @@ module Gitlab def create(change, branch_name) dry_run(change, branch_name) - Shell.execute('git', 'push', '-f', 'housekeeper', "#{branch_name}:#{branch_name}") + non_housekeeper_changes = gitlab_client.non_housekeeper_changes( + source_project_id: housekeeper_fork_project_id, + source_branch: branch_name, + target_branch: 'master', + target_project_id: housekeeper_target_project_id + ) + + unless non_housekeeper_changes.include?(:code) + Shell.execute('git', 'push', '-f', 'housekeeper', "#{branch_name}:#{branch_name}") + end gitlab_client.create_or_update_merge_request( source_project_id: housekeeper_fork_project_id, @@ -78,7 +87,9 @@ module Gitlab description: change.description, source_branch: branch_name, target_branch: 'master', - target_project_id: housekeeper_target_project_id + target_project_id: housekeeper_target_project_id, + update_title: !non_housekeeper_changes.include?(:title), + update_description: !non_housekeeper_changes.include?(:description) ) end diff --git a/gems/gitlab-housekeeper/spec/gitlab/housekeeper/gitlab_client_spec.rb b/gems/gitlab-housekeeper/spec/gitlab/housekeeper/gitlab_client_spec.rb index 36b2afdc306..c105ecf030b 100644 --- a/gems/gitlab-housekeeper/spec/gitlab/housekeeper/gitlab_client_spec.rb +++ b/gems/gitlab-housekeeper/spec/gitlab/housekeeper/gitlab_client_spec.rb @@ -3,9 +3,146 @@ require 'spec_helper' require 'gitlab/housekeeper/gitlab_client' +# rubocop:disable RSpec/MultipleMemoizedHelpers -- there are lots of parameters at play RSpec.describe ::Gitlab::Housekeeper::GitlabClient do let(:client) { described_class.new } + before do + stub_env('HOUSEKEEPER_GITLAB_API_TOKEN', 'the-api-token') + end + + describe '#non_housekeeper_changes' do + let(:housekeeper_user_id) { 666 } + + let(:added_commit_note) do + { + id: 1698248524, + body: "added 1 commit\n\n<ul><li>41b3a17f - Update stuff to test...", + author: { "id" => 1234 }, + system: true + } + end + + let(:irrelevant_note1) do + { + id: 1698248523, + body: "changed this line in ...", + author: { "id" => 1234 }, + system: true + } + end + + let(:not_a_system_note) do + { + id: 1698248524, + body: "added 1 commit\n\n<ul><li>41b3a17f - Update stuff to test...", + author: { "id" => 1234 }, + system: false + } + end + + let(:updated_title_note) do + { + id: 1698248527, + body: "changed title from **Add sharding{- -}key `namespace_id` to achievements**...", + author: { "id" => 1235 }, + system: true + } + end + + let(:updated_description_note) do + { + id: 1698248530, + body: "changed the description", + author: { "id" => 1236 }, + system: true + } + end + + let(:notes) do + [irrelevant_note1, not_a_system_note] + end + + subject(:non_housekeeper_changes) do + client.non_housekeeper_changes( + source_project_id: 123, + target_project_id: 456, + source_branch: 'the-source-branch', + target_branch: 'the-target-branch' + ) + end + + before do + # Get the current housekeeper user + stub_request(:get, "https://gitlab.com/api/v4/user") + .to_return(status: 200, body: { id: housekeeper_user_id }.to_json) + + # Get the id of the current merge request + stub_request(:get, "https://gitlab.com/api/v4/projects/456/merge_requests?state=opened&source_branch=the-source-branch&target_branch=the-target-branch&source_project_id=123") + .with( + headers: { + 'Private-Token' => 'the-api-token' + } + ) + .to_return(status: 200, body: [{ iid: 8765 }].to_json) + + # Get the notes of the current merge request + stub_request(:get, "https://gitlab.com/api/v4/projects/456/merge_requests/8765/notes?per_page=100") + .with( + headers: { + 'Private-Token' => 'the-api-token' + } + ) + .to_return(status: 200, body: notes.to_json) + end + + it 'does not match irrelevant notes' do + expect(non_housekeeper_changes).to eq([]) + end + + context 'when all important things change' do + let(:notes) do + [not_a_system_note, updated_title_note, updated_description_note, added_commit_note] + end + + it 'returns :title, :description, :code' do + expect(non_housekeeper_changes).to include(:title) + expect(non_housekeeper_changes).to include(:description) + expect(non_housekeeper_changes).to include(:code) + end + end + + context 'when title changes' do + let(:notes) do + [not_a_system_note, updated_title_note] + end + + it 'returns :title, :description, :code' do + expect(non_housekeeper_changes).to include(:title) + expect(non_housekeeper_changes).not_to include(:description) + expect(non_housekeeper_changes).not_to include(:code) + end + end + + context 'when description changes' do + let(:notes) do + [not_a_system_note, updated_description_note] + end + + it 'returns :title, :description, :code' do + expect(non_housekeeper_changes).not_to include(:title) + expect(non_housekeeper_changes).to include(:description) + expect(non_housekeeper_changes).not_to include(:code) + end + end + + context 'when the merge request does not exist' do + it 'returns empty array' do + expect(non_housekeeper_changes).to eq([]) + end + end + end + describe '#create_or_update_merge_request' do let(:params) do { @@ -14,15 +151,15 @@ RSpec.describe ::Gitlab::Housekeeper::GitlabClient do description: 'This merge request is pretty good.', source_branch: 'the-source-branch', target_branch: 'the-target-branch', - target_project_id: 456 + target_project_id: 456, + update_title: true, + update_description: true } end let(:existing_mrs) { [] } before do - stub_env('HOUSEKEEPER_GITLAB_API_TOKEN', 'the-api-token') - # Stub the check to see if the merge request already exists stub_request(:get, "https://gitlab.com/api/v4/projects/456/merge_requests?state=opened&source_branch=the-source-branch&target_branch=the-target-branch&source_project_id=123") .with( @@ -85,6 +222,48 @@ RSpec.describe ::Gitlab::Housekeeper::GitlabClient do expect { client.create_or_update_merge_request(**params) }.to raise_error(described_class::Error) end end + + context 'when update_title: false' do + it 'does not update the title' do + stub = stub_request(:put, "https://gitlab.com/api/v4/projects/456/merge_requests/1234") + .with( + body: { + description: "This merge request is pretty good." + }.to_json, + headers: { + 'Content-Type' => 'application/json', + 'Private-Token' => 'the-api-token' + } + ).to_return(status: 200, body: "") + + client.create_or_update_merge_request(**params.merge(update_title: false)) + expect(stub).to have_been_requested + end + end + + context 'when update_description: false' do + it 'does not update the description' do + stub = stub_request(:put, "https://gitlab.com/api/v4/projects/456/merge_requests/1234") + .with( + body: { + title: "A new merge request!" + }.to_json, + headers: { + 'Content-Type' => 'application/json', + 'Private-Token' => 'the-api-token' + } + ).to_return(status: 200, body: "") + + client.create_or_update_merge_request(**params.merge(update_description: false)) + expect(stub).to have_been_requested + end + end + + context 'when there is nothing to update' do + it 'does not make a request' do + client.create_or_update_merge_request(**params.merge(update_description: false, update_title: false)) + end + end end it 'raises an error when unsuccessful response' do @@ -97,3 +276,4 @@ RSpec.describe ::Gitlab::Housekeeper::GitlabClient do end end end +# rubocop:enable RSpec/MultipleMemoizedHelpers diff --git a/gems/gitlab-housekeeper/spec/gitlab/housekeeper/runner_spec.rb b/gems/gitlab-housekeeper/spec/gitlab/housekeeper/runner_spec.rb index 49b4926dbdd..c7ba4302d88 100644 --- a/gems/gitlab-housekeeper/spec/gitlab/housekeeper/runner_spec.rb +++ b/gems/gitlab-housekeeper/spec/gitlab/housekeeper/runner_spec.rb @@ -3,6 +3,7 @@ require 'spec_helper' require 'gitlab/housekeeper/runner' +# rubocop:disable RSpec/MultipleMemoizedHelpers -- there are lots of parameters at play RSpec.describe ::Gitlab::Housekeeper::Runner do let(:fake_keep) { instance_double(Class) } @@ -44,18 +45,34 @@ RSpec.describe ::Gitlab::Housekeeper::Runner do end describe '#run' do + let(:git) { instance_double(::Gitlab::Housekeeper::Git) } + let(:gitlab_client) { instance_double(::Gitlab::Housekeeper::GitlabClient) } + before do stub_env('HOUSEKEEPER_FORK_PROJECT_ID', '123') stub_env('HOUSEKEEPER_TARGET_PROJECT_ID', '456') + + allow(::Gitlab::Housekeeper::Git).to receive(:new) + .and_return(git) + + allow(git).to receive(:with_branch_from_branch) + .and_yield + allow(git).to receive(:commit_in_branch).with(change1) + .and_return('the-identifier-for-the-first-change') + allow(git).to receive(:commit_in_branch).with(change2) + .and_return('the-identifier-for-the-second-change') + + allow(::Gitlab::Housekeeper::GitlabClient).to receive(:new) + .and_return(gitlab_client) + + allow(gitlab_client).to receive(:non_housekeeper_changes) + .and_return([]) + + allow(::Gitlab::Housekeeper::Shell).to receive(:execute) end it 'loops over the keeps and creates MRs limited by max_mrs' do # Branches get created - git = instance_double(::Gitlab::Housekeeper::Git) - expect(::Gitlab::Housekeeper::Git).to receive(:new) - .and_return(git) - expect(git).to receive(:with_branch_from_branch) - .and_yield expect(git).to receive(:commit_in_branch).with(change1) .and_return('the-identifier-for-the-first-change') expect(git).to receive(:commit_in_branch).with(change2) @@ -76,9 +93,6 @@ RSpec.describe ::Gitlab::Housekeeper::Runner do 'the-identifier-for-the-second-change:the-identifier-for-the-second-change') # Merge requests get created - gitlab_client = instance_double(::Gitlab::Housekeeper::GitlabClient) - expect(::Gitlab::Housekeeper::GitlabClient).to receive(:new) - .and_return(gitlab_client) expect(gitlab_client).to receive(:create_or_update_merge_request) .with( source_project_id: '123', @@ -86,7 +100,9 @@ RSpec.describe ::Gitlab::Housekeeper::Runner do description: 'The description of the MR', source_branch: 'the-identifier-for-the-first-change', target_branch: 'master', - target_project_id: '456' + target_project_id: '456', + update_title: true, + update_description: true ) expect(gitlab_client).to receive(:create_or_update_merge_request) .with( @@ -95,10 +111,67 @@ RSpec.describe ::Gitlab::Housekeeper::Runner do description: 'The description of the MR', source_branch: 'the-identifier-for-the-second-change', target_branch: 'master', - target_project_id: '456' + target_project_id: '456', + update_title: true, + update_description: true ) described_class.new(max_mrs: 2, keeps: [fake_keep]).run end + + context 'when title, description, code has changed already' do + it 'does not update the changed details' do + # First change has updated code and description so should only update title + expect(gitlab_client).to receive(:non_housekeeper_changes) + .with( + source_project_id: '123', + source_branch: 'the-identifier-for-the-first-change', + target_branch: 'master', + target_project_id: '456' + ).and_return([:code, :description]) + + # Second change has updated title and description so it should push the code + expect(gitlab_client).to receive(:non_housekeeper_changes) + .with( + source_project_id: '123', + source_branch: 'the-identifier-for-the-second-change', + target_branch: 'master', + target_project_id: '456' + ).and_return([:title, :description]) + + expect(::Gitlab::Housekeeper::Shell).not_to receive(:execute) + .with('git', 'push', '-f', 'housekeeper', + 'the-identifier-for-the-first-change:the-identifier-for-the-first-change') + expect(::Gitlab::Housekeeper::Shell).to receive(:execute) + .with('git', 'push', '-f', 'housekeeper', + 'the-identifier-for-the-second-change:the-identifier-for-the-second-change') + + expect(gitlab_client).to receive(:create_or_update_merge_request) + .with( + source_project_id: '123', + title: 'The title of MR1', + description: 'The description of the MR', + source_branch: 'the-identifier-for-the-first-change', + target_branch: 'master', + target_project_id: '456', + update_title: true, + update_description: false + ) + expect(gitlab_client).to receive(:create_or_update_merge_request) + .with( + source_project_id: '123', + title: 'The title of MR2', + description: 'The description of the MR', + source_branch: 'the-identifier-for-the-second-change', + target_branch: 'master', + target_project_id: '456', + update_title: false, + update_description: false + ) + + described_class.new(max_mrs: 2, keeps: [fake_keep]).run + end + end end end +# rubocop:enable RSpec/MultipleMemoizedHelpers diff --git a/scripts/validate-monorepo-gem b/scripts/validate-monorepo-gem new file mode 100755 index 00000000000..9c379072102 --- /dev/null +++ b/scripts/validate-monorepo-gem @@ -0,0 +1,17 @@ +#!/bin/bash + +if [[ $# -ne 1 ]]; then + echo "usage: $0 <gem-name>" + exit 1 +fi + +if gem specification --remote --ruby "$1"; then + exit 0 +fi + +if gem specification --remote --ruby --pre "$1"; then + exit 0 +fi + +echo "The '$1' is missing. Push stub gem to RubyGems with version 0.0.1." +exit 1 |