Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow printing datafile per environment #275

Merged
merged 2 commits into from
Mar 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion docs/building-datafiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,18 @@ $ featurevisor build --revision 1.2.3

## Printing

You can print the contents of a datafile for a single feature without writing anything to disk by passing these flags:
You can print the contents of a datafile for a single feature in/or an environment without writing anything to disk by passing these flags:

```
$ featurevisor build --feature=foo --environment=production --print --pretty
```

Or if you with to print datafile containing all features for a specific environment:

```
$ featurevisor build --environment=production --print --pretty
```

This is useful primarily for debugging and testing purposes.

If you are an SDK developer in other languages besides JavaScript, you may want to use this handy command to get the generated datafile content in JSON format that you can use in your own [test runner](/docs/testing).
34 changes: 33 additions & 1 deletion packages/core/src/builder/buildDatafile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,45 @@ import {
VariableSchema,
} from "@featurevisor/types";

import { ProjectConfig } from "../config";
import { ProjectConfig, SCHEMA_VERSION } from "../config";
import { Datasource } from "../datasource";
import { extractAttributeKeysFromConditions, extractSegmentKeysFromGroupSegments } from "../utils";

import { getTraffic } from "./traffic";
import { getFeatureRanges } from "./getFeatureRanges";

export interface CustomDatafileOptions {
featureKey?: string;
environment: string;
projectConfig: ProjectConfig;
datasource: Datasource;
revision?: string;
}

export async function getCustomDatafile(options: CustomDatafileOptions): Promise<DatafileContent> {
let featuresToInclude;

if (options.featureKey) {
const requiredChain = await options.datasource.getRequiredFeaturesChain(options.featureKey);
featuresToInclude = Array.from(requiredChain);
}

const existingState = await options.datasource.readState(options.environment);
const datafileContent = await buildDatafile(
options.projectConfig,
options.datasource,
{
schemaVersion: SCHEMA_VERSION,
revision: options.revision || "tester",
environment: options.environment,
features: featuresToInclude,
},
existingState,
);

return datafileContent;
}

export interface BuildOptions {
schemaVersion: string;
revision: string;
Expand Down
17 changes: 8 additions & 9 deletions packages/core/src/builder/buildProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import * as path from "path";

import { SCHEMA_VERSION } from "../config";

import { buildDatafile } from "./buildDatafile";
import { getDatafileForFeature } from "../tester";
import { buildDatafile, getCustomDatafile } from "./buildDatafile";
import { Dependencies } from "../dependencies";

export interface BuildCLIOptions {
Expand All @@ -23,20 +22,20 @@ export async function buildProject(deps: Dependencies, cliOptions: BuildCLIOptio
* This build process does not write to disk, and prints only to stdout.
*
* This is ideally for test runners in other languages,
* when they wish to get datafile for a single feature,
* when they wish to get datafile for a single feature and/or environment,
* so they can run tests against their own SDKs in other languages.
*
* This way we centralize the datafile generation in one place,
* while tests can be run anywhere else.
*/
if (cliOptions.environment && cliOptions.feature && cliOptions.print) {
const datafileContent = await getDatafileForFeature(
cliOptions.feature,
cliOptions.environment,
if (cliOptions.environment && cliOptions.print) {
const datafileContent = await getCustomDatafile({
featureKey: cliOptions.feature,
environment: cliOptions.environment,
projectConfig,
datasource,
cliOptions.revision,
);
revision: cliOptions.revision,
});

if (cliOptions.pretty) {
console.log(JSON.stringify(datafileContent, null, 2));
Expand Down
37 changes: 5 additions & 32 deletions packages/core/src/tester/testFeature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,12 @@ import { createInstance, MAX_BUCKETED_NUMBER } from "@featurevisor/sdk";

import { Datasource } from "../datasource";
import { ProjectConfig } from "../config";
import { buildDatafile } from "../builder";
import { SCHEMA_VERSION } from "../config";
import { getCustomDatafile } from "../builder";

import { checkIfArraysAreEqual } from "./checkIfArraysAreEqual";
import { checkIfObjectsAreEqual } from "./checkIfObjectsAreEqual";
import { getFeatureAssertionsFromMatrix } from "./matrix";

export async function getDatafileForFeature(
featureKey: string,
environment: string,
projectConfig: ProjectConfig,
datasource: Datasource,
revision: string = "testing",
): Promise<DatafileContent> {
const requiredChain = await datasource.getRequiredFeaturesChain(featureKey);
const featuresToInclude = Array.from(requiredChain);

const existingState = await datasource.readState(environment);
const datafileContent = await buildDatafile(
projectConfig,
datasource,
{
schemaVersion: SCHEMA_VERSION,
revision,
environment: environment,
features: featuresToInclude,
},
existingState,
);

return datafileContent;
}

export async function testFeature(
datasource: Datasource,
projectConfig: ProjectConfig,
Expand Down Expand Up @@ -85,12 +58,12 @@ export async function testFeature(
const datafileContent =
typeof datafileContentByEnvironment[assertion.environment] !== "undefined"
? datafileContentByEnvironment[assertion.environment]
: await getDatafileForFeature(
test.feature,
assertion.environment,
: await getCustomDatafile({
featureKey: test.feature,
environment: assertion.environment,
projectConfig,
datasource,
);
});

if (options.showDatafile) {
console.log("");
Expand Down
Loading