Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-12-20 00:23:20 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-12-20 00:23:20 +0300
commitec2d2ecdf734e48f6603c90aea01abc67c6bb293 (patch)
treedffc3ea9b5e771785f4e9cc712a68aff76b9079e
parent39406b41a6f3178feea7153bb2ce7343bc193e93 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.checksum4
-rw-r--r--Gemfile.lock8
-rw-r--r--app/views/projects/_readme.html.haml2
-rw-r--r--app/views/projects/mirrors/_mirror_repos_list.html.haml2
-rw-r--r--app/views/shared/groups/_group.html.haml5
-rw-r--r--db/migrate/20231214222351_drop_index_users_forbidden_state.rb19
-rw-r--r--db/schema_migrations/202312142223511
-rw-r--r--db/structure.sql2
-rw-r--r--doc/ci/cloud_services/azure/index.md2
-rw-r--r--doc/ci/quick_start/tutorial.md2
-rw-r--r--doc/development/internal_analytics/internal_event_instrumentation/migration.md1
-rw-r--r--doc/gitlab-basics/start-using-git.md71
-rw-r--r--doc/topics/git/useful_git_commands.md104
-rw-r--r--doc/tutorials/make_first_git_commit/index.md2
-rw-r--r--doc/tutorials/update_commit_messages/index.md2
-rw-r--r--doc/user/project/repository/code_suggestions/index.md2
-rw-r--r--doc/user/project/repository/code_suggestions/saas.md2
-rw-r--r--doc/user/project/repository/code_suggestions/self_managed.md2
-rw-r--r--doc/user/project/repository/code_suggestions/troubleshooting.md2
-rw-r--r--doc/user/project/repository/index.md6
-rw-r--r--doc/user/project/repository/mirror/push.md2
-rw-r--r--gems/gem-pg.gitlab-ci.yml1
-rw-r--r--gems/gem.gitlab-ci.yml1
-rw-r--r--gems/gitlab-housekeeper/lib/gitlab/housekeeper/gitlab_client.rb107
-rw-r--r--gems/gitlab-housekeeper/lib/gitlab/housekeeper/runner.rb15
-rw-r--r--gems/gitlab-housekeeper/spec/gitlab/housekeeper/gitlab_client_spec.rb186
-rw-r--r--gems/gitlab-housekeeper/spec/gitlab/housekeeper/runner_spec.rb93
-rwxr-xr-xscripts/validate-monorepo-gem17
29 files changed, 504 insertions, 161 deletions
diff --git a/Gemfile b/Gemfile
index 0ddaf9afb3a..551a845f90f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -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