diff options
37 files changed, 404 insertions, 98 deletions
diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb index 8ff2b5ad532..1b296f8d52b 100644 --- a/app/graphql/types/base_field.rb +++ b/app/graphql/types/base_field.rb @@ -41,7 +41,7 @@ module Types attr_reader :feature_flag def feature_documentation_message(key, description) - "#{description}. Available only when feature flag #{key} is enabled." + "#{description}. Available only when feature flag `#{key}` is enabled." end def check_feature_flag(args) diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb index c982b48a94e..6702a805cb7 100644 --- a/app/helpers/system_note_helper.rb +++ b/app/helpers/system_note_helper.rb @@ -23,7 +23,7 @@ module SystemNoteHelper 'moved' => 'arrow-right', 'outdated' => 'pencil-square', 'pinned_embed' => 'thumbtack', - 'duplicate' => 'issue-duplicate', + 'duplicate' => 'duplicate', 'locked' => 'lock', 'unlocked' => 'lock-open', 'due_date' => 'calendar' diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index f79a5682963..fd099107fe7 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -59,15 +59,11 @@ module Ci ## # Since Gitlab 11.5, deployments records started being created right after # `ci_builds` creation. We can look up a relevant `environment` through - # `deployment` relation today. This is much more efficient than expanding - # environment name with variables. + # `deployment` relation today. # (See more https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/22380) # - # However, we have to still expand environment name if it's a stop action, - # because `deployment` persists information for start action only. - # - # We will follow up this by persisting expanded name in build metadata or - # persisting stop action in database. + # Since Gitlab 12.9, we started persisting the expanded environment name to + # avoid repeated variables expansion in `action: stop` builds as well. def persisted_environment return unless has_environment? @@ -465,7 +461,14 @@ module Ci return unless has_environment? strong_memoize(:expanded_environment_name) do - ExpandVariables.expand(environment, -> { simple_variables }) + # We're using a persisted expanded environment name in order to avoid + # variable expansion per request. + if Feature.enabled?(:ci_persisted_expanded_environment_name, project, default_enabled: true) && + metadata&.expanded_environment_name.present? + metadata.expanded_environment_name + else + ExpandVariables.expand(environment, -> { simple_variables }) + end end end diff --git a/app/models/concerns/ci/metadatable.rb b/app/models/concerns/ci/metadatable.rb index 9bfe76728e4..bd40af28bc9 100644 --- a/app/models/concerns/ci/metadatable.rb +++ b/app/models/concerns/ci/metadatable.rb @@ -14,6 +14,8 @@ module Ci inverse_of: :build, autosave: true + accepts_nested_attributes_for :metadata + delegate :timeout, to: :metadata, prefix: true, allow_nil: true delegate :interruptible, to: :metadata, prefix: false, allow_nil: true delegate :has_exposed_artifacts?, to: :metadata, prefix: false, allow_nil: true diff --git a/app/services/ci/retry_build_service.rb b/app/services/ci/retry_build_service.rb index 87f818ad497..a65fe2ecb3a 100644 --- a/app/services/ci/retry_build_service.rb +++ b/app/services/ci/retry_build_service.rb @@ -52,7 +52,7 @@ module Ci def create_build!(attributes) build = project.builds.new(attributes) - build.deployment = ::Gitlab::Ci::Pipeline::Seed::Deployment.new(build).to_resource + build.assign_attributes(::Gitlab::Ci::Pipeline::Seed::Build.environment_attributes_for(build)) build.retried = false build.save! build diff --git a/changelogs/unreleased/208798-replace-instances-of-the-issue-duplicate-icon-with-the-duplicate-i.yml b/changelogs/unreleased/208798-replace-instances-of-the-issue-duplicate-icon-with-the-duplicate-i.yml new file mode 100644 index 00000000000..9cbee38da7d --- /dev/null +++ b/changelogs/unreleased/208798-replace-instances-of-the-issue-duplicate-icon-with-the-duplicate-i.yml @@ -0,0 +1,5 @@ +--- +title: Replace issue-duplicate icon with duplicate icon +merge_request: +author: +type: other diff --git a/changelogs/unreleased/persist-expanded-environment-name-in-build-metadata.yml b/changelogs/unreleased/persist-expanded-environment-name-in-build-metadata.yml new file mode 100644 index 00000000000..a6de3aa78c5 --- /dev/null +++ b/changelogs/unreleased/persist-expanded-environment-name-in-build-metadata.yml @@ -0,0 +1,5 @@ +--- +title: Persist expanded environment name in ci build metadata +merge_request: 22374 +author: +type: performance diff --git a/db/migrate/20200102140148_add_expanded_environment_name_to_ci_build_metadata.rb b/db/migrate/20200102140148_add_expanded_environment_name_to_ci_build_metadata.rb new file mode 100644 index 00000000000..e76806c5d3f --- /dev/null +++ b/db/migrate/20200102140148_add_expanded_environment_name_to_ci_build_metadata.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class AddExpandedEnvironmentNameToCiBuildMetadata < ActiveRecord::Migration[5.2] + DOWNTIME = false + + def up + add_column :ci_builds_metadata, :expanded_environment_name, :string, limit: 255 + end + + def down + remove_column :ci_builds_metadata, :expanded_environment_name + end +end diff --git a/db/migrate/20200225111018_add_index_for_group_and_iid_search_to_epics.rb b/db/migrate/20200225111018_add_index_for_group_and_iid_search_to_epics.rb new file mode 100644 index 00000000000..98f35d9f1ae --- /dev/null +++ b/db/migrate/20200225111018_add_index_for_group_and_iid_search_to_epics.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class AddIndexForGroupAndIidSearchToEpics < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + INDEX_NAME = 'index_epics_on_group_id_and_iid_varchar_pattern' + + disable_ddl_transaction! + + def up + disable_statement_timeout do + execute "CREATE INDEX CONCURRENTLY \"#{INDEX_NAME}\" ON epics (group_id, CAST(iid AS VARCHAR) varchar_pattern_ops);" + end + end + + def down + disable_statement_timeout do + remove_concurrent_index_by_name :epics, INDEX_NAME + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 355b36e1483..188062b8897 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -722,6 +722,7 @@ ActiveRecord::Schema.define(version: 2020_02_27_165129) do t.jsonb "config_variables" t.boolean "has_exposed_artifacts" t.string "environment_auto_stop_in", limit: 255 + t.string "expanded_environment_name", limit: 255 t.index ["build_id"], name: "index_ci_builds_metadata_on_build_id", unique: true t.index ["build_id"], name: "index_ci_builds_metadata_on_build_id_and_has_exposed_artifacts", where: "(has_exposed_artifacts IS TRUE)" t.index ["build_id"], name: "index_ci_builds_metadata_on_build_id_and_interruptible", where: "(interruptible = true)" @@ -1581,6 +1582,7 @@ ActiveRecord::Schema.define(version: 2020_02_27_165129) do t.integer "start_date_sourcing_epic_id" t.integer "due_date_sourcing_epic_id" t.integer "health_status", limit: 2 + t.index "group_id, ((iid)::character varying) varchar_pattern_ops", name: "index_epics_on_group_id_and_iid_varchar_pattern" t.index ["assignee_id"], name: "index_epics_on_assignee_id" t.index ["author_id"], name: "index_epics_on_author_id" t.index ["closed_by_id"], name: "index_epics_on_closed_by_id" diff --git a/doc/administration/geo/replication/datatypes.md b/doc/administration/geo/replication/datatypes.md index 9ee215c60c5..feb0c2f2f4d 100644 --- a/doc/administration/geo/replication/datatypes.md +++ b/doc/administration/geo/replication/datatypes.md @@ -131,7 +131,7 @@ successfully, you must replicate their data using some other means. | Project wiki repository | **Yes** | **Yes** | | | Project designs repository | **Yes** | [No][design-verification] | | | Uploads | **Yes** | [No][upload-verification] | Verified only on transfer, or manually (*1*)| -| LFS objects | **Yes** | [No][lfs-verification] | Verified only on transfer, or manually (*1*)| +| LFS objects | **Yes** | [No][lfs-verification] | Verified only on transfer, or manually (*1*). Unavailable for new LFS objects in 11.11.x and 12.0.x (*2*). | | CI job artifacts (other than traces) | **Yes** | [No][artifact-verification] | Verified only manually (*1*) | | Archived traces | **Yes** | [No][artifact-verification] | Verified only on transfer, or manually (*1*)| | Personal snippets | **Yes** | **Yes** | | @@ -148,7 +148,10 @@ successfully, you must replicate their data using some other means. | Content in object storage | **Yes** | No | | - (*1*): The integrity can be verified manually using - [Integrity Check Rake Task](../../raketasks/check.md) on both nodes and comparing the output between them. + [Integrity Check Rake Task](../../raketasks/check.md) on both nodes and comparing + the output between them. +- (*2*): GitLab versions 11.11.x and 12.0.x are affected by [a bug that prevents any new + LFS objects from replicating](https://gitlab.com/gitlab-org/gitlab/issues/32696). [design-replication]: https://gitlab.com/groups/gitlab-org/-/epics/1633 [design-verification]: https://gitlab.com/gitlab-org/gitlab/issues/32467 diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md index b5be29f7dff..c3e1da3311f 100644 --- a/doc/administration/geo/replication/troubleshooting.md +++ b/doc/administration/geo/replication/troubleshooting.md @@ -377,6 +377,14 @@ sudo gitlab-ctl reconfigure This will increase the timeout to three hours (10800 seconds). Choose a time long enough to accommodate a full clone of your largest repositories. +### New LFS objects are never replicated + +If new LFS objects are never replicated to secondary Geo nodes, check the version of +GitLab you are running. GitLab versions 11.11.x or 12.0.x are affected by +[a bug that results in new LFS objects not being replicated to Geo secondary nodes](https://gitlab.com/gitlab-org/gitlab/issues/32696). + +To resolve the issue, upgrade to GitLab 12.1 or newer. + ### Resetting Geo **secondary** node replication If you get a **secondary** node in a broken state and want to reset the replication state, diff --git a/doc/administration/geo/replication/updating_the_geo_nodes.md b/doc/administration/geo/replication/updating_the_geo_nodes.md index d094ccf3e54..df66b1b36ec 100644 --- a/doc/administration/geo/replication/updating_the_geo_nodes.md +++ b/doc/administration/geo/replication/updating_the_geo_nodes.md @@ -14,6 +14,8 @@ different steps. - [Updating to GitLab 12.7](version_specific_updates.md#updating-to-gitlab-127) - [Updating to GitLab 12.2](version_specific_updates.md#updating-to-gitlab-122) - [Updating to GitLab 12.1](version_specific_updates.md#updating-to-gitlab-121) +- [Updating to GitLab 12.0](version_specific_updates.md#updating-to-gitlab-120) +- [Updating to GitLab 11.11](version_specific_updates.md#updating-to-gitlab-1111) - [Updating to GitLab 10.8](version_specific_updates.md#updating-to-gitlab-108) - [Updating to GitLab 10.6](version_specific_updates.md#updating-to-gitlab-106) - [Updating to GitLab 10.5](version_specific_updates.md#updating-to-gitlab-105) diff --git a/doc/administration/geo/replication/version_specific_updates.md b/doc/administration/geo/replication/version_specific_updates.md index 77fcaaba764..a697d07ded4 100644 --- a/doc/administration/geo/replication/version_specific_updates.md +++ b/doc/administration/geo/replication/version_specific_updates.md @@ -45,6 +45,20 @@ This can be temporarily disabled by running the following before updating: sudo touch /etc/gitlab/disable-postgresql-upgrade ``` +## Updating to GitLab 12.0 + +WARNING: **Warning:** +This version is affected by [a bug that results in new LFS objects not being replicated to +Geo secondary nodes](https://gitlab.com/gitlab-org/gitlab/issues/32696). The issue is fixed +in GitLab 12.1. Please upgrade to GitLab 12.1 or newer. + +## Updating to GitLab 11.11 + +WARNING: **Warning:** +This version is affected by [a bug that results in new LFS objects not being replicated to +Geo secondary nodes](https://gitlab.com/gitlab-org/gitlab/issues/32696). The issue is fixed +in GitLab 12.1. Please upgrade to GitLab 12.1 or newer. + ## Updating to GitLab 10.8 Before 10.8, broadcast messages would not propagate without flushing diff --git a/doc/api/epics.md b/doc/api/epics.md index 54dc3754de0..fddf7e22d0d 100644 --- a/doc/api/epics.md +++ b/doc/api/epics.md @@ -53,7 +53,7 @@ GET /groups/:id/epics?state=opened | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user | | `author_id` | integer | no | Return epics created by the given user `id` | | `labels` | string | no | Return epics matching a comma separated list of labels names. Label names from the epic group or a parent group can be used | -| `with_labels_details` | Boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. Introduced in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413)| +| `with_labels_details` | boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. Introduced in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413)| | `order_by` | string | no | Return epics ordered by `created_at` or `updated_at` fields. Default is `created_at` | | `sort` | string | no | Return epics sorted in `asc` or `desc` order. Default is `desc` | | `search` | string | no | Search epics against their `title` and `description` | diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index d6a0cc97e25..eae3626515e 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -1891,6 +1891,11 @@ type Epic implements Noteable { iid: ID """ + Filter epics by iid for autocomplete + """ + iidStartsWith: String + + """ List of IIDs of epics, e.g., [1, 2] """ iids: [ID!] @@ -1944,7 +1949,7 @@ type Epic implements Noteable { """ Total weight of open and closed descendant epic's issues. Available only when - feature flag unfiltered_epic_aggregates is enabled. + feature flag `unfiltered_epic_aggregates` is enabled. """ descendantWeightSum: EpicDescendantWeights @@ -2409,7 +2414,7 @@ type EpicIssue implements Noteable { epicIssueId: ID! """ - Current health status. Available only when feature flag save_issuable_health_status is enabled. + Current health status. Available only when feature flag `save_issuable_health_status` is enabled. """ healthStatus: HealthStatus @@ -2942,6 +2947,11 @@ type Group { iid: ID """ + Filter epics by iid for autocomplete + """ + iidStartsWith: String + + """ List of IIDs of epics, e.g., [1, 2] """ iids: [ID!] @@ -3009,6 +3019,11 @@ type Group { iid: ID """ + Filter epics by iid for autocomplete + """ + iidStartsWith: String + + """ List of IIDs of epics, e.g., [1, 2] """ iids: [ID!] @@ -3390,7 +3405,7 @@ type Issue implements Noteable { epic: Epic """ - Current health status. Available only when feature flag save_issuable_health_status is enabled. + Current health status. Available only when feature flag `save_issuable_health_status` is enabled. """ healthStatus: HealthStatus diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 4429bc6621d..bf59c94f6cc 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -3513,6 +3513,16 @@ } }, "defaultValue": null + }, + { + "name": "iidStartsWith", + "description": "Filter epics by iid for autocomplete", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null } ], "type": { @@ -3634,6 +3644,16 @@ "defaultValue": null }, { + "name": "iidStartsWith", + "description": "Filter epics by iid for autocomplete", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { @@ -4867,6 +4887,16 @@ "defaultValue": null }, { + "name": "iidStartsWith", + "description": "Filter epics by iid for autocomplete", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 54333464603..79be0c0d626 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -317,7 +317,7 @@ Represents an epic. | `closedAt` | Time | Timestamp of the epic's closure | | `createdAt` | Time | Timestamp of the epic's creation | | `descendantCounts` | EpicDescendantCount | Number of open and closed descendant epics and issues | -| `descendantWeightSum` | EpicDescendantWeights | Total weight of open and closed descendant epic's issues. Available only when feature flag unfiltered_epic_aggregates is enabled. | +| `descendantWeightSum` | EpicDescendantWeights | Total weight of open and closed descendant epic's issues. Available only when feature flag `unfiltered_epic_aggregates` is enabled. | | `description` | String | Description of the epic | | `downvotes` | Int! | Number of downvotes the epic has received | | `dueDate` | Time | Due date of the epic | @@ -385,7 +385,7 @@ Relationship between an epic and an issue | `dueDate` | Time | Due date of the issue | | `epic` | Epic | Epic to which this issue belongs | | `epicIssueId` | ID! | ID of the epic-issue relation | -| `healthStatus` | HealthStatus | Current health status. Available only when feature flag save_issuable_health_status is enabled. | +| `healthStatus` | HealthStatus | Current health status. Available only when feature flag `save_issuable_health_status` is enabled. | | `id` | ID | Global ID of the epic-issue relation | | `iid` | ID! | Internal ID of the issue | | `milestone` | Milestone | Milestone of the issue | @@ -506,7 +506,7 @@ Autogenerated return type of EpicTreeReorder | `downvotes` | Int! | Number of downvotes the issue has received | | `dueDate` | Time | Due date of the issue | | `epic` | Epic | Epic to which this issue belongs | -| `healthStatus` | HealthStatus | Current health status. Available only when feature flag save_issuable_health_status is enabled. | +| `healthStatus` | HealthStatus | Current health status. Available only when feature flag `save_issuable_health_status` is enabled. | | `iid` | ID! | Internal ID of the issue | | `milestone` | Milestone | Milestone of the issue | | `reference` | String! | Internal reference of the issue. Returned in shortened format by default | diff --git a/doc/api/group_clusters.md b/doc/api/group_clusters.md index afe1561b129..0b783c2fc72 100644 --- a/doc/api/group_clusters.md +++ b/doc/api/group_clusters.md @@ -153,16 +153,16 @@ Parameters: | Attribute | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) | -| `name` | String | yes | The name of the cluster | -| `domain` | String | no | The [base domain](../user/group/clusters/index.md#base-domain) of the cluster | +| `name` | string | yes | The name of the cluster | +| `domain` | string | no | The [base domain](../user/group/clusters/index.md#base-domain) of the cluster | | `management_project_id` | integer | no | The ID of the [management project](../user/clusters/management_project.md) for the cluster | -| `enabled` | Boolean | no | Determines if cluster is active or not, defaults to true | -| `managed` | Boolean | no | Determines if GitLab will manage namespaces and service accounts for this cluster, defaults to true | -| `platform_kubernetes_attributes[api_url]` | String | yes | The URL to access the Kubernetes API | -| `platform_kubernetes_attributes[token]` | String | yes | The token to authenticate against Kubernetes | -| `platform_kubernetes_attributes[ca_cert]` | String | no | TLS certificate (needed if API is using a self-signed TLS certificate | -| `platform_kubernetes_attributes[authorization_type]` | String | no | The cluster authorization type: `rbac`, `abac` or `unknown_authorization`. Defaults to `rbac`. | -| `environment_scope` | String | no | The associated environment to the cluster. Defaults to `*` **(PREMIUM)** | +| `enabled` | boolean | no | Determines if cluster is active or not, defaults to true | +| `managed` | boolean | no | Determines if GitLab will manage namespaces and service accounts for this cluster, defaults to true | +| `platform_kubernetes_attributes[api_url]` | string | yes | The URL to access the Kubernetes API | +| `platform_kubernetes_attributes[token]` | string | yes | The token to authenticate against Kubernetes | +| `platform_kubernetes_attributes[ca_cert]` | string | no | TLS certificate (needed if API is using a self-signed TLS certificate | +| `platform_kubernetes_attributes[authorization_type]` | string | no | The cluster authorization type: `rbac`, `abac` or `unknown_authorization`. Defaults to `rbac`. | +| `environment_scope` | string | no | The associated environment to the cluster. Defaults to `*` **(PREMIUM)** | Example request: @@ -223,12 +223,12 @@ Parameters: | --------- | ---- | -------- | ----------- | | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) | | `cluster_id` | integer | yes | The ID of the cluster | -| `name` | String | no | The name of the cluster | -| `domain` | String | no | The [base domain](../user/group/clusters/index.md#base-domain) of the cluster | -| `platform_kubernetes_attributes[api_url]` | String | no | The URL to access the Kubernetes API | -| `platform_kubernetes_attributes[token]` | String | no | The token to authenticate against Kubernetes | -| `platform_kubernetes_attributes[ca_cert]` | String | no | TLS certificate (needed if API is using a self-signed TLS certificate | -| `environment_scope` | String | no | The associated environment to the cluster **(PREMIUM)** | +| `name` | string | no | The name of the cluster | +| `domain` | string | no | The [base domain](../user/group/clusters/index.md#base-domain) of the cluster | +| `platform_kubernetes_attributes[api_url]` | string | no | The URL to access the Kubernetes API | +| `platform_kubernetes_attributes[token]` | string | no | The token to authenticate against Kubernetes | +| `platform_kubernetes_attributes[ca_cert]` | string | no | TLS certificate (needed if API is using a self-signed TLS certificate | +| `environment_scope` | string | no | The associated environment to the cluster **(PREMIUM)** | NOTE: **Note:** `name`, `api_url`, `ca_cert` and `token` can only be updated if the cluster was added diff --git a/doc/api/issues.md b/doc/api/issues.md index 612971d8f5e..d1404efd265 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -47,7 +47,7 @@ GET /issues?confidential=true | ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `state` | string | no | Return `all` issues or just those that are `opened` or `closed` | | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. | -| `with_labels_details` | Boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. The `description_html` attribute was introduced in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413)| +| `with_labels_details` | boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. The `description_html` attribute was introduced in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413)| | `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. | | `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`. Defaults to `created_by_me`<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced][ce-13004] in GitLab 9.5. [Changed to snake_case][ce-18935] in GitLab 11.0)_ | | `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. _([Introduced][ce-13004] in GitLab 9.5)_ | @@ -65,7 +65,7 @@ GET /issues?confidential=true | `created_before` | datetime | no | Return issues created on or before the given time | | `updated_after` | datetime | no | Return issues updated on or after the given time | | `updated_before` | datetime | no | Return issues updated on or before the given time | -| `confidential` | Boolean | no | Filter confidential or public issues. | +| `confidential` | boolean | no | Filter confidential or public issues. | | `not` | Hash | no | Return issues that do not match the parameters supplied. Accepts: `labels`, `milestone`, `author_id`, `author_username`, `assignee_id`, `assignee_username`, `my_reaction_emoji`, `search`, `in` | ```shell @@ -203,7 +203,7 @@ GET /groups/:id/issues?confidential=true | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user | | `state` | string | no | Return all issues or just those that are `opened` or `closed` | | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. | -| `with_labels_details` | Boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. The `description_html` attribute was introduced in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413) | +| `with_labels_details` | boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. The `description_html` attribute was introduced in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413) | | `iids[]` | integer array | no | Return only the issues having the given `iid` | | `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. | | `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced][ce-13004] in GitLab 9.5. [Changed to snake_case][ce-18935] in GitLab 11.0)_ | @@ -220,9 +220,9 @@ GET /groups/:id/issues?confidential=true | `created_before` | datetime | no | Return issues created on or before the given time | | `updated_after` | datetime | no | Return issues updated on or after the given time | | `updated_before` | datetime | no | Return issues updated on or before the given time | -| `confidential` | Boolean | no | Filter confidential or public issues. | +| `confidential` | boolean | no | Filter confidential or public issues. | | `not` | Hash | no | Return issues that do not match the parameters supplied. Accepts: `labels`, `milestone`, `author_id`, `author_username`, `assignee_id`, `assignee_username`, `my_reaction_emoji`, `search`, `in` | -| `non_archived` | Boolean | no | Return issues from non archived projects. Default is true. _(Introduced in [GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23785))_ | +| `non_archived` | boolean | no | Return issues from non archived projects. Default is true. _(Introduced in [GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23785))_ | ```shell curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/4/issues @@ -359,7 +359,7 @@ GET /projects/:id/issues?confidential=true | `iids[]` | integer array | no | Return only the milestone having the given `iid` | | `state` | string | no | Return all issues or just those that are `opened` or `closed` | | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. | -| `with_labels_details` | Boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. `description_html` Introduced in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413) | +| `with_labels_details` | boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. `description_html` Introduced in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413) | | `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. | | `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced][ce-13004] in GitLab 9.5. [Changed to snake_case][ce-18935] in GitLab 11.0)_ | | `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. _([Introduced][ce-13004] in GitLab 9.5)_ | @@ -375,7 +375,7 @@ GET /projects/:id/issues?confidential=true | `created_before` | datetime | no | Return issues created on or before the given time | | `updated_after` | datetime | no | Return issues updated on or after the given time | | `updated_before` | datetime | no | Return issues updated on or before the given time | -| `confidential` | Boolean | no | Filter confidential or public issues. | +| `confidential` | boolean | no | Filter confidential or public issues. | | `not` | Hash | no | Return issues that do not match the parameters supplied. Accepts: `labels`, `milestone`, `author_id`, `author_username`, `assignee_id`, `assignee_username`, `my_reaction_emoji`, `search`, `in` | ```shell @@ -647,7 +647,7 @@ POST /projects/:id/issues | `iid` | integer/string | no | The internal ID of the project's issue (requires admin or project owner rights) | | `title` | string | yes | The title of an issue | | `description` | string | no | The description of an issue. Limited to 1,048,576 characters. | -| `confidential` | Boolean | no | Set an issue to be confidential. Default is `false`. | +| `confidential` | boolean | no | Set an issue to be confidential. Default is `false`. | | `assignee_ids` | integer array | no | The ID of a user to assign issue | | `milestone_id` | integer | no | The global ID of a milestone to assign issue | | `labels` | string | no | Comma-separated label names for an issue | @@ -755,7 +755,7 @@ PUT /projects/:id/issues/:issue_iid | `issue_iid` | integer | yes | The internal ID of a project's issue | | `title` | string | no | The title of an issue | | `description` | string | no | The description of an issue. Limited to 1,048,576 characters. | -| `confidential` | Boolean | no | Updates an issue to be confidential | +| `confidential` | boolean | no | Updates an issue to be confidential | | `assignee_ids` | integer array | no | The ID of the user(s) to assign the issue to. Set to `0` or provide an empty value to unassign all assignees. | | `milestone_id` | integer | no | The global ID of a milestone to assign the issue to. Set to `0` or provide an empty value to unassign a milestone.| | `labels` | string | no | Comma-separated label names for an issue. Set to an empty string to unassign all labels. | @@ -763,7 +763,7 @@ PUT /projects/:id/issues/:issue_iid | `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights). Empty string or null values are not accepted.| | `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` | | `weight` **(STARTER)** | integer | no | The weight of the issue. Valid values are greater than or equal to 0. 0 | -| `discussion_locked` | Boolean | no | Flag indicating if the issue's discussion is locked. If the discussion is locked only project members can add or edit comments. | +| `discussion_locked` | boolean | no | Flag indicating if the issue's discussion is locked. If the discussion is locked only project members can add or edit comments. | | `epic_id` **(ULTIMATE)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. | | `epic_iid` **(ULTIMATE)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [will be removed in 13.0](https://gitlab.com/gitlab-org/gitlab/issues/35157)) | diff --git a/doc/api/issues_statistics.md b/doc/api/issues_statistics.md index cb8379aba64..511078f3028 100644 --- a/doc/api/issues_statistics.md +++ b/doc/api/issues_statistics.md @@ -43,7 +43,7 @@ GET /issues_statistics?confidential=true | `created_before` | datetime | no | Return issues created on or before the given time | | `updated_after` | datetime | no | Return issues updated on or after the given time | | `updated_before` | datetime | no | Return issues updated on or before the given time | -| `confidential` | Boolean | no | Filter confidential or public issues. | +| `confidential` | boolean | no | Filter confidential or public issues. | ```shell curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/issues_statistics @@ -99,7 +99,7 @@ GET /groups/:id/issues_statistics?confidential=true | `created_before` | datetime | no | Return issues created on or before the given time | | `updated_after` | datetime | no | Return issues updated on or after the given time | | `updated_before` | datetime | no | Return issues updated on or before the given time | -| `confidential` | Boolean | no | Filter confidential or public issues. | +| `confidential` | boolean | no | Filter confidential or public issues. | ```shell curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/4/issues_statistics @@ -155,7 +155,7 @@ GET /projects/:id/issues_statistics?confidential=true | `created_before` | datetime | no | Return issues created on or before the given time | | `updated_after` | datetime | no | Return issues updated on or after the given time | | `updated_before` | datetime | no | Return issues updated on or before the given time | -| `confidential` | Boolean | no | Filter confidential or public issues. | +| `confidential` | boolean | no | Filter confidential or public issues. | ```shell curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/issues_statistics diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index a0f9a120480..75cb0e7f49b 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -45,7 +45,7 @@ Parameters: | `milestone` | string | no | Return merge requests for a specific milestone. `None` returns merge requests with no milestone. `Any` returns merge requests that have an assigned milestone. | | `view` | string | no | If `simple`, returns the `iid`, URL, title, description, and basic state of merge request | | `labels` | string | no | Return merge requests matching a comma separated list of labels. `None` lists all merge requests with no labels. `Any` lists all merge requests with at least one label. `No+Label` (Deprecated) lists all merge requests with no labels. Predefined names are case-insensitive. | -| `with_labels_details` | Boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. Introduced in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413) | +| `with_labels_details` | boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. Introduced in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413) | | `created_after` | datetime | no | Return merge requests created on or after the given time | | `created_before` | datetime | no | Return merge requests created on or before the given time | | `updated_after` | datetime | no | Return merge requests updated on or after the given time | @@ -221,7 +221,7 @@ Parameters: | `milestone` | string | no | Return merge requests for a specific milestone. `None` returns merge requests with no milestone. `Any` returns merge requests that have an assigned milestone. | | `view` | string | no | If `simple`, returns the `iid`, URL, title, description, and basic state of merge request | | `labels` | string | no | Return merge requests matching a comma separated list of labels. `None` lists all merge requests with no labels. `Any` lists all merge requests with at least one label. `No+Label` (Deprecated) lists all merge requests with no labels. Predefined names are case-insensitive. | -| `with_labels_details` | Boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. Introduced in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413) | +| `with_labels_details` | boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. Introduced in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413) | | `created_after` | datetime | no | Return merge requests created on or after the given time | | `created_before` | datetime | no | Return merge requests created on or before the given time | | `updated_after` | datetime | no | Return merge requests updated on or after the given time | @@ -383,7 +383,7 @@ Parameters: | `milestone` | string | no | Return merge requests for a specific milestone. `None` returns merge requests with no milestone. `Any` returns merge requests that have an assigned milestone. | | `view` | string | no | If `simple`, returns the `iid`, URL, title, description, and basic state of merge request | | `labels` | string | no | Return merge requests matching a comma separated list of labels. `None` lists all merge requests with no labels. `Any` lists all merge requests with at least one label. `No+Label` (Deprecated) lists all merge requests with no labels. Predefined names are case-insensitive. | -| `with_labels_details` | Boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. Introduced in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413)| +| `with_labels_details` | boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. Introduced in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413)| | `created_after` | datetime | no | Return merge requests created on or after the given time | | `created_before` | datetime | no | Return merge requests created on or before the given time | | `updated_after` | datetime | no | Return merge requests updated on or after the given time | @@ -397,7 +397,7 @@ Parameters: | `source_branch` | string | no | Return merge requests with the given source branch | | `target_branch` | string | no | Return merge requests with the given target branch | | `search` | string | no | Search merge requests against their `title` and `description` | -| `non_archived` | Boolean | no | Return merge requests from non archived projects only. Default is true. _(Introduced in [GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23809))_ | +| `non_archived` | boolean | no | Return merge requests from non archived projects only. Default is true. _(Introduced in [GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23809))_ | ```json [ diff --git a/doc/api/project_clusters.md b/doc/api/project_clusters.md index 448d5966135..6586cfc9f7f 100644 --- a/doc/api/project_clusters.md +++ b/doc/api/project_clusters.md @@ -179,8 +179,8 @@ Parameters: | `id` | integer | yes | The ID of the project owned by the authenticated user | | `name` | String | yes | The name of the cluster | | `domain` | String | no | The [base domain](../user/project/clusters/index.md#base-domain) of the cluster | -| `enabled` | Boolean | no | Determines if cluster is active or not, defaults to true | -| `managed` | Boolean | no | Determines if GitLab will manage namespaces and service accounts for this cluster, defaults to true | +| `enabled` | boolean | no | Determines if cluster is active or not, defaults to true | +| `managed` | boolean | no | Determines if GitLab will manage namespaces and service accounts for this cluster, defaults to true | | `platform_kubernetes_attributes[api_url]` | String | yes | The URL to access the Kubernetes API | | `platform_kubernetes_attributes[token]` | String | yes | The token to authenticate against Kubernetes | | `platform_kubernetes_attributes[ca_cert]` | String | no | TLS certificate (needed if API is using a self-signed TLS certificate | diff --git a/doc/security/user_email_confirmation.md b/doc/security/user_email_confirmation.md index a493b374d66..d435d928c51 100644 --- a/doc/security/user_email_confirmation.md +++ b/doc/security/user_email_confirmation.md @@ -5,8 +5,12 @@ type: howto # User email confirmation at sign-up GitLab can be configured to require confirmation of a user's email address when -the user signs up. When this setting is enabled, the user is unable to sign in until -they confirm their email address. +the user signs up. When this setting is enabled: + +- For GitLab 12.1 and earlier, the user is unable to sign in until they confirm their + email address. +- For GitLab 12.2 and later, the user [has 30 days to confirm their email address](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/31245). + After 30 days, they will be unable to log in and access GitLab features. In **Admin Area > Settings** (`/admin/application_settings/general`), go to the section **Sign-up Restrictions** and look for the **Send confirmation email on sign-up** option. diff --git a/doc/user/admin_area/settings/sign_up_restrictions.md b/doc/user/admin_area/settings/sign_up_restrictions.md index a7a6b0ecefd..6dbdf24d477 100644 --- a/doc/user/admin_area/settings/sign_up_restrictions.md +++ b/doc/user/admin_area/settings/sign_up_restrictions.md @@ -37,7 +37,12 @@ email domains to prevent malicious users from creating accounts. ## Require email confirmation You can send confirmation emails during sign-up and require that users confirm -their email address before they are allowed to sign in. +their email address. If this setting is selected: + +- For GitLab 12.1 and earlier, the user is unable to sign in until they confirm their + email address. +- For GitLab 12.2 and later, the user [has 30 days to confirm their email address](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/31245). + After 30 days, they will be unable to log in and access GitLab features. ![Email confirmation](img/email_confirmation_v12_7.png) diff --git a/lib/gitlab/ci/pipeline/seed/build.rb b/lib/gitlab/ci/pipeline/seed/build.rb index 98b4b4593e0..114a46ca9f6 100644 --- a/lib/gitlab/ci/pipeline/seed/build.rb +++ b/lib/gitlab/ci/pipeline/seed/build.rb @@ -7,6 +7,8 @@ module Gitlab class Build < Seed::Base include Gitlab::Utils::StrongMemoize + EnvironmentCreationFailure = Class.new(StandardError) + delegate :dig, to: :@seed_attributes # When the `ci_dag_limit_needs` is enabled it uses the lower limit @@ -77,14 +79,39 @@ module Gitlab if bridge? ::Ci::Bridge.new(attributes) else - ::Ci::Build.new(attributes).tap do |job| - job.deployment = Seed::Deployment.new(job).to_resource - job.resource_group = Seed::Build::ResourceGroup.new(job, @resource_group_key).to_resource + ::Ci::Build.new(attributes).tap do |build| + build.assign_attributes(self.class.environment_attributes_for(build)) + build.resource_group = Seed::Build::ResourceGroup.new(build, @resource_group_key).to_resource end end end end + def self.environment_attributes_for(build) + return {} unless build.has_environment? + + environment = Seed::Environment.new(build).to_resource + + # If there is a validation error on environment creation, such as + # the name contains invalid character, the build falls back to a + # non-environment job. + unless environment.persisted? + Gitlab::ErrorTracking.track_exception( + EnvironmentCreationFailure.new, + project_id: build.project_id, + reason: environment.errors.full_messages.to_sentence) + + return { environment: nil } + end + + { + deployment: Seed::Deployment.new(build, environment).to_resource, + metadata_attributes: { + expanded_environment_name: environment.name + } + } + end + private def all_of_only? diff --git a/lib/gitlab/ci/pipeline/seed/deployment.rb b/lib/gitlab/ci/pipeline/seed/deployment.rb index cc63fb4c609..624189acc8a 100644 --- a/lib/gitlab/ci/pipeline/seed/deployment.rb +++ b/lib/gitlab/ci/pipeline/seed/deployment.rb @@ -7,9 +7,9 @@ module Gitlab class Deployment < Seed::Base attr_reader :job, :environment - def initialize(job) + def initialize(job, environment) @job = job - @environment = Seed::Environment.new(@job) + @environment = environment end def to_resource @@ -17,7 +17,6 @@ module Gitlab return unless job.starts_environment? deployment = ::Deployment.new(attributes) - deployment.environment = environment.to_resource # If there is a validation error on environment creation, such as # the name contains invalid character, the job will fall back to a @@ -45,6 +44,7 @@ module Gitlab def attributes { project: job.project, + environment: environment, user: job.user, ref: job.ref, tag: job.tag, diff --git a/lib/gitlab/ci/pipeline/seed/environment.rb b/lib/gitlab/ci/pipeline/seed/environment.rb index 2d3a1e702f9..42e8c365824 100644 --- a/lib/gitlab/ci/pipeline/seed/environment.rb +++ b/lib/gitlab/ci/pipeline/seed/environment.rb @@ -12,25 +12,15 @@ module Gitlab end def to_resource - find_environment || ::Environment.create(attributes) + job.project.environments + .safe_find_or_create_by(name: expanded_environment_name) end private - def find_environment - job.project.environments.find_by_name(expanded_environment_name) - end - def expanded_environment_name job.expanded_environment_name end - - def attributes - { - project: job.project, - name: expanded_environment_name - } - end end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index a6eef56feb2..08b7ec47129 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -19907,6 +19907,9 @@ msgstr "" msgid "This group" msgstr "" +msgid "This group cannot be invited to a project inside a group with enforced SSO" +msgstr "" + msgid "This group does not provide any group Runners yet." msgstr "" diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index 5127d55645c..b6f18240b9e 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -230,8 +230,9 @@ FactoryBot.define do # Build deployment/environment relations if environment name is set # to the job. If `build.deployment` has already been set, it doesn't # build a new instance. + environment = Gitlab::Ci::Pipeline::Seed::Environment.new(build).to_resource build.deployment = - Gitlab::Ci::Pipeline::Seed::Deployment.new(build).to_resource + Gitlab::Ci::Pipeline::Seed::Deployment.new(build, environment).to_resource end end diff --git a/spec/graphql/types/base_field_spec.rb b/spec/graphql/types/base_field_spec.rb index 9e5f6dd2037..2547d39bcb2 100644 --- a/spec/graphql/types/base_field_spec.rb +++ b/spec/graphql/types/base_field_spec.rb @@ -174,7 +174,7 @@ describe Types::BaseField do let(:flag) { :test_flag } it 'prepends the description' do - expect(field.description). to eq 'Test description. Available only when feature flag test_flag is enabled.' + expect(field.description). to eq 'Test description. Available only when feature flag `test_flag` is enabled.' end context 'falsey feature_flag values' do diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb index 1f5fc000832..01f65939da7 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb @@ -214,24 +214,98 @@ describe Gitlab::Ci::Pipeline::Seed::Build do it { is_expected.to be_a(::Ci::Build) } it { is_expected.to be_valid } - context 'when job has environment name' do - let(:attributes) { { name: 'rspec', ref: 'master', environment: 'production' } } - + shared_examples_for 'deployment job' do it 'returns a job with deployment' do expect(subject.deployment).not_to be_nil expect(subject.deployment.deployable).to eq(subject) - expect(subject.deployment.environment.name).to eq('production') + expect(subject.deployment.environment.name).to eq(expected_environment_name) end + end + + shared_examples_for 'non-deployment job' do + it 'returns a job without deployment' do + expect(subject.deployment).to be_nil + end + end + + shared_examples_for 'ensures environment existence' do + it 'has environment' do + expect(subject).to be_has_environment + expect(subject.environment).to eq(environment_name) + expect(subject.metadata.expanded_environment_name).to eq(expected_environment_name) + expect(Environment.exists?(name: expected_environment_name)).to eq(true) + end + end + + shared_examples_for 'ensures environment inexistence' do + it 'does not have environment' do + expect(subject).not_to be_has_environment + expect(subject.environment).to be_nil + expect(subject.metadata.expanded_environment_name).to be_nil + expect(Environment.exists?(name: expected_environment_name)).to eq(false) + end + end + + context 'when job deploys to production' do + let(:environment_name) { 'production' } + let(:expected_environment_name) { 'production' } + let(:attributes) { { name: 'deploy', ref: 'master', environment: 'production' } } + + it_behaves_like 'deployment job' + it_behaves_like 'ensures environment existence' context 'when the environment name is invalid' do - let(:attributes) { { name: 'rspec', ref: 'master', environment: '!!!' } } + let(:attributes) { { name: 'deploy', ref: 'master', environment: '!!!' } } - it 'returns a job without deployment' do - expect(subject.deployment).to be_nil + it_behaves_like 'non-deployment job' + it_behaves_like 'ensures environment inexistence' + + it 'tracks an exception' do + expect(Gitlab::ErrorTracking).to receive(:track_exception) + .with(an_instance_of(described_class::EnvironmentCreationFailure), + project_id: project.id, + reason: %q{Name can contain only letters, digits, '-', '_', '/', '$', '{', '}', '.', and spaces, but it cannot start or end with '/'}) + .once + + subject end end end + context 'when job starts a review app' do + let(:environment_name) { 'review/$CI_COMMIT_REF_NAME' } + let(:expected_environment_name) { "review/#{pipeline.ref}" } + + let(:attributes) do + { + name: 'deploy', ref: 'master', environment: environment_name, + options: { environment: { name: environment_name } } + } + end + + it_behaves_like 'deployment job' + it_behaves_like 'ensures environment existence' + end + + context 'when job stops a review app' do + let(:environment_name) { 'review/$CI_COMMIT_REF_NAME' } + let(:expected_environment_name) { "review/#{pipeline.ref}" } + + let(:attributes) do + { + name: 'deploy', ref: 'master', environment: environment_name, + options: { environment: { name: environment_name, action: 'stop' } } + } + end + + it 'returns a job without deployment' do + expect(subject.deployment).to be_nil + end + + it_behaves_like 'non-deployment job' + it_behaves_like 'ensures environment existence' + end + context 'when job belongs to a resource group' do let(:attributes) { { name: 'rspec', ref: 'master', resource_group_key: 'iOS' } } diff --git a/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb index c5c91135f60..8d097bdd740 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb @@ -10,7 +10,8 @@ describe Gitlab::Ci::Pipeline::Seed::Deployment do end let(:job) { build(:ci_build, project: project, pipeline: pipeline) } - let(:seed) { described_class.new(job) } + let(:environment) { Gitlab::Ci::Pipeline::Seed::Environment.new(job).to_resource } + let(:seed) { described_class.new(job, environment) } let(:attributes) { {} } before do @@ -82,5 +83,13 @@ describe Gitlab::Ci::Pipeline::Seed::Deployment do is_expected.to be_nil end end + + context 'when job does not have environment attribute' do + let(:attributes) { { name: 'test' } } + + it 'returns nothing' do + is_expected.to be_nil + end + end end end diff --git a/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb index 71389999c6e..4c0464e5e7c 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb @@ -15,29 +15,68 @@ describe Gitlab::Ci::Pipeline::Seed::Environment do describe '#to_resource' do subject { seed.to_resource } - context 'when job has environment attribute' do - let(:attributes) do - { - environment: 'production', - options: { environment: { name: 'production' } } - } - end - + shared_examples_for 'returning a correct environment' do it 'returns a persisted environment object' do + expect { subject }.to change { Environment.count }.by(1) + expect(subject).to be_a(Environment) expect(subject).to be_persisted expect(subject.project).to eq(project) - expect(subject.name).to eq('production') + expect(subject.name).to eq(expected_environment_name) end context 'when environment has already existed' do - let!(:environment) { create(:environment, project: project, name: 'production') } + let!(:environment) { create(:environment, project: project, name: expected_environment_name) } it 'returns the existing environment object' do + expect { subject }.not_to change { Environment.count } + expect(subject).to be_persisted expect(subject).to eq(environment) end end end + + context 'when job has environment attribute' do + let(:environment_name) { 'production' } + let(:expected_environment_name) { 'production' } + + let(:attributes) do + { + environment: environment_name, + options: { environment: { name: environment_name } } + } + end + + it_behaves_like 'returning a correct environment' + end + + context 'when job starts a review app' do + let(:environment_name) { 'review/$CI_COMMIT_REF_NAME' } + let(:expected_environment_name) { "review/#{job.ref}" } + + let(:attributes) do + { + environment: environment_name, + options: { environment: { name: environment_name } } + } + end + + it_behaves_like 'returning a correct environment' + end + + context 'when job stops a review app' do + let(:environment_name) { 'review/$CI_COMMIT_REF_NAME' } + let(:expected_environment_name) { "review/#{job.ref}" } + + let(:attributes) do + { + environment: environment_name, + options: { environment: { name: environment_name, action: 'stop' } } + } + end + + it_behaves_like 'returning a correct environment' + end end end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 37219365ecf..757c158e16a 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1293,7 +1293,35 @@ describe Ci::Build do environment: 'review/$APP_HOST') end - it { is_expected.to eq('review/host') } + it 'returns an expanded environment name with a list of variables' do + expect(build).to receive(:simple_variables).once.and_call_original + + is_expected.to eq('review/host') + end + + context 'when build metadata has already persisted the expanded environment name' do + before do + build.metadata.expanded_environment_name = 'review/host' + end + + it 'returns a persisted expanded environment name without a list of variables' do + expect(build).not_to receive(:simple_variables) + + is_expected.to eq('review/host') + end + + context 'when ci_persisted_expanded_environment_name feature flag is disabled' do + before do + stub_feature_flags(ci_persisted_expanded_environment_name: false) + end + + it 'returns an expanded environment name with a list of variables' do + expect(build).to receive(:simple_variables).once.and_call_original + + is_expected.to eq('review/host') + end + end + end end context 'when using persisted variables' do diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index 3e5c16c2491..4ecbc671c72 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -56,8 +56,6 @@ describe Issuable do end describe "Scope" do - subject { build(:issue) } - it { expect(issuable_class).to respond_to(:opened) } it { expect(issuable_class).to respond_to(:closed) } it { expect(issuable_class).to respond_to(:assigned) } diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 188271f4a75..8a22b2c8da3 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -238,6 +238,10 @@ describe Ci::RetryBuildService do it 'creates a new deployment' do expect { new_build }.to change { Deployment.count }.by(1) end + + it 'persists expanded environment name' do + expect(new_build.metadata.expanded_environment_name).to eq('production') + end end context 'when scheduling_type of build is nil' do |