diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-11-30 15:14:19 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-11-30 15:14:19 +0000 |
commit | 048f666f8a2ba77e45146845ad280ea1c5460ccd (patch) | |
tree | 38a2d1438d6c3bd060a72f889f9c1eaa4e7b79b3 | |
parent | 19c9422e1f3792680aa3f9e6190218b31a838fe3 (diff) | |
download | gitlab-ce-048f666f8a2ba77e45146845ad280ea1c5460ccd.tar.gz |
Add latest changes from gitlab-org/gitlab@master
271 files changed, 1544 insertions, 418 deletions
diff --git a/.eslintrc.yml b/.eslintrc.yml index c514dc7bf12..7e87db0c72a 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -124,9 +124,9 @@ overrides: parserOptions: parser: '@graphql-eslint/eslint-plugin' operations: - - '{,ee/,jh/}app/**/*.graphql' - # You can run `bundle exec rake gitlab:graphql:schema:dump` and then uncomment this line - # schema: './tmp/tests/graphql/gitlab_schema.graphql' + - '{,ee/,jh/}app/**/*.graphql' + # You can run `bundle exec rake gitlab:graphql:schema:dump` and then uncomment this line + # schema: './tmp/tests/graphql/gitlab_schema.graphql' rules: filenames/match-regex: off spaced-comment: off @@ -138,3 +138,4 @@ overrides: #'@graphql-eslint/known-type-names': error '@graphql-eslint/no-anonymous-operations': error '@graphql-eslint/unique-operation-name': error + # '@graphql-eslint/require-id-when-available': error diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml index a74350c8ff0..4f6180e2aa3 100644 --- a/.gitlab/ci/rails.gitlab-ci.yml +++ b/.gitlab/ci/rails.gitlab-ci.yml @@ -31,6 +31,7 @@ RUBY_GC_MALLOC_LIMIT: 67108864 RUBY_GC_MALLOC_LIMIT_MAX: 134217728 RECORD_DEPRECATIONS: "true" + GEO_SECONDARY_PROXY: 0 needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets", "detect-tests"] script: - !reference [.base-script, script] diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml index 64172533f68..924fde6c51b 100644 --- a/.rubocop_manual_todo.yml +++ b/.rubocop_manual_todo.yml @@ -2576,7 +2576,6 @@ Style/OpenStructUse: - 'spec/graphql/mutations/clusters/agents/create_spec.rb' - 'spec/graphql/mutations/clusters/agents/delete_spec.rb' - 'spec/graphql/mutations/commits/create_spec.rb' - - 'spec/graphql/mutations/merge_requests/accept_spec.rb' - 'spec/helpers/application_settings_helper_spec.rb' - 'spec/helpers/profiles_helper_spec.rb' - 'spec/initializers/doorkeeper_spec.rb' @@ -2598,7 +2597,6 @@ Style/OpenStructUse: - 'spec/support/helpers/import_spec_helper.rb' - 'spec/support/helpers/login_helpers.rb' - 'spec/support/helpers/repo_helpers.rb' - - 'spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb' - 'spec/tooling/rspec_flaky/flaky_example_spec.rb' - 'tooling/rspec_flaky/flaky_example.rb' diff --git a/app/assets/javascripts/alert_management/graphql/queries/get_count_by_status.query.graphql b/app/assets/javascripts/alert_management/graphql/queries/get_count_by_status.query.graphql index 40ec4c56171..0f9075c58bf 100644 --- a/app/assets/javascripts/alert_management/graphql/queries/get_count_by_status.query.graphql +++ b/app/assets/javascripts/alert_management/graphql/queries/get_count_by_status.query.graphql @@ -1,5 +1,6 @@ query getAlertsCount($searchTerm: String, $projectPath: ID!, $assigneeUsername: String = "") { project(fullPath: $projectPath) { + id alertManagementAlertStatusCounts(search: $searchTerm, assigneeUsername: $assigneeUsername) { all open diff --git a/app/assets/javascripts/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql b/app/assets/javascripts/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql index babcdea935d..172add06785 100644 --- a/app/assets/javascripts/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql +++ b/app/assets/javascripts/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql @@ -3,6 +3,9 @@ mutation createHttpIntegration($projectPath: ID!, $name: String!, $active: Boolean!) { httpIntegrationCreate(input: { projectPath: $projectPath, name: $name, active: $active }) { errors + # We have ID in a deeply nested fragment + # TODO: Uncomment next line when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75220 is merged and the rule is enabled + # # eslint-disable-next-line @graphql-eslint/require-id-when-available integration { ...HttpIntegrationItem } diff --git a/app/assets/javascripts/alerts_settings/graphql/mutations/destroy_http_integration.mutation.graphql b/app/assets/javascripts/alerts_settings/graphql/mutations/destroy_http_integration.mutation.graphql index a3a50651fd0..f1d357b229a 100644 --- a/app/assets/javascripts/alerts_settings/graphql/mutations/destroy_http_integration.mutation.graphql +++ b/app/assets/javascripts/alerts_settings/graphql/mutations/destroy_http_integration.mutation.graphql @@ -3,6 +3,9 @@ mutation destroyHttpIntegration($id: ID!) { httpIntegrationDestroy(input: { id: $id }) { errors + # We have ID in a deeply nested fragment + # TODO: Uncomment next line when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75220 is merged and the rule is enabled + # # eslint-disable-next-line @graphql-eslint/require-id-when-available integration { ...HttpIntegrationItem } diff --git a/app/assets/javascripts/alerts_settings/graphql/mutations/reset_http_token.mutation.graphql b/app/assets/javascripts/alerts_settings/graphql/mutations/reset_http_token.mutation.graphql index c0754d8e32b..e541fe49968 100644 --- a/app/assets/javascripts/alerts_settings/graphql/mutations/reset_http_token.mutation.graphql +++ b/app/assets/javascripts/alerts_settings/graphql/mutations/reset_http_token.mutation.graphql @@ -3,6 +3,9 @@ mutation resetHttpIntegrationToken($id: ID!) { httpIntegrationResetToken(input: { id: $id }) { errors + # We have ID in a deeply nested fragment + # TODO: Uncomment next line when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75220 is merged and the rule is enabled + # # eslint-disable-next-line @graphql-eslint/require-id-when-available integration { ...HttpIntegrationItem } diff --git a/app/assets/javascripts/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql b/app/assets/javascripts/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql index 37df9ec25eb..e9942c1720d 100644 --- a/app/assets/javascripts/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql +++ b/app/assets/javascripts/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql @@ -3,6 +3,9 @@ mutation updateHttpIntegration($id: ID!, $name: String!, $active: Boolean!) { httpIntegrationUpdate(input: { id: $id, name: $name, active: $active }) { errors + # We have ID in a deeply nested fragment + # TODO: Uncomment next line when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75220 is merged and the rule is enabled + # # eslint-disable-next-line @graphql-eslint/require-id-when-available integration { ...HttpIntegrationItem } diff --git a/app/assets/javascripts/alerts_settings/graphql/queries/get_http_integration.query.graphql b/app/assets/javascripts/alerts_settings/graphql/queries/get_http_integration.query.graphql index d20a8b8334b..7299e6836d4 100644 --- a/app/assets/javascripts/alerts_settings/graphql/queries/get_http_integration.query.graphql +++ b/app/assets/javascripts/alerts_settings/graphql/queries/get_http_integration.query.graphql @@ -2,6 +2,7 @@ query getHttpIntegration($projectPath: ID!, $id: ID) { project(fullPath: $projectPath) { + id alertManagementHttpIntegrations(id: $id) { nodes { ...HttpIntegrationPayloadData diff --git a/app/assets/javascripts/alerts_settings/graphql/queries/get_integrations.query.graphql b/app/assets/javascripts/alerts_settings/graphql/queries/get_integrations.query.graphql index 228dd5fb176..3cd3f2d92f8 100644 --- a/app/assets/javascripts/alerts_settings/graphql/queries/get_integrations.query.graphql +++ b/app/assets/javascripts/alerts_settings/graphql/queries/get_integrations.query.graphql @@ -2,6 +2,7 @@ query getIntegrations($projectPath: ID!) { project(fullPath: $projectPath) { + id alertManagementIntegrations { nodes { ...IntegrationItem diff --git a/app/assets/javascripts/alerts_settings/graphql/queries/parse_sample_payload.query.graphql b/app/assets/javascripts/alerts_settings/graphql/queries/parse_sample_payload.query.graphql index 159b2661f0b..15df4a08cc2 100644 --- a/app/assets/javascripts/alerts_settings/graphql/queries/parse_sample_payload.query.graphql +++ b/app/assets/javascripts/alerts_settings/graphql/queries/parse_sample_payload.query.graphql @@ -1,5 +1,6 @@ query parsePayloadFields($projectPath: ID!, $payload: String!) { project(fullPath: $projectPath) { + id alertManagementPayloadFields(payloadExample: $payload) { path label diff --git a/app/assets/javascripts/analytics/shared/graphql/projects.query.graphql b/app/assets/javascripts/analytics/shared/graphql/projects.query.graphql index b870ed4dcbf..ea2f911fb54 100644 --- a/app/assets/javascripts/analytics/shared/graphql/projects.query.graphql +++ b/app/assets/javascripts/analytics/shared/graphql/projects.query.graphql @@ -5,6 +5,7 @@ query analyticsGetGroupProjects( $includeSubgroups: Boolean = false ) { group(fullPath: $groupFullPath) { + id projects( search: $search first: $first diff --git a/app/assets/javascripts/artifacts_settings/graphql/queries/get_keep_latest_artifact_project_setting.query.graphql b/app/assets/javascripts/artifacts_settings/graphql/queries/get_keep_latest_artifact_project_setting.query.graphql index 7486512c57c..91fa468fc8c 100644 --- a/app/assets/javascripts/artifacts_settings/graphql/queries/get_keep_latest_artifact_project_setting.query.graphql +++ b/app/assets/javascripts/artifacts_settings/graphql/queries/get_keep_latest_artifact_project_setting.query.graphql @@ -1,5 +1,6 @@ query getKeepLatestArtifactProjectSetting($fullPath: ID!) { project(fullPath: $fullPath) { + id ciCdSettings { keepLatestArtifact } diff --git a/app/assets/javascripts/boards/graphql/board_labels.query.graphql b/app/assets/javascripts/boards/graphql/board_labels.query.graphql index b19a24e8808..525a4863379 100644 --- a/app/assets/javascripts/boards/graphql/board_labels.query.graphql +++ b/app/assets/javascripts/boards/graphql/board_labels.query.graphql @@ -7,6 +7,7 @@ query BoardLabels( $isProject: Boolean = false ) { group(fullPath: $fullPath) @include(if: $isGroup) { + id labels(searchTerm: $searchTerm, onlyGroupLabels: true, includeAncestorGroups: true) { nodes { ...Label @@ -14,6 +15,7 @@ query BoardLabels( } } project(fullPath: $fullPath) @include(if: $isProject) { + id labels(searchTerm: $searchTerm, includeAncestorGroups: true) { nodes { ...Label diff --git a/app/assets/javascripts/boards/graphql/board_list_create.mutation.graphql b/app/assets/javascripts/boards/graphql/board_list_create.mutation.graphql index 0e1d11727cf..d662c33e592 100644 --- a/app/assets/javascripts/boards/graphql/board_list_create.mutation.graphql +++ b/app/assets/javascripts/boards/graphql/board_list_create.mutation.graphql @@ -2,6 +2,9 @@ mutation createBoardList($boardId: BoardID!, $backlog: Boolean, $labelId: LabelID) { boardListCreate(input: { boardId: $boardId, backlog: $backlog, labelId: $labelId }) { + # We have ID in a deeply nested fragment + # TODO: Uncomment next line when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75220 is merged and the rule is enabled + # # eslint-disable-next-line @graphql-eslint/require-id-when-available list { ...BoardListFragment } diff --git a/app/assets/javascripts/boards/graphql/board_list_update.mutation.graphql b/app/assets/javascripts/boards/graphql/board_list_update.mutation.graphql index b474c9acb93..e083decdb35 100644 --- a/app/assets/javascripts/boards/graphql/board_list_update.mutation.graphql +++ b/app/assets/javascripts/boards/graphql/board_list_update.mutation.graphql @@ -2,6 +2,9 @@ mutation UpdateBoardList($listId: ID!, $position: Int, $collapsed: Boolean) { updateBoardList(input: { listId: $listId, position: $position, collapsed: $collapsed }) { + # We have ID in a deeply nested fragment + # TODO: Uncomment next line when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75220 is merged and the rule is enabled + # # eslint-disable-next-line @graphql-eslint/require-id-when-available list { ...BoardListFragment } diff --git a/app/assets/javascripts/boards/graphql/board_lists.query.graphql b/app/assets/javascripts/boards/graphql/board_lists.query.graphql index 47e87907d76..b1f0b86b3bf 100644 --- a/app/assets/javascripts/boards/graphql/board_lists.query.graphql +++ b/app/assets/javascripts/boards/graphql/board_lists.query.graphql @@ -8,9 +8,14 @@ query BoardLists( $isProject: Boolean = false ) { group(fullPath: $fullPath) @include(if: $isGroup) { + id board(id: $boardId) { + id hideBacklogList lists(issueFilters: $filters) { + # We have ID in a deeply nested fragment + # TODO: Uncomment next line when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75220 is merged and the rule is enabled + # # eslint-disable-next-line @graphql-eslint/require-id-when-available nodes { ...BoardListFragment } @@ -18,9 +23,14 @@ query BoardLists( } } project(fullPath: $fullPath) @include(if: $isProject) { + id board(id: $boardId) { + id hideBacklogList lists(issueFilters: $filters) { + # We have ID in a deeply nested fragment + # TODO: Uncomment next line when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75220 is merged and the rule is enabled + # # eslint-disable-next-line @graphql-eslint/require-id-when-available nodes { ...BoardListFragment } diff --git a/app/assets/javascripts/boards/graphql/group_board.query.graphql b/app/assets/javascripts/boards/graphql/group_board.query.graphql index 77c8e0378f0..8d87b83da96 100644 --- a/app/assets/javascripts/boards/graphql/group_board.query.graphql +++ b/app/assets/javascripts/boards/graphql/group_board.query.graphql @@ -2,6 +2,7 @@ query GroupBoard($fullPath: ID!, $boardId: ID!) { workspace: group(fullPath: $fullPath) { + id board(id: $boardId) { ...BoardScopeFragment } diff --git a/app/assets/javascripts/boards/graphql/group_board_members.query.graphql b/app/assets/javascripts/boards/graphql/group_board_members.query.graphql index d3251c2aa12..aec674eb006 100644 --- a/app/assets/javascripts/boards/graphql/group_board_members.query.graphql +++ b/app/assets/javascripts/boards/graphql/group_board_members.query.graphql @@ -3,6 +3,7 @@ query GroupBoardMembers($fullPath: ID!, $search: String) { workspace: group(fullPath: $fullPath) { __typename + id assignees: groupMembers(search: $search, relations: [DIRECT, DESCENDANTS, INHERITED]) { __typename nodes { diff --git a/app/assets/javascripts/boards/graphql/group_board_milestones.query.graphql b/app/assets/javascripts/boards/graphql/group_board_milestones.query.graphql index 73aa9137dec..0963b3fbfaa 100644 --- a/app/assets/javascripts/boards/graphql/group_board_milestones.query.graphql +++ b/app/assets/javascripts/boards/graphql/group_board_milestones.query.graphql @@ -1,5 +1,6 @@ query GroupBoardMilestones($fullPath: ID!, $searchTerm: String) { group(fullPath: $fullPath) { + id milestones(includeAncestors: true, searchTitle: $searchTerm) { nodes { id diff --git a/app/assets/javascripts/boards/graphql/group_boards.query.graphql b/app/assets/javascripts/boards/graphql/group_boards.query.graphql index feafd6ae10d..0823c4f5a83 100644 --- a/app/assets/javascripts/boards/graphql/group_boards.query.graphql +++ b/app/assets/javascripts/boards/graphql/group_boards.query.graphql @@ -2,6 +2,7 @@ query group_boards($fullPath: ID!) { group(fullPath: $fullPath) { + id boards { edges { node { diff --git a/app/assets/javascripts/boards/graphql/group_projects.query.graphql b/app/assets/javascripts/boards/graphql/group_projects.query.graphql index c5732bbaff3..0da14d0b872 100644 --- a/app/assets/javascripts/boards/graphql/group_projects.query.graphql +++ b/app/assets/javascripts/boards/graphql/group_projects.query.graphql @@ -2,6 +2,7 @@ query boardsGetGroupProjects($fullPath: ID!, $search: String, $after: String) { group(fullPath: $fullPath) { + id projects(search: $search, after: $after, first: 100, includeSubgroups: true) { nodes { id diff --git a/app/assets/javascripts/boards/graphql/issue_set_subscription.mutation.graphql b/app/assets/javascripts/boards/graphql/issue_set_subscription.mutation.graphql index bfb87758e17..c130a64cac4 100644 --- a/app/assets/javascripts/boards/graphql/issue_set_subscription.mutation.graphql +++ b/app/assets/javascripts/boards/graphql/issue_set_subscription.mutation.graphql @@ -1,6 +1,7 @@ mutation issueSetSubscription($input: IssueSetSubscriptionInput!) { updateIssuableSubscription: issueSetSubscription(input: $input) { issue { + id subscribed } errors diff --git a/app/assets/javascripts/boards/graphql/issue_set_title.mutation.graphql b/app/assets/javascripts/boards/graphql/issue_set_title.mutation.graphql index 6ad12d982e0..147cf040a85 100644 --- a/app/assets/javascripts/boards/graphql/issue_set_title.mutation.graphql +++ b/app/assets/javascripts/boards/graphql/issue_set_title.mutation.graphql @@ -1,6 +1,7 @@ mutation issueSetTitle($input: UpdateIssueInput!) { updateIssuableTitle: updateIssue(input: $input) { issue { + id title } errors diff --git a/app/assets/javascripts/boards/graphql/lists_issues.query.graphql b/app/assets/javascripts/boards/graphql/lists_issues.query.graphql index 9f93bc6d5bf..4e47b1123ed 100644 --- a/app/assets/javascripts/boards/graphql/lists_issues.query.graphql +++ b/app/assets/javascripts/boards/graphql/lists_issues.query.graphql @@ -11,7 +11,9 @@ query BoardListEE( $first: Int ) { group(fullPath: $fullPath) @include(if: $isGroup) { + id board(id: $boardId) { + id lists(id: $id, issueFilters: $filters) { nodes { id @@ -33,7 +35,9 @@ query BoardListEE( } } project(fullPath: $fullPath) @include(if: $isProject) { + id board(id: $boardId) { + id lists(id: $id, issueFilters: $filters) { nodes { id diff --git a/app/assets/javascripts/boards/graphql/project_board.query.graphql b/app/assets/javascripts/boards/graphql/project_board.query.graphql index 6e4cd6bed57..8246d615a6a 100644 --- a/app/assets/javascripts/boards/graphql/project_board.query.graphql +++ b/app/assets/javascripts/boards/graphql/project_board.query.graphql @@ -2,6 +2,7 @@ query ProjectBoard($fullPath: ID!, $boardId: ID!) { workspace: project(fullPath: $fullPath) { + id board(id: $boardId) { ...BoardScopeFragment } diff --git a/app/assets/javascripts/boards/graphql/project_board_members.query.graphql b/app/assets/javascripts/boards/graphql/project_board_members.query.graphql index fc6cc6b832c..45bec5e574b 100644 --- a/app/assets/javascripts/boards/graphql/project_board_members.query.graphql +++ b/app/assets/javascripts/boards/graphql/project_board_members.query.graphql @@ -3,6 +3,7 @@ query ProjectBoardMembers($fullPath: ID!, $search: String) { workspace: project(fullPath: $fullPath) { __typename + id assignees: projectMembers(search: $search) { __typename nodes { diff --git a/app/assets/javascripts/boards/graphql/project_board_milestones.query.graphql b/app/assets/javascripts/boards/graphql/project_board_milestones.query.graphql index 8dd4d256caa..e456823d78a 100644 --- a/app/assets/javascripts/boards/graphql/project_board_milestones.query.graphql +++ b/app/assets/javascripts/boards/graphql/project_board_milestones.query.graphql @@ -1,5 +1,6 @@ query ProjectBoardMilestones($fullPath: ID!, $searchTerm: String) { project(fullPath: $fullPath) { + id milestones(searchTitle: $searchTerm, includeAncestors: true) { nodes { id diff --git a/app/assets/javascripts/boards/graphql/project_boards.query.graphql b/app/assets/javascripts/boards/graphql/project_boards.query.graphql index f98d25ba671..b8879bc260c 100644 --- a/app/assets/javascripts/boards/graphql/project_boards.query.graphql +++ b/app/assets/javascripts/boards/graphql/project_boards.query.graphql @@ -2,6 +2,7 @@ query project_boards($fullPath: ID!) { project(fullPath: $fullPath) { + id boards { edges { node { diff --git a/app/assets/javascripts/boards/graphql/project_milestones.query.graphql b/app/assets/javascripts/boards/graphql/project_milestones.query.graphql index 61c9ddded9b..4c952096d76 100644 --- a/app/assets/javascripts/boards/graphql/project_milestones.query.graphql +++ b/app/assets/javascripts/boards/graphql/project_milestones.query.graphql @@ -5,6 +5,7 @@ query boardProjectMilestones( $searchTitle: String ) { project(fullPath: $fullPath) { + id milestones(state: $state, includeAncestors: $includeAncestors, searchTitle: $searchTitle) { edges { node { diff --git a/app/assets/javascripts/clusters/agents/graphql/fragments/cluster_agent_token.fragment.graphql b/app/assets/javascripts/clusters/agents/graphql/fragments/cluster_agent_token.fragment.graphql index 1e9187e8ad1..7deb057ede9 100644 --- a/app/assets/javascripts/clusters/agents/graphql/fragments/cluster_agent_token.fragment.graphql +++ b/app/assets/javascripts/clusters/agents/graphql/fragments/cluster_agent_token.fragment.graphql @@ -4,8 +4,8 @@ fragment Token on ClusterAgentToken { description lastUsedAt name - createdByUser { + id name } } diff --git a/app/assets/javascripts/clusters/agents/graphql/queries/get_cluster_agent.query.graphql b/app/assets/javascripts/clusters/agents/graphql/queries/get_cluster_agent.query.graphql index d01db8f0a6a..3662e925261 100644 --- a/app/assets/javascripts/clusters/agents/graphql/queries/get_cluster_agent.query.graphql +++ b/app/assets/javascripts/clusters/agents/graphql/queries/get_cluster_agent.query.graphql @@ -10,11 +10,13 @@ query getClusterAgent( $beforeToken: String ) { project(fullPath: $projectPath) { + id clusterAgent(name: $agentName) { id createdAt createdByUser { + id name } diff --git a/app/assets/javascripts/clusters_list/graphql/cache_update.js b/app/assets/javascripts/clusters_list/graphql/cache_update.js index c32f25f83a4..4d12bc8151c 100644 --- a/app/assets/javascripts/clusters_list/graphql/cache_update.js +++ b/app/assets/javascripts/clusters_list/graphql/cache_update.js @@ -13,6 +13,7 @@ export function addAgentToStore(store, createClusterAgent, query, variables) { const data = produce(sourceData, (draftData) => { const configuration = { + id: clusterAgent.id, name: clusterAgent.name, path: getAgentConfigPath(clusterAgent.name), webPath: clusterAgent.webPath, diff --git a/app/assets/javascripts/clusters_list/graphql/fragments/cluster_agent.fragment.graphql b/app/assets/javascripts/clusters_list/graphql/fragments/cluster_agent.fragment.graphql index 9b40260471c..cd46dfee170 100644 --- a/app/assets/javascripts/clusters_list/graphql/fragments/cluster_agent.fragment.graphql +++ b/app/assets/javascripts/clusters_list/graphql/fragments/cluster_agent.fragment.graphql @@ -4,6 +4,7 @@ fragment ClusterAgentFragment on ClusterAgent { webPath tokens { nodes { + id lastUsedAt } } diff --git a/app/assets/javascripts/clusters_list/graphql/queries/agent_configurations.query.graphql b/app/assets/javascripts/clusters_list/graphql/queries/agent_configurations.query.graphql index 40b61337024..9a24cec5a9c 100644 --- a/app/assets/javascripts/clusters_list/graphql/queries/agent_configurations.query.graphql +++ b/app/assets/javascripts/clusters_list/graphql/queries/agent_configurations.query.graphql @@ -1,5 +1,6 @@ query agentConfigurations($projectPath: ID!) { project(fullPath: $projectPath) { + id agentConfigurations { nodes { agentName @@ -8,6 +9,7 @@ query agentConfigurations($projectPath: ID!) { clusterAgents { nodes { + id name } } diff --git a/app/assets/javascripts/clusters_list/graphql/queries/get_agents.query.graphql b/app/assets/javascripts/clusters_list/graphql/queries/get_agents.query.graphql index 47b25988877..f8efb6683f6 100644 --- a/app/assets/javascripts/clusters_list/graphql/queries/get_agents.query.graphql +++ b/app/assets/javascripts/clusters_list/graphql/queries/get_agents.query.graphql @@ -12,6 +12,7 @@ query getAgents( $beforeTree: String ) { project(fullPath: $projectPath) { + id clusterAgents(first: $first, last: $last, before: $beforeAgent, after: $afterAgent) { nodes { ...ClusterAgentFragment @@ -28,6 +29,7 @@ query getAgents( tree(path: ".gitlab/agents", ref: $defaultBranchName) { trees(first: $first, last: $last, after: $afterTree, before: $beforeTree) { nodes { + id name path webPath diff --git a/app/assets/javascripts/design_management/graphql/fragments/discussion_resolved_status.fragment.graphql b/app/assets/javascripts/design_management/graphql/fragments/discussion_resolved_status.fragment.graphql index 7483b508721..9ad85017921 100644 --- a/app/assets/javascripts/design_management/graphql/fragments/discussion_resolved_status.fragment.graphql +++ b/app/assets/javascripts/design_management/graphql/fragments/discussion_resolved_status.fragment.graphql @@ -1,8 +1,10 @@ fragment ResolvedStatus on Discussion { + id resolvable resolved resolvedAt resolvedBy { + id name webUrl } diff --git a/app/assets/javascripts/design_management/graphql/mutations/upload_design.mutation.graphql b/app/assets/javascripts/design_management/graphql/mutations/upload_design.mutation.graphql index 111f5ac18a7..24ec1816974 100644 --- a/app/assets/javascripts/design_management/graphql/mutations/upload_design.mutation.graphql +++ b/app/assets/javascripts/design_management/graphql/mutations/upload_design.mutation.graphql @@ -3,6 +3,8 @@ mutation uploadDesign($files: [Upload!]!, $projectPath: ID!, $iid: ID!) { designManagementUpload(input: { projectPath: $projectPath, iid: $iid, files: $files }) { + # TODO: Uncomment next line when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75220 is merged and the rule is enabled + # # eslint-disable-next-line @graphql-eslint/require-id-when-available designs { ...DesignItem versions { @@ -14,6 +16,7 @@ mutation uploadDesign($files: [Upload!]!, $projectPath: ID!, $iid: ID!) { } } skippedDesigns { + id filename } errors diff --git a/app/assets/javascripts/design_management/graphql/queries/get_design.query.graphql b/app/assets/javascripts/design_management/graphql/queries/get_design.query.graphql index 99a61191c6e..a638f80d095 100644 --- a/app/assets/javascripts/design_management/graphql/queries/get_design.query.graphql +++ b/app/assets/javascripts/design_management/graphql/queries/get_design.query.graphql @@ -10,8 +10,11 @@ query getDesign( project(fullPath: $fullPath) { id issue(iid: $iid) { + id designCollection { designs(atVersion: $atVersion, filenames: $filenames) { + # TODO: Uncomment next line when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75220 is merged and the rule is enabled + # # eslint-disable-next-line @graphql-eslint/require-id-when-available nodes { ...DesignItem issue { diff --git a/app/assets/javascripts/error_tracking/queries/details.query.graphql b/app/assets/javascripts/error_tracking/queries/details.query.graphql index af386528f00..f70e09d76f7 100644 --- a/app/assets/javascripts/error_tracking/queries/details.query.graphql +++ b/app/assets/javascripts/error_tracking/queries/details.query.graphql @@ -1,5 +1,6 @@ query errorDetails($fullPath: ID!, $errorId: ID!) { project(fullPath: $fullPath) { + id sentryErrors { detailedError(id: $errorId) { id diff --git a/app/assets/javascripts/graphql_shared/fragments/alert.fragment.graphql b/app/assets/javascripts/graphql_shared/fragments/alert.fragment.graphql index 2c771c32e16..64f547f933a 100644 --- a/app/assets/javascripts/graphql_shared/fragments/alert.fragment.graphql +++ b/app/assets/javascripts/graphql_shared/fragments/alert.fragment.graphql @@ -6,6 +6,7 @@ fragment AlertListItem on AlertManagementAlert { startedAt eventCount issue { + id iid state title diff --git a/app/assets/javascripts/graphql_shared/fragments/alert_detail_item.fragment.graphql b/app/assets/javascripts/graphql_shared/fragments/alert_detail_item.fragment.graphql index 9a9ae369519..794fe0a6151 100644 --- a/app/assets/javascripts/graphql_shared/fragments/alert_detail_item.fragment.graphql +++ b/app/assets/javascripts/graphql_shared/fragments/alert_detail_item.fragment.graphql @@ -12,6 +12,7 @@ fragment AlertDetailItem on AlertManagementAlert { endedAt hosts environment { + id name path } diff --git a/app/assets/javascripts/graphql_shared/fragments/issuable_timelogs.fragment.graphql b/app/assets/javascripts/graphql_shared/fragments/issuable_timelogs.fragment.graphql index 3551394ff97..78b2cd34a5c 100644 --- a/app/assets/javascripts/graphql_shared/fragments/issuable_timelogs.fragment.graphql +++ b/app/assets/javascripts/graphql_shared/fragments/issuable_timelogs.fragment.graphql @@ -1,10 +1,12 @@ fragment TimelogFragment on Timelog { timeSpent user { + id name } spentAt note { + id body } summary diff --git a/app/assets/javascripts/graphql_shared/fragments/user_availability.fragment.graphql b/app/assets/javascripts/graphql_shared/fragments/user_availability.fragment.graphql index 0b451262b5a..bb3b4f0e9f8 100644 --- a/app/assets/javascripts/graphql_shared/fragments/user_availability.fragment.graphql +++ b/app/assets/javascripts/graphql_shared/fragments/user_availability.fragment.graphql @@ -1,3 +1,5 @@ +# TODO: Uncomment next line when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75220 is merged and the rule is enabled +# # eslint-disable-next-line @graphql-eslint/require-id-when-available fragment UserAvailability on User { status { availability diff --git a/app/assets/javascripts/graphql_shared/mutations/create_merge_request.mutation.graphql b/app/assets/javascripts/graphql_shared/mutations/create_merge_request.mutation.graphql index 79c56448b3f..2adaf24ed34 100644 --- a/app/assets/javascripts/graphql_shared/mutations/create_merge_request.mutation.graphql +++ b/app/assets/javascripts/graphql_shared/mutations/create_merge_request.mutation.graphql @@ -1,6 +1,7 @@ mutation createMergeRequest($input: MergeRequestCreateInput!) { mergeRequestCreate(input: $input) { mergeRequest { + id iid } errors diff --git a/app/assets/javascripts/graphql_shared/queries/alert_details.query.graphql b/app/assets/javascripts/graphql_shared/queries/alert_details.query.graphql index 5ee2cf7ca44..8debc6113d1 100644 --- a/app/assets/javascripts/graphql_shared/queries/alert_details.query.graphql +++ b/app/assets/javascripts/graphql_shared/queries/alert_details.query.graphql @@ -2,6 +2,7 @@ query alertDetails($fullPath: ID!, $alertId: String) { project(fullPath: $fullPath) { + id alertManagementAlerts(iid: $alertId) { nodes { ...AlertDetailItem diff --git a/app/assets/javascripts/graphql_shared/queries/get_alerts.query.graphql b/app/assets/javascripts/graphql_shared/queries/get_alerts.query.graphql index 095e4fe29df..9ffa0bad9ad 100644 --- a/app/assets/javascripts/graphql_shared/queries/get_alerts.query.graphql +++ b/app/assets/javascripts/graphql_shared/queries/get_alerts.query.graphql @@ -14,6 +14,7 @@ query getAlerts( $domain: AlertManagementDomainFilter = operations ) { project(fullPath: $projectPath) { + id alertManagementAlerts( search: $searchTerm assigneeUsername: $assigneeUsername diff --git a/app/assets/javascripts/graphql_shared/queries/group_users_search.query.graphql b/app/assets/javascripts/graphql_shared/queries/group_users_search.query.graphql index c5f99a1657e..7c88e494a2e 100644 --- a/app/assets/javascripts/graphql_shared/queries/group_users_search.query.graphql +++ b/app/assets/javascripts/graphql_shared/queries/group_users_search.query.graphql @@ -6,6 +6,7 @@ query groupUsersSearch($search: String!, $fullPath: ID!) { id users: groupMembers(search: $search, relations: [DIRECT, DESCENDANTS, INHERITED]) { nodes { + id user { ...User ...UserAvailability diff --git a/app/assets/javascripts/graphql_shared/queries/project_user_members_search.query.graphql b/app/assets/javascripts/graphql_shared/queries/project_user_members_search.query.graphql index 62ce27815c7..ef3070d3437 100644 --- a/app/assets/javascripts/graphql_shared/queries/project_user_members_search.query.graphql +++ b/app/assets/javascripts/graphql_shared/queries/project_user_members_search.query.graphql @@ -3,6 +3,7 @@ query searchProjectMembers($fullPath: ID!, $search: String) { id projectMembers(search: $search) { nodes { + id user { id name diff --git a/app/assets/javascripts/graphql_shared/queries/users_search.query.graphql b/app/assets/javascripts/graphql_shared/queries/users_search.query.graphql index d04a49f8b3a..bb34e4032f4 100644 --- a/app/assets/javascripts/graphql_shared/queries/users_search.query.graphql +++ b/app/assets/javascripts/graphql_shared/queries/users_search.query.graphql @@ -3,8 +3,10 @@ query projectUsersSearch($search: String!, $fullPath: ID!) { workspace: project(fullPath: $fullPath) { + id users: projectMembers(search: $search, relations: [DIRECT, INHERITED, INVITED_GROUPS]) { nodes { + id user { ...User ...UserAvailability diff --git a/app/assets/javascripts/ide/queries/ide_project.fragment.graphql b/app/assets/javascripts/ide/queries/ide_project.fragment.graphql index c107f2376f9..a0b520858e6 100644 --- a/app/assets/javascripts/ide/queries/ide_project.fragment.graphql +++ b/app/assets/javascripts/ide/queries/ide_project.fragment.graphql @@ -1,4 +1,5 @@ fragment IdeProject on Project { + id userPermissions { createMergeRequestIn readMergeRequest diff --git a/app/assets/javascripts/incidents/graphql/fragments/incident_fields.fragment.graphql b/app/assets/javascripts/incidents/graphql/fragments/incident_fields.fragment.graphql index eb2dde14464..ac826fe26de 100644 --- a/app/assets/javascripts/incidents/graphql/fragments/incident_fields.fragment.graphql +++ b/app/assets/javascripts/incidents/graphql/fragments/incident_fields.fragment.graphql @@ -1,3 +1,5 @@ +# TODO: Uncomment next line when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75220 is merged and the rule is enabled +# # eslint-disable-next-line @graphql-eslint/require-id-when-available fragment IncidentFields on Issue { severity } diff --git a/app/assets/javascripts/incidents/graphql/queries/get_count_by_status.query.graphql b/app/assets/javascripts/incidents/graphql/queries/get_count_by_status.query.graphql index 4e44a506c4f..fda8a65d4a4 100644 --- a/app/assets/javascripts/incidents/graphql/queries/get_count_by_status.query.graphql +++ b/app/assets/javascripts/incidents/graphql/queries/get_count_by_status.query.graphql @@ -6,6 +6,7 @@ query getIncidentsCountByStatus( $assigneeUsername: String = "" ) { project(fullPath: $projectPath) { + id issueStatusCounts( search: $searchTerm types: $issueTypes diff --git a/app/assets/javascripts/incidents/graphql/queries/get_incidents.query.graphql b/app/assets/javascripts/incidents/graphql/queries/get_incidents.query.graphql index f97664a3b77..1e18d89b656 100644 --- a/app/assets/javascripts/incidents/graphql/queries/get_incidents.query.graphql +++ b/app/assets/javascripts/incidents/graphql/queries/get_incidents.query.graphql @@ -14,6 +14,7 @@ query getIncidents( $assigneeUsername: String = "" ) { project(fullPath: $projectPath) { + id issues( search: $searchTerm types: $issueTypes @@ -27,18 +28,21 @@ query getIncidents( before: $prevPageCursor ) { nodes { + id iid title createdAt state labels { nodes { + id title color } } assignees { nodes { + id name username avatarUrl diff --git a/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue b/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue index 85018f133cb..3fc554c5371 100644 --- a/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue +++ b/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue @@ -6,8 +6,12 @@ import { DEFAULT_PER_PAGE } from '~/api'; import { fetchOverrides } from '~/integrations/overrides/api'; import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils'; import { truncateNamespace } from '~/lib/utils/text_utility'; +import { getParameterByName } from '~/lib/utils/url_utility'; import { __, s__ } from '~/locale'; import ProjectAvatar from '~/vue_shared/components/project_avatar.vue'; +import UrlSync from '~/vue_shared/components/url_sync.vue'; + +const DEFAULT_PAGE = 1; export default { name: 'IntegrationOverrides', @@ -18,6 +22,7 @@ export default { GlTable, GlAlert, ProjectAvatar, + UrlSync, }, props: { overridesPath: { @@ -35,7 +40,7 @@ export default { return { isLoading: true, overrides: [], - page: 1, + page: DEFAULT_PAGE, totalItems: 0, errorMessage: null, }; @@ -44,12 +49,21 @@ export default { showPagination() { return this.totalItems > this.$options.DEFAULT_PER_PAGE && this.overrides.length > 0; }, + query() { + return { + page: this.page, + }; + }, }, - mounted() { - this.loadOverrides(); + created() { + const initialPage = this.getInitialPage(); + this.loadOverrides(initialPage); }, methods: { - loadOverrides(page = this.page) { + getInitialPage() { + return getParameterByName('page') ?? DEFAULT_PAGE; + }, + loadOverrides(page) { this.isLoading = true; this.errorMessage = null; @@ -119,14 +133,16 @@ export default { </template> </gl-table> <div class="gl-display-flex gl-justify-content-center gl-mt-5"> - <gl-pagination - v-if="showPagination" - :per-page="$options.DEFAULT_PER_PAGE" - :total-items="totalItems" - :value="page" - :disabled="isLoading" - @input="loadOverrides" - /> + <template v-if="showPagination"> + <gl-pagination + :per-page="$options.DEFAULT_PER_PAGE" + :total-items="totalItems" + :value="page" + :disabled="isLoading" + @input="loadOverrides" + /> + <url-sync :query="query" /> + </template> </div> </div> </template> diff --git a/app/assets/javascripts/issuable_suggestions/queries/issues.query.graphql b/app/assets/javascripts/issuable_suggestions/queries/issues.query.graphql index 2384b381344..dc0757b141f 100644 --- a/app/assets/javascripts/issuable_suggestions/queries/issues.query.graphql +++ b/app/assets/javascripts/issuable_suggestions/queries/issues.query.graphql @@ -1,8 +1,10 @@ query issueSuggestion($fullPath: ID!, $search: String) { project(fullPath: $fullPath) { + id issues(search: $search, sort: updated_desc, first: 5) { edges { node { + id iid title confidential @@ -14,6 +16,7 @@ query issueSuggestion($fullPath: ID!, $search: String) { createdAt updatedAt author { + id name username avatarUrl diff --git a/app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql b/app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql index 938b90b3f7c..d88633f2ae9 100644 --- a/app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql +++ b/app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql @@ -1,5 +1,6 @@ query getAlert($iid: String!, $fullPath: ID!) { project(fullPath: $fullPath) { + id issue(iid: $iid) { id alertManagementAlert { diff --git a/app/assets/javascripts/issue_show/queries/promote_to_epic.mutation.graphql b/app/assets/javascripts/issue_show/queries/promote_to_epic.mutation.graphql index 12d05af0f5e..e3e3a2bc667 100644 --- a/app/assets/javascripts/issue_show/queries/promote_to_epic.mutation.graphql +++ b/app/assets/javascripts/issue_show/queries/promote_to_epic.mutation.graphql @@ -1,6 +1,7 @@ mutation promoteToEpic($input: PromoteToEpicInput!) { promoteToEpic(input: $input) { epic { + id webPath } errors diff --git a/app/assets/javascripts/issues_list/queries/get_issues.query.graphql b/app/assets/javascripts/issues_list/queries/get_issues.query.graphql index 9866efbcecc..be8deb3fe97 100644 --- a/app/assets/javascripts/issues_list/queries/get_issues.query.graphql +++ b/app/assets/javascripts/issues_list/queries/get_issues.query.graphql @@ -26,6 +26,7 @@ query getIssues( $lastPageSize: Int ) { group(fullPath: $fullPath) @skip(if: $isProject) { + id issues( includeSubgroups: true search: $search @@ -56,6 +57,7 @@ query getIssues( } } project(fullPath: $fullPath) @include(if: $isProject) { + id issues( search: $search sort: $sort diff --git a/app/assets/javascripts/issues_list/queries/get_issues_counts.query.graphql b/app/assets/javascripts/issues_list/queries/get_issues_counts.query.graphql index 5e755ec5870..1a345fd2877 100644 --- a/app/assets/javascripts/issues_list/queries/get_issues_counts.query.graphql +++ b/app/assets/javascripts/issues_list/queries/get_issues_counts.query.graphql @@ -16,6 +16,7 @@ query getIssuesCount( $not: NegatedIssueFilterInput ) { group(fullPath: $fullPath) @skip(if: $isProject) { + id openedIssues: issues( includeSubgroups: true state: opened @@ -69,6 +70,7 @@ query getIssuesCount( } } project(fullPath: $fullPath) @include(if: $isProject) { + id openedIssues: issues( state: opened search: $search diff --git a/app/assets/javascripts/issues_list/queries/get_issues_list_details.query.graphql b/app/assets/javascripts/issues_list/queries/get_issues_list_details.query.graphql index 8c95e6114d3..a53dba8c7c8 100644 --- a/app/assets/javascripts/issues_list/queries/get_issues_list_details.query.graphql +++ b/app/assets/javascripts/issues_list/queries/get_issues_list_details.query.graphql @@ -1,9 +1,12 @@ query getIssuesListDetails($fullPath: ID!) { project(fullPath: $fullPath) { + id issues { nodes { + id labels { nodes { + id title color } diff --git a/app/assets/javascripts/issues_list/queries/search_labels.query.graphql b/app/assets/javascripts/issues_list/queries/search_labels.query.graphql index 1515bd91da3..44b57317161 100644 --- a/app/assets/javascripts/issues_list/queries/search_labels.query.graphql +++ b/app/assets/javascripts/issues_list/queries/search_labels.query.graphql @@ -2,6 +2,7 @@ query searchLabels($fullPath: ID!, $search: String, $isProject: Boolean = false) { group(fullPath: $fullPath) @skip(if: $isProject) { + id labels(searchTerm: $search, includeAncestorGroups: true, includeDescendantGroups: true) { nodes { ...Label @@ -9,6 +10,7 @@ query searchLabels($fullPath: ID!, $search: String, $isProject: Boolean = false) } } project(fullPath: $fullPath) @include(if: $isProject) { + id labels(searchTerm: $search, includeAncestorGroups: true) { nodes { ...Label diff --git a/app/assets/javascripts/issues_list/queries/search_milestones.query.graphql b/app/assets/javascripts/issues_list/queries/search_milestones.query.graphql index 8c6c50e9dc2..e7eb08104a6 100644 --- a/app/assets/javascripts/issues_list/queries/search_milestones.query.graphql +++ b/app/assets/javascripts/issues_list/queries/search_milestones.query.graphql @@ -2,6 +2,7 @@ query searchMilestones($fullPath: ID!, $search: String, $isProject: Boolean = false) { group(fullPath: $fullPath) @skip(if: $isProject) { + id milestones(searchTitle: $search, includeAncestors: true, includeDescendants: true) { nodes { ...Milestone @@ -9,6 +10,7 @@ query searchMilestones($fullPath: ID!, $search: String, $isProject: Boolean = fa } } project(fullPath: $fullPath) @include(if: $isProject) { + id milestones(searchTitle: $search, includeAncestors: true) { nodes { ...Milestone diff --git a/app/assets/javascripts/issues_list/queries/search_projects.query.graphql b/app/assets/javascripts/issues_list/queries/search_projects.query.graphql index 75463f643a2..bd2f9bc2340 100644 --- a/app/assets/javascripts/issues_list/queries/search_projects.query.graphql +++ b/app/assets/javascripts/issues_list/queries/search_projects.query.graphql @@ -1,5 +1,6 @@ query searchProjects($fullPath: ID!, $search: String) { group(fullPath: $fullPath) { + id projects(search: $search, includeSubgroups: true) { nodes { id diff --git a/app/assets/javascripts/issues_list/queries/search_users.query.graphql b/app/assets/javascripts/issues_list/queries/search_users.query.graphql index 0211fc66235..92517ad35d0 100644 --- a/app/assets/javascripts/issues_list/queries/search_users.query.graphql +++ b/app/assets/javascripts/issues_list/queries/search_users.query.graphql @@ -2,8 +2,10 @@ query searchUsers($fullPath: ID!, $search: String, $isProject: Boolean = false) { group(fullPath: $fullPath) @skip(if: $isProject) { + id groupMembers(search: $search) { nodes { + id user { ...User } @@ -11,8 +13,10 @@ query searchUsers($fullPath: ID!, $search: String, $isProject: Boolean = false) } } project(fullPath: $fullPath) @include(if: $isProject) { + id projectMembers(search: $search) { nodes { + id user { ...User } diff --git a/app/assets/javascripts/jira_connect/branches/graphql/queries/get_project.query.graphql b/app/assets/javascripts/jira_connect/branches/graphql/queries/get_project.query.graphql index f3428e816d7..df72a1ca6e6 100644 --- a/app/assets/javascripts/jira_connect/branches/graphql/queries/get_project.query.graphql +++ b/app/assets/javascripts/jira_connect/branches/graphql/queries/get_project.query.graphql @@ -5,6 +5,7 @@ query getProject( $branchNamesSearchPattern: String! ) { project(fullPath: $projectPath) { + id repository { branchNames( limit: $branchNamesLimit diff --git a/app/assets/javascripts/jira_import/queries/get_jira_import_details.query.graphql b/app/assets/javascripts/jira_import/queries/get_jira_import_details.query.graphql index 6fec07cc6f8..4c26399e16b 100644 --- a/app/assets/javascripts/jira_import/queries/get_jira_import_details.query.graphql +++ b/app/assets/javascripts/jira_import/queries/get_jira_import_details.query.graphql @@ -2,6 +2,7 @@ query getJiraImportDetails($fullPath: ID!) { project(fullPath: $fullPath) { + id jiraImportStatus jiraImports { nodes { diff --git a/app/assets/javascripts/jira_import/queries/jira_import.fragment.graphql b/app/assets/javascripts/jira_import/queries/jira_import.fragment.graphql index fde2ebeff91..fe797879d07 100644 --- a/app/assets/javascripts/jira_import/queries/jira_import.fragment.graphql +++ b/app/assets/javascripts/jira_import/queries/jira_import.fragment.graphql @@ -2,6 +2,7 @@ fragment JiraImport on JiraImport { jiraProjectKey scheduledAt scheduledBy { + id name } } diff --git a/app/assets/javascripts/jira_import/queries/search_project_members.query.graphql b/app/assets/javascripts/jira_import/queries/search_project_members.query.graphql index 6ea8963e6a6..7666fa3bd97 100644 --- a/app/assets/javascripts/jira_import/queries/search_project_members.query.graphql +++ b/app/assets/javascripts/jira_import/queries/search_project_members.query.graphql @@ -1,7 +1,9 @@ query jiraSearchProjectMembers($fullPath: ID!, $search: String) { project(fullPath: $fullPath) { + id projectMembers(search: $search) { nodes { + id user { id name diff --git a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql b/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql index c8763d4767e..e6a26675773 100644 --- a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql +++ b/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql @@ -7,6 +7,7 @@ query getJobs( $statuses: [CiJobStatus!] ) { project(fullPath: $fullPath) { + id jobs(after: $after, before: $before, first: $first, last: $last, statuses: $statuses) { pageInfo { endCursor @@ -27,6 +28,7 @@ query getJobs( triggered createdByTag detailedStatus { + id detailsPath group icon @@ -34,6 +36,7 @@ query getJobs( text tooltip action { + id buttonTitle icon method @@ -51,11 +54,13 @@ query getJobs( id path user { + id webPath avatarUrl } } stage { + id name } name diff --git a/app/assets/javascripts/monitoring/queries/getDashboardValidationWarnings.query.graphql b/app/assets/javascripts/monitoring/queries/getDashboardValidationWarnings.query.graphql index 302383512d3..a61d601cd34 100644 --- a/app/assets/javascripts/monitoring/queries/getDashboardValidationWarnings.query.graphql +++ b/app/assets/javascripts/monitoring/queries/getDashboardValidationWarnings.query.graphql @@ -7,6 +7,7 @@ query getDashboardValidationWarnings( id environments(name: $environmentName) { nodes { + id name metricsDashboard(path: $dashboardPath) { path diff --git a/app/assets/javascripts/mr_popover/queries/merge_request.query.graphql b/app/assets/javascripts/mr_popover/queries/merge_request.query.graphql index 087383e7549..b3e5d89d495 100644 --- a/app/assets/javascripts/mr_popover/queries/merge_request.query.graphql +++ b/app/assets/javascripts/mr_popover/queries/merge_request.query.graphql @@ -1,11 +1,15 @@ query mergeRequest($projectPath: ID!, $mergeRequestIID: String!) { project(fullPath: $projectPath) { + id mergeRequest(iid: $mergeRequestIID) { + id title createdAt state headPipeline { + id detailedStatus { + id icon group } diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repositories_details.query.graphql b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repositories_details.query.graphql index 01cb7fa1cab..bc34e9b5ef2 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repositories_details.query.graphql +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repositories_details.query.graphql @@ -9,6 +9,7 @@ query getContainerRepositoriesDetails( $sort: ContainerRepositorySort ) { project(fullPath: $fullPath) @skip(if: $isGroupPage) { + id containerRepositories( name: $name after: $after @@ -24,6 +25,7 @@ query getContainerRepositoriesDetails( } } group(fullPath: $fullPath) @include(if: $isGroupPage) { + id containerRepositories( name: $name after: $after diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_details.query.graphql b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_details.query.graphql index b5a99fd9ac1..916740f41b8 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_details.query.graphql +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_details.query.graphql @@ -11,6 +11,7 @@ query getContainerRepositoryDetails($id: ID!) { expirationPolicyStartedAt expirationPolicyCleanupStatus project { + id visibility path containerExpirationPolicy { diff --git a/app/assets/javascripts/packages_and_registries/dependency_proxy/graphql/queries/get_dependency_proxy_details.query.graphql b/app/assets/javascripts/packages_and_registries/dependency_proxy/graphql/queries/get_dependency_proxy_details.query.graphql index 63d5469c955..9241dccb2d5 100644 --- a/app/assets/javascripts/packages_and_registries/dependency_proxy/graphql/queries/get_dependency_proxy_details.query.graphql +++ b/app/assets/javascripts/packages_and_registries/dependency_proxy/graphql/queries/get_dependency_proxy_details.query.graphql @@ -8,6 +8,7 @@ query getDependencyProxyDetails( $before: String ) { group(fullPath: $fullPath) { + id dependencyProxyBlobCount dependencyProxyTotalSize dependencyProxyImagePrefix @@ -16,6 +17,7 @@ query getDependencyProxyDetails( } dependencyProxyManifests(after: $after, before: $before, first: $first, last: $last) { nodes { + id createdAt imageName } diff --git a/app/assets/javascripts/packages_and_registries/package_registry/graphql/fragments/package_data.fragment.graphql b/app/assets/javascripts/packages_and_registries/package_registry/graphql/fragments/package_data.fragment.graphql index 7588a474051..66315fda9e9 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/graphql/fragments/package_data.fragment.graphql +++ b/app/assets/javascripts/packages_and_registries/package_registry/graphql/fragments/package_data.fragment.graphql @@ -7,20 +7,24 @@ fragment PackageData on Package { status tags { nodes { + id name } } pipelines(last: 1) { nodes { + id sha ref commitPath user { + id name } } } project { + id fullPath webUrl } diff --git a/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql b/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql index 14aa14e9822..08ea0938a59 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql +++ b/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql @@ -8,6 +8,7 @@ query getPackageDetails($id: ID!) { updatedAt status project { + id path } tags(first: 10) { @@ -25,9 +26,11 @@ query getPackageDetails($id: ID!) { commitPath path user { + id name } project { + id name webUrl } @@ -86,15 +89,18 @@ query getPackageDetails($id: ID!) { } } ... on PypiMetadata { + id requiredPython } ... on ConanMetadata { + id packageChannel packageUsername recipe recipePath } ... on MavenMetadata { + id appName appGroup appVersion @@ -102,6 +108,7 @@ query getPackageDetails($id: ID!) { } ... on NugetMetadata { + id iconUrl licenseUrl projectUrl diff --git a/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql b/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql index e3115365f8b..4b913590949 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql +++ b/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql @@ -14,6 +14,7 @@ query getPackages( $before: String ) { project(fullPath: $fullPath) @skip(if: $isGroupPage) { + id packages( sort: $sort packageName: $packageName @@ -33,6 +34,7 @@ query getPackages( } } group(fullPath: $fullPath) @include(if: $isGroupPage) { + id packages( sort: $groupSort packageName: $packageName diff --git a/app/assets/javascripts/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql b/app/assets/javascripts/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql index d3edebfbe20..96dc2357f8b 100644 --- a/app/assets/javascripts/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql +++ b/app/assets/javascripts/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql @@ -1,5 +1,6 @@ query getGroupPackagesSettings($fullPath: ID!) { group(fullPath: $fullPath) { + id dependencyProxySetting { enabled } diff --git a/app/assets/javascripts/packages_and_registries/settings/project/graphql/queries/get_expiration_policy.query.graphql b/app/assets/javascripts/packages_and_registries/settings/project/graphql/queries/get_expiration_policy.query.graphql index c171be0ad07..6a862da92df 100644 --- a/app/assets/javascripts/packages_and_registries/settings/project/graphql/queries/get_expiration_policy.query.graphql +++ b/app/assets/javascripts/packages_and_registries/settings/project/graphql/queries/get_expiration_policy.query.graphql @@ -2,6 +2,7 @@ query getProjectExpirationPolicy($projectPath: ID!) { project(fullPath: $projectPath) { + id containerExpirationPolicy { ...ContainerExpirationPolicyFields } diff --git a/app/assets/javascripts/pages/projects/edit/index.js b/app/assets/javascripts/pages/projects/edit/index.js index f4beefea90c..03fc785ff26 100644 --- a/app/assets/javascripts/pages/projects/edit/index.js +++ b/app/assets/javascripts/pages/projects/edit/index.js @@ -1,5 +1,6 @@ import { PROJECT_BADGE } from '~/badges/constants'; import initLegacyConfirmDangerModal from '~/confirm_danger_modal'; +import initConfirmDanger from '~/init_confirm_danger'; import dirtySubmitFactory from '~/dirty_submit/dirty_submit_factory'; import initFilePickers from '~/file_pickers'; import mountBadgeSettings from '~/pages/shared/mount_badge_settings'; @@ -15,6 +16,7 @@ import initProjectLoadingSpinner from '../shared/save_project_loader'; initFilePickers(); initLegacyConfirmDangerModal(); +initConfirmDanger(); initSettingsPanels(); initProjectDeleteButton(); mountBadgeSettings(PROJECT_BADGE); diff --git a/app/assets/javascripts/pages/projects/merge_requests/queries/get_state.query.graphql b/app/assets/javascripts/pages/projects/merge_requests/queries/get_state.query.graphql index b5a82b9428e..1edb37a228d 100644 --- a/app/assets/javascripts/pages/projects/merge_requests/queries/get_state.query.graphql +++ b/app/assets/javascripts/pages/projects/merge_requests/queries/get_state.query.graphql @@ -1,6 +1,8 @@ query getMergeRequestState($projectPath: ID!, $iid: String!) { workspace: project(fullPath: $projectPath) { + id issuable: mergeRequest(iid: $iid) { + id state } } diff --git a/app/assets/javascripts/pipeline_editor/graphql/mutations/commit_ci_file.mutation.graphql b/app/assets/javascripts/pipeline_editor/graphql/mutations/commit_ci_file.mutation.graphql index 65bb755ad2e..77a3cdf586c 100644 --- a/app/assets/javascripts/pipeline_editor/graphql/mutations/commit_ci_file.mutation.graphql +++ b/app/assets/javascripts/pipeline_editor/graphql/mutations/commit_ci_file.mutation.graphql @@ -22,6 +22,7 @@ mutation commitCIFile( __typename commit { __typename + id sha } commitPipelinePath diff --git a/app/assets/javascripts/pipeline_editor/graphql/queries/available_branches.graphql b/app/assets/javascripts/pipeline_editor/graphql/queries/available_branches.graphql index 46e9b108b41..359b4a846c7 100644 --- a/app/assets/javascripts/pipeline_editor/graphql/queries/available_branches.graphql +++ b/app/assets/javascripts/pipeline_editor/graphql/queries/available_branches.graphql @@ -5,6 +5,7 @@ query getAvailableBranches( $searchPattern: String! ) { project(fullPath: $projectFullPath) { + id repository { branchNames(limit: $limit, offset: $offset, searchPattern: $searchPattern) } diff --git a/app/assets/javascripts/pipeline_editor/graphql/queries/blob_content.graphql b/app/assets/javascripts/pipeline_editor/graphql/queries/blob_content.graphql index 5500244b430..5928d90f7c4 100644 --- a/app/assets/javascripts/pipeline_editor/graphql/queries/blob_content.graphql +++ b/app/assets/javascripts/pipeline_editor/graphql/queries/blob_content.graphql @@ -1,8 +1,10 @@ query getBlobContent($projectPath: ID!, $path: String!, $ref: String) { project(fullPath: $projectPath) { + id repository { blobs(paths: [$path], ref: $ref) { nodes { + id rawBlob } } diff --git a/app/assets/javascripts/pipeline_editor/graphql/queries/client/pipeline.graphql b/app/assets/javascripts/pipeline_editor/graphql/queries/client/pipeline.graphql index 34e98ae3eb3..021b858d72e 100644 --- a/app/assets/javascripts/pipeline_editor/graphql/queries/client/pipeline.graphql +++ b/app/assets/javascripts/pipeline_editor/graphql/queries/client/pipeline.graphql @@ -1,14 +1,17 @@ query getPipeline($fullPath: ID!, $sha: String!) { project(fullPath: $fullPath) { + id pipeline(sha: $sha) { id iid status commit { + id title webPath } detailedStatus { + id detailsPath icon group diff --git a/app/assets/javascripts/pipeline_editor/graphql/queries/get_starter_template.query.graphql b/app/assets/javascripts/pipeline_editor/graphql/queries/get_starter_template.query.graphql index 88825718f7b..a34c8f365f4 100644 --- a/app/assets/javascripts/pipeline_editor/graphql/queries/get_starter_template.query.graphql +++ b/app/assets/javascripts/pipeline_editor/graphql/queries/get_starter_template.query.graphql @@ -1,5 +1,6 @@ query getTemplate($projectPath: ID!, $templateName: String!) { project(fullPath: $projectPath) { + id ciTemplate(name: $templateName) { content } diff --git a/app/assets/javascripts/pipeline_editor/graphql/queries/latest_commit_sha.query.graphql b/app/assets/javascripts/pipeline_editor/graphql/queries/latest_commit_sha.query.graphql index 02d49507947..d62fda40237 100644 --- a/app/assets/javascripts/pipeline_editor/graphql/queries/latest_commit_sha.query.graphql +++ b/app/assets/javascripts/pipeline_editor/graphql/queries/latest_commit_sha.query.graphql @@ -1,8 +1,10 @@ query getLatestCommitSha($projectPath: ID!, $ref: String) { project(fullPath: $projectPath) { + id repository { tree(ref: $ref) { lastCommit { + id sha } } diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql b/app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql index 887c217da41..2a0b13dd0cc 100644 --- a/app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql +++ b/app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql @@ -1,19 +1,24 @@ query getDagVisData($projectPath: ID!, $iid: ID!) { project(fullPath: $projectPath) { + id pipeline(iid: $iid) { id stages { nodes { + id name groups { nodes { + id name size jobs { nodes { + id name needs { nodes { + id name } } diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql b/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql index 8fcae9dbad8..47bc167ca52 100644 --- a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql +++ b/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql @@ -1,5 +1,6 @@ query getPipelineHeaderData($fullPath: ID!, $iid: ID!) { project(fullPath: $fullPath) { + id pipeline(iid: $iid) { id iid @@ -11,6 +12,7 @@ query getPipelineHeaderData($fullPath: ID!, $iid: ID!) { updatePipeline } detailedStatus { + id detailsPath icon group diff --git a/app/assets/javascripts/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql b/app/assets/javascripts/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql index ee18c70b6fd..c6a0d48626a 100644 --- a/app/assets/javascripts/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql +++ b/app/assets/javascripts/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql @@ -1,15 +1,19 @@ query getLinkedPipelines($fullPath: ID!, $iid: ID!) { project(fullPath: $fullPath) { + id pipeline(iid: $iid) { + id path downstream { nodes { id path project { + id name } detailedStatus { + id group icon label @@ -20,9 +24,11 @@ query getLinkedPipelines($fullPath: ID!, $iid: ID!) { id path project { + id name } detailedStatus { + id group icon label diff --git a/app/assets/javascripts/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql b/app/assets/javascripts/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql index 74febec5a51..568e05d1966 100644 --- a/app/assets/javascripts/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql +++ b/app/assets/javascripts/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql @@ -1,5 +1,6 @@ query searchNamespacesWhereUserCanCreateProjects($search: String) { currentUser { + id groups(permissionScope: CREATE_PROJECTS, search: $search) { nodes { id diff --git a/app/assets/javascripts/projects/pipelines/charts/graphql/queries/get_pipeline_count_by_status.query.graphql b/app/assets/javascripts/projects/pipelines/charts/graphql/queries/get_pipeline_count_by_status.query.graphql index d68df689f5f..ac7fe51384c 100644 --- a/app/assets/javascripts/projects/pipelines/charts/graphql/queries/get_pipeline_count_by_status.query.graphql +++ b/app/assets/javascripts/projects/pipelines/charts/graphql/queries/get_pipeline_count_by_status.query.graphql @@ -1,5 +1,6 @@ query getPipelineCountByStatus($projectPath: ID!) { project(fullPath: $projectPath) { + id totalPipelines: pipelines { count } diff --git a/app/assets/javascripts/projects/pipelines/charts/graphql/queries/get_project_pipeline_statistics.query.graphql b/app/assets/javascripts/projects/pipelines/charts/graphql/queries/get_project_pipeline_statistics.query.graphql index 18b645f8831..46e8a6dc87d 100644 --- a/app/assets/javascripts/projects/pipelines/charts/graphql/queries/get_project_pipeline_statistics.query.graphql +++ b/app/assets/javascripts/projects/pipelines/charts/graphql/queries/get_project_pipeline_statistics.query.graphql @@ -1,5 +1,6 @@ query getProjectPipelineStatistics($projectPath: ID!) { project(fullPath: $projectPath) { + id pipelineAnalytics { weekPipelinesTotals weekPipelinesLabels diff --git a/app/assets/javascripts/releases/graphql/fragments/release.fragment.graphql b/app/assets/javascripts/releases/graphql/fragments/release.fragment.graphql index 3a927dfc756..8a5613c75d2 100644 --- a/app/assets/javascripts/releases/graphql/fragments/release.fragment.graphql +++ b/app/assets/javascripts/releases/graphql/fragments/release.fragment.graphql @@ -35,6 +35,7 @@ fragment Release on Release { __typename nodes { __typename + id filepath collectedAt sha @@ -52,12 +53,14 @@ fragment Release on Release { } commit { __typename + id sha webUrl title } author { __typename + id webUrl avatarUrl username diff --git a/app/assets/javascripts/releases/graphql/fragments/release_for_editing.fragment.graphql b/app/assets/javascripts/releases/graphql/fragments/release_for_editing.fragment.graphql index 75a73acb9ae..1823a327350 100644 --- a/app/assets/javascripts/releases/graphql/fragments/release_for_editing.fragment.graphql +++ b/app/assets/javascripts/releases/graphql/fragments/release_for_editing.fragment.graphql @@ -18,6 +18,7 @@ fragment ReleaseForEditing on Release { } milestones { nodes { + id title } } diff --git a/app/assets/javascripts/releases/graphql/queries/all_releases.query.graphql b/app/assets/javascripts/releases/graphql/queries/all_releases.query.graphql index c69481150e0..7f67f7d11a3 100644 --- a/app/assets/javascripts/releases/graphql/queries/all_releases.query.graphql +++ b/app/assets/javascripts/releases/graphql/queries/all_releases.query.graphql @@ -16,6 +16,7 @@ query allReleasesDeprecated( ) { project(fullPath: $fullPath) { __typename + id releases(first: $first, last: $last, before: $before, after: $after, sort: $sort) { __typename nodes { diff --git a/app/assets/javascripts/releases/graphql/queries/one_release.query.graphql b/app/assets/javascripts/releases/graphql/queries/one_release.query.graphql index c80d6e753ab..dab92d5d41c 100644 --- a/app/assets/javascripts/releases/graphql/queries/one_release.query.graphql +++ b/app/assets/javascripts/releases/graphql/queries/one_release.query.graphql @@ -2,6 +2,7 @@ query oneRelease($fullPath: ID!, $tagName: String!) { project(fullPath: $fullPath) { + id release(tagName: $tagName) { ...Release } diff --git a/app/assets/javascripts/releases/graphql/queries/one_release_for_editing.query.graphql b/app/assets/javascripts/releases/graphql/queries/one_release_for_editing.query.graphql index 767ba4aeca0..962d554303a 100644 --- a/app/assets/javascripts/releases/graphql/queries/one_release_for_editing.query.graphql +++ b/app/assets/javascripts/releases/graphql/queries/one_release_for_editing.query.graphql @@ -2,6 +2,7 @@ query oneReleaseForEditing($fullPath: ID!, $tagName: String!) { project(fullPath: $fullPath) { + id release(tagName: $tagName) { ...ReleaseForEditing } diff --git a/app/assets/javascripts/repository/mutations/lock_path.mutation.graphql b/app/assets/javascripts/repository/mutations/lock_path.mutation.graphql index eaebc4ddf17..0851564bb24 100644 --- a/app/assets/javascripts/repository/mutations/lock_path.mutation.graphql +++ b/app/assets/javascripts/repository/mutations/lock_path.mutation.graphql @@ -4,6 +4,7 @@ mutation toggleLock($projectPath: ID!, $filePath: String!, $lock: Boolean!) { id pathLocks { nodes { + id path } } diff --git a/app/assets/javascripts/repository/queries/blob_info.query.graphql b/app/assets/javascripts/repository/queries/blob_info.query.graphql index 539719175e3..1679d6f9f5d 100644 --- a/app/assets/javascripts/repository/queries/blob_info.query.graphql +++ b/app/assets/javascripts/repository/queries/blob_info.query.graphql @@ -9,6 +9,7 @@ query getBlobInfo($projectPath: ID!, $filePath: String!, $ref: String!) { } pathLocks { nodes { + id path } } @@ -16,6 +17,7 @@ query getBlobInfo($projectPath: ID!, $filePath: String!, $ref: String!) { empty blobs(paths: [$filePath], ref: $ref) { nodes { + id webPath name size diff --git a/app/assets/javascripts/runner/graphql/get_group_runners.query.graphql b/app/assets/javascripts/runner/graphql/get_group_runners.query.graphql index 3e5109b1ac4..6da9e276f74 100644 --- a/app/assets/javascripts/runner/graphql/get_group_runners.query.graphql +++ b/app/assets/javascripts/runner/graphql/get_group_runners.query.graphql @@ -13,6 +13,7 @@ query getGroupRunners( $sort: CiRunnerSort ) { group(fullPath: $groupFullPath) { + id runners( membership: DESCENDANTS before: $before diff --git a/app/assets/javascripts/runner/graphql/get_runner.query.graphql b/app/assets/javascripts/runner/graphql/get_runner.query.graphql index c294cb9bf22..95b3603c1c6 100644 --- a/app/assets/javascripts/runner/graphql/get_runner.query.graphql +++ b/app/assets/javascripts/runner/graphql/get_runner.query.graphql @@ -1,6 +1,9 @@ #import "ee_else_ce/runner/graphql/runner_details.fragment.graphql" query getRunner($id: CiRunnerID!) { + # We have an id in deeply nested fragment + # TODO: Uncomment next line when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75220 is merged and the rule is enabled + # # eslint-disable-next-line @graphql-eslint/require-id-when-available runner(id: $id) { ...RunnerDetails } diff --git a/app/assets/javascripts/runner/graphql/runner_update.mutation.graphql b/app/assets/javascripts/runner/graphql/runner_update.mutation.graphql index ea622fd4958..a493d1a6f68 100644 --- a/app/assets/javascripts/runner/graphql/runner_update.mutation.graphql +++ b/app/assets/javascripts/runner/graphql/runner_update.mutation.graphql @@ -5,6 +5,9 @@ mutation runnerUpdate($input: RunnerUpdateInput!) { runnerUpdate(input: $input) { + # We have an id in deep nested fragment + # TODO: Uncomment next line when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75220 is merged and the rule is enabled + # # eslint-disable-next-line @graphql-eslint/require-id-when-available runner { ...RunnerDetails } diff --git a/app/assets/javascripts/sidebar/components/lock/mutations/update_issue_lock.mutation.graphql b/app/assets/javascripts/sidebar/components/lock/mutations/update_issue_lock.mutation.graphql index 2a1bcdf7136..cb9ee6abc9b 100644 --- a/app/assets/javascripts/sidebar/components/lock/mutations/update_issue_lock.mutation.graphql +++ b/app/assets/javascripts/sidebar/components/lock/mutations/update_issue_lock.mutation.graphql @@ -1,6 +1,7 @@ mutation updateIssueLocked($input: IssueSetLockedInput!) { issueSetLocked(input: $input) { issue { + id discussionLocked } errors diff --git a/app/assets/javascripts/sidebar/components/lock/mutations/update_merge_request_lock.mutation.graphql b/app/assets/javascripts/sidebar/components/lock/mutations/update_merge_request_lock.mutation.graphql index 8590c8e71a6..11eb3611006 100644 --- a/app/assets/javascripts/sidebar/components/lock/mutations/update_merge_request_lock.mutation.graphql +++ b/app/assets/javascripts/sidebar/components/lock/mutations/update_merge_request_lock.mutation.graphql @@ -1,6 +1,7 @@ mutation updateMergeRequestLocked($input: MergeRequestSetLockedInput!) { mergeRequestSetLocked(input: $input) { mergeRequest { + id discussionLocked } errors diff --git a/app/assets/javascripts/sidebar/components/severity/graphql/mutations/update_issuable_severity.mutation.graphql b/app/assets/javascripts/sidebar/components/severity/graphql/mutations/update_issuable_severity.mutation.graphql index 750e757971f..c9d36dfdb67 100644 --- a/app/assets/javascripts/sidebar/components/severity/graphql/mutations/update_issuable_severity.mutation.graphql +++ b/app/assets/javascripts/sidebar/components/severity/graphql/mutations/update_issuable_severity.mutation.graphql @@ -3,6 +3,7 @@ mutation updateIssuableSeverity($projectPath: ID!, $severity: IssuableSeverity!, errors issue { iid + id severity } } diff --git a/app/assets/javascripts/sidebar/queries/epic_confidential.query.graphql b/app/assets/javascripts/sidebar/queries/epic_confidential.query.graphql index 7a1fdb40e93..4998b2af666 100644 --- a/app/assets/javascripts/sidebar/queries/epic_confidential.query.graphql +++ b/app/assets/javascripts/sidebar/queries/epic_confidential.query.graphql @@ -1,6 +1,7 @@ query epicConfidential($fullPath: ID!, $iid: ID) { workspace: group(fullPath: $fullPath) { __typename + id issuable: epic(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/epic_due_date.query.graphql b/app/assets/javascripts/sidebar/queries/epic_due_date.query.graphql index f60f44abebd..00529042e92 100644 --- a/app/assets/javascripts/sidebar/queries/epic_due_date.query.graphql +++ b/app/assets/javascripts/sidebar/queries/epic_due_date.query.graphql @@ -1,6 +1,7 @@ query epicDueDate($fullPath: ID!, $iid: ID) { workspace: group(fullPath: $fullPath) { __typename + id issuable: epic(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/epic_participants.query.graphql b/app/assets/javascripts/sidebar/queries/epic_participants.query.graphql index fbebc50ab08..dada7ffc034 100644 --- a/app/assets/javascripts/sidebar/queries/epic_participants.query.graphql +++ b/app/assets/javascripts/sidebar/queries/epic_participants.query.graphql @@ -4,6 +4,7 @@ query epicParticipants($fullPath: ID!, $iid: ID) { workspace: group(fullPath: $fullPath) { __typename + id issuable: epic(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/epic_reference.query.graphql b/app/assets/javascripts/sidebar/queries/epic_reference.query.graphql index bd10f09aed8..f35ca896ef8 100644 --- a/app/assets/javascripts/sidebar/queries/epic_reference.query.graphql +++ b/app/assets/javascripts/sidebar/queries/epic_reference.query.graphql @@ -1,6 +1,7 @@ query epicReference($fullPath: ID!, $iid: ID) { workspace: group(fullPath: $fullPath) { __typename + id issuable: epic(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/epic_start_date.query.graphql b/app/assets/javascripts/sidebar/queries/epic_start_date.query.graphql index c6c24fd3d95..85fc7de8d02 100644 --- a/app/assets/javascripts/sidebar/queries/epic_start_date.query.graphql +++ b/app/assets/javascripts/sidebar/queries/epic_start_date.query.graphql @@ -1,6 +1,7 @@ query epicStartDate($fullPath: ID!, $iid: ID) { workspace: group(fullPath: $fullPath) { __typename + id issuable: epic(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/epic_subscribed.query.graphql b/app/assets/javascripts/sidebar/queries/epic_subscribed.query.graphql index 9f1967e1685..a8fe6b8ddc3 100644 --- a/app/assets/javascripts/sidebar/queries/epic_subscribed.query.graphql +++ b/app/assets/javascripts/sidebar/queries/epic_subscribed.query.graphql @@ -1,6 +1,7 @@ query epicSubscribed($fullPath: ID!, $iid: ID) { workspace: group(fullPath: $fullPath) { __typename + id emailsDisabled issuable: epic(iid: $iid) { __typename diff --git a/app/assets/javascripts/sidebar/queries/epic_todo.query.graphql b/app/assets/javascripts/sidebar/queries/epic_todo.query.graphql index 1e6f9bad5b2..b0ba724e727 100644 --- a/app/assets/javascripts/sidebar/queries/epic_todo.query.graphql +++ b/app/assets/javascripts/sidebar/queries/epic_todo.query.graphql @@ -1,6 +1,7 @@ query epicTodos($fullPath: ID!, $iid: ID) { workspace: group(fullPath: $fullPath) { __typename + id issuable: epic(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/issuable_assignees.subscription.graphql b/app/assets/javascripts/sidebar/queries/issuable_assignees.subscription.graphql index 47ce094418c..a58a04d87c4 100644 --- a/app/assets/javascripts/sidebar/queries/issuable_assignees.subscription.graphql +++ b/app/assets/javascripts/sidebar/queries/issuable_assignees.subscription.graphql @@ -3,6 +3,7 @@ subscription issuableAssigneesUpdated($issuableId: IssuableID!) { issuableAssigneesUpdated(issuableId: $issuableId) { ... on Issue { + id assignees { nodes { ...User diff --git a/app/assets/javascripts/sidebar/queries/issue_confidential.query.graphql b/app/assets/javascripts/sidebar/queries/issue_confidential.query.graphql index 92cabf46af7..e578cf3bda5 100644 --- a/app/assets/javascripts/sidebar/queries/issue_confidential.query.graphql +++ b/app/assets/javascripts/sidebar/queries/issue_confidential.query.graphql @@ -1,6 +1,7 @@ query issueConfidential($fullPath: ID!, $iid: String) { workspace: project(fullPath: $fullPath) { __typename + id issuable: issue(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/issue_due_date.query.graphql b/app/assets/javascripts/sidebar/queries/issue_due_date.query.graphql index 6d3f782bd0a..48cbff252b3 100644 --- a/app/assets/javascripts/sidebar/queries/issue_due_date.query.graphql +++ b/app/assets/javascripts/sidebar/queries/issue_due_date.query.graphql @@ -1,6 +1,7 @@ query issueDueDate($fullPath: ID!, $iid: String) { workspace: project(fullPath: $fullPath) { __typename + id issuable: issue(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/issue_reference.query.graphql b/app/assets/javascripts/sidebar/queries/issue_reference.query.graphql index db4f58a4f69..c3128d6d961 100644 --- a/app/assets/javascripts/sidebar/queries/issue_reference.query.graphql +++ b/app/assets/javascripts/sidebar/queries/issue_reference.query.graphql @@ -1,5 +1,6 @@ query issueReference($fullPath: ID!, $iid: String) { workspace: project(fullPath: $fullPath) { + id __typename issuable: issue(iid: $iid) { __typename diff --git a/app/assets/javascripts/sidebar/queries/issue_subscribed.query.graphql b/app/assets/javascripts/sidebar/queries/issue_subscribed.query.graphql index 7d38b5d3bd8..e2722fc86a4 100644 --- a/app/assets/javascripts/sidebar/queries/issue_subscribed.query.graphql +++ b/app/assets/javascripts/sidebar/queries/issue_subscribed.query.graphql @@ -1,6 +1,7 @@ query issueSubscribed($fullPath: ID!, $iid: String) { workspace: project(fullPath: $fullPath) { __typename + id issuable: issue(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/issue_time_tracking.query.graphql b/app/assets/javascripts/sidebar/queries/issue_time_tracking.query.graphql index 7ac989b5c63..059361dd370 100644 --- a/app/assets/javascripts/sidebar/queries/issue_time_tracking.query.graphql +++ b/app/assets/javascripts/sidebar/queries/issue_time_tracking.query.graphql @@ -1,6 +1,7 @@ query issueTimeTracking($fullPath: ID!, $iid: String) { workspace: project(fullPath: $fullPath) { __typename + id issuable: issue(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/issue_todo.query.graphql b/app/assets/javascripts/sidebar/queries/issue_todo.query.graphql index 783d36352fe..5cd5d81c439 100644 --- a/app/assets/javascripts/sidebar/queries/issue_todo.query.graphql +++ b/app/assets/javascripts/sidebar/queries/issue_todo.query.graphql @@ -1,6 +1,7 @@ query issueTodos($fullPath: ID!, $iid: String!) { workspace: project(fullPath: $fullPath) { __typename + id issuable: issue(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/merge_request_milestone.query.graphql b/app/assets/javascripts/sidebar/queries/merge_request_milestone.query.graphql index 5c0edf5acee..b0a16677cf2 100644 --- a/app/assets/javascripts/sidebar/queries/merge_request_milestone.query.graphql +++ b/app/assets/javascripts/sidebar/queries/merge_request_milestone.query.graphql @@ -3,6 +3,7 @@ query mergeRequestMilestone($fullPath: ID!, $iid: String!) { workspace: project(fullPath: $fullPath) { __typename + id issuable: mergeRequest(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/merge_request_reference.query.graphql b/app/assets/javascripts/sidebar/queries/merge_request_reference.query.graphql index 7979a1ccb3e..7c78f812b67 100644 --- a/app/assets/javascripts/sidebar/queries/merge_request_reference.query.graphql +++ b/app/assets/javascripts/sidebar/queries/merge_request_reference.query.graphql @@ -1,6 +1,7 @@ query mergeRequestReference($fullPath: ID!, $iid: String!) { workspace: project(fullPath: $fullPath) { __typename + id issuable: mergeRequest(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/merge_request_subscribed.query.graphql b/app/assets/javascripts/sidebar/queries/merge_request_subscribed.query.graphql index 3b54a2e529b..d5e27ca7b69 100644 --- a/app/assets/javascripts/sidebar/queries/merge_request_subscribed.query.graphql +++ b/app/assets/javascripts/sidebar/queries/merge_request_subscribed.query.graphql @@ -1,6 +1,7 @@ query mergeRequestSubscribed($fullPath: ID!, $iid: String!) { workspace: project(fullPath: $fullPath) { __typename + id issuable: mergeRequest(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/merge_request_time_tracking.query.graphql b/app/assets/javascripts/sidebar/queries/merge_request_time_tracking.query.graphql index b1ab1bcbe87..d480ff3d5ba 100644 --- a/app/assets/javascripts/sidebar/queries/merge_request_time_tracking.query.graphql +++ b/app/assets/javascripts/sidebar/queries/merge_request_time_tracking.query.graphql @@ -1,6 +1,7 @@ query mergeRequestTimeTracking($fullPath: ID!, $iid: String!) { workspace: project(fullPath: $fullPath) { __typename + id issuable: mergeRequest(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/merge_request_todo.query.graphql b/app/assets/javascripts/sidebar/queries/merge_request_todo.query.graphql index 93a1c9ea925..65b9ef45260 100644 --- a/app/assets/javascripts/sidebar/queries/merge_request_todo.query.graphql +++ b/app/assets/javascripts/sidebar/queries/merge_request_todo.query.graphql @@ -1,6 +1,7 @@ query mergeRequestTodos($fullPath: ID!, $iid: String!) { workspace: project(fullPath: $fullPath) { __typename + id issuable: mergeRequest(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/project_issue_milestone.query.graphql b/app/assets/javascripts/sidebar/queries/project_issue_milestone.query.graphql index 2bc42a0b011..c7f3adc9aca 100644 --- a/app/assets/javascripts/sidebar/queries/project_issue_milestone.query.graphql +++ b/app/assets/javascripts/sidebar/queries/project_issue_milestone.query.graphql @@ -3,6 +3,7 @@ query projectIssueMilestone($fullPath: ID!, $iid: String!) { workspace: project(fullPath: $fullPath) { __typename + id issuable: issue(iid: $iid) { __typename id diff --git a/app/assets/javascripts/sidebar/queries/project_milestones.query.graphql b/app/assets/javascripts/sidebar/queries/project_milestones.query.graphql index a3ab1ebc872..d9eab18628d 100644 --- a/app/assets/javascripts/sidebar/queries/project_milestones.query.graphql +++ b/app/assets/javascripts/sidebar/queries/project_milestones.query.graphql @@ -3,6 +3,7 @@ query projectMilestones($fullPath: ID!, $title: String, $state: MilestoneStateEnum) { workspace: project(fullPath: $fullPath) { __typename + id attributes: milestones( searchTitle: $title state: $state diff --git a/app/assets/javascripts/sidebar/queries/sidebarDetails.query.graphql b/app/assets/javascripts/sidebar/queries/sidebarDetails.query.graphql index dd85eb1631b..90d1a7794ea 100644 --- a/app/assets/javascripts/sidebar/queries/sidebarDetails.query.graphql +++ b/app/assets/javascripts/sidebar/queries/sidebarDetails.query.graphql @@ -1,6 +1,8 @@ query sidebarDetails($fullPath: ID!, $iid: String!) { project(fullPath: $fullPath) { + id issue(iid: $iid) { + id iid } } diff --git a/app/assets/javascripts/sidebar/queries/sidebarDetailsMR.query.graphql b/app/assets/javascripts/sidebar/queries/sidebarDetailsMR.query.graphql index 02498b18832..0505f88773d 100644 --- a/app/assets/javascripts/sidebar/queries/sidebarDetailsMR.query.graphql +++ b/app/assets/javascripts/sidebar/queries/sidebarDetailsMR.query.graphql @@ -1,6 +1,8 @@ query mergeRequestSidebarDetails($fullPath: ID!, $iid: String!) { project(fullPath: $fullPath) { + id mergeRequest(iid: $iid) { + id iid # currently unused. } } diff --git a/app/assets/javascripts/sidebar/queries/update_epic_title.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_epic_title.mutation.graphql index 2e6bc8c36ba..809cb2c9f76 100644 --- a/app/assets/javascripts/sidebar/queries/update_epic_title.mutation.graphql +++ b/app/assets/javascripts/sidebar/queries/update_epic_title.mutation.graphql @@ -1,6 +1,7 @@ mutation updateEpicTitle($input: UpdateEpicInput!) { updateIssuableTitle: updateEpic(input: $input) { epic { + id title } errors diff --git a/app/assets/javascripts/snippets/fragments/project.fragment.graphql b/app/assets/javascripts/snippets/fragments/project.fragment.graphql deleted file mode 100644 index 64bb2315c1b..00000000000 --- a/app/assets/javascripts/snippets/fragments/project.fragment.graphql +++ /dev/null @@ -1,6 +0,0 @@ -fragment SnippetProject on Snippet { - project { - fullPath - webUrl - } -} diff --git a/app/assets/javascripts/snippets/mutations/createSnippet.mutation.graphql b/app/assets/javascripts/snippets/mutations/createSnippet.mutation.graphql index f688868d1b9..8640c4725f4 100644 --- a/app/assets/javascripts/snippets/mutations/createSnippet.mutation.graphql +++ b/app/assets/javascripts/snippets/mutations/createSnippet.mutation.graphql @@ -2,6 +2,7 @@ mutation CreateSnippet($input: CreateSnippetInput!) { createSnippet(input: $input) { errors snippet { + id webUrl } } diff --git a/app/assets/javascripts/snippets/mutations/updateSnippet.mutation.graphql b/app/assets/javascripts/snippets/mutations/updateSnippet.mutation.graphql index 548725f7357..99242c5d500 100644 --- a/app/assets/javascripts/snippets/mutations/updateSnippet.mutation.graphql +++ b/app/assets/javascripts/snippets/mutations/updateSnippet.mutation.graphql @@ -2,6 +2,7 @@ mutation UpdateSnippet($input: UpdateSnippetInput!) { updateSnippet(input: $input) { errors snippet { + id webUrl } } diff --git a/app/assets/javascripts/static_site_editor/graphql/queries/source_content.query.graphql b/app/assets/javascripts/static_site_editor/graphql/queries/source_content.query.graphql index cfe30c601ed..c8c4195e1cd 100644 --- a/app/assets/javascripts/static_site_editor/graphql/queries/source_content.query.graphql +++ b/app/assets/javascripts/static_site_editor/graphql/queries/source_content.query.graphql @@ -1,5 +1,6 @@ query sourceContent($project: ID!, $sourcePath: String!) { project(fullPath: $project) { + id fullPath file(path: $sourcePath) @client { title diff --git a/app/assets/javascripts/terraform/graphql/fragments/state_version.fragment.graphql b/app/assets/javascripts/terraform/graphql/fragments/state_version.fragment.graphql index 70ba5c960be..bb1e7195b17 100644 --- a/app/assets/javascripts/terraform/graphql/fragments/state_version.fragment.graphql +++ b/app/assets/javascripts/terraform/graphql/fragments/state_version.fragment.graphql @@ -1,23 +1,23 @@ #import "~/graphql_shared/fragments/user.fragment.graphql" fragment StateVersion on TerraformStateVersion { + id downloadPath serial updatedAt - createdByUser { ...User } - job { + id detailedStatus { + id detailsPath group icon label text } - pipeline { id path diff --git a/app/assets/javascripts/terraform/graphql/queries/get_states.query.graphql b/app/assets/javascripts/terraform/graphql/queries/get_states.query.graphql index 9453e32b1b5..4d26ea88ddf 100644 --- a/app/assets/javascripts/terraform/graphql/queries/get_states.query.graphql +++ b/app/assets/javascripts/terraform/graphql/queries/get_states.query.graphql @@ -3,13 +3,12 @@ query getStates($projectPath: ID!, $first: Int, $last: Int, $before: String, $after: String) { project(fullPath: $projectPath) { + id terraformStates(first: $first, last: $last, before: $before, after: $after) { count - nodes { ...State } - pageInfo { ...PageInfo } diff --git a/app/assets/javascripts/token_access/graphql/queries/get_ci_job_token_scope.query.graphql b/app/assets/javascripts/token_access/graphql/queries/get_ci_job_token_scope.query.graphql index d4f559c3701..0e5334b468f 100644 --- a/app/assets/javascripts/token_access/graphql/queries/get_ci_job_token_scope.query.graphql +++ b/app/assets/javascripts/token_access/graphql/queries/get_ci_job_token_scope.query.graphql @@ -1,5 +1,6 @@ query getCIJobTokenScope($fullPath: ID!) { project(fullPath: $fullPath) { + id ciCdSettings { jobTokenScopeEnabled } diff --git a/app/assets/javascripts/token_access/graphql/queries/get_projects_with_ci_job_token_scope.query.graphql b/app/assets/javascripts/token_access/graphql/queries/get_projects_with_ci_job_token_scope.query.graphql index bec0710a1dd..664991bc110 100644 --- a/app/assets/javascripts/token_access/graphql/queries/get_projects_with_ci_job_token_scope.query.graphql +++ b/app/assets/javascripts/token_access/graphql/queries/get_projects_with_ci_job_token_scope.query.graphql @@ -1,8 +1,10 @@ query getProjectsWithCIJobTokenScope($fullPath: ID!) { project(fullPath: $fullPath) { + id ciJobTokenScope { projects { nodes { + id name fullPath } diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/issues.query.graphql b/app/assets/javascripts/vue_merge_request_widget/extensions/issues.query.graphql index 690f571c083..5c54560bd02 100644 --- a/app/assets/javascripts/vue_merge_request_widget/extensions/issues.query.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/extensions/issues.query.graphql @@ -1,5 +1,6 @@ query getAllIssues($projectPath: ID!) { project(fullPath: $projectPath) { + id issues { nodes { id diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/issues_collapsed.query.graphql b/app/assets/javascripts/vue_merge_request_widget/extensions/issues_collapsed.query.graphql index da1cace4598..bf278e1ea85 100644 --- a/app/assets/javascripts/vue_merge_request_widget/extensions/issues_collapsed.query.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/extensions/issues_collapsed.query.graphql @@ -1,5 +1,6 @@ query getProjectIssues($projectPath: ID!) { project(fullPath: $projectPath) { + id issues { count } diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/get_state.query.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/get_state.query.graphql index bfb1517be81..0b8396b4461 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/get_state.query.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/get_state.query.graphql @@ -1,9 +1,11 @@ query getState($projectPath: ID!, $iid: String!) { project(fullPath: $projectPath) { + id archived onlyAllowMergeIfPipelineSucceeds mergeRequest(iid: $iid) { + id autoMergeEnabled commitCount conflicts diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/permissions.query.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/permissions.query.graphql index ae2a67440fe..7ca3ff39fbe 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/permissions.query.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/permissions.query.graphql @@ -1,6 +1,8 @@ query userPermissionsQuery($projectPath: ID!, $iid: String!) { project(fullPath: $projectPath) { + id mergeRequest(iid: $iid) { + id userPermissions { canMerge pushToSourceBranch diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_enabled.fragment.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_enabled.fragment.graphql index ad715599eb1..fc25e699e39 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_enabled.fragment.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_enabled.fragment.graphql @@ -1,4 +1,5 @@ fragment autoMergeEnabled on MergeRequest { + id autoMergeStrategy mergeUser { id diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_enabled.query.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_enabled.query.graphql index e0215fbd969..2d79d35cf24 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_enabled.query.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_enabled.query.graphql @@ -2,6 +2,7 @@ query autoMergeEnabled($projectPath: ID!, $iid: String!) { project(fullPath: $projectPath) { + id mergeRequest(iid: $iid) { ...autoMergeEnabled } diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_failed.query.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_failed.query.graphql index 2fe0d174b67..da8aeab9dcb 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_failed.query.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_failed.query.graphql @@ -1,6 +1,8 @@ query autoMergeFailedQuery($projectPath: ID!, $iid: String!) { project(fullPath: $projectPath) { + id mergeRequest(iid: $iid) { + id mergeError } } diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/states/conflicts.query.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/states/conflicts.query.graphql index e66ac01ab12..faf21b28f86 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/states/conflicts.query.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/states/conflicts.query.graphql @@ -1,6 +1,8 @@ query workInProgress($projectPath: ID!, $iid: String!) { project(fullPath: $projectPath) { + id mergeRequest(iid: $iid) { + id shouldBeRebased sourceBranchProtected } diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/states/draft.query.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/states/draft.query.graphql index 0983c28448e..54f2233439f 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/states/draft.query.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/states/draft.query.graphql @@ -1,6 +1,8 @@ query mrUserPermission($projectPath: ID!, $iid: String!) { project(fullPath: $projectPath) { + id mergeRequest(iid: $iid) { + id userPermissions { updateMergeRequest } diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/states/missing_branch.query.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/states/missing_branch.query.graphql index ea95218aec6..4d87d55f671 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/states/missing_branch.query.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/states/missing_branch.query.graphql @@ -1,6 +1,8 @@ query missingBranchQuery($projectPath: ID!, $iid: String!) { project(fullPath: $projectPath) { + id mergeRequest(iid: $iid) { + id sourceBranchExists } } diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/states/new_ready_to_merge.query.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/states/new_ready_to_merge.query.graphql index 21c3ffd8321..73c9e77b7bc 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/states/new_ready_to_merge.query.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/states/new_ready_to_merge.query.graphql @@ -1,6 +1,8 @@ query getReadyToMergeStatus($projectPath: ID!, $iid: String!) { project(fullPath: $projectPath) { + id mergeRequest(iid: $iid) { + id userPermissions { canMerge } diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/states/ready_to_merge.fragment.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/states/ready_to_merge.fragment.graphql index b2a1be5c5a9..d85794f7245 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/states/ready_to_merge.fragment.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/states/ready_to_merge.fragment.graphql @@ -1,8 +1,10 @@ fragment ReadyToMerge on Project { + id onlyAllowMergeIfPipelineSucceeds mergeRequestsFfOnlyEnabled squashReadOnly mergeRequest(iid: $iid) { + id autoMergeEnabled shouldRemoveSourceBranch forceRemoveSourceBranch @@ -26,6 +28,7 @@ fragment ReadyToMerge on Project { mergeError commitsWithoutMergeCommits { nodes { + id sha shortId title diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/states/rebase.query.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/states/rebase.query.graphql index a8c7d2610bf..283177267d4 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/states/rebase.query.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/states/rebase.query.graphql @@ -1,6 +1,8 @@ query rebaseQuery($projectPath: ID!, $iid: String!) { project(fullPath: $projectPath) { + id mergeRequest(iid: $iid) { + id rebaseInProgress targetBranch userPermissions { diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/toggle_draft.mutation.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/toggle_draft.mutation.graphql index 200fb1b7ca5..022629bb802 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/toggle_draft.mutation.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/toggle_draft.mutation.graphql @@ -1,6 +1,7 @@ mutation toggleDraftStatus($projectPath: ID!, $iid: String!, $draft: Boolean!) { mergeRequestSetDraft(input: { projectPath: $projectPath, iid: $iid, draft: $draft }) { mergeRequest { + id mergeableDiscussionsState title draft diff --git a/app/assets/javascripts/vue_shared/alert_details/graphql/mutations/alert_issue_create.mutation.graphql b/app/assets/javascripts/vue_shared/alert_details/graphql/mutations/alert_issue_create.mutation.graphql index f0095abfca1..0460d250f75 100644 --- a/app/assets/javascripts/vue_shared/alert_details/graphql/mutations/alert_issue_create.mutation.graphql +++ b/app/assets/javascripts/vue_shared/alert_details/graphql/mutations/alert_issue_create.mutation.graphql @@ -2,6 +2,7 @@ mutation createAlertIssue($projectPath: ID!, $iid: String!) { createAlertIssue(input: { iid: $iid, projectPath: $projectPath }) { errors issue { + id iid webUrl } diff --git a/app/assets/javascripts/vue_shared/alert_details/graphql/queries/alert_sidebar_details.query.graphql b/app/assets/javascripts/vue_shared/alert_details/graphql/queries/alert_sidebar_details.query.graphql index 0c26fcc0ab2..0ea209ffd39 100644 --- a/app/assets/javascripts/vue_shared/alert_details/graphql/queries/alert_sidebar_details.query.graphql +++ b/app/assets/javascripts/vue_shared/alert_details/graphql/queries/alert_sidebar_details.query.graphql @@ -3,6 +3,7 @@ query alertDetailsAssignees($fullPath: ID!, $alertId: String) { project(fullPath: $fullPath) { + id alertManagementAlerts(iid: $alertId) { nodes { ...AlertDetailItem diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/epic_labels.query.graphql b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/epic_labels.query.graphql index c130cc426dc..c442c17eb88 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/epic_labels.query.graphql +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/epic_labels.query.graphql @@ -2,6 +2,7 @@ query epicLabels($fullPath: ID!, $iid: ID) { workspace: group(fullPath: $fullPath) { + id issuable: epic(iid: $iid) { id labels { diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/issue_labels.query.graphql b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/issue_labels.query.graphql index e471d279b24..2904857270e 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/issue_labels.query.graphql +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/issue_labels.query.graphql @@ -2,6 +2,7 @@ query issueLabels($fullPath: ID!, $iid: String) { workspace: project(fullPath: $fullPath) { + id issuable: issue(iid: $iid) { id labels { diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/merge_request_labels.query.graphql b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/merge_request_labels.query.graphql index dd80e89c8a7..e0cdfd91658 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/merge_request_labels.query.graphql +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/merge_request_labels.query.graphql @@ -2,6 +2,7 @@ query mergeRequestLabels($fullPath: ID!, $iid: String!) { workspace: project(fullPath: $fullPath) { + id issuable: mergeRequest(iid: $iid) { id labels { diff --git a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_alert_assignees.query.graphql b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_alert_assignees.query.graphql index d99fc125012..bb6c7181e5c 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_alert_assignees.query.graphql +++ b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_alert_assignees.query.graphql @@ -7,6 +7,7 @@ query alertAssignees( $iid: String! ) { workspace: project(fullPath: $fullPath) { + id issuable: alertManagementAlert(domain: $domain, iid: $iid) { iid assignees { diff --git a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_issue_assignees.query.graphql b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_issue_assignees.query.graphql index 93b9833bb7d..be270e440ed 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_issue_assignees.query.graphql +++ b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_issue_assignees.query.graphql @@ -4,6 +4,7 @@ query issueAssignees($fullPath: ID!, $iid: String!) { workspace: project(fullPath: $fullPath) { __typename + id issuable: issue(iid: $iid) { __typename id diff --git a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_issue_participants.query.graphql b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_issue_participants.query.graphql index 48787305459..96a40e597ee 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_issue_participants.query.graphql +++ b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_issue_participants.query.graphql @@ -4,6 +4,7 @@ query issueParticipants($fullPath: ID!, $iid: String!) { workspace: project(fullPath: $fullPath) { __typename + id issuable: issue(iid: $iid) { __typename id diff --git a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_mr_assignees.query.graphql b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_mr_assignees.query.graphql index 53f7381760e..81e19e48d75 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_mr_assignees.query.graphql +++ b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_mr_assignees.query.graphql @@ -3,6 +3,7 @@ query getMrAssignees($fullPath: ID!, $iid: String!) { workspace: project(fullPath: $fullPath) { + id issuable: mergeRequest(iid: $iid) { id assignees { diff --git a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_mr_participants.query.graphql b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_mr_participants.query.graphql index 6adbd4098f2..3496d5f4a2e 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_mr_participants.query.graphql +++ b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_mr_participants.query.graphql @@ -3,6 +3,7 @@ query getMrParticipants($fullPath: ID!, $iid: String!) { workspace: project(fullPath: $fullPath) { + id issuable: mergeRequest(iid: $iid) { id participants { diff --git a/app/assets/javascripts/vue_shared/security_reports/graphql/fragments/job_artifacts.fragment.graphql b/app/assets/javascripts/vue_shared/security_reports/graphql/fragments/job_artifacts.fragment.graphql index ae77a2ce5e4..829b9d9f9d8 100644 --- a/app/assets/javascripts/vue_shared/security_reports/graphql/fragments/job_artifacts.fragment.graphql +++ b/app/assets/javascripts/vue_shared/security_reports/graphql/fragments/job_artifacts.fragment.graphql @@ -1,6 +1,8 @@ fragment JobArtifacts on Pipeline { + id jobs(securityReportTypes: $reportTypes) { nodes { + id name artifacts { nodes { diff --git a/app/assets/javascripts/vue_shared/security_reports/graphql/queries/security_report_merge_request_download_paths.query.graphql b/app/assets/javascripts/vue_shared/security_reports/graphql/queries/security_report_merge_request_download_paths.query.graphql index 4ce13827da2..2e80db30e9a 100644 --- a/app/assets/javascripts/vue_shared/security_reports/graphql/queries/security_report_merge_request_download_paths.query.graphql +++ b/app/assets/javascripts/vue_shared/security_reports/graphql/queries/security_report_merge_request_download_paths.query.graphql @@ -4,11 +4,14 @@ query securityReportDownloadPaths( $reportTypes: [SecurityReportTypeEnum!] ) { project(fullPath: $projectPath) { + id mergeRequest(iid: $iid) { + id headPipeline { id jobs(securityReportTypes: $reportTypes) { nodes { + id name artifacts { nodes { diff --git a/app/assets/javascripts/vue_shared/security_reports/graphql/queries/security_report_pipeline_download_paths.query.graphql b/app/assets/javascripts/vue_shared/security_reports/graphql/queries/security_report_pipeline_download_paths.query.graphql index e1f3c55a886..e4f0c392b91 100644 --- a/app/assets/javascripts/vue_shared/security_reports/graphql/queries/security_report_pipeline_download_paths.query.graphql +++ b/app/assets/javascripts/vue_shared/security_reports/graphql/queries/security_report_pipeline_download_paths.query.graphql @@ -2,8 +2,8 @@ query getPipelineCorpuses($projectPath: ID!, $iid: ID, $reportTypes: [SecurityReportTypeEnum!]) { project(fullPath: $projectPath) { + id pipeline(iid: $iid) { - id ...JobArtifacts } } diff --git a/app/assets/stylesheets/lazy_bundles/select2_overrides.scss b/app/assets/stylesheets/lazy_bundles/select2_overrides.scss index 3e5271f84d5..2c5ea8347ae 100644 --- a/app/assets/stylesheets/lazy_bundles/select2_overrides.scss +++ b/app/assets/stylesheets/lazy_bundles/select2_overrides.scss @@ -326,10 +326,6 @@ } } -.transfer-project .select2-container { - min-width: 200px; -} - .right-sidebar { .block { .select2-container span { diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 17d4a449d4e..b617ec7bda5 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -126,6 +126,8 @@ class ProjectsController < Projects::ApplicationController if ::Projects::UnlinkForkService.new(@project, current_user).execute flash[:notice] = _('The fork relationship has been removed.') end + + redirect_to edit_project_path(@project) end def activity diff --git a/app/finders/user_group_notification_settings_finder.rb b/app/finders/user_group_notification_settings_finder.rb index 4ad9d1d7bf4..c2af581dd14 100644 --- a/app/finders/user_group_notification_settings_finder.rb +++ b/app/finders/user_group_notification_settings_finder.rb @@ -8,7 +8,12 @@ class UserGroupNotificationSettingsFinder def execute # rubocop: disable CodeReuse/ActiveRecord - groups_with_ancestors = Gitlab::ObjectHierarchy.new(Group.where(id: groups.select(:id))).base_and_ancestors + selected_groups = Group.where(id: groups.select(:id)) + groups_with_ancestors = if Feature.enabled?(:linear_user_group_notification_settings_finder_ancestors_scopes, user, default_enabled: :yaml) + selected_groups.self_and_ancestors + else + Gitlab::ObjectHierarchy.new(selected_groups).base_and_ancestors + end # rubocop: enable CodeReuse/ActiveRecord @loaded_groups_with_ancestors = groups_with_ancestors.index_by(&:id) diff --git a/app/graphql/queries/container_registry/get_container_repositories.query.graphql b/app/graphql/queries/container_registry/get_container_repositories.query.graphql index df0b590acac..40e2934a038 100644 --- a/app/graphql/queries/container_registry/get_container_repositories.query.graphql +++ b/app/graphql/queries/container_registry/get_container_repositories.query.graphql @@ -10,6 +10,7 @@ query getProjectContainerRepositories( ) { project(fullPath: $fullPath) @skip(if: $isGroupPage) { __typename + id containerRepositoriesCount containerRepositories( name: $name @@ -43,6 +44,7 @@ query getProjectContainerRepositories( } group(fullPath: $fullPath) @include(if: $isGroupPage) { __typename + id containerRepositoriesCount containerRepositories( name: $name diff --git a/app/graphql/queries/design_management/design_permissions.query.graphql b/app/graphql/queries/design_management/design_permissions.query.graphql index 55dfa35129c..a81afd47625 100644 --- a/app/graphql/queries/design_management/design_permissions.query.graphql +++ b/app/graphql/queries/design_management/design_permissions.query.graphql @@ -4,6 +4,7 @@ query permissions($fullPath: ID!, $iid: String!) { id issue(iid: $iid) { __typename + id userPermissions { __typename createDesign diff --git a/app/graphql/queries/design_management/get_design_list.query.graphql b/app/graphql/queries/design_management/get_design_list.query.graphql index 01503a9572f..f0caa7c5b4c 100644 --- a/app/graphql/queries/design_management/get_design_list.query.graphql +++ b/app/graphql/queries/design_management/get_design_list.query.graphql @@ -4,6 +4,7 @@ query getDesignList($fullPath: ID!, $iid: String!, $atVersion: ID) { id issue(iid: $iid) { __typename + id designCollection { __typename copyState diff --git a/app/graphql/queries/epic/epic_children.query.graphql b/app/graphql/queries/epic/epic_children.query.graphql index be82813dddb..9e76af48152 100644 --- a/app/graphql/queries/epic/epic_children.query.graphql +++ b/app/graphql/queries/epic/epic_children.query.graphql @@ -47,6 +47,7 @@ fragment EpicNode on Epic { hasIssues group { __typename + id fullPath } } @@ -70,6 +71,9 @@ query childItems( __typename edges { __typename + # We have an id in deeply nested fragment + # TODO: Uncomment next line when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75220 is merged and the rule is enabled + # # eslint-disable-next-line @graphql-eslint/require-id-when-available node { __typename ...EpicNode @@ -86,6 +90,7 @@ query childItems( __typename node { __typename + id iid epicIssueId title @@ -106,6 +111,7 @@ query childItems( __typename node { __typename + id webUrl name username @@ -115,6 +121,7 @@ query childItems( } milestone { __typename + id title startDate dueDate diff --git a/app/graphql/queries/epic/epic_details.query.graphql b/app/graphql/queries/epic/epic_details.query.graphql index 406d630b180..eb4757a845a 100644 --- a/app/graphql/queries/epic/epic_details.query.graphql +++ b/app/graphql/queries/epic/epic_details.query.graphql @@ -1,14 +1,17 @@ query epicDetails($fullPath: ID!, $iid: ID!) { group(fullPath: $fullPath) { __typename + id epic(iid: $iid) { __typename + id participants { __typename edges { __typename node { __typename + id name avatarUrl webUrl diff --git a/app/graphql/queries/pipelines/get_pipeline_details.query.graphql b/app/graphql/queries/pipelines/get_pipeline_details.query.graphql index 4e4caa1e27c..dd5c9e07488 100644 --- a/app/graphql/queries/pipelines/get_pipeline_details.query.graphql +++ b/app/graphql/queries/pipelines/get_pipeline_details.query.graphql @@ -5,16 +5,19 @@ fragment LinkedPipelineData on Pipeline { path status: detailedStatus { __typename + id group label icon } sourceJob { __typename + id name } project { __typename + id name fullPath } @@ -23,6 +26,7 @@ fragment LinkedPipelineData on Pipeline { query getPipelineDetails($projectPath: ID!, $iid: ID!) { project(fullPath: $projectPath) { __typename + id pipeline(iid: $iid) { __typename id @@ -45,11 +49,14 @@ query getPipelineDetails($projectPath: ID!, $iid: ID!) { __typename nodes { __typename + id name status: detailedStatus { __typename + id action { __typename + id icon path title @@ -59,8 +66,10 @@ query getPipelineDetails($projectPath: ID!, $iid: ID!) { __typename nodes { __typename + id status: detailedStatus { __typename + id label group icon @@ -71,17 +80,20 @@ query getPipelineDetails($projectPath: ID!, $iid: ID!) { __typename nodes { __typename + id name scheduledAt needs { __typename nodes { __typename + id name } } status: detailedStatus { __typename + id icon tooltip hasDetails @@ -89,6 +101,7 @@ query getPipelineDetails($projectPath: ID!, $iid: ID!) { group action { __typename + id buttonTitle icon path diff --git a/app/graphql/queries/releases/all_releases.query.graphql b/app/graphql/queries/releases/all_releases.query.graphql index ab8cbcb8aa3..150f59832f3 100644 --- a/app/graphql/queries/releases/all_releases.query.graphql +++ b/app/graphql/queries/releases/all_releases.query.graphql @@ -11,6 +11,7 @@ query allReleases( ) { project(fullPath: $fullPath) { __typename + id releases(first: $first, last: $last, before: $before, after: $after, sort: $sort) { __typename nodes { @@ -50,6 +51,7 @@ query allReleases( __typename nodes { __typename + id filepath collectedAt sha @@ -67,12 +69,14 @@ query allReleases( } commit { __typename + id sha webUrl title } author { __typename + id webUrl avatarUrl username diff --git a/app/graphql/queries/repository/path_last_commit.query.graphql b/app/graphql/queries/repository/path_last_commit.query.graphql index b5c5f653429..bcb07ae3182 100644 --- a/app/graphql/queries/repository/path_last_commit.query.graphql +++ b/app/graphql/queries/repository/path_last_commit.query.graphql @@ -1,13 +1,14 @@ query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) { project(fullPath: $projectPath) { - id __typename + id repository { __typename tree(path: $path, ref: $ref) { __typename lastCommit { __typename + id sha title titleHtml @@ -19,6 +20,7 @@ query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) { authorGravatar author { __typename + id name avatarUrl webPath @@ -30,8 +32,10 @@ query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) { __typename node { __typename + id detailedStatus { __typename + id detailsPath icon tooltip diff --git a/app/graphql/queries/snippet/project_permissions.query.graphql b/app/graphql/queries/snippet/project_permissions.query.graphql index 0c38e4f8a07..e0de79f4449 100644 --- a/app/graphql/queries/snippet/project_permissions.query.graphql +++ b/app/graphql/queries/snippet/project_permissions.query.graphql @@ -1,6 +1,7 @@ query CanCreateProjectSnippet($fullPath: ID!) { project(fullPath: $fullPath) { __typename + id userPermissions { __typename createSnippet diff --git a/app/graphql/queries/snippet/snippet.query.graphql b/app/graphql/queries/snippet/snippet.query.graphql index ebfc135c51c..24b268ec853 100644 --- a/app/graphql/queries/snippet/snippet.query.graphql +++ b/app/graphql/queries/snippet/snippet.query.graphql @@ -49,6 +49,7 @@ query GetSnippetQuery($ids: [SnippetID!]) { } project { __typename + id fullPath webUrl } diff --git a/app/graphql/queries/snippet/user_permissions.query.graphql b/app/graphql/queries/snippet/user_permissions.query.graphql index a4914189807..4d131c48feb 100644 --- a/app/graphql/queries/snippet/user_permissions.query.graphql +++ b/app/graphql/queries/snippet/user_permissions.query.graphql @@ -1,6 +1,7 @@ query CanCreatePersonalSnippet { currentUser { __typename + id userPermissions { __typename createSnippet diff --git a/app/graphql/resolvers/container_repository_tags_resolver.rb b/app/graphql/resolvers/container_repository_tags_resolver.rb new file mode 100644 index 00000000000..55a83dd49da --- /dev/null +++ b/app/graphql/resolvers/container_repository_tags_resolver.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module Resolvers + class ContainerRepositoryTagsResolver < BaseResolver + type Types::ContainerRepositoryTagType.connection_type, null: true + + argument :sort, Types::ContainerRepositoryTagsSortEnum, + description: 'Sort tags by these criteria.', + required: false, + default_value: nil + + argument :name, GraphQL::Types::String, + description: 'Search by tag name.', + required: false, + default_value: nil + + def resolve(sort:, **filters) + result = tags + + if filters[:name] + result = tags.filter do |tag| + tag.name.include?(filters[:name]) + end + end + + result = sort_tags(result, sort) if sort + result + end + + private + + def sort_tags(to_be_sorted, sort) + raise StandardError unless Types::ContainerRepositoryTagsSortEnum.enum.include?(sort) + + sort_value, _, direction = sort.to_s.rpartition('_') + + sorted = to_be_sorted.sort_by(&sort_value.to_sym) + return sorted.reverse if direction == 'desc' + + sorted + end + + def tags + object.tags + rescue Faraday::Error + raise ::Gitlab::Graphql::Errors::ResourceNotAvailable, "Can't connect to the Container Registry. If this error persists, please review the troubleshooting documentation." + end + end +end diff --git a/app/graphql/types/container_repository_details_type.rb b/app/graphql/types/container_repository_details_type.rb index 8190cc9bc25..e713aaebe36 100644 --- a/app/graphql/types/container_repository_details_type.rb +++ b/app/graphql/types/container_repository_details_type.rb @@ -12,16 +12,11 @@ module Types Types::ContainerRepositoryTagType.connection_type, null: true, description: 'Tags of the container repository.', - max_page_size: 20 + max_page_size: 20, + resolver: Resolvers::ContainerRepositoryTagsResolver def can_delete Ability.allowed?(current_user, :destroy_container_image, object) end - - def tags - object.tags - rescue Faraday::Error - raise ::Gitlab::Graphql::Errors::ResourceNotAvailable, 'We are having trouble connecting to the Container Registry. If this error persists, please review the troubleshooting documentation.' - end end end diff --git a/app/graphql/types/container_repository_tags_sort_enum.rb b/app/graphql/types/container_repository_tags_sort_enum.rb new file mode 100644 index 00000000000..253cffd9a8c --- /dev/null +++ b/app/graphql/types/container_repository_tags_sort_enum.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Types + class ContainerRepositoryTagsSortEnum < BaseEnum + graphql_name 'ContainerRepositoryTagSort' + description 'Values for sorting tags' + + value 'NAME_ASC', 'Ordered by name in ascending order.', value: :name_asc + value 'NAME_DESC', 'Ordered by name in descending order.', value: :name_desc + end +end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 8aedea4799d..827d2cb7164 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -120,6 +120,15 @@ module ProjectsHelper { project_full_name: project.full_name } end + def remove_fork_project_confirm_json(project, remove_form_id) + { + remove_form_id: remove_form_id, + button_text: _('Remove fork relationship'), + confirm_danger_message: remove_fork_project_warning_message(project), + phrase: @project.path + } + end + def visible_fork_source(project) project.fork_source if project.fork_source && can?(current_user, :read_project, project.fork_source) end diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb index 2746b8b7188..3dfc8136d45 100644 --- a/app/mailers/emails/merge_requests.rb +++ b/app/mailers/emails/merge_requests.rb @@ -97,6 +97,13 @@ module Emails mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason)) end + def attention_requested_merge_request_email(recipient_id, merge_request_id, updated_by_user_id, reason = nil) + setup_merge_request_mail(merge_request_id, recipient_id) + + @updated_by = User.find(updated_by_user_id) + mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason)) + end + def merge_request_status_email(recipient_id, merge_request_id, status, updated_by_user_id, reason = nil) setup_merge_request_mail(merge_request_id, recipient_id) diff --git a/app/models/notification_reason.rb b/app/models/notification_reason.rb index c227626af9e..3713be6cb91 100644 --- a/app/models/notification_reason.rb +++ b/app/models/notification_reason.rb @@ -6,6 +6,7 @@ class NotificationReason OWN_ACTIVITY = 'own_activity' ASSIGNED = 'assigned' REVIEW_REQUESTED = 'review_requested' + ATTENTION_REQUESTED = 'attention_requested' MENTIONED = 'mentioned' SUBSCRIBED = 'subscribed' @@ -14,6 +15,7 @@ class NotificationReason OWN_ACTIVITY, ASSIGNED, REVIEW_REQUESTED, + ATTENTION_REQUESTED, MENTIONED, SUBSCRIBED ].freeze diff --git a/app/models/project.rb b/app/models/project.rb index 937e6f9c2d7..d3206f691f2 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -2750,6 +2750,12 @@ class Project < ApplicationRecord end end + def remove_project_authorizations(user_ids, per_batch = 1000) + user_ids.each_slice(per_batch) do |user_ids_batch| + project_authorizations.where(user_id: user_ids_batch).delete_all + end + end + private # overridden in EE diff --git a/app/models/project_authorization.rb b/app/models/project_authorization.rb index fed19a37a16..c76332b21cd 100644 --- a/app/models/project_authorization.rb +++ b/app/models/project_authorization.rb @@ -17,20 +17,6 @@ class ProjectAuthorization < ApplicationRecord .group(:project_id) end - def self.insert_authorizations(rows, per_batch = 1000) - rows.each_slice(per_batch) do |slice| - tuples = slice.map do |tuple| - tuple.map { |value| connection.quote(value) } - end - - connection.execute <<-EOF.strip_heredoc - INSERT INTO project_authorizations (user_id, project_id, access_level) - VALUES #{tuples.map { |tuple| "(#{tuple.join(', ')})" }.join(', ')} - ON CONFLICT DO NOTHING - EOF - end - end - # This method overrides its ActiveRecord's version in order to work correctly # with composite primary keys and fix the tests for Rails 6.1 # @@ -39,6 +25,12 @@ class ProjectAuthorization < ApplicationRecord def self.insert_all(attributes) super(attributes, unique_by: connection.schema_cache.primary_keys(table_name)) end + + def self.insert_all_in_batches(attributes, per_batch = 1000) + attributes.each_slice(per_batch) do |attributes_batch| + insert_all(attributes_batch) + end + end end ProjectAuthorization.prepend_mod_with('ProjectAuthorization') diff --git a/app/models/snippet.rb b/app/models/snippet.rb index dd76f2c3c84..d4e564f77e3 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -98,87 +98,108 @@ class Snippet < ApplicationRecord mode: :per_attribute_iv, algorithm: 'aes-256-cbc' - def self.with_optional_visibility(value = nil) - if value - where(visibility_level: value) - else - all + class << self + # Searches for snippets with a matching title, description or file name. + # + # This method uses ILIKE on PostgreSQL. + # + # query - The search query as a String. + # + # Returns an ActiveRecord::Relation. + def search(query) + fuzzy_search(query, [:title, :description, :file_name]) end - end - def self.only_personal_snippets - where(project_id: nil) - end + def parent_class + ::Project + end - def self.only_project_snippets - where.not(project_id: nil) - end + def sanitized_file_name(file_name) + file_name.gsub(/[^a-zA-Z0-9_\-\.]+/, '') + end - def self.only_include_projects_visible_to(current_user = nil) - levels = Gitlab::VisibilityLevel.levels_for_user(current_user) + def with_optional_visibility(value = nil) + if value + where(visibility_level: value) + else + all + end + end - joins(:project).where(projects: { visibility_level: levels }) - end + def only_personal_snippets + where(project_id: nil) + end - def self.only_include_projects_with_snippets_enabled(include_private: false) - column = ProjectFeature.access_level_attribute(:snippets) - levels = [ProjectFeature::ENABLED, ProjectFeature::PUBLIC] + def only_project_snippets + where.not(project_id: nil) + end - levels << ProjectFeature::PRIVATE if include_private + def only_include_projects_visible_to(current_user = nil) + levels = Gitlab::VisibilityLevel.levels_for_user(current_user) - joins(project: :project_feature) - .where(project_features: { column => levels }) - end + joins(:project).where(projects: { visibility_level: levels }) + end - def self.only_include_authorized_projects(current_user) - where( - 'EXISTS (?)', - ProjectAuthorization - .select(1) - .where('project_id = snippets.project_id') - .where(user_id: current_user.id) - ) - end + def only_include_projects_with_snippets_enabled(include_private: false) + column = ProjectFeature.access_level_attribute(:snippets) + levels = [ProjectFeature::ENABLED, ProjectFeature::PUBLIC] - def self.for_project_with_user(project, user = nil) - return none unless project.snippets_visible?(user) + levels << ProjectFeature::PRIVATE if include_private - if user && project.team.member?(user) - project.snippets - else - project.snippets.public_to_user(user) + joins(project: :project_feature) + .where(project_features: { column => levels }) end - end - def self.visible_to_or_authored_by(user) - query = where(visibility_level: Gitlab::VisibilityLevel.levels_for_user(user)) - query.or(where(author_id: user.id)) - end + def only_include_authorized_projects(current_user) + where( + 'EXISTS (?)', + ProjectAuthorization + .select(1) + .where('project_id = snippets.project_id') + .where(user_id: current_user.id) + ) + end - def self.reference_prefix - '$' - end + def for_project_with_user(project, user = nil) + return none unless project.snippets_visible?(user) + + if user && project.team.member?(user) + project.snippets + else + project.snippets.public_to_user(user) + end + end + + def visible_to_or_authored_by(user) + query = where(visibility_level: Gitlab::VisibilityLevel.levels_for_user(user)) + query.or(where(author_id: user.id)) + end + + def reference_prefix + '$' + end - # Pattern used to extract `$123` snippet references from text - # - # This pattern supports cross-project references. - def self.reference_pattern - @reference_pattern ||= %r{ + # Pattern used to extract `$123` snippet references from text + # + # This pattern supports cross-project references. + def reference_pattern + @reference_pattern ||= %r{ (#{Project.reference_pattern})? #{Regexp.escape(reference_prefix)}(?<snippet>\d+) }x - end + end - def self.link_reference_pattern - @link_reference_pattern ||= super("snippets", /(?<snippet>\d+)/) - end + def link_reference_pattern + @link_reference_pattern ||= super("snippets", /(?<snippet>\d+)/) + end - def self.find_by_id_and_project(id:, project:) - Snippet.find_by(id: id, project: project) - end + def find_by_id_and_project(id:, project:) + Snippet.find_by(id: id, project: project) + end - def self.max_file_limit - MAX_FILE_COUNT + def max_file_limit + MAX_FILE_COUNT + end end def initialize(attributes = {}) @@ -230,10 +251,6 @@ class Snippet < ApplicationRecord super.to_s end - def self.sanitized_file_name(file_name) - file_name.gsub(/[^a-zA-Z0-9_\-\.]+/, '') - end - def visibility_level_field :visibility_level end @@ -371,23 +388,6 @@ class Snippet < ApplicationRecord def multiple_files? list_files.size > 1 end - - class << self - # Searches for snippets with a matching title, description or file name. - # - # This method uses ILIKE on PostgreSQL. - # - # query - The search query as a String. - # - # Returns an ActiveRecord::Relation. - def search(query) - fuzzy_search(query, [:title, :description, :file_name]) - end - - def parent_class - ::Project - end - end end Snippet.prepend_mod_with('Snippet') diff --git a/app/serializers/analytics/cycle_analytics/stage_entity.rb b/app/serializers/analytics/cycle_analytics/stage_entity.rb index c5cc8c89fb7..cfbf6f60e38 100644 --- a/app/serializers/analytics/cycle_analytics/stage_entity.rb +++ b/app/serializers/analytics/cycle_analytics/stage_entity.rb @@ -3,6 +3,10 @@ module Analytics module CycleAnalytics class StageEntity < Grape::Entity + include ActionView::Context + include LabelsHelper + include ActionView::Helpers::TagHelper + expose :title expose :hidden expose :legend @@ -43,10 +47,20 @@ module Analytics html_description(object.end_event) end + # Avoid including ActionView::Helpers::UrlHelper + def link_to(*args) + ActionController::Base.helpers.link_to(*args) + end + private def html_description(event) - Banzai::Renderer.render(event.markdown_description, { group: object.group, project: nil }) + options = {} + if event.label_based? + options[:label_html] = render_label(event.label, link: '', small: true, tooltip: true) + end + + content_tag(:p) { event.html_description(options).html_safe } end end end diff --git a/app/services/authorized_project_update/find_records_due_for_refresh_service.rb b/app/services/authorized_project_update/find_records_due_for_refresh_service.rb index c4b18a26d0e..3a2251f15cc 100644 --- a/app/services/authorized_project_update/find_records_due_for_refresh_service.rb +++ b/app/services/authorized_project_update/find_records_due_for_refresh_service.rb @@ -47,7 +47,11 @@ module AuthorizedProjectUpdate missing_auth_found_callback.call(project_id, level) end - array << [user.id, project_id, level] + array << { + user_id: user.id, + project_id: project_id, + access_level: level + } end end diff --git a/app/services/authorized_project_update/project_group_link_create_service.rb b/app/services/authorized_project_update/project_group_link_create_service.rb index e9e7c56d7c7..10cf4c50569 100644 --- a/app/services/authorized_project_update/project_group_link_create_service.rb +++ b/app/services/authorized_project_update/project_group_link_create_service.rb @@ -65,16 +65,8 @@ module AuthorizedProjectUpdate end def update_authorizations(user_ids_to_delete, authorizations_to_create) - ProjectAuthorization.transaction do - if user_ids_to_delete.any? - ProjectAuthorization.where(project_id: project.id, user_id: user_ids_to_delete) # rubocop: disable CodeReuse/ActiveRecord - .delete_all - end - - if authorizations_to_create.any? - ProjectAuthorization.insert_all(authorizations_to_create) - end - end + project.remove_project_authorizations(user_ids_to_delete) if user_ids_to_delete.any? + ProjectAuthorization.insert_all_in_batches(authorizations_to_create) if authorizations_to_create.any? end end end diff --git a/app/services/authorized_project_update/project_recalculate_service.rb b/app/services/authorized_project_update/project_recalculate_service.rb index d70d0efc2af..17ba48cffcd 100644 --- a/app/services/authorized_project_update/project_recalculate_service.rb +++ b/app/services/authorized_project_update/project_recalculate_service.rb @@ -64,16 +64,8 @@ module AuthorizedProjectUpdate end def refresh_authorizations - ProjectAuthorization.transaction do - if user_ids_to_remove.any? - ProjectAuthorization.where(project_id: project.id, user_id: user_ids_to_remove) # rubocop: disable CodeReuse/ActiveRecord - .delete_all - end - - if authorizations_to_create.any? - ProjectAuthorization.insert_all(authorizations_to_create) - end - end + project.remove_project_authorizations(user_ids_to_remove) if user_ids_to_remove.any? + ProjectAuthorization.insert_all_in_batches(authorizations_to_create) if authorizations_to_create.any? end def apply_scopes(project_authorizations) diff --git a/app/services/auto_merge/base_service.rb b/app/services/auto_merge/base_service.rb index e756e8c14d8..da80211f9bb 100644 --- a/app/services/auto_merge/base_service.rb +++ b/app/services/auto_merge/base_service.rb @@ -64,7 +64,7 @@ module AutoMerge # NOTE: This method is to be removed when `disallow_to_create_merge_request_pipelines_in_target_project` # feature flag is removed. def self.can_add_to_merge_train?(merge_request) - if Gitlab::Ci::Features.disallow_to_create_merge_request_pipelines_in_target_project?(merge_request.target_project) + if ::Feature.enabled?(:ci_disallow_to_create_merge_request_pipelines_in_target_project, merge_request.target_project) merge_request.for_same_project? else true diff --git a/app/services/ci/update_build_state_service.rb b/app/services/ci/update_build_state_service.rb index 826d9a2eda3..9df36b86404 100644 --- a/app/services/ci/update_build_state_service.rb +++ b/app/services/ci/update_build_state_service.rb @@ -216,11 +216,12 @@ module Ci end def chunks_migration_enabled? - ::Gitlab::Ci::Features.accept_trace?(build.project) + ::Feature.enabled?(:ci_enable_live_trace, build.project) && + ::Feature.enabled?(:ci_accept_trace, build.project, type: :ops, default_enabled: true) end def log_invalid_chunks? - ::Gitlab::Ci::Features.log_invalid_trace_chunks?(build.project) + ::Feature.enabled?(:ci_trace_log_invalid_chunks, build.project, type: :ops, default_enabled: false) end end end diff --git a/app/services/merge_requests/after_create_service.rb b/app/services/merge_requests/after_create_service.rb index 77564521d45..f120cb26d22 100644 --- a/app/services/merge_requests/after_create_service.rb +++ b/app/services/merge_requests/after_create_service.rb @@ -3,12 +3,19 @@ module MergeRequests class AfterCreateService < MergeRequests::BaseService def execute(merge_request) + prepare_for_mergeability(merge_request) if early_prepare_for_mergeability?(merge_request) prepare_merge_request(merge_request) - merge_request.mark_as_unchecked if merge_request.preparing? + mark_as_unchecked(merge_request) unless early_prepare_for_mergeability?(merge_request) end private + def prepare_for_mergeability(merge_request) + create_pipeline_for(merge_request, current_user) + merge_request.update_head_pipeline + mark_as_unchecked(merge_request) + end + def prepare_merge_request(merge_request) event_service.open_mr(merge_request, current_user) @@ -17,8 +24,10 @@ module MergeRequests notification_service.new_merge_request(merge_request, current_user) - create_pipeline_for(merge_request, current_user) - merge_request.update_head_pipeline + unless early_prepare_for_mergeability?(merge_request) + create_pipeline_for(merge_request, current_user) + merge_request.update_head_pipeline + end merge_request.diffs(include_stats: false).write_cache merge_request.create_cross_references!(current_user) @@ -37,6 +46,14 @@ module MergeRequests def link_lfs_objects(merge_request) LinkLfsObjectsService.new(project: merge_request.target_project).execute(merge_request) end + + def early_prepare_for_mergeability?(merge_request) + Feature.enabled?(:early_prepare_for_mergeability, merge_request.target_project) + end + + def mark_as_unchecked(merge_request) + merge_request.mark_as_unchecked if merge_request.preparing? + end end end diff --git a/app/services/merge_requests/create_pipeline_service.rb b/app/services/merge_requests/create_pipeline_service.rb index 6b032545230..9d7f8393ba5 100644 --- a/app/services/merge_requests/create_pipeline_service.rb +++ b/app/services/merge_requests/create_pipeline_service.rb @@ -48,7 +48,7 @@ module MergeRequests end def can_create_pipeline_in_target_project?(merge_request) - if Gitlab::Ci::Features.disallow_to_create_merge_request_pipelines_in_target_project?(merge_request.target_project) + if ::Feature.enabled?(:ci_disallow_to_create_merge_request_pipelines_in_target_project, merge_request.target_project) merge_request.for_same_project? else can?(current_user, :create_pipeline, merge_request.target_project) && diff --git a/app/services/merge_requests/toggle_attention_requested_service.rb b/app/services/merge_requests/toggle_attention_requested_service.rb index 66c5d6fce5d..4e36ae065bb 100644 --- a/app/services/merge_requests/toggle_attention_requested_service.rb +++ b/app/services/merge_requests/toggle_attention_requested_service.rb @@ -31,6 +31,7 @@ module MergeRequests private def notity_user + notification_service.async.attention_requested_of_merge_request(merge_request, current_user, user) todo_service.create_attention_requested_todo(merge_request, current_user, user) end diff --git a/app/services/notification_recipients/build_service.rb b/app/services/notification_recipients/build_service.rb index 52070abbad7..aeb859af4d9 100644 --- a/app/services/notification_recipients/build_service.rb +++ b/app/services/notification_recipients/build_service.rb @@ -40,5 +40,9 @@ module NotificationRecipients def self.build_requested_review_recipients(*args) ::NotificationRecipients::Builder::RequestReview.new(*args).notification_recipients end + + def self.build_attention_requested_recipients(*args) + ::NotificationRecipients::Builder::AttentionRequested.new(*args).notification_recipients + end end end diff --git a/app/services/notification_recipients/builder/attention_requested.rb b/app/services/notification_recipients/builder/attention_requested.rb new file mode 100644 index 00000000000..cdc371fcece --- /dev/null +++ b/app/services/notification_recipients/builder/attention_requested.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module NotificationRecipients + module Builder + class AttentionRequested < Base + attr_reader :merge_request, :current_user, :user + + def initialize(merge_request, current_user, user) + @merge_request = merge_request + @current_user = current_user + @user = user + end + + def target + merge_request + end + + def build! + add_recipients(user, :mention, NotificationReason::ATTENTION_REQUESTED) + end + end + end +end diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 6ad3a74b85d..5b1733422d0 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -301,6 +301,14 @@ class NotificationService end end + def attention_requested_of_merge_request(merge_request, current_user, user) + recipients = NotificationRecipients::BuildService.build_attention_requested_recipients(merge_request, current_user, user) + + recipients.each do |recipient| + mailer.attention_requested_merge_request_email(recipient.user.id, merge_request.id, current_user.id, recipient.reason).deliver_later + end + end + # When we add labels to a merge request we should send an email to: # # * watchers of the mr's labels diff --git a/app/services/users/refresh_authorized_projects_service.rb b/app/services/users/refresh_authorized_projects_service.rb index 2d9766c3c56..fe61335f3ed 100644 --- a/app/services/users/refresh_authorized_projects_service.rb +++ b/app/services/users/refresh_authorized_projects_service.rb @@ -63,12 +63,12 @@ module Users # Updates the list of authorizations for the current user. # # remove - The IDs of the authorization rows to remove. - # add - Rows to insert in the form `[user id, project id, access level]` + # add - Rows to insert in the form `[{ user_id: user_id, project_id: project_id, access_level: access_level}, ...]` def update_authorizations(remove = [], add = []) log_refresh_details(remove, add) - user.remove_project_authorizations(remove) unless remove.empty? - ProjectAuthorization.insert_authorizations(add) unless add.empty? + user.remove_project_authorizations(remove) if remove.any? + ProjectAuthorization.insert_all_in_batches(add) if add.any? # Since we batch insert authorization rows, Rails' associations may get # out of sync. As such we force a reload of the User object. @@ -88,7 +88,7 @@ module Users # most often there's only a few entries in remove and add, but limit it to the first 5 # entries to avoid flooding the logs 'authorized_projects_refresh.rows_deleted_slice': remove.first(5), - 'authorized_projects_refresh.rows_added_slice': add.first(5)) + 'authorized_projects_refresh.rows_added_slice': add.first(5).map(&:values)) end end end diff --git a/app/views/notify/attention_requested_merge_request_email.html.haml b/app/views/notify/attention_requested_merge_request_email.html.haml new file mode 100644 index 00000000000..af42f180ae7 --- /dev/null +++ b/app/views/notify/attention_requested_merge_request_email.html.haml @@ -0,0 +1,2 @@ +%p + #{sanitize_name(@updated_by.name)} requested your attention on #{merge_request_reference_link(@merge_request)}. diff --git a/app/views/notify/attention_requested_merge_request_email.text.erb b/app/views/notify/attention_requested_merge_request_email.text.erb new file mode 100644 index 00000000000..97b1d4a824b --- /dev/null +++ b/app/views/notify/attention_requested_merge_request_email.text.erb @@ -0,0 +1 @@ +<%= sanitize_name(@updated_by.name) %> requested your attention on <%= merge_request_reference_link(@merge_request) %>. diff --git a/app/views/projects/_remove_fork.html.haml b/app/views/projects/_remove_fork.html.haml index 92eb29dc407..bb51aa86170 100644 --- a/app/views/projects/_remove_fork.html.haml +++ b/app/views/projects/_remove_fork.html.haml @@ -1,11 +1,12 @@ - return unless @project.forked? && can?(current_user, :remove_fork_project, @project) +- remove_form_id = "js-remove-project-fork-form" .sub-section %h4.danger-title= _('Remove fork relationship') %p= remove_fork_project_description_message(@project) - = form_for @project, url: remove_fork_project_path(@project), method: :delete, remote: true, html: { class: 'transfer-project' } do |f| + = form_for @project, url: remove_fork_project_path(@project), method: :delete, html: { id: remove_form_id } do |f| %p %strong= _('Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks.') = link_to _('Learn more.'), help_page_path('user/project/settings/index', anchor: 'removing-a-fork-relationship'), target: '_blank', rel: 'noopener noreferrer' - = button_to _('Remove fork relationship'), '#', class: "gl-button btn btn-danger js-legacy-confirm-danger", data: { "confirm-danger-message" => remove_fork_project_warning_message(@project) } + .js-confirm-danger{ data: remove_fork_project_confirm_json(@project, remove_form_id) } diff --git a/app/views/projects/remove_fork.js.haml b/app/views/projects/remove_fork.js.haml deleted file mode 100644 index 6d083c5c516..00000000000 --- a/app/views/projects/remove_fork.js.haml +++ /dev/null @@ -1,2 +0,0 @@ -:plain - location.href = "#{edit_project_path(@project)}"; diff --git a/config/feature_flags/development/early_prepare_for_mergeability.yml b/config/feature_flags/development/early_prepare_for_mergeability.yml new file mode 100644 index 00000000000..c6377bd9a60 --- /dev/null +++ b/config/feature_flags/development/early_prepare_for_mergeability.yml @@ -0,0 +1,8 @@ +--- +name: early_prepare_for_mergeability +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75402 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/346667 +milestone: '14.6' +type: development +group: group::code review +default_enabled: false diff --git a/config/feature_flags/development/jira_use_first_ref_by_oid.yml b/config/feature_flags/development/jira_use_first_ref_by_oid.yml index 10e2ad1b8ad..88db6c1ab4c 100644 --- a/config/feature_flags/development/jira_use_first_ref_by_oid.yml +++ b/config/feature_flags/development/jira_use_first_ref_by_oid.yml @@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/343585 milestone: '14.5' type: development group: group::integrations -default_enabled: false +default_enabled: true diff --git a/config/feature_flags/development/linear_application_settings_elasticsearch_limited_namespaces.yml b/config/feature_flags/development/linear_user_group_notification_settings_finder_ancestors_scopes.yml index 27342e1e1c2..b54b82d00a0 100644 --- a/config/feature_flags/development/linear_application_settings_elasticsearch_limited_namespaces.yml +++ b/config/feature_flags/development/linear_user_group_notification_settings_finder_ancestors_scopes.yml @@ -1,8 +1,8 @@ --- -name: linear_application_settings_elasticsearch_limited_namespaces -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68931 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/339438 -milestone: '14.3' +name: linear_user_group_notification_settings_finder_ancestors_scopes +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74606 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345792 +milestone: '14.6' type: development group: group::access default_enabled: false diff --git a/db/migrate/20211124132319_add_encrypted_static_objects_external_storage_auth_token.rb b/db/migrate/20211124132319_add_encrypted_static_objects_external_storage_auth_token.rb new file mode 100644 index 00000000000..868bc4f14f2 --- /dev/null +++ b/db/migrate/20211124132319_add_encrypted_static_objects_external_storage_auth_token.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class AddEncryptedStaticObjectsExternalStorageAuthToken < Gitlab::Database::Migration[1.0] + def up + # rubocop:disable Migration/AddLimitToTextColumns + # limit is added in 20211126113029_add_text_limit_for_static_objects_external_storage_auth_token + add_column :application_settings, :static_objects_external_storage_auth_token_encrypted, :text + # rubocop:enable Migration/AddLimitToTextColumns + end + + def down + remove_column :application_settings, :static_objects_external_storage_auth_token_encrypted + end +end diff --git a/db/migrate/20211126113029_add_text_limit_for_static_objects_external_storage_auth_token.rb b/db/migrate/20211126113029_add_text_limit_for_static_objects_external_storage_auth_token.rb new file mode 100644 index 00000000000..45c4686e674 --- /dev/null +++ b/db/migrate/20211126113029_add_text_limit_for_static_objects_external_storage_auth_token.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true +class AddTextLimitForStaticObjectsExternalStorageAuthToken < Gitlab::Database::Migration[1.0] + disable_ddl_transaction! + + def up + add_text_limit :application_settings, :static_objects_external_storage_auth_token_encrypted, 255 + end + + def down + remove_text_limit :application_settings, :static_objects_external_storage_auth_token_encrypted + end +end diff --git a/db/schema_migrations/20211124132319 b/db/schema_migrations/20211124132319 new file mode 100644 index 00000000000..1809d13a553 --- /dev/null +++ b/db/schema_migrations/20211124132319 @@ -0,0 +1 @@ +cdb85c8633687338a11ebce0603f82f5cab00e7c58f923d30b68a877b94e2db2
\ No newline at end of file diff --git a/db/schema_migrations/20211126113029 b/db/schema_migrations/20211126113029 new file mode 100644 index 00000000000..aaf1a421982 --- /dev/null +++ b/db/schema_migrations/20211126113029 @@ -0,0 +1 @@ +96abde258e6527a2b09bb60e1cc0cb90802c8a7e43a2132e9956536390a8aab8
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index ab7f7d1c984..688c8b4553f 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -10477,6 +10477,7 @@ CREATE TABLE application_settings ( sentry_dsn text, sentry_clientside_dsn text, sentry_environment text, + static_objects_external_storage_auth_token_encrypted text, CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)), CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)), CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)), @@ -10485,6 +10486,7 @@ CREATE TABLE application_settings ( CONSTRAINT app_settings_yaml_max_size_positive CHECK ((max_yaml_size_bytes > 0)), CONSTRAINT check_17d9558205 CHECK ((char_length((kroki_url)::text) <= 1024)), CONSTRAINT check_2dba05b802 CHECK ((char_length(gitpod_url) <= 255)), + CONSTRAINT check_32710817e9 CHECK ((char_length(static_objects_external_storage_auth_token_encrypted) <= 255)), CONSTRAINT check_3def0f1829 CHECK ((char_length(sentry_clientside_dsn) <= 255)), CONSTRAINT check_4f8b811780 CHECK ((char_length(sentry_dsn) <= 255)), CONSTRAINT check_51700b31b5 CHECK ((char_length(default_branch_name) <= 255)), diff --git a/doc/administration/instance_review.md b/doc/administration/instance_review.md index 62897651166..872cdb239bd 100644 --- a/doc/administration/instance_review.md +++ b/doc/administration/instance_review.md @@ -12,7 +12,7 @@ If you run a medium-sized self-managed instance (50+ users) of a free version of [either Community Edition or unlicensed Enterprise Edition](https://about.gitlab.com/install/ce-or-ee/), you qualify for a free Instance Review. -1. Sign in as a user with Administrator [role](../user/permissions.md). +1. Sign in as an administrator. 1. In the top menu, click your user icon, and select **Get a free instance review**: diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index c4167e3ecd2..20b22a843d2 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -9011,10 +9011,28 @@ Details of a container repository. | <a id="containerrepositorydetailspath"></a>`path` | [`String!`](#string) | Path of the container repository. | | <a id="containerrepositorydetailsproject"></a>`project` | [`Project!`](#project) | Project of the container registry. | | <a id="containerrepositorydetailsstatus"></a>`status` | [`ContainerRepositoryStatus`](#containerrepositorystatus) | Status of the container repository. | -| <a id="containerrepositorydetailstags"></a>`tags` | [`ContainerRepositoryTagConnection`](#containerrepositorytagconnection) | Tags of the container repository. (see [Connections](#connections)) | | <a id="containerrepositorydetailstagscount"></a>`tagsCount` | [`Int!`](#int) | Number of tags associated with this image. | | <a id="containerrepositorydetailsupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp when the container repository was updated. | +#### Fields with arguments + +##### `ContainerRepositoryDetails.tags` + +Tags of the container repository. + +Returns [`ContainerRepositoryTagConnection`](#containerrepositorytagconnection). + +This field returns a [connection](#connections). It accepts the +four standard [pagination arguments](#connection-pagination-arguments): +`before: String`, `after: String`, `first: Int`, `last: Int`. + +###### Arguments + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="containerrepositorydetailstagsname"></a>`name` | [`String`](#string) | Search by tag name. | +| <a id="containerrepositorydetailstagssort"></a>`sort` | [`ContainerRepositoryTagSort`](#containerrepositorytagsort) | Sort tags by these criteria. | + ### `ContainerRepositoryTag` A tag from a container repository. @@ -16021,6 +16039,15 @@ Status of a container repository. | <a id="containerrepositorystatusdelete_failed"></a>`DELETE_FAILED` | Delete Failed status. | | <a id="containerrepositorystatusdelete_scheduled"></a>`DELETE_SCHEDULED` | Delete Scheduled status. | +### `ContainerRepositoryTagSort` + +Values for sorting tags. + +| Value | Description | +| ----- | ----------- | +| <a id="containerrepositorytagsortname_asc"></a>`NAME_ASC` | Ordered by name in ascending order. | +| <a id="containerrepositorytagsortname_desc"></a>`NAME_DESC` | Ordered by name in descending order. | + ### `DastProfileCadenceUnit` Unit for the duration of Dast Profile Cadence. diff --git a/doc/api/project_import_export.md b/doc/api/project_import_export.md index 92b1558551d..888b6e539d3 100644 --- a/doc/api/project_import_export.md +++ b/doc/api/project_import_export.md @@ -225,6 +225,7 @@ The passed override parameters take precedence over all values defined in the ex ```shell curl --request POST \ --header "PRIVATE-TOKEN: <your_access_token>" \ + --header "Content-Type: application/json" \ --url "https://gitlab.example.com/api/v4/projects/remote-import" \ --data '{"url":"https://remoteobject/file?token=123123","path":"remote-project"}' ``` diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event.rb b/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event.rb index 945cecfcf8c..e99ad42b0b2 100644 --- a/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event.rb +++ b/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event.rb @@ -19,7 +19,7 @@ module Gitlab raise NotImplementedError end - def markdown_description + def html_description(options = {}) self.class.name end diff --git a/lib/gitlab/ci/features.rb b/lib/gitlab/ci/features.rb deleted file mode 100644 index 51051b0490f..00000000000 --- a/lib/gitlab/ci/features.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module Ci - ## - # Deprecated: Ci::Features is a class that aggregates all CI/CD feature flags in one place. - # - module Features - # NOTE: The feature flag `disallow_to_create_merge_request_pipelines_in_target_project` - # is a safe switch to disable the feature for a particular project when something went wrong, - # therefore it's not supposed to be enabled by default. - def self.disallow_to_create_merge_request_pipelines_in_target_project?(target_project) - ::Feature.enabled?(:ci_disallow_to_create_merge_request_pipelines_in_target_project, target_project) - end - - def self.accept_trace?(project) - ::Feature.enabled?(:ci_enable_live_trace, project) && - ::Feature.enabled?(:ci_accept_trace, project, type: :ops, default_enabled: true) - end - - def self.log_invalid_trace_chunks?(project) - ::Feature.enabled?(:ci_trace_log_invalid_chunks, project, type: :ops, default_enabled: false) - end - - def self.gldropdown_tags_enabled? - ::Feature.enabled?(:gldropdown_tags, default_enabled: :yaml) - end - end - end -end diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index dafa639a2d5..a0f0b388b9e 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -1092,7 +1092,7 @@ RSpec.describe ProjectsController do expect(forked_project.reload.forked?).to be_falsey expect(flash[:notice]).to eq(s_('The fork relationship has been removed.')) - expect(response).to render_template(:remove_fork) + expect(response).to redirect_to(edit_project_path(forked_project)) end end @@ -1108,7 +1108,7 @@ RSpec.describe ProjectsController do format: :js) expect(flash[:notice]).to be_nil - expect(response).to render_template(:remove_fork) + expect(response).to redirect_to(edit_project_path(unforked_project)) end end end diff --git a/spec/features/projects/settings/forked_project_settings_spec.rb b/spec/features/projects/settings/forked_project_settings_spec.rb index a84516e19f9..04fb6953b51 100644 --- a/spec/features/projects/settings/forked_project_settings_spec.rb +++ b/spec/features/projects/settings/forked_project_settings_spec.rb @@ -15,7 +15,7 @@ RSpec.describe 'Projects > Settings > For a forked project', :js do end shared_examples 'project settings for a forked projects' do - it 'allows deleting the link to the forked project', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/327817' do + it 'allows deleting the link to the forked project' do visit edit_project_path(forked_project) click_button 'Remove fork relationship' diff --git a/spec/finders/user_group_notification_settings_finder_spec.rb b/spec/finders/user_group_notification_settings_finder_spec.rb index b9d800d8e55..ea44688bc8d 100644 --- a/spec/finders/user_group_notification_settings_finder_spec.rb +++ b/spec/finders/user_group_notification_settings_finder_spec.rb @@ -11,155 +11,167 @@ RSpec.describe UserGroupNotificationSettingsFinder do subject.map(&proc).uniq end - context 'when the groups have no existing notification settings' do - context 'when the groups have no ancestors' do - let_it_be(:groups) { create_list(:group, 3) } - - it 'will be a default Global notification setting', :aggregate_failures do - expect(subject.count).to eq(3) - expect(attributes(&:notification_email)).to eq([nil]) - expect(attributes(&:level)).to eq(['global']) + shared_examples 'user group notifications settings tests' do + context 'when the groups have no existing notification settings' do + context 'when the groups have no ancestors' do + let_it_be(:groups) { create_list(:group, 3) } + + it 'will be a default Global notification setting', :aggregate_failures do + expect(subject.count).to eq(3) + expect(attributes(&:notification_email)).to match_array([nil]) + expect(attributes(&:level)).to match_array(['global']) + end end - end - context 'when the groups have ancestors' do - context 'when an ancestor has a level other than Global' do - let_it_be(:ancestor_a) { create(:group) } - let_it_be(:group_a) { create(:group, parent: ancestor_a) } - let_it_be(:ancestor_b) { create(:group) } - let_it_be(:group_b) { create(:group, parent: ancestor_b) } - let_it_be(:email) { create(:email, :confirmed, email: 'ancestor@example.com', user: user) } + context 'when the groups have ancestors' do + context 'when an ancestor has a level other than Global' do + let_it_be(:ancestor_a) { create(:group) } + let_it_be(:group_a) { create(:group, parent: ancestor_a) } + let_it_be(:ancestor_b) { create(:group) } + let_it_be(:group_b) { create(:group, parent: ancestor_b) } + let_it_be(:email) { create(:email, :confirmed, email: 'ancestor@example.com', user: user) } - let_it_be(:groups) { [group_a, group_b] } + let_it_be(:groups) { [group_a, group_b] } - before do - create(:notification_setting, user: user, source: ancestor_a, level: 'participating', notification_email: email.email) - create(:notification_setting, user: user, source: ancestor_b, level: 'participating', notification_email: email.email) - end + before do + create(:notification_setting, user: user, source: ancestor_a, level: 'participating', notification_email: email.email) + create(:notification_setting, user: user, source: ancestor_b, level: 'participating', notification_email: email.email) + end - it 'has the same level set' do - expect(attributes(&:level)).to eq(['participating']) - end + it 'has the same level set' do + expect(attributes(&:level)).to match_array(['participating']) + end - it 'has the same email set' do - expect(attributes(&:notification_email)).to eq(['ancestor@example.com']) + it 'has the same email set' do + expect(attributes(&:notification_email)).to match_array(['ancestor@example.com']) + end + + it 'only returns the two queried groups' do + expect(subject.count).to eq(2) + end end - it 'only returns the two queried groups' do - expect(subject.count).to eq(2) + context 'when an ancestor has a Global level but has an email set' do + let_it_be(:grand_ancestor) { create(:group) } + let_it_be(:ancestor) { create(:group, parent: grand_ancestor) } + let_it_be(:group) { create(:group, parent: ancestor) } + let_it_be(:ancestor_email) { create(:email, :confirmed, email: 'ancestor@example.com', user: user) } + let_it_be(:grand_email) { create(:email, :confirmed, email: 'grand@example.com', user: user) } + + let_it_be(:groups) { [group] } + + before do + create(:notification_setting, user: user, source: grand_ancestor, level: 'participating', notification_email: grand_email.email) + create(:notification_setting, user: user, source: ancestor, level: 'global', notification_email: ancestor_email.email) + end + + it 'has the same email and level set', :aggregate_failures do + expect(subject.count).to eq(1) + expect(attributes(&:level)).to match_array(['global']) + expect(attributes(&:notification_email)).to match_array(['ancestor@example.com']) + end end - end - context 'when an ancestor has a Global level but has an email set' do - let_it_be(:grand_ancestor) { create(:group) } - let_it_be(:ancestor) { create(:group, parent: grand_ancestor) } - let_it_be(:group) { create(:group, parent: ancestor) } - let_it_be(:ancestor_email) { create(:email, :confirmed, email: 'ancestor@example.com', user: user) } - let_it_be(:grand_email) { create(:email, :confirmed, email: 'grand@example.com', user: user) } + context 'when the group has parent_id set but that does not belong to any group' do + let_it_be(:group) { create(:group) } + let_it_be(:groups) { [group] } - let_it_be(:groups) { [group] } + before do + # Let's set a parent_id for a group that definitely doesn't exist + group.update_columns(parent_id: 19283746) + end - before do - create(:notification_setting, user: user, source: grand_ancestor, level: 'participating', notification_email: grand_email.email) - create(:notification_setting, user: user, source: ancestor, level: 'global', notification_email: ancestor_email.email) + it 'returns a default Global notification setting' do + expect(subject.count).to eq(1) + expect(attributes(&:level)).to match_array(['global']) + expect(attributes(&:notification_email)).to match_array([nil]) + end end - it 'has the same email and level set', :aggregate_failures do - expect(subject.count).to eq(1) - expect(attributes(&:level)).to eq(['global']) - expect(attributes(&:notification_email)).to eq(['ancestor@example.com']) + context 'when the group has a private parent' do + let_it_be(:ancestor) { create(:group, :private) } + let_it_be(:group) { create(:group, :private, parent: ancestor) } + let_it_be(:ancestor_email) { create(:email, :confirmed, email: 'ancestor@example.com', user: user) } + let_it_be(:groups) { [group] } + + before do + group.add_reporter(user) + # Adding the user creates a NotificationSetting, so we remove it here + user.notification_settings.where(source: group).delete_all + + create(:notification_setting, user: user, source: ancestor, level: 'participating', notification_email: ancestor_email.email) + end + + it 'still inherits the notification settings' do + expect(subject.count).to eq(1) + expect(attributes(&:level)).to match_array(['participating']) + expect(attributes(&:notification_email)).to match_array([ancestor_email.email]) + end end - end - context 'when the group has parent_id set but that does not belong to any group' do - let_it_be(:group) { create(:group) } - let_it_be(:groups) { [group] } + it 'does not cause an N+1', :aggregate_failures do + parent = create(:group) + child = create(:group, parent: parent) - before do - # Let's set a parent_id for a group that definitely doesn't exist - group.update_columns(parent_id: 19283746) - end + control = ActiveRecord::QueryRecorder.new do + described_class.new(user, Group.where(id: child.id)).execute + end - it 'returns a default Global notification setting' do - expect(subject.count).to eq(1) - expect(attributes(&:level)).to eq(['global']) - expect(attributes(&:notification_email)).to eq([nil]) - end - end + other_parent = create(:group) + other_children = create_list(:group, 2, parent: other_parent) - context 'when the group has a private parent' do - let_it_be(:ancestor) { create(:group, :private) } - let_it_be(:group) { create(:group, :private, parent: ancestor) } - let_it_be(:ancestor_email) { create(:email, :confirmed, email: 'ancestor@example.com', user: user) } - let_it_be(:groups) { [group] } + result = nil - before do - group.add_reporter(user) - # Adding the user creates a NotificationSetting, so we remove it here - user.notification_settings.where(source: group).delete_all - - create(:notification_setting, user: user, source: ancestor, level: 'participating', notification_email: ancestor_email.email) - end + expect do + result = described_class.new(user, Group.where(id: other_children.append(child).map(&:id))).execute + end.not_to exceed_query_limit(control) - it 'still inherits the notification settings' do - expect(subject.count).to eq(1) - expect(attributes(&:level)).to eq(['participating']) - expect(attributes(&:notification_email)).to eq([ancestor_email.email]) + expect(result.count).to eq(3) end end + end - it 'does not cause an N+1', :aggregate_failures do - parent = create(:group) - child = create(:group, parent: parent) - - control = ActiveRecord::QueryRecorder.new do - described_class.new(user, Group.where(id: child.id)).execute - end + context 'preloading `emails_disabled`' do + let_it_be(:root_group) { create(:group) } + let_it_be(:sub_group) { create(:group, parent: root_group) } + let_it_be(:sub_sub_group) { create(:group, parent: sub_group) } - other_parent = create(:group) - other_children = create_list(:group, 2, parent: other_parent) + let_it_be(:another_root_group) { create(:group) } + let_it_be(:sub_group_with_emails_disabled) { create(:group, emails_disabled: true, parent: another_root_group) } + let_it_be(:another_sub_sub_group) { create(:group, parent: sub_group_with_emails_disabled) } - result = nil + let_it_be(:root_group_with_emails_disabled) { create(:group, emails_disabled: true) } + let_it_be(:group) { create(:group, parent: root_group_with_emails_disabled) } - expect do - result = described_class.new(user, Group.where(id: other_children.append(child).map(&:id))).execute - end.not_to exceed_query_limit(control) + let(:groups) { Group.where(id: [sub_sub_group, another_sub_sub_group, group]) } - expect(result.count).to eq(3) + before do + described_class.new(user, groups).execute end - end - end - - context 'preloading `emails_disabled`' do - let_it_be(:root_group) { create(:group) } - let_it_be(:sub_group) { create(:group, parent: root_group) } - let_it_be(:sub_sub_group) { create(:group, parent: sub_group) } - - let_it_be(:another_root_group) { create(:group) } - let_it_be(:sub_group_with_emails_disabled) { create(:group, emails_disabled: true, parent: another_root_group) } - let_it_be(:another_sub_sub_group) { create(:group, parent: sub_group_with_emails_disabled) } - let_it_be(:root_group_with_emails_disabled) { create(:group, emails_disabled: true) } - let_it_be(:group) { create(:group, parent: root_group_with_emails_disabled) } + it 'preloads the `group.emails_disabled` method' do + recorder = ActiveRecord::QueryRecorder.new do + groups.each(&:emails_disabled?) + end - let(:groups) { Group.where(id: [sub_sub_group, another_sub_sub_group, group]) } + expect(recorder.count).to eq(0) + end - before do - described_class.new(user, groups).execute + it 'preloads the `group.emails_disabled` method correctly' do + groups.each do |group| + expect(group.emails_disabled?).to eq(Group.find(group.id).emails_disabled?) # compare the memoized and the freshly loaded value + end + end end + end - it 'preloads the `group.emails_disabled` method' do - recorder = ActiveRecord::QueryRecorder.new do - groups.each(&:emails_disabled?) - end + it_behaves_like 'user group notifications settings tests' - expect(recorder.count).to eq(0) + context 'when feature flag :linear_user_group_notification_settings_finder_ancestors_scopes is disabled' do + before do + stub_feature_flags(linear_user_group_notification_settings_finder_ancestors_scopes: false) end - it 'preloads the `group.emails_disabled` method correctly' do - groups.each do |group| - expect(group.emails_disabled?).to eq(Group.find(group.id).emails_disabled?) # compare the memoized and the freshly loaded value - end - end + it_behaves_like 'user group notifications settings tests' end end diff --git a/spec/frontend/alerts_settings/components/mocks/apollo_mock.js b/spec/frontend/alerts_settings/components/mocks/apollo_mock.js index 828580a436b..e7ad2cd1d2a 100644 --- a/spec/frontend/alerts_settings/components/mocks/apollo_mock.js +++ b/spec/frontend/alerts_settings/components/mocks/apollo_mock.js @@ -34,6 +34,7 @@ export const updatePrometheusVariables = { export const getIntegrationsQueryResponse = { data: { project: { + id: '1', alertManagementIntegrations: { nodes: [ { diff --git a/spec/frontend/artifacts_settings/components/keep_latest_artifact_checkbox_spec.js b/spec/frontend/artifacts_settings/components/keep_latest_artifact_checkbox_spec.js index b0d1b70c198..bfa8274f0eb 100644 --- a/spec/frontend/artifacts_settings/components/keep_latest_artifact_checkbox_spec.js +++ b/spec/frontend/artifacts_settings/components/keep_latest_artifact_checkbox_spec.js @@ -13,6 +13,7 @@ localVue.use(VueApollo); const keepLatestArtifactProjectMock = { data: { project: { + id: '1', ciCdSettings: { keepLatestArtifact: true }, }, }, diff --git a/spec/frontend/clusters/agents/components/show_spec.js b/spec/frontend/clusters/agents/components/show_spec.js index c502e7d813e..d7107f07545 100644 --- a/spec/frontend/clusters/agents/components/show_spec.js +++ b/spec/frontend/clusters/agents/components/show_spec.js @@ -27,6 +27,7 @@ describe('ClusterAgentShow', () => { id: '1', createdAt: '2021-02-13T00:00:00Z', createdByUser: { + id: 'user-1', name: 'user-1', }, name: 'token-1', @@ -39,7 +40,8 @@ describe('ClusterAgentShow', () => { const createWrapper = ({ clusterAgent, queryResponse = null }) => { const agentQueryResponse = - queryResponse || jest.fn().mockResolvedValue({ data: { project: { clusterAgent } } }); + queryResponse || + jest.fn().mockResolvedValue({ data: { project: { id: 'project-1', clusterAgent } } }); const apolloProvider = createMockApollo([[getAgentQuery, agentQueryResponse]]); wrapper = extendedWrapper( diff --git a/spec/frontend/clusters_list/components/agents_spec.js b/spec/frontend/clusters_list/components/agents_spec.js index 24afb986424..c9ca10f6bf7 100644 --- a/spec/frontend/clusters_list/components/agents_spec.js +++ b/spec/frontend/clusters_list/components/agents_spec.js @@ -26,6 +26,7 @@ describe('Agents', () => { const apolloQueryResponse = { data: { project: { + id: '1', clusterAgents: { nodes: agents, pageInfo, tokens: { nodes: [] }, count }, repository: { tree: { trees: { nodes: trees, pageInfo } } }, }, @@ -75,6 +76,7 @@ describe('Agents', () => { tokens: { nodes: [ { + id: 'token-1', lastUsedAt: testDate, }, ], @@ -86,6 +88,7 @@ describe('Agents', () => { const trees = [ { + id: 'tree-1', name: 'agent-2', path: '.gitlab/agents/agent-2', webPath: '/project/path/.gitlab/agents/agent-2', diff --git a/spec/frontend/clusters_list/components/install_agent_modal_spec.js b/spec/frontend/clusters_list/components/install_agent_modal_spec.js index e324418bded..39419e94fe6 100644 --- a/spec/frontend/clusters_list/components/install_agent_modal_spec.js +++ b/spec/frontend/clusters_list/components/install_agent_modal_spec.js @@ -39,6 +39,7 @@ describe('InstallAgentModal', () => { const apolloQueryResponse = { data: { project: { + id: '1', clusterAgents: { nodes: [] }, agentConfigurations: { nodes: configurations }, }, diff --git a/spec/frontend/clusters_list/mocks/apollo.js b/spec/frontend/clusters_list/mocks/apollo.js index 1a7ef84a6d9..804f9834506 100644 --- a/spec/frontend/clusters_list/mocks/apollo.js +++ b/spec/frontend/clusters_list/mocks/apollo.js @@ -65,6 +65,7 @@ export const createAgentTokenErrorResponse = { export const getAgentResponse = { data: { project: { + id: 'project-1', clusterAgents: { nodes: [{ ...agent, tokens }], pageInfo, count }, repository: { tree: { diff --git a/spec/frontend/design_management/mock_data/apollo_mock.js b/spec/frontend/design_management/mock_data/apollo_mock.js index cdd07a16e90..2a43b5debee 100644 --- a/spec/frontend/design_management/mock_data/apollo_mock.js +++ b/spec/frontend/design_management/mock_data/apollo_mock.js @@ -5,6 +5,7 @@ export const designListQueryResponse = { id: '1', issue: { __typename: 'Issue', + id: 'issue-1', designCollection: { __typename: 'DesignCollection', copyState: 'READY', @@ -97,6 +98,7 @@ export const permissionsQueryResponse = { id: '1', issue: { __typename: 'Issue', + id: 'issue-1', userPermissions: { __typename: 'UserPermissions', createDesign: true }, }, }, diff --git a/spec/frontend/integrations/overrides/components/integration_overrides_spec.js b/spec/frontend/integrations/overrides/components/integration_overrides_spec.js index ae89d05cead..8abd83887f7 100644 --- a/spec/frontend/integrations/overrides/components/integration_overrides_spec.js +++ b/spec/frontend/integrations/overrides/components/integration_overrides_spec.js @@ -8,6 +8,7 @@ import IntegrationOverrides from '~/integrations/overrides/components/integratio import axios from '~/lib/utils/axios_utils'; import httpStatus from '~/lib/utils/http_status'; import ProjectAvatar from '~/vue_shared/components/project_avatar.vue'; +import UrlSync from '~/vue_shared/components/url_sync.vue'; const mockOverrides = Array(DEFAULT_PER_PAGE * 3) .fill(1) @@ -26,9 +27,10 @@ describe('IntegrationOverrides', () => { overridesPath: 'mock/overrides', }; - const createComponent = ({ mountFn = shallowMount } = {}) => { + const createComponent = ({ mountFn = shallowMount, stubs } = {}) => { wrapper = mountFn(IntegrationOverrides, { propsData: defaultProps, + stubs, }); }; @@ -127,27 +129,58 @@ describe('IntegrationOverrides', () => { }); describe('pagination', () => { - it('triggers fetch when `input` event is emitted', async () => { - createComponent(); - jest.spyOn(axios, 'get'); - await waitForPromises(); + describe('when total items does not exceed the page limit', () => { + it('does not render', async () => { + mockAxios.onGet(defaultProps.overridesPath).reply(httpStatus.OK, [mockOverrides[0]], { + 'X-TOTAL': DEFAULT_PER_PAGE - 1, + 'X-PAGE': 1, + }); + + createComponent(); + + // wait for initial load + await waitForPromises(); - await findPagination().vm.$emit('input', 2); - expect(axios.get).toHaveBeenCalledWith(defaultProps.overridesPath, { - params: { page: 2, per_page: DEFAULT_PER_PAGE }, + expect(findPagination().exists()).toBe(false); }); }); - it('does not render with <=1 page', async () => { - mockAxios.onGet(defaultProps.overridesPath).reply(httpStatus.OK, [mockOverrides[0]], { - 'X-TOTAL': 1, - 'X-PAGE': 1, + describe('when total items exceeds the page limit', () => { + const mockPage = 2; + + beforeEach(async () => { + createComponent({ stubs: { UrlSync } }); + mockAxios.onGet(defaultProps.overridesPath).reply(httpStatus.OK, [mockOverrides[0]], { + 'X-TOTAL': DEFAULT_PER_PAGE * 2, + 'X-PAGE': mockPage, + }); + + // wait for initial load + await waitForPromises(); }); - createComponent(); - await waitForPromises(); + it('renders', () => { + expect(findPagination().exists()).toBe(true); + }); - expect(findPagination().exists()).toBe(false); + describe('when navigating to a page', () => { + beforeEach(async () => { + jest.spyOn(axios, 'get'); + + // trigger a page change + await findPagination().vm.$emit('input', mockPage); + }); + + it('performs GET request with correct params', () => { + expect(axios.get).toHaveBeenCalledWith(defaultProps.overridesPath, { + params: { page: mockPage, per_page: DEFAULT_PER_PAGE }, + }); + }); + + it('updates `page` URL parameter', () => { + expect(window.location.search).toBe(`?page=${mockPage}`); + }); + }); }); }); }); diff --git a/spec/frontend/issues_list/components/issues_list_app_spec.js b/spec/frontend/issues_list/components/issues_list_app_spec.js index 8c068fa1f8c..6489582bd0a 100644 --- a/spec/frontend/issues_list/components/issues_list_app_spec.js +++ b/spec/frontend/issues_list/components/issues_list_app_spec.js @@ -643,6 +643,7 @@ describe('CE IssuesListApp component', () => { const response = (isProject = true) => ({ data: { [isProject ? 'project' : 'group']: { + id: '1', issues: { ...defaultQueryResponse.data.project.issues, nodes: [issueOne, issueTwo, issueThree, issueFour], diff --git a/spec/frontend/issues_list/mock_data.js b/spec/frontend/issues_list/mock_data.js index d408316a063..948699876ce 100644 --- a/spec/frontend/issues_list/mock_data.js +++ b/spec/frontend/issues_list/mock_data.js @@ -6,6 +6,7 @@ import { export const getIssuesQueryResponse = { data: { project: { + id: '1', issues: { pageInfo: { hasNextPage: true, @@ -75,6 +76,7 @@ export const getIssuesQueryResponse = { export const getIssuesCountsQueryResponse = { data: { project: { + id: '1', openedIssues: { count: 1, }, @@ -288,6 +290,7 @@ export const project3 = { export const searchProjectsQueryResponse = { data: { group: { + id: '1', projects: { nodes: [project1, project2, project3], }, @@ -298,6 +301,7 @@ export const searchProjectsQueryResponse = { export const emptySearchProjectsQueryResponse = { data: { group: { + id: '1', projects: { nodes: [], }, diff --git a/spec/frontend/jobs/mock_data.js b/spec/frontend/jobs/mock_data.js index 43755b46bc9..5654c8e424e 100644 --- a/spec/frontend/jobs/mock_data.js +++ b/spec/frontend/jobs/mock_data.js @@ -1474,6 +1474,7 @@ export const mockJobsInTable = [ export const mockJobsQueryResponse = { data: { project: { + id: '1', jobs: { pageInfo: { endCursor: 'eyJpZCI6IjIzMTcifQ', @@ -1509,6 +1510,7 @@ export const mockJobsQueryResponse = { triggered: null, createdByTag: false, detailedStatus: { + id: 'status-1', detailsPath: '/root/ci-project/-/jobs/2336', group: 'success', icon: 'status_success', @@ -1516,6 +1518,7 @@ export const mockJobsQueryResponse = { text: 'passed', tooltip: 'passed', action: { + id: 'action-1', buttonTitle: 'Retry this job', icon: 'retry', method: 'post', @@ -1535,6 +1538,7 @@ export const mockJobsQueryResponse = { id: 'gid://gitlab/Ci::Pipeline/473', path: '/root/ci-project/-/pipelines/473', user: { + id: 'user-1', webPath: '/root', avatarUrl: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', @@ -1543,6 +1547,7 @@ export const mockJobsQueryResponse = { __typename: 'Pipeline', }, stage: { + id: 'stage-1', name: 'deploy', __typename: 'CiStage', }, @@ -1573,6 +1578,7 @@ export const mockJobsQueryResponse = { export const mockJobsQueryEmptyResponse = { data: { project: { + id: '1', jobs: [], }, }, diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js b/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js index 04348a01dde..16625d913a5 100644 --- a/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js @@ -37,6 +37,7 @@ export const graphQLImageListMock = { data: { project: { __typename: 'Project', + id: '1', containerRepositoriesCount: 2, containerRepositories: { __typename: 'ContainerRepositoryConnection', @@ -51,6 +52,7 @@ export const graphQLEmptyImageListMock = { data: { project: { __typename: 'Project', + id: '1', containerRepositoriesCount: 2, containerRepositories: { __typename: 'ContainerRepositoryConnection', @@ -65,6 +67,7 @@ export const graphQLEmptyGroupImageListMock = { data: { group: { __typename: 'Group', + id: '1', containerRepositoriesCount: 2, containerRepositories: { __typename: 'ContainerRepositoryConnection', @@ -120,6 +123,7 @@ export const containerRepositoryMock = { project: { visibility: 'public', path: 'gitlab-test', + id: '1', containerExpirationPolicy: { enabled: false, nextRunAt: '2020-11-27T08:59:27Z', @@ -243,6 +247,7 @@ export const dockerCommands = { export const graphQLProjectImageRepositoriesDetailsMock = { data: { project: { + id: '1', containerRepositories: { nodes: [ { diff --git a/spec/frontend/packages_and_registries/dependency_proxy/mock_data.js b/spec/frontend/packages_and_registries/dependency_proxy/mock_data.js index 8bad22b5287..2aa427bc6af 100644 --- a/spec/frontend/packages_and_registries/dependency_proxy/mock_data.js +++ b/spec/frontend/packages_and_registries/dependency_proxy/mock_data.js @@ -8,8 +8,8 @@ export const proxyData = () => ({ export const proxySettings = (extend = {}) => ({ enabled: true, ...extend }); export const proxyManifests = () => [ - { createdAt: '2021-09-22T09:45:28Z', imageName: 'alpine:latest' }, - { createdAt: '2021-09-21T09:45:28Z', imageName: 'alpine:stable' }, + { id: 'proxy-1', createdAt: '2021-09-22T09:45:28Z', imageName: 'alpine:latest' }, + { id: 'proxy-2', createdAt: '2021-09-21T09:45:28Z', imageName: 'alpine:stable' }, ]; export const pagination = (extend) => ({ @@ -26,6 +26,7 @@ export const proxyDetailsQuery = ({ extendSettings = {}, extend } = {}) => ({ group: { ...proxyData(), __typename: 'Group', + id: '1', dependencyProxySetting: { ...proxySettings(extendSettings), __typename: 'DependencyProxySetting', diff --git a/spec/frontend/packages_and_registries/package_registry/mock_data.js b/spec/frontend/packages_and_registries/package_registry/mock_data.js index bacc748db81..4c23b52b8a2 100644 --- a/spec/frontend/packages_and_registries/package_registry/mock_data.js +++ b/spec/frontend/packages_and_registries/package_registry/mock_data.js @@ -16,11 +16,13 @@ export const packagePipelines = (extend) => [ ref: 'master', sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0', project: { + id: '1', name: 'project14', webUrl: 'http://gdk.test:3000/namespace14/project14', __typename: 'Project', }, user: { + id: 'user-1', name: 'Administrator', }, ...extend, @@ -89,6 +91,7 @@ export const dependencyLinks = () => [ ]; export const packageProject = () => ({ + id: '1', fullPath: 'gitlab-org/gitlab-test', webUrl: 'http://gdk.test:3000/gitlab-org/gitlab-test', __typename: 'Project', @@ -127,6 +130,7 @@ export const packageData = (extend) => ({ }); export const conanMetadata = () => ({ + id: 'conan-1', packageChannel: 'stable', packageUsername: 'gitlab-org+gitlab-test', recipe: 'package-8/1.0.0@gitlab-org+gitlab-test/stable', @@ -179,6 +183,7 @@ export const packageDetailsQuery = (extendPackage) => ({ ...nugetMetadata(), }, project: { + id: '1', path: 'projectPath', }, tags: { @@ -270,6 +275,7 @@ export const packageDestroyFileMutationError = () => ({ export const packagesListQuery = ({ type = 'group', extend = {}, extendPagination = {} } = {}) => ({ data: { [type]: { + id: '1', packages: { count: 2, nodes: [ diff --git a/spec/frontend/packages_and_registries/settings/group/mock_data.js b/spec/frontend/packages_and_registries/settings/group/mock_data.js index b1132015994..c74bebf1664 100644 --- a/spec/frontend/packages_and_registries/settings/group/mock_data.js +++ b/spec/frontend/packages_and_registries/settings/group/mock_data.js @@ -13,6 +13,7 @@ export const dependencyProxySettings = (extend) => ({ export const groupPackageSettingsMock = { data: { group: { + id: '1', fullPath: 'foo_group_path', packageSettings: packageSettings(), dependencyProxySetting: dependencyProxySettings(), diff --git a/spec/frontend/packages_and_registries/settings/project/settings/mock_data.js b/spec/frontend/packages_and_registries/settings/project/settings/mock_data.js index 9778f409010..a56bb75f8ed 100644 --- a/spec/frontend/packages_and_registries/settings/project/settings/mock_data.js +++ b/spec/frontend/packages_and_registries/settings/project/settings/mock_data.js @@ -11,6 +11,7 @@ export const containerExpirationPolicyData = () => ({ export const expirationPolicyPayload = (override) => ({ data: { project: { + id: '1', containerExpirationPolicy: { ...containerExpirationPolicyData(), ...override, diff --git a/spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js b/spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js index 29ab52bde8f..421a5c30f0c 100644 --- a/spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js +++ b/spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js @@ -136,7 +136,7 @@ describe('Pipeline Status', () => { describe('when pipeline is null', () => { beforeEach(() => { mockPipelineQuery.mockResolvedValue({ - data: { project: { pipeline: null } }, + data: { project: { id: '1', pipeline: null } }, }); createComponentWithApollo(); diff --git a/spec/frontend/pipeline_editor/mock_data.js b/spec/frontend/pipeline_editor/mock_data.js index e95f1e72f20..fc2cbdeda0a 100644 --- a/spec/frontend/pipeline_editor/mock_data.js +++ b/spec/frontend/pipeline_editor/mock_data.js @@ -39,6 +39,7 @@ job_build: export const mockCiTemplateQueryResponse = { data: { project: { + id: 'project-1', ciTemplate: { content: mockCiYml, }, @@ -48,19 +49,22 @@ export const mockCiTemplateQueryResponse = { export const mockBlobContentQueryResponse = { data: { - project: { repository: { blobs: { nodes: [{ rawBlob: mockCiYml }] } } }, + project: { + id: 'project-1', + repository: { blobs: { nodes: [{ id: 'blob-1', rawBlob: mockCiYml }] } }, + }, }, }; export const mockBlobContentQueryResponseNoCiFile = { data: { - project: { repository: { blobs: { nodes: [] } } }, + project: { id: 'project-1', repository: { blobs: { nodes: [] } } }, }, }; export const mockBlobContentQueryResponseEmptyCiFile = { data: { - project: { repository: { blobs: { nodes: [{ rawBlob: '' }] } } }, + project: { id: 'project-1', repository: { blobs: { nodes: [{ rawBlob: '' }] } } }, }, }; @@ -93,6 +97,7 @@ export const mockCiConfigQueryResponse = { groups: { nodes: [ { + id: 'group-1', name: 'job_test_1', size: 1, jobs: { @@ -108,6 +113,7 @@ export const mockCiConfigQueryResponse = { __typename: 'CiConfigGroup', }, { + id: 'group-2', name: 'job_test_2', size: 1, jobs: { @@ -170,9 +176,11 @@ export const mergeUnwrappedCiConfig = (mergedConfig) => { export const mockCommitShaResults = { data: { project: { + id: '1', repository: { tree: { lastCommit: { + id: 'commit-1', sha: mockCommitSha, }, }, @@ -184,9 +192,11 @@ export const mockCommitShaResults = { export const mockNewCommitShaResults = { data: { project: { + id: '1', repository: { tree: { lastCommit: { + id: 'commit-1', sha: 'eeff1122', }, }, @@ -198,9 +208,11 @@ export const mockNewCommitShaResults = { export const mockEmptyCommitShaResults = { data: { project: { + id: '1', repository: { tree: { lastCommit: { + id: 'commit-1', sha: '', }, }, @@ -212,6 +224,7 @@ export const mockEmptyCommitShaResults = { export const mockProjectBranches = { data: { project: { + id: '1', repository: { branchNames: [ 'main', @@ -236,6 +249,7 @@ export const mockTotalBranchResults = export const mockSearchBranches = { data: { project: { + id: '1', repository: { branchNames: ['test', 'better-feature', 'update-ci', 'test-merge-request'], }, @@ -248,6 +262,7 @@ export const mockTotalSearchResults = mockSearchBranches.data.project.repository export const mockEmptySearchBranches = { data: { project: { + id: '1', repository: { branchNames: [], }, @@ -284,16 +299,19 @@ export const mockProjectPipeline = ({ hasStages = true } = {}) => { : null; return { + id: '1', pipeline: { id: 'gid://gitlab/Ci::Pipeline/118', iid: '28', shortSha: mockCommitSha, status: 'SUCCESS', commit: { + id: 'commit-1', title: 'Update .gitlabe-ci.yml', webPath: '/-/commit/aabbccdd', }, detailedStatus: { + id: 'status-1', detailsPath: '/root/sample-ci-project/-/pipelines/118', group: 'success', icon: 'status_success', @@ -461,6 +479,7 @@ export const mockCommitCreateResponse = { errors: [], commit: { __typename: 'Commit', + id: 'commit-1', sha: mockCommitNextSha, }, commitPipelinePath: '', @@ -475,6 +494,7 @@ export const mockCommitCreateResponseNewEtag = { errors: [], commit: { __typename: 'Commit', + id: 'commit-2', sha: mockCommitNextSha, }, commitPipelinePath: '/api/graphql:pipelines/sha/550ceace1acd373c84d02bd539cb9d4614f786db', diff --git a/spec/frontend/pipelines/__snapshots__/utils_spec.js.snap b/spec/frontend/pipelines/__snapshots__/utils_spec.js.snap index 60625d301c0..99de0d2a3ef 100644 --- a/spec/frontend/pipelines/__snapshots__/utils_spec.js.snap +++ b/spec/frontend/pipelines/__snapshots__/utils_spec.js.snap @@ -6,9 +6,11 @@ Array [ "groups": Array [ Object { "__typename": "CiGroup", + "id": "4", "jobs": Array [ Object { "__typename": "CiJob", + "id": "6", "name": "build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl", "needs": Array [], "scheduledAt": null, @@ -18,6 +20,7 @@ Array [ "__typename": "StatusAction", "buttonTitle": "Retry this job", "icon": "retry", + "id": "8", "path": "/root/abcd-dag/-/jobs/1482/retry", "title": "Retry", }, @@ -25,6 +28,7 @@ Array [ "group": "success", "hasDetails": true, "icon": "status_success", + "id": "7", "tooltip": "passed", }, }, @@ -36,14 +40,17 @@ Array [ "__typename": "DetailedStatus", "group": "success", "icon": "status_success", + "id": "5", "label": "passed", }, }, Object { "__typename": "CiGroup", + "id": "9", "jobs": Array [ Object { "__typename": "CiJob", + "id": "11", "name": "build_b", "needs": Array [], "scheduledAt": null, @@ -53,6 +60,7 @@ Array [ "__typename": "StatusAction", "buttonTitle": "Retry this job", "icon": "retry", + "id": "13", "path": "/root/abcd-dag/-/jobs/1515/retry", "title": "Retry", }, @@ -60,6 +68,7 @@ Array [ "group": "success", "hasDetails": true, "icon": "status_success", + "id": "12", "tooltip": "passed", }, }, @@ -71,14 +80,17 @@ Array [ "__typename": "DetailedStatus", "group": "success", "icon": "status_success", + "id": "10", "label": "passed", }, }, Object { "__typename": "CiGroup", + "id": "14", "jobs": Array [ Object { "__typename": "CiJob", + "id": "16", "name": "build_c", "needs": Array [], "scheduledAt": null, @@ -88,6 +100,7 @@ Array [ "__typename": "StatusAction", "buttonTitle": "Retry this job", "icon": "retry", + "id": "18", "path": "/root/abcd-dag/-/jobs/1484/retry", "title": "Retry", }, @@ -95,6 +108,7 @@ Array [ "group": "success", "hasDetails": true, "icon": "status_success", + "id": "17", "tooltip": "passed", }, }, @@ -106,14 +120,17 @@ Array [ "__typename": "DetailedStatus", "group": "success", "icon": "status_success", + "id": "15", "label": "passed", }, }, Object { "__typename": "CiGroup", + "id": "19", "jobs": Array [ Object { "__typename": "CiJob", + "id": "21", "name": "build_d 1/3", "needs": Array [], "scheduledAt": null, @@ -123,6 +140,7 @@ Array [ "__typename": "StatusAction", "buttonTitle": "Retry this job", "icon": "retry", + "id": "23", "path": "/root/abcd-dag/-/jobs/1485/retry", "title": "Retry", }, @@ -130,11 +148,13 @@ Array [ "group": "success", "hasDetails": true, "icon": "status_success", + "id": "22", "tooltip": "passed", }, }, Object { "__typename": "CiJob", + "id": "24", "name": "build_d 2/3", "needs": Array [], "scheduledAt": null, @@ -144,6 +164,7 @@ Array [ "__typename": "StatusAction", "buttonTitle": "Retry this job", "icon": "retry", + "id": "26", "path": "/root/abcd-dag/-/jobs/1486/retry", "title": "Retry", }, @@ -151,11 +172,13 @@ Array [ "group": "success", "hasDetails": true, "icon": "status_success", + "id": "25", "tooltip": "passed", }, }, Object { "__typename": "CiJob", + "id": "27", "name": "build_d 3/3", "needs": Array [], "scheduledAt": null, @@ -165,6 +188,7 @@ Array [ "__typename": "StatusAction", "buttonTitle": "Retry this job", "icon": "retry", + "id": "29", "path": "/root/abcd-dag/-/jobs/1487/retry", "title": "Retry", }, @@ -172,6 +196,7 @@ Array [ "group": "success", "hasDetails": true, "icon": "status_success", + "id": "28", "tooltip": "passed", }, }, @@ -183,14 +208,17 @@ Array [ "__typename": "DetailedStatus", "group": "success", "icon": "status_success", + "id": "20", "label": "passed", }, }, Object { "__typename": "CiGroup", + "id": "57", "jobs": Array [ Object { "__typename": "CiJob", + "id": "59", "name": "test_c", "needs": Array [], "scheduledAt": null, @@ -201,6 +229,7 @@ Array [ "group": "success", "hasDetails": true, "icon": "status_success", + "id": "60", "tooltip": null, }, }, @@ -212,6 +241,7 @@ Array [ "__typename": "DetailedStatus", "group": "success", "icon": "status_success", + "id": "58", "label": null, }, }, @@ -226,9 +256,11 @@ Array [ "groups": Array [ Object { "__typename": "CiGroup", + "id": "32", "jobs": Array [ Object { "__typename": "CiJob", + "id": "34", "name": "test_a", "needs": Array [ "build_c", @@ -242,6 +274,7 @@ Array [ "__typename": "StatusAction", "buttonTitle": "Retry this job", "icon": "retry", + "id": "36", "path": "/root/abcd-dag/-/jobs/1514/retry", "title": "Retry", }, @@ -249,6 +282,7 @@ Array [ "group": "success", "hasDetails": true, "icon": "status_success", + "id": "35", "tooltip": "passed", }, }, @@ -260,14 +294,17 @@ Array [ "__typename": "DetailedStatus", "group": "success", "icon": "status_success", + "id": "33", "label": "passed", }, }, Object { "__typename": "CiGroup", + "id": "40", "jobs": Array [ Object { "__typename": "CiJob", + "id": "42", "name": "test_b 1/2", "needs": Array [ "build_d 3/3", @@ -283,6 +320,7 @@ Array [ "__typename": "StatusAction", "buttonTitle": "Retry this job", "icon": "retry", + "id": "44", "path": "/root/abcd-dag/-/jobs/1489/retry", "title": "Retry", }, @@ -290,11 +328,13 @@ Array [ "group": "success", "hasDetails": true, "icon": "status_success", + "id": "43", "tooltip": "passed", }, }, Object { "__typename": "CiJob", + "id": "67", "name": "test_b 2/2", "needs": Array [ "build_d 3/3", @@ -310,6 +350,7 @@ Array [ "__typename": "StatusAction", "buttonTitle": "Retry this job", "icon": "retry", + "id": "51", "path": "/root/abcd-dag/-/jobs/1490/retry", "title": "Retry", }, @@ -317,6 +358,7 @@ Array [ "group": "success", "hasDetails": true, "icon": "status_success", + "id": "50", "tooltip": "passed", }, }, @@ -328,14 +370,17 @@ Array [ "__typename": "DetailedStatus", "group": "success", "icon": "status_success", + "id": "41", "label": "passed", }, }, Object { "__typename": "CiGroup", + "id": "61", "jobs": Array [ Object { "__typename": "CiJob", + "id": "53", "name": "test_d", "needs": Array [ "build_b", @@ -348,6 +393,7 @@ Array [ "group": "success", "hasDetails": true, "icon": "status_success", + "id": "64", "tooltip": null, }, }, @@ -359,6 +405,7 @@ Array [ "__typename": "DetailedStatus", "group": "success", "icon": "status_success", + "id": "62", "label": null, }, }, diff --git a/spec/frontend/pipelines/graph/mock_data.js b/spec/frontend/pipelines/graph/mock_data.js index 3812483766d..dcbbde7bf36 100644 --- a/spec/frontend/pipelines/graph/mock_data.js +++ b/spec/frontend/pipelines/graph/mock_data.js @@ -4,6 +4,7 @@ export const mockPipelineResponse = { data: { project: { __typename: 'Project', + id: '1', pipeline: { __typename: 'Pipeline', id: 163, @@ -21,9 +22,11 @@ export const mockPipelineResponse = { nodes: [ { __typename: 'CiStage', + id: '2', name: 'build', status: { __typename: 'DetailedStatus', + id: '3', action: null, }, groups: { @@ -31,10 +34,12 @@ export const mockPipelineResponse = { nodes: [ { __typename: 'CiGroup', + id: '4', name: 'build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl', size: 1, status: { __typename: 'DetailedStatus', + id: '5', label: 'passed', group: 'success', icon: 'status_success', @@ -44,10 +49,12 @@ export const mockPipelineResponse = { nodes: [ { __typename: 'CiJob', + id: '6', name: 'build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl', scheduledAt: null, status: { __typename: 'DetailedStatus', + id: '7', icon: 'status_success', tooltip: 'passed', hasDetails: true, @@ -55,6 +62,7 @@ export const mockPipelineResponse = { group: 'success', action: { __typename: 'StatusAction', + id: '8', buttonTitle: 'Retry this job', icon: 'retry', path: '/root/abcd-dag/-/jobs/1482/retry', @@ -72,9 +80,11 @@ export const mockPipelineResponse = { { __typename: 'CiGroup', name: 'build_b', + id: '9', size: 1, status: { __typename: 'DetailedStatus', + id: '10', label: 'passed', group: 'success', icon: 'status_success', @@ -84,10 +94,12 @@ export const mockPipelineResponse = { nodes: [ { __typename: 'CiJob', + id: '11', name: 'build_b', scheduledAt: null, status: { __typename: 'DetailedStatus', + id: '12', icon: 'status_success', tooltip: 'passed', hasDetails: true, @@ -95,6 +107,7 @@ export const mockPipelineResponse = { group: 'success', action: { __typename: 'StatusAction', + id: '13', buttonTitle: 'Retry this job', icon: 'retry', path: '/root/abcd-dag/-/jobs/1515/retry', @@ -111,10 +124,12 @@ export const mockPipelineResponse = { }, { __typename: 'CiGroup', + id: '14', name: 'build_c', size: 1, status: { __typename: 'DetailedStatus', + id: '15', label: 'passed', group: 'success', icon: 'status_success', @@ -124,10 +139,12 @@ export const mockPipelineResponse = { nodes: [ { __typename: 'CiJob', + id: '16', name: 'build_c', scheduledAt: null, status: { __typename: 'DetailedStatus', + id: '17', icon: 'status_success', tooltip: 'passed', hasDetails: true, @@ -135,6 +152,7 @@ export const mockPipelineResponse = { group: 'success', action: { __typename: 'StatusAction', + id: '18', buttonTitle: 'Retry this job', icon: 'retry', path: '/root/abcd-dag/-/jobs/1484/retry', @@ -151,10 +169,12 @@ export const mockPipelineResponse = { }, { __typename: 'CiGroup', + id: '19', name: 'build_d', size: 3, status: { __typename: 'DetailedStatus', + id: '20', label: 'passed', group: 'success', icon: 'status_success', @@ -164,10 +184,12 @@ export const mockPipelineResponse = { nodes: [ { __typename: 'CiJob', + id: '21', name: 'build_d 1/3', scheduledAt: null, status: { __typename: 'DetailedStatus', + id: '22', icon: 'status_success', tooltip: 'passed', hasDetails: true, @@ -175,6 +197,7 @@ export const mockPipelineResponse = { group: 'success', action: { __typename: 'StatusAction', + id: '23', buttonTitle: 'Retry this job', icon: 'retry', path: '/root/abcd-dag/-/jobs/1485/retry', @@ -188,10 +211,12 @@ export const mockPipelineResponse = { }, { __typename: 'CiJob', + id: '24', name: 'build_d 2/3', scheduledAt: null, status: { __typename: 'DetailedStatus', + id: '25', icon: 'status_success', tooltip: 'passed', hasDetails: true, @@ -199,6 +224,7 @@ export const mockPipelineResponse = { group: 'success', action: { __typename: 'StatusAction', + id: '26', buttonTitle: 'Retry this job', icon: 'retry', path: '/root/abcd-dag/-/jobs/1486/retry', @@ -212,10 +238,12 @@ export const mockPipelineResponse = { }, { __typename: 'CiJob', + id: '27', name: 'build_d 3/3', scheduledAt: null, status: { __typename: 'DetailedStatus', + id: '28', icon: 'status_success', tooltip: 'passed', hasDetails: true, @@ -223,6 +251,7 @@ export const mockPipelineResponse = { group: 'success', action: { __typename: 'StatusAction', + id: '29', buttonTitle: 'Retry this job', icon: 'retry', path: '/root/abcd-dag/-/jobs/1487/retry', @@ -242,9 +271,11 @@ export const mockPipelineResponse = { }, { __typename: 'CiStage', + id: '30', name: 'test', status: { __typename: 'DetailedStatus', + id: '31', action: null, }, groups: { @@ -252,10 +283,12 @@ export const mockPipelineResponse = { nodes: [ { __typename: 'CiGroup', + id: '32', name: 'test_a', size: 1, status: { __typename: 'DetailedStatus', + id: '33', label: 'passed', group: 'success', icon: 'status_success', @@ -265,10 +298,12 @@ export const mockPipelineResponse = { nodes: [ { __typename: 'CiJob', + id: '34', name: 'test_a', scheduledAt: null, status: { __typename: 'DetailedStatus', + id: '35', icon: 'status_success', tooltip: 'passed', hasDetails: true, @@ -276,6 +311,7 @@ export const mockPipelineResponse = { group: 'success', action: { __typename: 'StatusAction', + id: '36', buttonTitle: 'Retry this job', icon: 'retry', path: '/root/abcd-dag/-/jobs/1514/retry', @@ -287,14 +323,17 @@ export const mockPipelineResponse = { nodes: [ { __typename: 'CiBuildNeed', + id: '37', name: 'build_c', }, { __typename: 'CiBuildNeed', + id: '38', name: 'build_b', }, { __typename: 'CiBuildNeed', + id: '39', name: 'build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl', }, @@ -306,10 +345,12 @@ export const mockPipelineResponse = { }, { __typename: 'CiGroup', + id: '40', name: 'test_b', size: 2, status: { __typename: 'DetailedStatus', + id: '41', label: 'passed', group: 'success', icon: 'status_success', @@ -319,10 +360,12 @@ export const mockPipelineResponse = { nodes: [ { __typename: 'CiJob', + id: '42', name: 'test_b 1/2', scheduledAt: null, status: { __typename: 'DetailedStatus', + id: '43', icon: 'status_success', tooltip: 'passed', hasDetails: true, @@ -330,6 +373,7 @@ export const mockPipelineResponse = { group: 'success', action: { __typename: 'StatusAction', + id: '44', buttonTitle: 'Retry this job', icon: 'retry', path: '/root/abcd-dag/-/jobs/1489/retry', @@ -341,22 +385,27 @@ export const mockPipelineResponse = { nodes: [ { __typename: 'CiBuildNeed', + id: '45', name: 'build_d 3/3', }, { __typename: 'CiBuildNeed', + id: '46', name: 'build_d 2/3', }, { __typename: 'CiBuildNeed', + id: '47', name: 'build_d 1/3', }, { __typename: 'CiBuildNeed', + id: '48', name: 'build_b', }, { __typename: 'CiBuildNeed', + id: '49', name: 'build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl', }, @@ -365,10 +414,12 @@ export const mockPipelineResponse = { }, { __typename: 'CiJob', + id: '67', name: 'test_b 2/2', scheduledAt: null, status: { __typename: 'DetailedStatus', + id: '50', icon: 'status_success', tooltip: 'passed', hasDetails: true, @@ -376,6 +427,7 @@ export const mockPipelineResponse = { group: 'success', action: { __typename: 'StatusAction', + id: '51', buttonTitle: 'Retry this job', icon: 'retry', path: '/root/abcd-dag/-/jobs/1490/retry', @@ -387,22 +439,27 @@ export const mockPipelineResponse = { nodes: [ { __typename: 'CiBuildNeed', + id: '52', name: 'build_d 3/3', }, { __typename: 'CiBuildNeed', + id: '53', name: 'build_d 2/3', }, { __typename: 'CiBuildNeed', + id: '54', name: 'build_d 1/3', }, { __typename: 'CiBuildNeed', + id: '55', name: 'build_b', }, { __typename: 'CiBuildNeed', + id: '56', name: 'build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl', }, @@ -415,9 +472,11 @@ export const mockPipelineResponse = { { __typename: 'CiGroup', name: 'test_c', + id: '57', size: 1, status: { __typename: 'DetailedStatus', + id: '58', label: null, group: 'success', icon: 'status_success', @@ -427,10 +486,12 @@ export const mockPipelineResponse = { nodes: [ { __typename: 'CiJob', + id: '59', name: 'test_c', scheduledAt: null, status: { __typename: 'DetailedStatus', + id: '60', icon: 'status_success', tooltip: null, hasDetails: true, @@ -448,9 +509,11 @@ export const mockPipelineResponse = { }, { __typename: 'CiGroup', + id: '61', name: 'test_d', size: 1, status: { + id: '62', __typename: 'DetailedStatus', label: null, group: 'success', @@ -461,10 +524,12 @@ export const mockPipelineResponse = { nodes: [ { __typename: 'CiJob', + id: '53', name: 'test_d', scheduledAt: null, status: { __typename: 'DetailedStatus', + id: '64', icon: 'status_success', tooltip: null, hasDetails: true, @@ -477,6 +542,7 @@ export const mockPipelineResponse = { nodes: [ { __typename: 'CiBuildNeed', + id: '65', name: 'build_b', }, ], @@ -502,6 +568,7 @@ export const downstream = { iid: '31', path: '/root/elemenohpee/-/pipelines/175', status: { + id: '70', group: 'success', label: 'passed', icon: 'status_success', @@ -509,6 +576,7 @@ export const downstream = { }, sourceJob: { name: 'test_c', + id: '71', __typename: 'CiJob', }, project: { @@ -525,12 +593,14 @@ export const downstream = { iid: '27', path: '/root/abcd-dag/-/pipelines/181', status: { + id: '72', group: 'success', label: 'passed', icon: 'status_success', __typename: 'DetailedStatus', }, sourceJob: { + id: '73', name: 'test_d', __typename: 'CiJob', }, @@ -551,6 +621,7 @@ export const upstream = { iid: '24', path: '/root/abcd-dag/-/pipelines/161', status: { + id: '74', group: 'success', label: 'passed', icon: 'status_success', @@ -571,6 +642,7 @@ export const wrappedPipelineReturn = { data: { project: { __typename: 'Project', + id: '75', pipeline: { __typename: 'Pipeline', id: 'gid://gitlab/Ci::Pipeline/175', @@ -592,12 +664,14 @@ export const wrappedPipelineReturn = { __typename: 'Pipeline', status: { __typename: 'DetailedStatus', + id: '77', group: 'success', label: 'passed', icon: 'status_success', }, sourceJob: { name: 'test_c', + id: '78', __typename: 'CiJob', }, project: { @@ -613,8 +687,10 @@ export const wrappedPipelineReturn = { { name: 'build', __typename: 'CiStage', + id: '79', status: { action: null, + id: '80', __typename: 'DetailedStatus', }, groups: { @@ -622,8 +698,10 @@ export const wrappedPipelineReturn = { nodes: [ { __typename: 'CiGroup', + id: '81', status: { __typename: 'DetailedStatus', + id: '82', label: 'passed', group: 'success', icon: 'status_success', @@ -635,6 +713,7 @@ export const wrappedPipelineReturn = { nodes: [ { __typename: 'CiJob', + id: '83', name: 'build_n', scheduledAt: null, needs: { @@ -643,6 +722,7 @@ export const wrappedPipelineReturn = { }, status: { __typename: 'DetailedStatus', + id: '84', icon: 'status_success', tooltip: 'passed', hasDetails: true, @@ -650,6 +730,7 @@ export const wrappedPipelineReturn = { group: 'success', action: { __typename: 'StatusAction', + id: '85', buttonTitle: 'Retry this job', icon: 'retry', path: '/root/elemenohpee/-/jobs/1662/retry', diff --git a/spec/frontend/pipelines/mock_data.js b/spec/frontend/pipelines/mock_data.js index fdc78d48901..a65a1d4f399 100644 --- a/spec/frontend/pipelines/mock_data.js +++ b/spec/frontend/pipelines/mock_data.js @@ -14,6 +14,7 @@ export const mockPipelineHeader = { }, createdAt: threeWeeksAgo.toISOString(), user: { + id: 'user-1', name: 'Foo', username: 'foobar', email: 'foo@bar.com', @@ -27,6 +28,7 @@ export const mockFailedPipelineHeader = { retryable: true, cancelable: false, detailedStatus: { + id: 'status-1', group: 'failed', icon: 'status_failed', label: 'failed', @@ -43,6 +45,7 @@ export const mockFailedPipelineNoPermissions = { }, createdAt: threeWeeksAgo.toISOString(), user: { + id: 'user-1', name: 'Foo', username: 'foobar', email: 'foo@bar.com', @@ -52,6 +55,7 @@ export const mockFailedPipelineNoPermissions = { retryable: true, cancelable: false, detailedStatus: { + id: 'status-1', group: 'running', icon: 'status_running', label: 'running', @@ -66,6 +70,7 @@ export const mockRunningPipelineHeader = { retryable: false, cancelable: true, detailedStatus: { + id: 'status-1', group: 'running', icon: 'status_running', label: 'running', @@ -82,6 +87,7 @@ export const mockRunningPipelineNoPermissions = { }, createdAt: threeWeeksAgo.toISOString(), user: { + id: 'user-1', name: 'Foo', username: 'foobar', email: 'foo@bar.com', @@ -91,6 +97,7 @@ export const mockRunningPipelineNoPermissions = { retryable: false, cancelable: true, detailedStatus: { + id: 'status-1', group: 'running', icon: 'status_running', label: 'running', @@ -105,6 +112,7 @@ export const mockCancelledPipelineHeader = { retryable: true, cancelable: false, detailedStatus: { + id: 'status-1', group: 'cancelled', icon: 'status_cancelled', label: 'cancelled', @@ -119,6 +127,7 @@ export const mockSuccessfulPipelineHeader = { retryable: false, cancelable: false, detailedStatus: { + id: 'status-1', group: 'success', icon: 'status_success', label: 'success', @@ -130,13 +139,16 @@ export const mockSuccessfulPipelineHeader = { export const mockRunningPipelineHeaderData = { data: { project: { + id: '1', pipeline: { ...mockRunningPipelineHeader, iid: '28', user: { + id: 'user-1', name: 'Foo', username: 'foobar', webPath: '/foo', + webUrl: '/foo', email: 'foo@bar.com', avatarUrl: 'link', status: null, diff --git a/spec/frontend/projects/new/components/new_project_url_select_spec.js b/spec/frontend/projects/new/components/new_project_url_select_spec.js index b3f177a1f12..bdce8af613b 100644 --- a/spec/frontend/projects/new/components/new_project_url_select_spec.js +++ b/spec/frontend/projects/new/components/new_project_url_select_spec.js @@ -19,6 +19,7 @@ describe('NewProjectUrlSelect component', () => { const data = { currentUser: { + id: 'user-1', groups: { nodes: [ { @@ -194,6 +195,7 @@ describe('NewProjectUrlSelect component', () => { it('renders `No matches found` when there are no matching dropdown items', async () => { const queryResponse = { currentUser: { + id: 'user-1', groups: { nodes: [], }, diff --git a/spec/frontend/projects/pipelines/charts/mock_data.js b/spec/frontend/projects/pipelines/charts/mock_data.js index 2e2c594102c..04971b5b20e 100644 --- a/spec/frontend/projects/pipelines/charts/mock_data.js +++ b/spec/frontend/projects/pipelines/charts/mock_data.js @@ -48,6 +48,7 @@ export const transformedAreaChartData = [ export const mockPipelineCount = { data: { project: { + id: '1', totalPipelines: { count: 34, __typename: 'PipelineConnection' }, successfulPipelines: { count: 23, __typename: 'PipelineConnection' }, failedPipelines: { count: 1, __typename: 'PipelineConnection' }, @@ -70,6 +71,7 @@ export const chartOptions = { export const mockPipelineStatistics = { data: { project: { + id: '1', pipelineAnalytics: { weekPipelinesTotals: [0, 0, 0, 0, 0, 0, 0, 0], weekPipelinesLabels: [ diff --git a/spec/frontend/releases/__snapshots__/util_spec.js.snap b/spec/frontend/releases/__snapshots__/util_spec.js.snap index b2580d47549..fd2a8eec4d4 100644 --- a/spec/frontend/releases/__snapshots__/util_spec.js.snap +++ b/spec/frontend/releases/__snapshots__/util_spec.js.snap @@ -44,6 +44,7 @@ Object { "author": Object { "__typename": "UserCore", "avatarUrl": "https://www.gravatar.com/avatar/16f8e2050ce10180ca571c2eb19cfce2?s=80&d=identicon", + "id": Any<String>, "username": "administrator", "webUrl": "http://localhost/administrator", }, @@ -139,6 +140,7 @@ Object { "author": Object { "__typename": "UserCore", "avatarUrl": "https://www.gravatar.com/avatar/16f8e2050ce10180ca571c2eb19cfce2?s=80&d=identicon", + "id": Any<String>, "username": "administrator", "webUrl": "http://localhost/administrator", }, @@ -153,6 +155,7 @@ Object { "__typename": "ReleaseEvidence", "collectedAt": "2018-12-03T00:00:00Z", "filepath": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/evidences/1.json", + "id": "gid://gitlab/Releases::Evidence/1", "sha": "760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d", }, ], @@ -247,6 +250,7 @@ Object { "evidences": Array [], "milestones": Array [ Object { + "id": "gid://gitlab/Milestone/123", "issueStats": Object {}, "stats": undefined, "title": "12.3", @@ -254,6 +258,7 @@ Object { "webUrl": undefined, }, Object { + "id": "gid://gitlab/Milestone/124", "issueStats": Object {}, "stats": undefined, "title": "12.4", @@ -347,6 +352,7 @@ Object { "author": Object { "__typename": "UserCore", "avatarUrl": "https://www.gravatar.com/avatar/16f8e2050ce10180ca571c2eb19cfce2?s=80&d=identicon", + "id": Any<String>, "username": "administrator", "webUrl": "http://localhost/administrator", }, @@ -361,6 +367,7 @@ Object { "__typename": "ReleaseEvidence", "collectedAt": "2018-12-03T00:00:00Z", "filepath": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/evidences/1.json", + "id": "gid://gitlab/Releases::Evidence/1", "sha": "760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d", }, ], diff --git a/spec/frontend/releases/components/app_show_spec.js b/spec/frontend/releases/components/app_show_spec.js index 72ebaaaf76c..a60b9bda66a 100644 --- a/spec/frontend/releases/components/app_show_spec.js +++ b/spec/frontend/releases/components/app_show_spec.js @@ -58,7 +58,6 @@ describe('Release show component', () => { const expectFlashWithMessage = (message) => { it(`shows a flash message that reads "${message}"`, () => { - expect(createFlash).toHaveBeenCalledTimes(1); expect(createFlash).toHaveBeenCalledWith({ message, captureError: true, diff --git a/spec/frontend/releases/util_spec.js b/spec/frontend/releases/util_spec.js index 3c1060cb0e8..055c8e8b39f 100644 --- a/spec/frontend/releases/util_spec.js +++ b/spec/frontend/releases/util_spec.js @@ -104,13 +104,32 @@ describe('releases/util.js', () => { describe('convertAllReleasesGraphQLResponse', () => { it('matches snapshot', () => { - expect(convertAllReleasesGraphQLResponse(originalAllReleasesQueryResponse)).toMatchSnapshot(); + expect(convertAllReleasesGraphQLResponse(originalAllReleasesQueryResponse)).toMatchSnapshot({ + data: [ + { + author: { + id: expect.any(String), + }, + }, + { + author: { + id: expect.any(String), + }, + }, + ], + }); }); }); describe('convertOneReleaseGraphQLResponse', () => { it('matches snapshot', () => { - expect(convertOneReleaseGraphQLResponse(originalOneReleaseQueryResponse)).toMatchSnapshot(); + expect(convertOneReleaseGraphQLResponse(originalOneReleaseQueryResponse)).toMatchSnapshot({ + data: { + author: { + id: expect.any(String), + }, + }, + }); }); }); diff --git a/spec/frontend/repository/mock_data.js b/spec/frontend/repository/mock_data.js index 99018de6efd..f67eed34a58 100644 --- a/spec/frontend/repository/mock_data.js +++ b/spec/frontend/repository/mock_data.js @@ -1,4 +1,5 @@ export const simpleViewerMock = { + id: '1', name: 'some_file.js', size: 123, rawSize: 123, diff --git a/spec/frontend/sidebar/components/time_tracking/mock_data.js b/spec/frontend/sidebar/components/time_tracking/mock_data.js index 938750bd58b..3f1b3fa8ec1 100644 --- a/spec/frontend/sidebar/components/time_tracking/mock_data.js +++ b/spec/frontend/sidebar/components/time_tracking/mock_data.js @@ -11,11 +11,13 @@ export const getIssueTimelogsQueryResponse = { __typename: 'Timelog', timeSpent: 14400, user: { + id: 'user-1', name: 'John Doe18', __typename: 'UserCore', }, spentAt: '2020-05-01T00:00:00Z', note: { + id: 'note-1', body: 'A note', __typename: 'Note', }, @@ -25,6 +27,7 @@ export const getIssueTimelogsQueryResponse = { __typename: 'Timelog', timeSpent: 1800, user: { + id: 'user-2', name: 'Administrator', __typename: 'UserCore', }, @@ -36,11 +39,13 @@ export const getIssueTimelogsQueryResponse = { __typename: 'Timelog', timeSpent: 14400, user: { + id: 'user-2', name: 'Administrator', __typename: 'UserCore', }, spentAt: '2021-05-01T00:00:00Z', note: { + id: 'note-2', body: 'A note', __typename: 'Note', }, @@ -65,11 +70,13 @@ export const getMrTimelogsQueryResponse = { __typename: 'Timelog', timeSpent: 1800, user: { + id: 'user-1', name: 'Administrator', __typename: 'UserCore', }, spentAt: '2021-05-07T14:44:55Z', note: { + id: 'note-1', body: 'Thirty minutes!', __typename: 'Note', }, @@ -79,6 +86,7 @@ export const getMrTimelogsQueryResponse = { __typename: 'Timelog', timeSpent: 3600, user: { + id: 'user-1', name: 'Administrator', __typename: 'UserCore', }, @@ -90,11 +98,13 @@ export const getMrTimelogsQueryResponse = { __typename: 'Timelog', timeSpent: 300, user: { + id: 'user-1', name: 'Administrator', __typename: 'UserCore', }, spentAt: '2021-03-10T00:00:00Z', note: { + id: 'note-2', body: 'A note with some time', __typename: 'Note', }, diff --git a/spec/frontend/sidebar/mock_data.js b/spec/frontend/sidebar/mock_data.js index 1ebd3c622ca..42e89a3ba84 100644 --- a/spec/frontend/sidebar/mock_data.js +++ b/spec/frontend/sidebar/mock_data.js @@ -223,6 +223,7 @@ const mockData = { export const issueConfidentialityResponse = (confidential = false) => ({ data: { workspace: { + id: '1', __typename: 'Project', issuable: { __typename: 'Issue', @@ -236,6 +237,7 @@ export const issueConfidentialityResponse = (confidential = false) => ({ export const issuableDueDateResponse = (dueDate = null) => ({ data: { workspace: { + id: '1', __typename: 'Project', issuable: { __typename: 'Issue', @@ -249,6 +251,7 @@ export const issuableDueDateResponse = (dueDate = null) => ({ export const issuableStartDateResponse = (startDate = null) => ({ data: { workspace: { + id: '1', __typename: 'Group', issuable: { __typename: 'Epic', @@ -265,6 +268,7 @@ export const issuableStartDateResponse = (startDate = null) => ({ export const epicParticipantsResponse = () => ({ data: { workspace: { + id: '1', __typename: 'Group', issuable: { __typename: 'Epic', @@ -290,6 +294,7 @@ export const epicParticipantsResponse = () => ({ export const issueReferenceResponse = (reference) => ({ data: { workspace: { + id: '1', __typename: 'Project', issuable: { __typename: 'Issue', @@ -303,6 +308,7 @@ export const issueReferenceResponse = (reference) => ({ export const issueSubscriptionsResponse = (subscribed = false, emailsDisabled = false) => ({ data: { workspace: { + id: '1', __typename: 'Project', issuable: { __typename: 'Issue', @@ -318,6 +324,7 @@ export const issuableQueryResponse = { data: { workspace: { __typename: 'Project', + id: '1', issuable: { __typename: 'Issue', id: 'gid://gitlab/Issue/1', @@ -344,6 +351,7 @@ export const searchQueryResponse = { data: { workspace: { __typename: 'Project', + id: '1', users: { nodes: [ { @@ -428,12 +436,15 @@ export const searchResponse = { data: { workspace: { __typename: 'Project', + id: '1', users: { nodes: [ { + id: 'gid://gitlab/User/1', user: mockUser1, }, { + id: 'gid://gitlab/User/4', user: mockUser2, }, ], @@ -445,6 +456,7 @@ export const searchResponse = { export const projectMembersResponse = { data: { workspace: { + id: '1', __typename: 'Project', users: { nodes: [ @@ -452,10 +464,11 @@ export const projectMembersResponse = { null, null, // Remove duplicated entry https://gitlab.com/gitlab-org/gitlab/-/issues/327822 - { user: mockUser1 }, - { user: mockUser1 }, - { user: mockUser2 }, + { id: 'user-1', user: mockUser1 }, + { id: 'user-2', user: mockUser1 }, + { id: 'user-3', user: mockUser2 }, { + id: 'user-4', user: { id: 'gid://gitlab/User/2', avatarUrl: @@ -477,16 +490,18 @@ export const projectMembersResponse = { export const groupMembersResponse = { data: { workspace: { - __typename: 'roup', + id: '1', + __typename: 'Group', users: { nodes: [ // Remove nulls https://gitlab.com/gitlab-org/gitlab/-/issues/329750 null, null, // Remove duplicated entry https://gitlab.com/gitlab-org/gitlab/-/issues/327822 - { user: mockUser1 }, - { user: mockUser1 }, + { id: 'user-1', user: mockUser1 }, + { id: 'user-2', user: mockUser1 }, { + id: 'user-3', user: { id: 'gid://gitlab/User/2', avatarUrl: @@ -509,6 +524,7 @@ export const participantsQueryResponse = { data: { workspace: { __typename: 'Project', + id: '1', issuable: { __typename: 'Issue', id: 'gid://gitlab/Issue/1', @@ -578,6 +594,7 @@ export const mockMilestone2 = { export const mockProjectMilestonesResponse = { data: { workspace: { + id: 'gid://gitlab/Project/1', attributes: { nodes: [mockMilestone1, mockMilestone2], }, @@ -663,6 +680,7 @@ export const todosResponse = { data: { workspace: { __typename: 'Group', + id: '1', issuable: { __typename: 'Epic', id: 'gid://gitlab/Epic/4', @@ -681,6 +699,7 @@ export const todosResponse = { export const noTodosResponse = { data: { workspace: { + id: '1', __typename: 'Group', issuable: { __typename: 'Epic', diff --git a/spec/frontend/snippets/components/edit_spec.js b/spec/frontend/snippets/components/edit_spec.js index 4e88ab9504e..80a8b8ec489 100644 --- a/spec/frontend/snippets/components/edit_spec.js +++ b/spec/frontend/snippets/components/edit_spec.js @@ -53,6 +53,7 @@ const createMutationResponse = (key, obj = {}) => ({ errors: [], snippet: { __typename: 'Snippet', + id: 1, webUrl: TEST_WEB_URL, }, }, diff --git a/spec/frontend/snippets/test_utils.js b/spec/frontend/snippets/test_utils.js index 8ba5a2fe5dc..dcef8fc9a8b 100644 --- a/spec/frontend/snippets/test_utils.js +++ b/spec/frontend/snippets/test_utils.js @@ -27,6 +27,7 @@ export const createGQLSnippet = () => ({ }, project: { __typename: 'Project', + id: 'project-1', fullPath: 'group/project', webUrl: `${TEST_HOST}/group/project`, }, diff --git a/spec/frontend/terraform/components/terraform_list_spec.js b/spec/frontend/terraform/components/terraform_list_spec.js index c622f86072d..8e565df81ae 100644 --- a/spec/frontend/terraform/components/terraform_list_spec.js +++ b/spec/frontend/terraform/components/terraform_list_spec.js @@ -23,6 +23,7 @@ describe('TerraformList', () => { const apolloQueryResponse = { data: { project: { + id: '1', terraformStates, }, }, diff --git a/spec/frontend/token_access/mock_data.js b/spec/frontend/token_access/mock_data.js index 14d7b00cb6d..0f121fd1beb 100644 --- a/spec/frontend/token_access/mock_data.js +++ b/spec/frontend/token_access/mock_data.js @@ -1,6 +1,7 @@ export const enabledJobTokenScope = { data: { project: { + id: '1', ciCdSettings: { jobTokenScopeEnabled: true, __typename: 'ProjectCiCdSetting', @@ -13,6 +14,7 @@ export const enabledJobTokenScope = { export const disabledJobTokenScope = { data: { project: { + id: '1', ciCdSettings: { jobTokenScopeEnabled: false, __typename: 'ProjectCiCdSetting', @@ -39,12 +41,14 @@ export const projectsWithScope = { data: { project: { __typename: 'Project', + id: '1', ciJobTokenScope: { __typename: 'CiJobTokenScopeType', projects: { __typename: 'ProjectConnection', nodes: [ { + id: '2', fullPath: 'root/332268-test', name: 'root/332268-test', }, @@ -75,10 +79,17 @@ export const removeProjectSuccess = { export const mockProjects = [ { + id: '1', name: 'merge-train-stuff', fullPath: 'root/merge-train-stuff', isLocked: false, __typename: 'Project', }, - { name: 'ci-project', fullPath: 'root/ci-project', isLocked: true, __typename: 'Project' }, + { + id: '2', + name: 'ci-project', + fullPath: 'root/ci-project', + isLocked: true, + __typename: 'Project', + }, ]; diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js index 5c5bf5f2187..7c147713a7f 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js @@ -118,6 +118,7 @@ export const workspaceLabelsQueryResponse = { export const issuableLabelsQueryResponse = { data: { workspace: { + id: 'workspace-1', issuable: { id: '1', labels: { diff --git a/spec/frontend/vue_shared/security_reports/mock_data.js b/spec/frontend/vue_shared/security_reports/mock_data.js index cdaeec78e47..2b1513bb0f8 100644 --- a/spec/frontend/vue_shared/security_reports/mock_data.js +++ b/spec/frontend/vue_shared/security_reports/mock_data.js @@ -341,12 +341,15 @@ export const securityReportMergeRequestDownloadPathsQueryNoArtifactsResponse = { export const securityReportMergeRequestDownloadPathsQueryResponse = { project: { + id: '1', mergeRequest: { + id: 'mr-1', headPipeline: { id: 'gid://gitlab/Ci::Pipeline/176', jobs: { nodes: [ { + id: 'job-1', name: 'secret_detection', artifacts: { nodes: [ @@ -368,6 +371,7 @@ export const securityReportMergeRequestDownloadPathsQueryResponse = { __typename: 'CiJob', }, { + id: 'job-2', name: 'bandit-sast', artifacts: { nodes: [ @@ -389,6 +393,7 @@ export const securityReportMergeRequestDownloadPathsQueryResponse = { __typename: 'CiJob', }, { + id: 'job-3', name: 'eslint-sast', artifacts: { nodes: [ @@ -410,6 +415,7 @@ export const securityReportMergeRequestDownloadPathsQueryResponse = { __typename: 'CiJob', }, { + id: 'job-4', name: 'all_artifacts', artifacts: { nodes: [ @@ -449,11 +455,13 @@ export const securityReportMergeRequestDownloadPathsQueryResponse = { export const securityReportPipelineDownloadPathsQueryResponse = { project: { + id: 'project-1', pipeline: { id: 'gid://gitlab/Ci::Pipeline/176', jobs: { nodes: [ { + id: 'job-1', name: 'secret_detection', artifacts: { nodes: [ @@ -475,6 +483,7 @@ export const securityReportPipelineDownloadPathsQueryResponse = { __typename: 'CiJob', }, { + id: 'job-2', name: 'bandit-sast', artifacts: { nodes: [ @@ -496,6 +505,7 @@ export const securityReportPipelineDownloadPathsQueryResponse = { __typename: 'CiJob', }, { + id: 'job-3', name: 'eslint-sast', artifacts: { nodes: [ @@ -517,6 +527,7 @@ export const securityReportPipelineDownloadPathsQueryResponse = { __typename: 'CiJob', }, { + id: 'job-4', name: 'all_artifacts', artifacts: { nodes: [ diff --git a/spec/graphql/mutations/merge_requests/accept_spec.rb b/spec/graphql/mutations/merge_requests/accept_spec.rb index db75c64a447..c97c78ec206 100644 --- a/spec/graphql/mutations/merge_requests/accept_spec.rb +++ b/spec/graphql/mutations/merge_requests/accept_spec.rb @@ -5,14 +5,14 @@ require 'spec_helper' RSpec.describe Mutations::MergeRequests::Accept do include AfterNextHelpers - let_it_be(:user) { create(:user) } - let(:project) { create(:project, :public, :repository) } - subject(:mutation) { described_class.new(context: context, object: nil, field: nil) } - let_it_be(:context) do + let_it_be(:user) { create(:user) } + + let(:project) { create(:project, :public, :repository) } + let(:context) do GraphQL::Query::Context.new( - query: OpenStruct.new(schema: GitlabSchema), + query: double('query', schema: GitlabSchema), values: { current_user: user }, object: nil ) diff --git a/spec/graphql/resolvers/container_repository_tags_resolver_spec.rb b/spec/graphql/resolvers/container_repository_tags_resolver_spec.rb new file mode 100644 index 00000000000..4e7ea253c87 --- /dev/null +++ b/spec/graphql/resolvers/container_repository_tags_resolver_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Resolvers::ContainerRepositoryTagsResolver do + include GraphqlHelpers + + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, :public) } + let_it_be_with_reload(:repository) { create(:container_repository, project: project) } + + let(:args) { { sort: nil } } + + describe '#resolve' do + let(:resolver) { resolve(described_class, ctx: { current_user: user }, obj: repository, args: args) } + + before do + stub_container_registry_config(enabled: true) + end + + context 'by name' do + subject { resolver.map(&:name) } + + before do + stub_container_registry_tags(repository: repository.path, tags: %w(aaa bab bbb ccc 123), with_manifest: false) + end + + context 'without sort' do + # order is not guaranteed + it { is_expected.to contain_exactly('aaa', 'bab', 'bbb', 'ccc', '123') } + end + + context 'with sorting and filtering' do + context "name_asc" do + let(:args) { { sort: :name_asc } } + + it { is_expected.to eq(%w(123 aaa bab bbb ccc)) } + end + + context "name_desc" do + let(:args) { { sort: :name_desc } } + + it { is_expected.to eq(%w(ccc bbb bab aaa 123)) } + end + + context 'filter by name' do + let(:args) { { sort: :name_desc, name: 'b' } } + + it { is_expected.to eq(%w(bbb bab)) } + end + end + end + end +end diff --git a/spec/graphql/types/container_respository_tags_sort_enum_spec.rb b/spec/graphql/types/container_respository_tags_sort_enum_spec.rb new file mode 100644 index 00000000000..b464037d8d9 --- /dev/null +++ b/spec/graphql/types/container_respository_tags_sort_enum_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['ContainerRepositoryTagSort'] do + specify { expect(described_class.graphql_name).to eq('ContainerRepositoryTagSort') } + + it 'exposes all the existing issue sort values' do + expect(described_class.values.keys).to include( + *%w[NAME_ASC NAME_DESC] + ) + end +end diff --git a/spec/models/project_authorization_spec.rb b/spec/models/project_authorization_spec.rb index 58c0ff48b46..37da30fb54c 100644 --- a/spec/models/project_authorization_spec.rb +++ b/spec/models/project_authorization_spec.rb @@ -3,40 +3,59 @@ require 'spec_helper' RSpec.describe ProjectAuthorization do - let_it_be(:user) { create(:user) } - let_it_be(:project1) { create(:project) } - let_it_be(:project2) { create(:project) } - let_it_be(:project3) { create(:project) } + describe 'relations' do + it { is_expected.to belong_to(:user) } + it { is_expected.to belong_to(:project) } + end - describe '.insert_authorizations' do - it 'inserts the authorizations' do - described_class - .insert_authorizations([[user.id, project1.id, Gitlab::Access::MAINTAINER]]) + describe 'validations' do + it { is_expected.to validate_presence_of(:project) } + it { is_expected.to validate_presence_of(:user) } + it { is_expected.to validate_presence_of(:access_level) } + it { is_expected.to validate_inclusion_of(:access_level).in_array(Gitlab::Access.all_values) } + end - expect(user.project_authorizations.count).to eq(1) - end + describe '.insert_all' do + let_it_be(:user) { create(:user) } + let_it_be(:project_1) { create(:project) } + let_it_be(:project_2) { create(:project) } + let_it_be(:project_3) { create(:project) } - it 'inserts rows in batches' do - described_class.insert_authorizations([ - [user.id, project1.id, Gitlab::Access::MAINTAINER], - [user.id, project2.id, Gitlab::Access::MAINTAINER] - ], 1) + it 'skips duplicates and inserts the remaining rows without error' do + create(:project_authorization, user: user, project: project_1, access_level: Gitlab::Access::MAINTAINER) + + attributes = [ + { user_id: user.id, project_id: project_1.id, access_level: Gitlab::Access::MAINTAINER }, + { user_id: user.id, project_id: project_2.id, access_level: Gitlab::Access::MAINTAINER }, + { user_id: user.id, project_id: project_3.id, access_level: Gitlab::Access::MAINTAINER } + ] - expect(user.project_authorizations.count).to eq(2) + described_class.insert_all(attributes) + + expect(user.project_authorizations.pluck(:user_id, :project_id, :access_level)).to match_array(attributes.map(&:values)) end + end - it 'skips duplicates and inserts the remaining rows without error' do - create(:project_authorization, user: user, project: project1, access_level: Gitlab::Access::MAINTAINER) + describe '.insert_all_in_batches' do + let_it_be(:user) { create(:user) } + let_it_be(:project_1) { create(:project) } + let_it_be(:project_2) { create(:project) } + let_it_be(:project_3) { create(:project) } - rows = [ - [user.id, project1.id, Gitlab::Access::MAINTAINER], - [user.id, project2.id, Gitlab::Access::MAINTAINER], - [user.id, project3.id, Gitlab::Access::MAINTAINER] + let(:per_batch_size) { 2 } + + it 'inserts the rows in batches, as per the `per_batch` size' do + attributes = [ + { user_id: user.id, project_id: project_1.id, access_level: Gitlab::Access::MAINTAINER }, + { user_id: user.id, project_id: project_2.id, access_level: Gitlab::Access::MAINTAINER }, + { user_id: user.id, project_id: project_3.id, access_level: Gitlab::Access::MAINTAINER } ] - described_class.insert_authorizations(rows) + expect(described_class).to receive(:insert_all).twice.and_call_original + + described_class.insert_all_in_batches(attributes, per_batch_size) - expect(user.project_authorizations.pluck(:user_id, :project_id, :access_level)).to match_array(rows) + expect(user.project_authorizations.pluck(:user_id, :project_id, :access_level)).to match_array(attributes.map(&:values)) end end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index ec26bc5edfc..a612a30369d 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -851,6 +851,23 @@ RSpec.describe Project, factory_default: :keep do end end + describe '#remove_project_authorizations' do + let_it_be(:project) { create(:project) } + let_it_be(:user_1) { create(:user) } + let_it_be(:user_2) { create(:user) } + let_it_be(:user_3) { create(:user) } + + it 'removes the project authorizations of the specified users in the current project' do + create(:project_authorization, user: user_1, project: project) + create(:project_authorization, user: user_2, project: project) + create(:project_authorization, user: user_3, project: project) + + project.remove_project_authorizations([user_1.id, user_2.id]) + + expect(project.project_authorizations.pluck(:user_id)).not_to include(user_1.id, user_2.id) + end + end + describe 'reference methods' do let_it_be(:owner) { create(:user, name: 'Gitlab') } let_it_be(:namespace) { create(:namespace, name: 'Sample namespace', path: 'sample-namespace', owner: owner) } diff --git a/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb b/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb index d93afcc0f33..802ab847b3d 100644 --- a/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb +++ b/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb @@ -30,6 +30,14 @@ RSpec.describe 'container repository details' do subject { post_graphql(query, current_user: user, variables: variables) } + shared_examples 'returning an invalid value error' do + it 'returns an error' do + subject + + expect(graphql_errors.first.dig('message')).to match(/invalid value/) + end + end + it_behaves_like 'a working graphql query' do before do subject @@ -138,6 +146,80 @@ RSpec.describe 'container repository details' do end end + context 'sorting the tags' do + let(:sort) { 'NAME_DESC' } + let(:tags_response) { container_repository_details_response.dig('tags', 'edges') } + let(:variables) do + { id: container_repository_global_id, n: sort } + end + + let(:query) do + <<~GQL + query($id: ID!, $n: ContainerRepositoryTagSort) { + containerRepository(id: $id) { + tags(sort: $n) { + edges { + node { + #{all_graphql_fields_for('ContainerRepositoryTag')} + } + } + } + } + } + GQL + end + + it 'sorts the tags', :aggregate_failures do + subject + + expect(tags_response.first.dig('node', 'name')).to eq('tag5') + expect(tags_response.last.dig('node', 'name')).to eq('latest') + end + + context 'invalid sort' do + let(:sort) { 'FOO_ASC' } + + it_behaves_like 'returning an invalid value error' + end + end + + context 'filtering by name' do + let(:name) { 'l' } + let(:tags_response) { container_repository_details_response.dig('tags', 'edges') } + let(:variables) do + { id: container_repository_global_id, n: name } + end + + let(:query) do + <<~GQL + query($id: ID!, $n: String) { + containerRepository(id: $id) { + tags(name: $n) { + edges { + node { + #{all_graphql_fields_for('ContainerRepositoryTag')} + } + } + } + } + } + GQL + end + + it 'sorts the tags', :aggregate_failures do + subject + + expect(tags_response.size).to eq(1) + expect(tags_response.first.dig('node', 'name')).to eq('latest') + end + + context 'invalid filter' do + let(:name) { 1 } + + it_behaves_like 'returning an invalid value error' + end + end + context 'with tags with a manifest containing nil fields' do let(:tags_response) { container_repository_details_response.dig('tags', 'nodes') } let(:errors) { container_repository_details_response.dig('errors') } diff --git a/spec/services/authorized_project_update/find_records_due_for_refresh_service_spec.rb b/spec/services/authorized_project_update/find_records_due_for_refresh_service_spec.rb index 8a53d9fbf7c..c6b184bd003 100644 --- a/spec/services/authorized_project_update/find_records_due_for_refresh_service_spec.rb +++ b/spec/services/authorized_project_update/find_records_due_for_refresh_service_spec.rb @@ -59,7 +59,9 @@ RSpec.describe AuthorizedProjectUpdate::FindRecordsDueForRefreshService do .create!(project: project2, access_level: Gitlab::Access::MAINTAINER) to_be_removed = [project2.id] - to_be_added = [[user.id, project.id, Gitlab::Access::MAINTAINER]] + to_be_added = [ + { user_id: user.id, project_id: project.id, access_level: Gitlab::Access::MAINTAINER } + ] expect(service.execute).to eq([to_be_removed, to_be_added]) end @@ -70,7 +72,9 @@ RSpec.describe AuthorizedProjectUpdate::FindRecordsDueForRefreshService do end to_be_removed = [project.id] - to_be_added = [[user.id, project.id, Gitlab::Access::MAINTAINER]] + to_be_added = [ + { user_id: user.id, project_id: project.id, access_level: Gitlab::Access::MAINTAINER } + ] expect(service.execute).to eq([to_be_removed, to_be_added]) end @@ -80,7 +84,9 @@ RSpec.describe AuthorizedProjectUpdate::FindRecordsDueForRefreshService do .create!(project: project, access_level: Gitlab::Access::DEVELOPER) to_be_removed = [project.id] - to_be_added = [[user.id, project.id, Gitlab::Access::MAINTAINER]] + to_be_added = [ + { user_id: user.id, project_id: project.id, access_level: Gitlab::Access::MAINTAINER } + ] expect(service.execute).to eq([to_be_removed, to_be_added]) end diff --git a/spec/services/merge_requests/after_create_service_spec.rb b/spec/services/merge_requests/after_create_service_spec.rb index cbbd193a411..781be57d709 100644 --- a/spec/services/merge_requests/after_create_service_spec.rb +++ b/spec/services/merge_requests/after_create_service_spec.rb @@ -85,13 +85,67 @@ RSpec.describe MergeRequests::AfterCreateService do context 'when merge request is in preparing state' do before do + merge_request.mark_as_unchecked! unless merge_request.unchecked? merge_request.mark_as_preparing! - execute_service end it 'marks the merge request as unchecked' do + execute_service + expect(merge_request.reload).to be_unchecked end + + context 'when preparing for mergeability fails' do + before do + # This is only one of the possible cases that can fail. This is to + # simulate a failure that happens during the service call. + allow(merge_request) + .to receive(:update_head_pipeline) + .and_raise(StandardError) + end + + it 'does not mark the merge request as unchecked' do + expect { execute_service }.to raise_error(StandardError) + expect(merge_request.reload).to be_preparing + end + + context 'when early_prepare_for_mergeability feature flag is disabled' do + before do + stub_feature_flags(early_prepare_for_mergeability: false) + end + + it 'does not mark the merge request as unchecked' do + expect { execute_service }.to raise_error(StandardError) + expect(merge_request.reload).to be_preparing + end + end + end + + context 'when preparing merge request fails' do + before do + # This is only one of the possible cases that can fail. This is to + # simulate a failure that happens during the service call. + allow(merge_request) + .to receive_message_chain(:diffs, :write_cache) + .and_raise(StandardError) + end + + it 'still marks the merge request as unchecked' do + expect { execute_service }.to raise_error(StandardError) + expect(merge_request.reload).to be_unchecked + end + + context 'when early_prepare_for_mergeability feature flag is disabled' do + before do + stub_feature_flags(early_prepare_for_mergeability: false) + end + + it 'does not mark the merge request as unchecked' do + expect { execute_service }.to raise_error(StandardError) + expect(merge_request.reload).to be_preparing + end + end + end end it 'increments the usage data counter of create event' do diff --git a/spec/services/merge_requests/toggle_attention_requested_service_spec.rb b/spec/services/merge_requests/toggle_attention_requested_service_spec.rb index a26b1be529e..e2455a71eef 100644 --- a/spec/services/merge_requests/toggle_attention_requested_service_spec.rb +++ b/spec/services/merge_requests/toggle_attention_requested_service_spec.rb @@ -13,9 +13,12 @@ RSpec.describe MergeRequests::ToggleAttentionRequestedService do let(:service) { described_class.new(project: project, current_user: current_user, merge_request: merge_request, user: user) } let(:result) { service.execute } let(:todo_service) { spy('todo service') } + let(:notification_service) { spy('notification service') } before do + allow(NotificationService).to receive(:new) { notification_service } allow(service).to receive(:todo_service).and_return(todo_service) + allow(service).to receive(:notification_service).and_return(notification_service) project.add_developer(current_user) project.add_developer(user) @@ -59,6 +62,12 @@ RSpec.describe MergeRequests::ToggleAttentionRequestedService do service.execute end + + it 'sends email to reviewer' do + expect(notification_service).to receive_message_chain(:async, :attention_requested_of_merge_request).with(merge_request, current_user, user) + + service.execute + end end context 'assignee exists' do diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index fbf5b183365..24775ce06a4 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -2425,6 +2425,45 @@ RSpec.describe NotificationService, :mailer do let(:notification_trigger) { notification.review_requested_of_merge_request(merge_request, current_user, reviewer) } end end + + describe '#attention_requested_of_merge_request' do + let_it_be(:current_user) { create(:user) } + let_it_be(:reviewer) { create(:user) } + let_it_be(:merge_request) { create(:merge_request, source_project: project, reviewers: [reviewer]) } + + it 'sends email to reviewer', :aggregate_failures do + notification.attention_requested_of_merge_request(merge_request, current_user, reviewer) + + merge_request.reviewers.each { |reviewer| should_email(reviewer) } + should_not_email(merge_request.author) + should_not_email(@u_watcher) + should_not_email(@u_participant_mentioned) + should_not_email(@subscriber) + should_not_email(@watcher_and_subscriber) + should_not_email(@u_guest_watcher) + should_not_email(@u_guest_custom) + should_not_email(@u_custom_global) + should_not_email(@unsubscriber) + should_not_email(@u_participating) + should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) + end + + it 'adds "attention requested" reason' do + notification.attention_requested_of_merge_request(merge_request, current_user, [reviewer]) + + merge_request.reviewers.each do |reviewer| + email = find_email_for(reviewer) + + expect(email).to have_header('X-GitLab-NotificationReason', NotificationReason::ATTENTION_REQUESTED) + end + end + + it_behaves_like 'project emails are disabled' do + let(:notification_target) { merge_request } + let(:notification_trigger) { notification.attention_requested_of_merge_request(merge_request, current_user, reviewer) } + end + end end describe 'Projects', :deliver_mails_inline do diff --git a/spec/services/users/refresh_authorized_projects_service_spec.rb b/spec/services/users/refresh_authorized_projects_service_spec.rb index a8ad0d02f60..aa4df93a241 100644 --- a/spec/services/users/refresh_authorized_projects_service_spec.rb +++ b/spec/services/users/refresh_authorized_projects_service_spec.rb @@ -67,11 +67,17 @@ RSpec.describe Users::RefreshAuthorizedProjectsService do it 'updates the authorized projects of the user' do project2 = create(:project) - to_remove = user.project_authorizations + project_authorization = user.project_authorizations .create!(project: project2, access_level: Gitlab::Access::MAINTAINER) + to_be_removed = [project_authorization.project_id] + + to_be_added = [ + { user_id: user.id, project_id: project.id, access_level: Gitlab::Access::MAINTAINER } + ] + expect(service).to receive(:update_authorizations) - .with([to_remove.project_id], [[user.id, project.id, Gitlab::Access::MAINTAINER]]) + .with(to_be_removed, to_be_added) service.execute_without_lease end @@ -81,9 +87,14 @@ RSpec.describe Users::RefreshAuthorizedProjectsService do user.project_authorizations.create!(project: project, access_level: access_level) end + to_be_removed = [project.id] + + to_be_added = [ + { user_id: user.id, project_id: project.id, access_level: Gitlab::Access::MAINTAINER } + ] expect(service).to( receive(:update_authorizations) - .with([project.id], [[user.id, project.id, Gitlab::Access::MAINTAINER]]) + .with(to_be_removed, to_be_added) .and_call_original) service.execute_without_lease @@ -99,11 +110,17 @@ RSpec.describe Users::RefreshAuthorizedProjectsService do it 'sets the access level of a project to the highest available level' do user.project_authorizations.delete_all - to_remove = user.project_authorizations + project_authorization = user.project_authorizations .create!(project: project, access_level: Gitlab::Access::DEVELOPER) + to_be_removed = [project_authorization.project_id] + + to_be_added = [ + { user_id: user.id, project_id: project.id, access_level: Gitlab::Access::MAINTAINER } + ] + expect(service).to receive(:update_authorizations) - .with([to_remove.project_id], [[user.id, project.id, Gitlab::Access::MAINTAINER]]) + .with(to_be_removed, to_be_added) service.execute_without_lease end @@ -134,7 +151,11 @@ RSpec.describe Users::RefreshAuthorizedProjectsService do it 'inserts authorizations that should be added' do user.project_authorizations.delete_all - service.update_authorizations([], [[user.id, project.id, Gitlab::Access::MAINTAINER]]) + to_be_added = [ + { user_id: user.id, project_id: project.id, access_level: Gitlab::Access::MAINTAINER } + ] + + service.update_authorizations([], to_be_added) authorizations = user.project_authorizations @@ -160,7 +181,11 @@ RSpec.describe Users::RefreshAuthorizedProjectsService do 'authorized_projects_refresh.rows_added_slice': [[user.id, project.id, Gitlab::Access::MAINTAINER]]) ) - service.update_authorizations([], [[user.id, project.id, Gitlab::Access::MAINTAINER]]) + to_be_added = [ + { user_id: user.id, project_id: project.id, access_level: Gitlab::Access::MAINTAINER } + ] + + service.update_authorizations([], to_be_added) end end end diff --git a/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb b/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb index 0ffa32dec9e..46fc2cbdc9b 100644 --- a/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb +++ b/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb @@ -58,11 +58,12 @@ RSpec.shared_examples 'a GitHub-ish import controller: GET new' do end RSpec.shared_examples 'a GitHub-ish import controller: GET status' do + let(:repo_fake) { Struct.new(:id, :login, :full_name, :name, :owner, keyword_init: true) } let(:new_import_url) { public_send("new_import_#{provider}_url") } let(:user) { create(:user) } - let(:repo) { OpenStruct.new(login: 'vim', full_name: 'asd/vim', name: 'vim', owner: { login: 'owner' }) } - let(:org) { OpenStruct.new(login: 'company') } - let(:org_repo) { OpenStruct.new(login: 'company', full_name: 'company/repo', name: 'repo', owner: { login: 'owner' }) } + let(:repo) { repo_fake.new(login: 'vim', full_name: 'asd/vim', name: 'vim', owner: { login: 'owner' }) } + let(:org) { double('org', login: 'company') } + let(:org_repo) { repo_fake.new(login: 'company', full_name: 'company/repo', name: 'repo', owner: { login: 'owner' }) } before do assign_session_token(provider) @@ -72,7 +73,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: GET status' do project = create(:project, import_type: provider, namespace: user.namespace, import_status: :finished, import_source: 'example/repo') group = create(:group) group.add_owner(user) - stub_client(repos: [repo, org_repo], orgs: [org], org_repos: [org_repo], each_page: [OpenStruct.new(objects: [repo, org_repo])].to_enum) + stub_client(repos: [repo, org_repo], orgs: [org], org_repos: [org_repo], each_page: [double('client', objects: [repo, org_repo])].to_enum) get :status, format: :json @@ -125,7 +126,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: GET status' do end context 'when filtering' do - let(:repo_2) { OpenStruct.new(login: 'emacs', full_name: 'asd/emacs', name: 'emacs', owner: { login: 'owner' }) } + let(:repo_2) { repo_fake.new(login: 'emacs', full_name: 'asd/emacs', name: 'emacs', owner: { login: 'owner' }) } let(:project) { create(:project, import_type: provider, namespace: user.namespace, import_status: :finished, import_source: 'example/repo') } let(:group) { create(:group) } let(:repos) { [repo, repo_2, org_repo] } @@ -133,7 +134,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: GET status' do before do group.add_owner(user) client = stub_client(repos: repos, orgs: [org], org_repos: [org_repo]) - allow(client).to receive(:each_page).and_return([OpenStruct.new(objects: repos)].to_enum) + allow(client).to receive(:each_page).and_return([double('client', objects: repos)].to_enum) # GitHub controller has filtering done using GitHub Search API stub_feature_flags(remove_legacy_github_client: false) end @@ -172,7 +173,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: GET status' do repos = [build(:project, name: 2, path: 'test')] client = stub_client(repos: repos) - allow(client).to receive(:each_page).and_return([OpenStruct.new(objects: repos)].to_enum) + allow(client).to receive(:each_page).and_return([double('client', objects: repos)].to_enum) end it 'does not raise an error' do @@ -189,13 +190,14 @@ end RSpec.shared_examples 'a GitHub-ish import controller: POST create' do let(:user) { create(:user) } let(:provider_username) { user.username } - let(:provider_user) { OpenStruct.new(login: provider_username) } + let(:provider_user) { double('user', login: provider_username) } let(:project) { create(:project, import_type: provider, import_status: :finished, import_source: "#{provider_username}/vim") } let(:provider_repo) do - OpenStruct.new( + double( + 'provider', name: 'vim', full_name: "#{provider_username}/vim", - owner: OpenStruct.new(login: provider_username) + owner: double('owner', login: provider_username) ) end @@ -265,10 +267,9 @@ RSpec.shared_examples 'a GitHub-ish import controller: POST create' do end context "when the repository owner is not the provider user" do - let(:other_username) { "someone_else" } + let(:provider_username) { "someone_else" } before do - provider_repo.owner = OpenStruct.new(login: other_username) assign_session_token(provider) end @@ -277,8 +278,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: POST create' do context "when the namespace is owned by the GitLab user" do before do - user.username = other_username - user.save! + user.update!(username: provider_username) end it "takes the existing namespace" do @@ -292,7 +292,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: POST create' do context "when the namespace is not owned by the GitLab user" do it "creates a project using user's namespace" do - create(:user, username: other_username) + create(:user, username: provider_username) expect(Gitlab::LegacyGithubImport::ProjectCreator) .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, type: provider, **access_params) diff --git a/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb index bd8bdd70ce5..bce889b454d 100644 --- a/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb +++ b/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb @@ -9,7 +9,7 @@ RSpec.shared_examples_for 'value stream analytics event' do it { expect(described_class.identifier).to be_a_kind_of(Symbol) } it { expect(instance.object_type.ancestors).to include(ApplicationRecord) } it { expect(instance).to respond_to(:timestamp_projection) } - it { expect(instance).to respond_to(:markdown_description) } + it { expect(instance).to respond_to(:html_description) } it { expect(instance.column_list).to be_a_kind_of(Array) } describe '#apply_query_customization' do diff --git a/tooling/rspec_flaky/report.rb b/tooling/rspec_flaky/report.rb index bde5115f03c..3acfe7d2125 100644 --- a/tooling/rspec_flaky/report.rb +++ b/tooling/rspec_flaky/report.rb @@ -10,7 +10,7 @@ module RspecFlaky # This class is responsible for loading/saving JSON reports, and pruning # outdated examples. class Report < SimpleDelegator - OUTDATED_DAYS_THRESHOLD = 30 + OUTDATED_DAYS_THRESHOLD = 7 attr_reader :flaky_examples |