Verified Commit 4eb4dc10 authored by Radek Antoniuk's avatar Radek Antoniuk Committed by GitLab
Browse files

feat(feature_flags): support gitlabUserList and strategy removal

Changelog: Improvements
parent de942651
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -65,6 +65,11 @@ type ProjectFeatureFlag struct {
type ProjectFeatureFlagScope struct {
	ID               int64  `json:"id"`
	EnvironmentScope string `json:"environment_scope"`

	// Destroy removes the scope identified by ID when set to true. Used
	// during UpdateProjectFeatureFlag to delete a scope that is no longer
	// wanted.
	Destroy *bool `json:"_destroy,omitempty"`
}

// ProjectFeatureFlagStrategy defines the strategy used for a feature flag
@@ -75,6 +80,7 @@ type ProjectFeatureFlagStrategy struct {
	Name       string                               `json:"name"`
	Parameters *ProjectFeatureFlagStrategyParameter `json:"parameters"`
	Scopes     []*ProjectFeatureFlagScope           `json:"scopes"`
	UserList   *FeatureFlagUserList                 `json:"user_list,omitempty"`
}

// ProjectFeatureFlagStrategyParameter is used in updating and creating feature flags
@@ -143,6 +149,15 @@ type FeatureFlagStrategyOptions struct {
	Name       *string                              `url:"name,omitempty" json:"name,omitempty"`
	Parameters *ProjectFeatureFlagStrategyParameter `url:"parameters,omitempty" json:"parameters,omitempty"`
	Scopes     *[]*ProjectFeatureFlagScope          `url:"scopes,omitempty" json:"scopes,omitempty"`

	// UserListID sets the feature flag user list bound to the strategy. Only
	// used when Name is "gitlabUserList".
	UserListID *int64 `url:"user_list_id,omitempty" json:"user_list_id,omitempty"`

	// Destroy removes the strategy identified by ID when set to true. Used
	// during UpdateProjectFeatureFlag to delete a strategy that is no longer
	// wanted.
	Destroy *bool `url:"_destroy,omitempty" json:"_destroy,omitempty"`
}

// ProjectFeatureFlagScopeOptions represents the available feature flag scope
+123 −0
Original line number Diff line number Diff line
@@ -216,6 +216,129 @@ func TestUpdateProjectFeatureFlag(t *testing.T) {
	assert.Equal(t, expected, actual)
}

func TestUpdateProjectFeatureFlag_GitLabUserListAndDestroy(t *testing.T) {
	t.Parallel()
	mux, client := setup(t)

	mux.HandleFunc("/api/v4/projects/1/feature_flags/testing", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodPut)
		testBodyJSON(t, r, map[string]any{
			"strategies": []any{
				map[string]any{
					"name":         "gitlabUserList",
					"user_list_id": float64(7),
				},
				map[string]any{
					"id":       float64(38),
					"_destroy": true,
				},
			},
		})
		mustWriteHTTPResponse(t, w, "testdata/update_project_feature_flag_gitlab_user_list.json")
	})

	opt := &UpdateProjectFeatureFlagOptions{
		Strategies: &[]*FeatureFlagStrategyOptions{
			{
				Name:       Ptr("gitlabUserList"),
				UserListID: Ptr(int64(7)),
			},
			{
				ID:      Ptr(int64(38)),
				Destroy: Ptr(true),
			},
		},
	}

	actual, _, err := client.ProjectFeatureFlags.UpdateProjectFeatureFlag(1, "testing", opt)
	require.NoError(t, err)

	expected := &ProjectFeatureFlag{
		Name:      "awesome_feature",
		Active:    true,
		Version:   "new_version_flag",
		CreatedAt: Ptr(time.Date(2020, time.May, 13, 20, 10, 32, 0, time.UTC)),
		UpdatedAt: Ptr(time.Date(2020, time.May, 13, 20, 10, 32, 0, time.UTC)),
		Scopes:    []*ProjectFeatureFlagScope{},
		Strategies: []*ProjectFeatureFlagStrategy{
			{
				ID:         39,
				Name:       "gitlabUserList",
				Parameters: &ProjectFeatureFlagStrategyParameter{},
				Scopes:     []*ProjectFeatureFlagScope{},
				UserList: &FeatureFlagUserList{
					ID:       7,
					IID:      1,
					Name:     "my_user_list",
					UserXIDs: "user1,user2,user3",
				},
			},
		},
	}

	assert.Equal(t, expected, actual)
}

func TestUpdateProjectFeatureFlag_ScopeDestroy(t *testing.T) {
	t.Parallel()
	mux, client := setup(t)

	mux.HandleFunc("/api/v4/projects/1/feature_flags/testing", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodPut)
		testBodyJSON(t, r, map[string]any{
			"strategies": []any{
				map[string]any{
					"id": float64(36),
					"scopes": []any{
						map[string]any{
							"id":                float64(37),
							"environment_scope": "",
							"_destroy":          true,
						},
					},
				},
			},
		})
		mustWriteHTTPResponse(t, w, "testdata/update_project_feature_flag_scope_destroy.json")
	})

	opt := &UpdateProjectFeatureFlagOptions{
		Strategies: &[]*FeatureFlagStrategyOptions{
			{
				ID: Ptr(int64(36)),
				Scopes: &[]*ProjectFeatureFlagScope{
					{
						ID:      37,
						Destroy: Ptr(true),
					},
				},
			},
		},
	}

	actual, _, err := client.ProjectFeatureFlags.UpdateProjectFeatureFlag(1, "testing", opt)
	require.NoError(t, err)

	expected := &ProjectFeatureFlag{
		Name:      "awesome_feature",
		Active:    true,
		Version:   "new_version_flag",
		CreatedAt: Ptr(time.Date(2020, time.May, 13, 20, 10, 32, 0, time.UTC)),
		UpdatedAt: Ptr(time.Date(2020, time.May, 13, 20, 10, 32, 0, time.UTC)),
		Scopes:    []*ProjectFeatureFlagScope{},
		Strategies: []*ProjectFeatureFlagStrategy{
			{
				ID:         36,
				Name:       "default",
				Parameters: &ProjectFeatureFlagStrategyParameter{},
				Scopes:     []*ProjectFeatureFlagScope{},
			},
		},
	}

	assert.Equal(t, expected, actual)
}

func TestDeleteProjectFeatureFlag(t *testing.T) {
	t.Parallel()
	mux, client := setup(t)
+23 −0
Original line number Diff line number Diff line
{
  "name": "awesome_feature",
  "description": null,
  "active": true,
  "version": "new_version_flag",
  "created_at": "2020-05-13T20:10:32Z",
  "updated_at": "2020-05-13T20:10:32Z",
  "scopes": [],
  "strategies": [
    {
      "id": 39,
      "name": "gitlabUserList",
      "parameters": {},
      "scopes": [],
      "user_list": {
        "id": 7,
        "iid": 1,
        "name": "my_user_list",
        "user_xids": "user1,user2,user3"
      }
    }
  ]
}
+17 −0
Original line number Diff line number Diff line
{
  "name": "awesome_feature",
  "description": null,
  "active": true,
  "version": "new_version_flag",
  "created_at": "2020-05-13T20:10:32Z",
  "updated_at": "2020-05-13T20:10:32Z",
  "scopes": [],
  "strategies": [
    {
      "id": 36,
      "name": "default",
      "parameters": {},
      "scopes": []
    }
  ]
}