Commit dd8012f9 authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Merge branch '276931-gitlab-api-doesn-t-expose-cluster-managed-state' into 'master'

Resolve "GitLab API doesn't expose Cluster Managed state"

See merge request gitlab-org/gitlab!47310
parents a09d14e8 8fa89bea
This diff is collapsed.
...@@ -35,6 +35,8 @@ Example response: ...@@ -35,6 +35,8 @@ Example response:
"id": 9, "id": 9,
"name": "cluster-1", "name": "cluster-1",
"created_at": "2020-07-14T18:36:10.440Z", "created_at": "2020-07-14T18:36:10.440Z",
"managed": true,
"enabled": true,
"domain": null, "domain": null,
"provider_type": "user", "provider_type": "user",
"platform_type": "kubernetes", "platform_type": "kubernetes",
...@@ -98,9 +100,9 @@ Returns a single instance cluster. ...@@ -98,9 +100,9 @@ Returns a single instance cluster.
Parameters: Parameters:
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- | | ------------ | ------- | -------- | --------------------- |
| `cluster_id` | integer | yes | The ID of the cluster | | `cluster_id` | integer | yes | The ID of the cluster |
```plaintext ```plaintext
GET /admin/clusters/:cluster_id GET /admin/clusters/:cluster_id
...@@ -119,6 +121,8 @@ Example response: ...@@ -119,6 +121,8 @@ Example response:
"id": 9, "id": 9,
"name": "cluster-1", "name": "cluster-1",
"created_at": "2020-07-14T18:36:10.440Z", "created_at": "2020-07-14T18:36:10.440Z",
"managed": true,
"enabled": true,
"domain": null, "domain": null,
"provider_type": "user", "provider_type": "user",
"platform_type": "kubernetes", "platform_type": "kubernetes",
...@@ -153,19 +157,19 @@ POST /admin/clusters/add ...@@ -153,19 +157,19 @@ POST /admin/clusters/add
Parameters: Parameters:
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- | | ---------------------------------------------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------- |
| `name` | string | yes | The name of the cluster | | `name` | string | yes | The name of the cluster |
| `domain` | string | no | The [base domain](../user/project/clusters/index.md#base-domain) of the cluster | | `domain` | string | no | The [base domain](../user/project/clusters/index.md#base-domain) of the cluster |
| `environment_scope` | string | no | The associated environment to the cluster. Defaults to `*` | | `environment_scope` | string | no | The associated environment to the cluster. Defaults to `*` |
| `management_project_id` | integer | no | The ID of the [management project](../user/clusters/management_project.md) for 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 | | `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 | | `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[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[token]` | string | yes | The token to authenticate against Kubernetes |
| `platform_kubernetes_attributes[ca_cert]` | string | no | TLS certificate. Required if API is using a self-signed TLS certificate. | | `platform_kubernetes_attributes[ca_cert]` | string | no | TLS certificate. Required if API is using a self-signed TLS certificate. |
| `platform_kubernetes_attributes[namespace]` | string | no | The unique namespace related to the project | | `platform_kubernetes_attributes[namespace]` | string | no | The unique namespace related to the project |
| `platform_kubernetes_attributes[authorization_type]` | string | no | The cluster authorization type: `rbac`, `abac` or `unknown_authorization`. Defaults to `rbac`. | | `platform_kubernetes_attributes[authorization_type]` | string | no | The cluster authorization type: `rbac`, `abac` or `unknown_authorization`. Defaults to `rbac`. |
Example request: Example request:
...@@ -184,6 +188,8 @@ Example response: ...@@ -184,6 +188,8 @@ Example response:
"id": 11, "id": 11,
"name": "cluster-3", "name": "cluster-3",
"created_at": "2020-07-14T18:42:50.805Z", "created_at": "2020-07-14T18:42:50.805Z",
"managed": true,
"enabled": true,
"domain": null, "domain": null,
"provider_type": "user", "provider_type": "user",
"platform_type": "kubernetes", "platform_type": "kubernetes",
...@@ -218,18 +224,19 @@ PUT /admin/clusters/:cluster_id ...@@ -218,18 +224,19 @@ PUT /admin/clusters/:cluster_id
Parameters: Parameters:
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- | | ------------------------------------------- | ------- | -------- | ------------------------------------------------------------------------------------------ |
| `cluster_id` | integer | yes | The ID of the cluster | | `cluster_id` | integer | yes | The ID of the cluster |
| `name` | string | no | The name of the cluster | | `name` | string | no | The name of the cluster |
| `domain` | string | no | The [base domain](../user/project/clusters/index.md#base-domain) of the cluster | | `domain` | string | no | The [base domain](../user/project/clusters/index.md#base-domain) of the cluster |
| `environment_scope` | string | no | The associated environment to the cluster | | `environment_scope` | string | no | The associated environment to the cluster |
| `management_project_id` | integer | no | The ID of the [management project](../user/clusters/management_project.md) for 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 | | `enabled` | boolean | no | Determines if cluster is active or not |
| `platform_kubernetes_attributes[api_url]` | string | no | The URL to access the Kubernetes API | | `managed` | boolean | no | Determines if GitLab will manage namespaces and service accounts for this cluster |
| `platform_kubernetes_attributes[token]` | string | no | The token to authenticate against Kubernetes | | `platform_kubernetes_attributes[api_url]` | string | no | The URL to access the Kubernetes API |
| `platform_kubernetes_attributes[ca_cert]` | string | no | TLS certificate. Required if API is using a self-signed TLS certificate. | | `platform_kubernetes_attributes[token]` | string | no | The token to authenticate against Kubernetes |
| `platform_kubernetes_attributes[namespace]` | string | no | The unique namespace related to the project | | `platform_kubernetes_attributes[ca_cert]` | string | no | TLS certificate. Required if API is using a self-signed TLS certificate. |
| `platform_kubernetes_attributes[namespace]` | string | no | The unique namespace related to the project |
NOTE: **Note:** NOTE: **Note:**
`name`, `api_url`, `ca_cert` and `token` can only be updated if the cluster was added `name`, `api_url`, `ca_cert` and `token` can only be updated if the cluster was added
...@@ -252,6 +259,8 @@ Example response: ...@@ -252,6 +259,8 @@ Example response:
"id": 9, "id": 9,
"name": "update-cluster-name", "name": "update-cluster-name",
"created_at": "2020-07-14T18:36:10.440Z", "created_at": "2020-07-14T18:36:10.440Z",
"managed": true,
"enabled": true,
"domain": null, "domain": null,
"provider_type": "user", "provider_type": "user",
"platform_type": "kubernetes", "platform_type": "kubernetes",
...@@ -288,9 +297,9 @@ DELETE /admin/clusters/:cluster_id ...@@ -288,9 +297,9 @@ DELETE /admin/clusters/:cluster_id
Parameters: Parameters:
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- | | ------------ | ------- | -------- | --------------------- |
| `cluster_id` | integer | yes | The ID of the cluster | | `cluster_id` | integer | yes | The ID of the cluster |
Example request: Example request:
......
This diff is collapsed.
...@@ -76,6 +76,7 @@ module API ...@@ -76,6 +76,7 @@ module API
optional :namespace_per_environment, default: true, type: Boolean, desc: 'Deploy each environment to a separate Kubernetes namespace' optional :namespace_per_environment, default: true, type: Boolean, desc: 'Deploy each environment to a separate Kubernetes namespace'
optional :domain, type: String, desc: 'Cluster base domain' optional :domain, type: String, desc: 'Cluster base domain'
optional :management_project_id, type: Integer, desc: 'The ID of the management project' optional :management_project_id, type: Integer, desc: 'The ID of the management project'
optional :managed, type: Boolean, desc: 'Determines if GitLab will manage namespaces and service accounts for this cluster'
optional :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do optional :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do
optional :api_url, type: String, desc: 'URL to access the Kubernetes API' optional :api_url, type: String, desc: 'URL to access the Kubernetes API'
optional :token, type: String, desc: 'Token to authenticate against Kubernetes' optional :token, type: String, desc: 'Token to authenticate against Kubernetes'
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module API module API
module Entities module Entities
class Cluster < Grape::Entity class Cluster < Grape::Entity
expose :id, :name, :created_at, :domain expose :id, :name, :created_at, :domain, :enabled, :managed
expose :provider_type, :platform_type, :environment_scope, :cluster_type, :namespace_per_environment expose :provider_type, :platform_type, :environment_scope, :cluster_type, :namespace_per_environment
expose :user, using: Entities::UserBasic expose :user, using: Entities::UserBasic
expose :platform_kubernetes, using: Entities::Platform::Kubernetes expose :platform_kubernetes, using: Entities::Platform::Kubernetes
......
...@@ -75,10 +75,12 @@ module API ...@@ -75,10 +75,12 @@ module API
params do params do
requires :cluster_id, type: Integer, desc: 'The cluster ID' requires :cluster_id, type: Integer, desc: 'The cluster ID'
optional :name, type: String, desc: 'Cluster name' optional :name, type: String, desc: 'Cluster name'
optional :enabled, type: Boolean, desc: 'Determines if cluster is active or not'
optional :domain, type: String, desc: 'Cluster base domain' optional :domain, type: String, desc: 'Cluster base domain'
optional :environment_scope, type: String, desc: 'The associated environment to the cluster' optional :environment_scope, type: String, desc: 'The associated environment to the cluster'
optional :namespace_per_environment, default: true, type: Boolean, desc: 'Deploy each environment to a separate Kubernetes namespace' optional :namespace_per_environment, default: true, type: Boolean, desc: 'Deploy each environment to a separate Kubernetes namespace'
optional :management_project_id, type: Integer, desc: 'The ID of the management project' optional :management_project_id, type: Integer, desc: 'The ID of the management project'
optional :managed, type: Boolean, desc: 'Determines if GitLab will manage namespaces and service accounts for this cluster'
optional :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do optional :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do
optional :api_url, type: String, desc: 'URL to access the Kubernetes API' optional :api_url, type: String, desc: 'URL to access the Kubernetes API'
optional :token, type: String, desc: 'Token to authenticate against Kubernetes' optional :token, type: String, desc: 'Token to authenticate against Kubernetes'
......
...@@ -83,6 +83,8 @@ module API ...@@ -83,6 +83,8 @@ module API
optional :environment_scope, type: String, desc: 'The associated environment to the cluster' optional :environment_scope, type: String, desc: 'The associated environment to the cluster'
optional :namespace_per_environment, default: true, type: Boolean, desc: 'Deploy each environment to a separate Kubernetes namespace' optional :namespace_per_environment, default: true, type: Boolean, desc: 'Deploy each environment to a separate Kubernetes namespace'
optional :management_project_id, type: Integer, desc: 'The ID of the management project' optional :management_project_id, type: Integer, desc: 'The ID of the management project'
optional :enabled, type: Boolean, desc: 'Determines if cluster is active or not'
optional :managed, type: Boolean, desc: 'Determines if GitLab will manage namespaces and service accounts for this cluster'
optional :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do optional :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do
optional :api_url, type: String, desc: 'URL to access the Kubernetes API' optional :api_url, type: String, desc: 'URL to access the Kubernetes API'
optional :token, type: String, desc: 'Token to authenticate against Kubernetes' optional :token, type: String, desc: 'Token to authenticate against Kubernetes'
......
...@@ -90,6 +90,8 @@ RSpec.describe ::API::Admin::InstanceClusters do ...@@ -90,6 +90,8 @@ RSpec.describe ::API::Admin::InstanceClusters do
expect(json_response['environment_scope']).to eq('*') expect(json_response['environment_scope']).to eq('*')
expect(json_response['cluster_type']).to eq('instance_type') expect(json_response['cluster_type']).to eq('instance_type')
expect(json_response['domain']).to eq('example.com') expect(json_response['domain']).to eq('example.com')
expect(json_response['enabled']).to be_truthy
expect(json_response['managed']).to be_truthy
end end
it 'returns kubernetes platform information' do it 'returns kubernetes platform information' do
...@@ -163,6 +165,7 @@ RSpec.describe ::API::Admin::InstanceClusters do ...@@ -163,6 +165,7 @@ RSpec.describe ::API::Admin::InstanceClusters do
name: 'test-instance-cluster', name: 'test-instance-cluster',
domain: 'domain.example.com', domain: 'domain.example.com',
managed: false, managed: false,
enabled: false,
namespace_per_environment: false, namespace_per_environment: false,
platform_kubernetes_attributes: platform_kubernetes_attributes, platform_kubernetes_attributes: platform_kubernetes_attributes,
clusterable: clusterable clusterable: clusterable
...@@ -205,9 +208,9 @@ RSpec.describe ::API::Admin::InstanceClusters do ...@@ -205,9 +208,9 @@ RSpec.describe ::API::Admin::InstanceClusters do
expect(cluster_result.name).to eq('test-instance-cluster') expect(cluster_result.name).to eq('test-instance-cluster')
expect(cluster_result.domain).to eq('domain.example.com') expect(cluster_result.domain).to eq('domain.example.com')
expect(cluster_result.environment_scope).to eq('*') expect(cluster_result.environment_scope).to eq('*')
expect(cluster_result.enabled).to eq(true)
expect(platform_kubernetes.authorization_type).to eq('rbac')
expect(cluster_result.managed).to be_falsy expect(cluster_result.managed).to be_falsy
expect(cluster_result.enabled).to be_falsy
expect(platform_kubernetes.authorization_type).to eq('rbac')
expect(cluster_result.namespace_per_environment).to eq(false) expect(cluster_result.namespace_per_environment).to eq(false)
expect(platform_kubernetes.api_url).to eq("https://example.com") expect(platform_kubernetes.api_url).to eq("https://example.com")
expect(platform_kubernetes.token).to eq('sample-token') expect(platform_kubernetes.token).to eq('sample-token')
...@@ -301,6 +304,8 @@ RSpec.describe ::API::Admin::InstanceClusters do ...@@ -301,6 +304,8 @@ RSpec.describe ::API::Admin::InstanceClusters do
let(:update_params) do let(:update_params) do
{ {
domain: domain, domain: domain,
managed: false,
enabled: false,
platform_kubernetes_attributes: platform_kubernetes_attributes platform_kubernetes_attributes: platform_kubernetes_attributes
} }
end end
...@@ -326,6 +331,8 @@ RSpec.describe ::API::Admin::InstanceClusters do ...@@ -326,6 +331,8 @@ RSpec.describe ::API::Admin::InstanceClusters do
it 'updates cluster attributes' do it 'updates cluster attributes' do
expect(cluster.domain).to eq('new-domain.com') expect(cluster.domain).to eq('new-domain.com')
expect(cluster.managed).to be_falsy
expect(cluster.enabled).to be_falsy
end end
end end
...@@ -338,6 +345,8 @@ RSpec.describe ::API::Admin::InstanceClusters do ...@@ -338,6 +345,8 @@ RSpec.describe ::API::Admin::InstanceClusters do
it 'does not update cluster attributes' do it 'does not update cluster attributes' do
expect(cluster.domain).to eq('old-domain.com') expect(cluster.domain).to eq('old-domain.com')
expect(cluster.managed).to be_truthy
expect(cluster.enabled).to be_truthy
end end
it 'returns validation errors' do it 'returns validation errors' do
......
...@@ -89,6 +89,8 @@ RSpec.describe API::GroupClusters do ...@@ -89,6 +89,8 @@ RSpec.describe API::GroupClusters do
expect(json_response['environment_scope']).to eq('*') expect(json_response['environment_scope']).to eq('*')
expect(json_response['cluster_type']).to eq('group_type') expect(json_response['cluster_type']).to eq('group_type')
expect(json_response['domain']).to eq('example.com') expect(json_response['domain']).to eq('example.com')
expect(json_response['enabled']).to be_truthy
expect(json_response['managed']).to be_truthy
end end
it 'returns group information' do it 'returns group information' do
...@@ -172,6 +174,7 @@ RSpec.describe API::GroupClusters do ...@@ -172,6 +174,7 @@ RSpec.describe API::GroupClusters do
name: 'test-cluster', name: 'test-cluster',
domain: 'domain.example.com', domain: 'domain.example.com',
managed: false, managed: false,
enabled: false,
namespace_per_environment: false, namespace_per_environment: false,
platform_kubernetes_attributes: platform_kubernetes_attributes, platform_kubernetes_attributes: platform_kubernetes_attributes,
management_project_id: management_project_id management_project_id: management_project_id
...@@ -206,6 +209,7 @@ RSpec.describe API::GroupClusters do ...@@ -206,6 +209,7 @@ RSpec.describe API::GroupClusters do
expect(cluster_result.name).to eq('test-cluster') expect(cluster_result.name).to eq('test-cluster')
expect(cluster_result.domain).to eq('domain.example.com') expect(cluster_result.domain).to eq('domain.example.com')
expect(cluster_result.managed).to be_falsy expect(cluster_result.managed).to be_falsy
expect(cluster_result.enabled).to be_falsy
expect(cluster_result.management_project_id).to eq management_project_id expect(cluster_result.management_project_id).to eq management_project_id
expect(cluster_result.namespace_per_environment).to eq(false) expect(cluster_result.namespace_per_environment).to eq(false)
expect(platform_kubernetes.rbac?).to be_truthy expect(platform_kubernetes.rbac?).to be_truthy
...@@ -342,7 +346,9 @@ RSpec.describe API::GroupClusters do ...@@ -342,7 +346,9 @@ RSpec.describe API::GroupClusters do
{ {
domain: domain, domain: domain,
platform_kubernetes_attributes: platform_kubernetes_attributes, platform_kubernetes_attributes: platform_kubernetes_attributes,
management_project_id: management_project_id management_project_id: management_project_id,
managed: false,
enabled: false
} }
end end
...@@ -381,6 +387,8 @@ RSpec.describe API::GroupClusters do ...@@ -381,6 +387,8 @@ RSpec.describe API::GroupClusters do
it 'updates cluster attributes' do it 'updates cluster attributes' do
expect(cluster.domain).to eq('new-domain.com') expect(cluster.domain).to eq('new-domain.com')
expect(cluster.management_project).to eq(management_project) expect(cluster.management_project).to eq(management_project)
expect(cluster.managed).to be_falsy
expect(cluster.enabled).to be_falsy
end end
end end
...@@ -394,6 +402,8 @@ RSpec.describe API::GroupClusters do ...@@ -394,6 +402,8 @@ RSpec.describe API::GroupClusters do
it 'does not update cluster attributes' do it 'does not update cluster attributes' do
expect(cluster.domain).to eq('old-domain.com') expect(cluster.domain).to eq('old-domain.com')
expect(cluster.management_project).to be_nil expect(cluster.management_project).to be_nil
expect(cluster.managed).to be_truthy
expect(cluster.enabled).to be_truthy
end end
it 'returns validation errors' do it 'returns validation errors' do
......
...@@ -88,6 +88,8 @@ RSpec.describe API::ProjectClusters do ...@@ -88,6 +88,8 @@ RSpec.describe API::ProjectClusters do
expect(json_response['environment_scope']).to eq('*') expect(json_response['environment_scope']).to eq('*')
expect(json_response['cluster_type']).to eq('project_type') expect(json_response['cluster_type']).to eq('project_type')
expect(json_response['domain']).to eq('example.com') expect(json_response['domain']).to eq('example.com')
expect(json_response['enabled']).to be_truthy
expect(json_response['managed']).to be_truthy
end end
it 'returns project information' do it 'returns project information' do
...@@ -171,6 +173,7 @@ RSpec.describe API::ProjectClusters do ...@@ -171,6 +173,7 @@ RSpec.describe API::ProjectClusters do
name: 'test-cluster', name: 'test-cluster',
domain: 'domain.example.com', domain: 'domain.example.com',
managed: false, managed: false,
enabled: false,
namespace_per_environment: false, namespace_per_environment: false,
platform_kubernetes_attributes: platform_kubernetes_attributes, platform_kubernetes_attributes: platform_kubernetes_attributes,
management_project_id: management_project_id management_project_id: management_project_id
...@@ -202,6 +205,7 @@ RSpec.describe API::ProjectClusters do ...@@ -202,6 +205,7 @@ RSpec.describe API::ProjectClusters do
expect(cluster_result.name).to eq('test-cluster') expect(cluster_result.name).to eq('test-cluster')
expect(cluster_result.domain).to eq('domain.example.com') expect(cluster_result.domain).to eq('domain.example.com')
expect(cluster_result.managed).to be_falsy expect(cluster_result.managed).to be_falsy
expect(cluster_result.enabled).to be_falsy
expect(cluster_result.management_project_id).to eq management_project_id expect(cluster_result.management_project_id).to eq management_project_id
expect(cluster_result.namespace_per_environment).to eq(false) expect(cluster_result.namespace_per_environment).to eq(false)
expect(platform_kubernetes.rbac?).to be_truthy expect(platform_kubernetes.rbac?).to be_truthy
...@@ -337,7 +341,9 @@ RSpec.describe API::ProjectClusters do ...@@ -337,7 +341,9 @@ RSpec.describe API::ProjectClusters do
{ {
domain: 'new-domain.com', domain: 'new-domain.com',
platform_kubernetes_attributes: platform_kubernetes_attributes, platform_kubernetes_attributes: platform_kubernetes_attributes,
management_project_id: management_project_id management_project_id: management_project_id,
managed: false,
enabled: false
} }
end end
...@@ -373,6 +379,8 @@ RSpec.describe API::ProjectClusters do ...@@ -373,6 +379,8 @@ RSpec.describe API::ProjectClusters do
it 'updates cluster attributes' do it 'updates cluster attributes' do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(cluster.domain).to eq('new-domain.com') expect(cluster.domain).to eq('new-domain.com')
expect(cluster.managed).to be_falsy
expect(cluster.enabled).to be_falsy
expect(cluster.platform_kubernetes.namespace).to eq('new-namespace') expect(cluster.platform_kubernetes.namespace).to eq('new-namespace')
expect(cluster.management_project).to eq(management_project) expect(cluster.management_project).to eq(management_project)
end end
...@@ -384,6 +392,8 @@ RSpec.describe API::ProjectClusters do ...@@ -384,6 +392,8 @@ RSpec.describe API::ProjectClusters do
it 'does not update cluster attributes' do it 'does not update cluster attributes' do
expect(response).to have_gitlab_http_status(:bad_request) expect(response).to have_gitlab_http_status(:bad_request)
expect(cluster.domain).not_to eq('new_domain.com') expect(cluster.domain).not_to eq('new_domain.com')
expect(cluster.managed).to be_truthy
expect(cluster.enabled).to be_truthy
expect(cluster.platform_kubernetes.namespace).not_to eq('invalid_namespace') expect(cluster.platform_kubernetes.namespace).not_to eq('invalid_namespace')
expect(cluster.management_project).not_to eq(management_project) expect(cluster.management_project).not_to eq(management_project)
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment