Skip to content

Commit

Permalink
[ResponseOps] Package for feature flags (#185000)
Browse files Browse the repository at this point in the history
## Summary

This PR creates a package to expose tools for managing feature flags in
the ResponseOps codebase.

Usage:

```
const featureFlagService = createFeatureFlagService(['test.myFeature', 'test.myFeature.subFeature']);


if (featureFlagService.isFeatureFlagSet('test.myFeature')) {
  // my feature code
}
```

The code is typed so if you do
`featureFlagService.isFeatureFlagSet('foo')` and `foo` is not part of
the feature flags set TS will report an error.

### Checklist

Delete any items that are not applicable to this PR.

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

### For maintainers

- [x] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
cnasikas and kibanamachine authored Jun 13, 2024
1 parent 75f3af5 commit fe59dd4
Show file tree
Hide file tree
Showing 12 changed files with 140 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,7 @@ packages/kbn-reporting/server @elastic/appex-sharedux
packages/kbn-resizable-layout @elastic/kibana-data-discovery
examples/resizable_layout_examples @elastic/kibana-data-discovery
x-pack/test/plugin_functional/plugins/resolver_test @elastic/security-solution
packages/response-ops/feature_flag_service @elastic/response-ops
examples/response_stream @elastic/ml-ui
packages/kbn-rison @elastic/kibana-operations
x-pack/plugins/rollup @elastic/kibana-management
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,7 @@
"@kbn/resizable-layout": "link:packages/kbn-resizable-layout",
"@kbn/resizable-layout-examples-plugin": "link:examples/resizable_layout_examples",
"@kbn/resolver-test-plugin": "link:x-pack/test/plugin_functional/plugins/resolver_test",
"@kbn/response-ops-feature-flag-service": "link:packages/response-ops/feature_flag_service",
"@kbn/response-stream-plugin": "link:examples/response_stream",
"@kbn/rison": "link:packages/kbn-rison",
"@kbn/rollup-plugin": "link:x-pack/plugins/rollup",
Expand Down
27 changes: 27 additions & 0 deletions packages/response-ops/feature_flag_service/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# @kbn/response-ops-feature-flags

This packages exposes a feature flag service that is used in the ResponseOps plugins and packages to handle feature flags.

## Usage

### Create feature flag service

```
const featureFlagService = createFeatureFlagService(['test.myFeature', 'test.myFeature.subFeature']); // TS will infer the types automatically
```

or

```
type FeatureFlagValues = 'test.myFeature' | 'test.myOtherFeature'
const featureFlagService = createFeatureFlagService<FeatureFlagValues>(['test.myFeature']);
```

### Checking the existence of a feature flag
```
const featureFlagService = createFeatureFlagService(['test.myFeature', 'test.myFeature.subFeature']);
if (featureFlagService.isFeatureFlagSet('test.myFeature')) {
// my feature code
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { createFeatureFlagService } from './feature_flag_service';

type FeatureFlagValues = 'test.myFeature' | 'test.myOtherFeature';

describe('FeatureFlagService', () => {
it('returns true if the feature exists', () => {
const featureFlagService = createFeatureFlagService(['test.myFeature']);
expect(featureFlagService.isFeatureFlagSet('test.myFeature')).toBe(true);
});

it('returns false if the feature does not exist', () => {
const featureFlagService = createFeatureFlagService(['test.myFeature']);
// @ts-expect-error: foo is not part of the valid feature flags
expect(featureFlagService.isFeatureFlagSet('foo')).toBe(false);
});

it('returns true if the feature exists (as typed)', () => {
const featureFlagService = createFeatureFlagService<FeatureFlagValues>(['test.myFeature']);
expect(featureFlagService.isFeatureFlagSet('test.myFeature')).toBe(true);
});
});
25 changes: 25 additions & 0 deletions packages/response-ops/feature_flag_service/feature_flag_service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

class FeatureFlag<T extends string = string> {
private readonly featureFlags = new Set<T>();

constructor(featureFlags: T[]) {
featureFlags.forEach((featureFlag) => this.featureFlags.add(featureFlag));
}

public isFeatureFlagSet(featureFlag: T): boolean {
return this.featureFlags.has(featureFlag);
}
}

export const createFeatureFlagService = <T extends string>(featureFlags: T[]) => {
return new FeatureFlag<typeof featureFlags[number]>(featureFlags);
};

export type FeatureFlagService<T extends string = string> = InstanceType<typeof FeatureFlag<T>>;
10 changes: 10 additions & 0 deletions packages/response-ops/feature_flag_service/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export { createFeatureFlagService } from './feature_flag_service';
export type { FeatureFlagService } from './feature_flag_service';
13 changes: 13 additions & 0 deletions packages/response-ops/feature_flag_service/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

module.exports = {
preset: '@kbn/test/jest_node',
rootDir: '../../..',
roots: ['<rootDir>/packages/response-ops/feature_flag_service'],
};
5 changes: 5 additions & 0 deletions packages/response-ops/feature_flag_service/kibana.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/response-ops-feature-flag-service",
"owner": "@elastic/response-ops"
}
6 changes: 6 additions & 0 deletions packages/response-ops/feature_flag_service/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "@kbn/response-ops-feature-flag-service",
"private": true,
"version": "1.0.0",
"license": "SSPL-1.0 OR Elastic License 2.0"
}
17 changes: 17 additions & 0 deletions packages/response-ops/feature_flag_service/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node"
]
},
"include": [
"**/*.ts",
],
"exclude": [
"target/**/*"
],
"kbn_references": []
}
2 changes: 2 additions & 0 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -1356,6 +1356,8 @@
"@kbn/resizable-layout-examples-plugin/*": ["examples/resizable_layout_examples/*"],
"@kbn/resolver-test-plugin": ["x-pack/test/plugin_functional/plugins/resolver_test"],
"@kbn/resolver-test-plugin/*": ["x-pack/test/plugin_functional/plugins/resolver_test/*"],
"@kbn/response-ops-feature-flag-service": ["packages/response-ops/feature_flag_service"],
"@kbn/response-ops-feature-flag-service/*": ["packages/response-ops/feature_flag_service/*"],
"@kbn/response-stream-plugin": ["examples/response_stream"],
"@kbn/response-stream-plugin/*": ["examples/response_stream/*"],
"@kbn/rison": ["packages/kbn-rison"],
Expand Down
4 changes: 4 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5880,6 +5880,10 @@
version "0.0.0"
uid ""

"@kbn/response-ops-feature-flag-service@link:packages/response-ops/feature_flag_service":
version "0.0.0"
uid ""

"@kbn/response-stream-plugin@link:examples/response_stream":
version "0.0.0"
uid ""
Expand Down

0 comments on commit fe59dd4

Please sign in to comment.