diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 4868ee4..6ea0b2a 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -2,50 +2,55 @@ name: Checks on: push: - branches: ["**"] + branches: + - main + pull_request: + +permissions: + contents: read + +concurrency: + group: checks-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - ci: + checks: runs-on: ubuntu-latest - - strategy: - matrix: - java-version: [24] + timeout-minutes: 15 steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up JDK ${{ matrix.java-version }} - uses: actions/setup-java@v4 - with: - java-version: ${{ matrix.java-version }} - distribution: "temurin" - cache: "maven" + - name: Check out repository + uses: actions/checkout@v6 - - name: Cache Maven packages - uses: actions/cache@v4 + - name: Set up Java + uses: actions/setup-java@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + java-version: "24" + distribution: temurin + cache: maven - - name: Build with Maven - run: mvn clean compile package -DskipTests + - name: Build and test Maven reactor + run: mvn --batch-mode clean verify - - name: Test - run: mvn test + - name: Verify published artifact boundaries + run: bash scripts/verify-artifacts.sh - - uses: actions/setup-node@v4 + - name: Set up Node.js + uses: actions/setup-node@v7 with: - node-version-file: ".nvmrc" + node-version-file: .nvmrc - - name: Setup Featurevisor example-1 project + - name: Set up Featurevisor example-1 project run: | mkdir example-1 - (cd example-1 && npx @featurevisor/cli@2.x init --example=1) - (cd example-1 && npm install) - (cd example-1 && npx featurevisor test) + cd example-1 + npx --yes @featurevisor/cli@3 init --example=1 + npm install + npx featurevisor build + npx featurevisor test --onlyFailures - name: Run Featurevisor project tests against Java SDK - run: mvn exec:java -Dexec.mainClass="com.featurevisor.cli.CLI" -Dexec.args="test --projectDirectoryPath=example-1" + run: >- + mvn --batch-mode -pl featurevisor-sdk exec:java + -Dexec.mainClass=com.featurevisor.cli.CLI + -Dexec.args="test --projectDirectoryPath=example-1 --onlyFailures" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index dbfc351..f93e356 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -5,49 +5,45 @@ on: tags: - "v*" +permissions: + contents: read + packages: write + +concurrency: + group: publish-${{ github.ref }} + cancel-in-progress: false + jobs: publish: runs-on: ubuntu-latest - - permissions: - contents: read - packages: write + timeout-minutes: 15 steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Required for flatten-maven-plugin to work with Git tags + - name: Check out repository + uses: actions/checkout@v6 - - name: Set up JDK 24 and Maven - uses: actions/setup-java@v4 + - name: Set up Java and Maven publishing + uses: actions/setup-java@v5 with: java-version: "24" - distribution: "temurin" - cache: "maven" + distribution: temurin + cache: maven + server-id: github + server-username: GITHUB_ACTOR + server-password: GITHUB_TOKEN - name: Extract version from Git tag id: version + shell: bash run: | - VERSION=${GITHUB_REF#refs/tags/v} - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "Extracted version: $VERSION" + version="${GITHUB_REF_NAME#v}" + echo "version=$version" >> "$GITHUB_OUTPUT" + echo "Publishing Featurevisor Java $version" - - name: Update version in pom.xml - run: | - # Cross-platform sed command that works on both Linux and macOS - if [[ "$OSTYPE" == "darwin"* ]]; then - # macOS (BSD sed) - sed -i '' "/featurevisor-java<\/artifactId>/,// s/.*<\/version>/${{ steps.version.outputs.version }}<\/version>/" pom.xml - else - # Linux (GNU sed) - sed -i "/featurevisor-java<\/artifactId>/,// s/.*<\/version>/${{ steps.version.outputs.version }}<\/version>/" pom.xml - fi - - cat pom.xml | grep '' - - - name: Build and Publish + - name: Build, test, and publish all artifacts env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - mvn clean deploy -DskipTests + run: >- + mvn --batch-mode + -Drevision=${{ steps.version.outputs.version }} + clean deploy diff --git a/LICENSE b/LICENSE index d9fbfa5..434d943 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2025 Fahad Heylaal (https://fahad19.com) +Copyright (c) 2026 Fahad Heylaal (https://fahad19.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index bbe8978..fc009de 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: install build test test-example-1 setup-monorepo update-monorepo setup-golang-sdk update-golang-sdk setup-references update-references +.PHONY: install build test verify-artifacts test-example-1 setup-monorepo update-monorepo setup-golang-sdk update-golang-sdk setup-references update-references install: mvn install @@ -9,9 +9,13 @@ build: test: mvn test +verify-artifacts: + mvn package + bash scripts/verify-artifacts.sh + test-example-1: mvn test - mvn exec:java -Dexec.mainClass="com.featurevisor.cli.CLI" -Dexec.args="test --projectDirectoryPath=../featurevisor/examples/example-1 --onlyFailures" + mvn -pl featurevisor-sdk exec:java -Dexec.mainClass="com.featurevisor.cli.CLI" -Dexec.args="test --projectDirectoryPath=../featurevisor/examples/example-1 --onlyFailures" ## # Monorepo diff --git a/README.md b/README.md index d0d9342..79fb3b4 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ This SDK supports Featurevisor v3 behavior and v2 datafiles. Generated datafiles - [Registering modules](#registering-modules) - [Child instance](#child-instance) - [Close](#close) +- [OpenFeature](#openfeature) - [CLI usage](#cli-usage) - [Test](#test) - [Benchmark](#benchmark) @@ -78,7 +79,7 @@ For finding GitHub Package (public package): ### Dependency -Add Featurevisor Java SDK as a dependency with your desired version: +Add the Featurevisor Java SDK as a dependency with your desired version: ```xml @@ -834,6 +835,56 @@ Learn more about assessing distribution [here](https://featurevisor.com/docs/cli $ mvn exec:java -Dexec.mainClass="com.featurevisor.cli.CLI" -Dexec.args="assess-distribution --projectDirectoryPath=/absolute/path/to/your/featurevisor/project --environment=production --feature=foo --variation --context='{\"country\": \"nl\"}' --populateUuid=userId --populateUuid=deviceId --n=1000" ``` +## OpenFeature + +The OpenFeature provider is published as a separate artifact. Applications that use only `com.featurevisor:featurevisor-java` receive no provider classes or OpenFeature dependency. + +Add the provider with the same version as the Featurevisor Java SDK: + +```xml + + com.featurevisor + featurevisor-openfeature + FEATUREVISOR_VERSION + +``` + +The provider artifact depends on the matching Featurevisor Java SDK and the compatible official OpenFeature SDK, so no additional dependency is required. + +When upgrading from an earlier release, replace the direct `dev.openfeature:sdk` dependency with `com.featurevisor:featurevisor-openfeature`. The provider's Java package and public API are unchanged. + +```java +import com.featurevisor.openfeature.FeaturevisorOpenFeatureProvider; +import com.featurevisor.sdk.Featurevisor; +import dev.openfeature.sdk.ImmutableContext; +import dev.openfeature.sdk.OpenFeatureAPI; + +var provider = new FeaturevisorOpenFeatureProvider( + new Featurevisor.FeaturevisorOptions().datafile(datafileContent) +); + +var api = OpenFeatureAPI.getInstance(); +api.setProviderAndWait(provider); + +var client = api.getClient(); +boolean enabled = client.getBooleanValue("checkout", false, new ImmutableContext("user-123")); +``` + +Use `checkout` for a flag, `checkout:variation` for its variation, and `checkout:title` for its `title` variable. Boolean variables use the boolean resolver. Lists, structures, and JSON variables use the object resolver. + +OpenFeature's targeting key maps to `userId` by default. `targetingKeyField`, `keySeparator`, and `variationKey` on `FeaturevisorOpenFeatureProvider.Options` can customize the mapping. + +You can also reuse an existing Featurevisor instance: + +```java +Featurevisor featurevisor = Featurevisor.createFeaturevisor(featurevisorOptions); +var provider = new FeaturevisorOpenFeatureProvider(featurevisor); +``` + +The caller owns an instance passed this way. Provider shutdown does not close it. Call `featurevisor.close()` when every consumer is finished with it. When the provider creates the instance from options, the provider owns and closes it. If both are configured, the existing instance takes precedence. + +See the [OpenFeature provider guide](https://featurevisor.com/docs/sdks/openfeature/) for resolution reasons, errors, metadata, tracking, lifecycle, and providers for other languages. + ## Development of this package @@ -852,11 +903,22 @@ $ mvn install $ mvn test ``` +The repository is a Maven reactor with two published libraries: + +- `com.featurevisor:featurevisor-java` +- `com.featurevisor:featurevisor-openfeature` + +To verify their published JAR and POM boundaries locally: + +```bash +$ make verify-artifacts +``` + ### Releasing - Manually create a new release on [GitHub](https://github.com/featurevisor/featurevisor-java/releases) - Tag it with a prefix of `v`, like `v1.0.0` -- GitHub Actions is set up to automatically publish the package to [GitHub Packages](https://github.com/orgs/featurevisor/packages?repo_name=featurevisor-java) +- GitHub Actions publishes the parent POM, Java SDK, and OpenFeature provider to [GitHub Packages](https://github.com/orgs/featurevisor/packages?repo_name=featurevisor-java) ## License diff --git a/featurevisor-openfeature/pom.xml b/featurevisor-openfeature/pom.xml new file mode 100644 index 0000000..8f2603c --- /dev/null +++ b/featurevisor-openfeature/pom.xml @@ -0,0 +1,73 @@ + + + 4.0.0 + + + com.featurevisor + featurevisor-parent + ${revision} + ../pom.xml + + + featurevisor-openfeature + jar + + Featurevisor OpenFeature Provider for Java + OpenFeature provider for the Featurevisor Java SDK + https://github.com/featurevisor/featurevisor-java + + + scm:git:git://github.com/featurevisor/featurevisor-java.git + scm:git:ssh://github.com:featurevisor/featurevisor-java.git + https://github.com/featurevisor/featurevisor-java + HEAD + + + + + com.featurevisor + featurevisor-java + ${project.version} + + + dev.openfeature + sdk + + + com.fasterxml.jackson.core + jackson-databind + + + org.junit.jupiter + junit-jupiter + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + org.codehaus.mojo + flatten-maven-plugin + + + + diff --git a/featurevisor-openfeature/src/main/java/com/featurevisor/openfeature/FeaturevisorOpenFeatureProvider.java b/featurevisor-openfeature/src/main/java/com/featurevisor/openfeature/FeaturevisorOpenFeatureProvider.java new file mode 100644 index 0000000..c282e37 --- /dev/null +++ b/featurevisor-openfeature/src/main/java/com/featurevisor/openfeature/FeaturevisorOpenFeatureProvider.java @@ -0,0 +1,255 @@ +package com.featurevisor.openfeature; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.featurevisor.sdk.Evaluation; +import com.featurevisor.sdk.Emitter; +import com.featurevisor.sdk.Featurevisor; +import com.featurevisor.sdk.FeaturevisorDiagnosticHandler; +import com.featurevisor.sdk.VariableType; +import dev.openfeature.sdk.ErrorCode; +import dev.openfeature.sdk.EvaluationContext; +import dev.openfeature.sdk.FeatureProvider; +import dev.openfeature.sdk.ImmutableMetadata; +import dev.openfeature.sdk.Metadata; +import dev.openfeature.sdk.ProviderEvaluation; +import dev.openfeature.sdk.Reason; +import dev.openfeature.sdk.Structure; +import dev.openfeature.sdk.TrackingEventDetails; +import dev.openfeature.sdk.Value; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** OpenFeature provider backed by the Featurevisor v3 SDK. */ +public final class FeaturevisorOpenFeatureProvider implements FeatureProvider { + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + @FunctionalInterface + public interface TrackingHandler { + void track(String eventName, EvaluationContext context, TrackingEventDetails details); + } + + public static final class Options { + private Featurevisor featurevisor; + private Featurevisor.FeaturevisorOptions featurevisorOptions = new Featurevisor.FeaturevisorOptions(); + private String targetingKeyField = "userId"; + private String keySeparator = ":"; + private String variationKey = "variation"; + private TrackingHandler onTrack; + + public Options featurevisor(Featurevisor value) { this.featurevisor = value; return this; } + public Options featurevisorOptions(Featurevisor.FeaturevisorOptions value) { this.featurevisorOptions = value; return this; } + public Options targetingKeyField(String value) { this.targetingKeyField = value; return this; } + public Options keySeparator(String value) { this.keySeparator = value; return this; } + public Options variationKey(String value) { this.variationKey = value; return this; } + public Options onTrack(TrackingHandler value) { this.onTrack = value; return this; } + } + + private final Featurevisor featurevisor; + private final String targetingKeyField; + private final String keySeparator; + private final String variationKey; + private final TrackingHandler onTrack; + private final Emitter.UnsubscribeFunction datafileUnsubscribe; + private final boolean ownsFeaturevisor; + private String datafileError; + + public FeaturevisorOpenFeatureProvider(Options options) { + Options resolved = options != null ? options : new Options(); + this.targetingKeyField = nonEmpty(resolved.targetingKeyField, "userId"); + this.keySeparator = nonEmpty(resolved.keySeparator, ":"); + this.variationKey = nonEmpty(resolved.variationKey, "variation"); + this.onTrack = resolved.onTrack; + this.ownsFeaturevisor = resolved.featurevisor == null; + if (resolved.featurevisor != null) { + this.featurevisor = resolved.featurevisor; + } else { + Featurevisor.FeaturevisorOptions fvOptions = resolved.featurevisorOptions != null + ? resolved.featurevisorOptions : new Featurevisor.FeaturevisorOptions(); + if (fvOptions.getDatafileString() != null) { + try { + com.featurevisor.sdk.DatafileContent.fromJson(fvOptions.getDatafileString()); + } catch (Exception ignored) { + datafileError = "Could not parse datafile"; + } + } + FeaturevisorDiagnosticHandler original = fvOptions.getOnDiagnostic(); + fvOptions.onDiagnostic(diagnostic -> { + if ("invalid_datafile".equals(diagnostic.getCode())) datafileError = diagnostic.getMessage(); + if ("datafile_set".equals(diagnostic.getCode())) datafileError = null; + if (original != null) original.handle(diagnostic); + }); + this.featurevisor = Featurevisor.createFeaturevisor(fvOptions); + } + this.datafileUnsubscribe = this.featurevisor.on(Emitter.EventName.DATAFILE_SET, details -> datafileError = null); + } + + public FeaturevisorOpenFeatureProvider(Featurevisor.FeaturevisorOptions options) { + this(new Options().featurevisorOptions(options)); + } + + public FeaturevisorOpenFeatureProvider(Featurevisor featurevisor) { + this(new Options().featurevisor(featurevisor)); + } + + public Featurevisor getFeaturevisor() { return featurevisor; } + @Override public Metadata getMetadata() { return () -> "Featurevisor"; } + @Override public void shutdown() { + datafileUnsubscribe.unsubscribe(); + if (ownsFeaturevisor) featurevisor.close(); + } + @Override public void track(String name, EvaluationContext context, TrackingEventDetails details) { + if (onTrack != null) onTrack.track(name, context, details); + } + + @Override public ProviderEvaluation getBooleanEvaluation(String key, Boolean defaultValue, EvaluationContext context) { + return cast(resolve(key, defaultValue, context, "boolean"), defaultValue, Boolean.class); + } + @Override public ProviderEvaluation getStringEvaluation(String key, String defaultValue, EvaluationContext context) { + return cast(resolve(key, defaultValue, context, "string"), defaultValue, String.class); + } + @Override public ProviderEvaluation getIntegerEvaluation(String key, Integer defaultValue, EvaluationContext context) { + ProviderEvaluation result = resolve(key, defaultValue, context, "integer"); + Integer value = result.getValue() instanceof Number ? ((Number) result.getValue()).intValue() : defaultValue; + return copy(result, value); + } + @Override public ProviderEvaluation getDoubleEvaluation(String key, Double defaultValue, EvaluationContext context) { + ProviderEvaluation result = resolve(key, defaultValue, context, "number"); + Double value = result.getValue() instanceof Number ? ((Number) result.getValue()).doubleValue() : defaultValue; + return copy(result, value); + } + @Override public ProviderEvaluation getObjectEvaluation(String key, Value defaultValue, EvaluationContext context) { + ProviderEvaluation result = resolve(key, defaultValue, context, "object"); + try { + return copy(result, toValue(result.getValue())); + } catch (Exception exception) { + return error(defaultValue, ErrorCode.TYPE_MISMATCH, "Flag \"" + key + "\" did not resolve to an object value", result.getFlagMetadata()); + } + } + + private ProviderEvaluation resolve(String flagKey, Object defaultValue, EvaluationContext context, String expectedType) { + if (datafileError != null) return error(defaultValue, ErrorCode.PARSE_ERROR, datafileError, ImmutableMetadata.EMPTY); + int separatorIndex = flagKey.indexOf(keySeparator); + String featureKey = separatorIndex < 0 ? flagKey : flagKey.substring(0, separatorIndex); + String selector = separatorIndex < 0 ? null : flagKey.substring(separatorIndex + keySeparator.length()); + Map fvContext = context != null ? normalizeMap(context.asObjectMap()) : new HashMap<>(); + if (context != null && context.getTargetingKey() != null && !context.getTargetingKey().isEmpty()) { + fvContext.put(targetingKeyField, context.getTargetingKey()); + } + + Evaluation evaluation; + Object value; + if (selector == null || selector.isEmpty()) { + if (!"boolean".equals(expectedType)) return typeMismatch(flagKey, defaultValue, expectedType, ImmutableMetadata.EMPTY); + evaluation = featurevisor.evaluateFlag(featureKey, fvContext); + value = evaluation.getEnabled(); + } else if (selector.equals(variationKey)) { + evaluation = featurevisor.evaluateVariation(featureKey, fvContext); + value = evaluation.getVariationValue() != null ? evaluation.getVariationValue() + : evaluation.getVariation() != null ? evaluation.getVariation().getValue() : null; + } else { + evaluation = featurevisor.evaluateVariable(featureKey, selector, fvContext); + value = evaluation.getVariableValue(); + if (evaluation.getVariableSchema() != null + && evaluation.getVariableSchema().getType() == VariableType.JSON + && value instanceof String) { + try { value = OBJECT_MAPPER.readValue((String) value, Object.class); } catch (Exception ignored) { } + } + } + + ImmutableMetadata metadata = metadata(evaluation); + ErrorCode errorCode = errorCode(evaluation.getReason()); + if (errorCode != null) return error(defaultValue, errorCode, errorMessage(evaluation), metadata); + if (value == null) return success(defaultValue, evaluation, metadata); + if (!matches(value, expectedType)) return typeMismatch(flagKey, defaultValue, expectedType, metadata); + return success(value, evaluation, metadata); + } + + private ProviderEvaluation success(Object value, Evaluation evaluation, ImmutableMetadata metadata) { + return ProviderEvaluation.builder().value(value).variant(variant(evaluation)).reason(reason(evaluation.getReason()).name()).flagMetadata(metadata).build(); + } + + private ImmutableMetadata metadata(Evaluation evaluation) { + ImmutableMetadata.ImmutableMetadataBuilder builder = ImmutableMetadata.builder() + .addString("featureKey", evaluation.getFeatureKey()) + .addString("featurevisorReason", evaluation.getReason()) + .addString("schemaVersion", featurevisor.getSchemaVersion()); + if (featurevisor.getRevision() != null) builder.addString("revision", featurevisor.getRevision()); + if (evaluation.getVariableKey() != null) builder.addString("variableKey", evaluation.getVariableKey()); + if (evaluation.getRuleKey() != null) builder.addString("ruleKey", evaluation.getRuleKey()); + if (evaluation.getBucketKey() != null) builder.addString("bucketKey", evaluation.getBucketKey()); + if (evaluation.getBucketValue() != null) builder.addInteger("bucketValue", evaluation.getBucketValue()); + if (evaluation.getForceIndex() != null) builder.addInteger("forceIndex", evaluation.getForceIndex()); + if (evaluation.getVariableOverrideIndex() != null) builder.addInteger("variableOverrideIndex", evaluation.getVariableOverrideIndex()); + return builder.build(); + } + + private static Reason reason(String reason) { + if (List.of(Evaluation.REASON_FEATURE_NOT_FOUND, Evaluation.REASON_VARIABLE_NOT_FOUND, Evaluation.REASON_NO_VARIATIONS, Evaluation.REASON_ERROR).contains(reason)) return Reason.ERROR; + if (List.of(Evaluation.REASON_REQUIRED, Evaluation.REASON_FORCED, Evaluation.REASON_STICKY, Evaluation.REASON_RULE, Evaluation.REASON_VARIABLE_OVERRIDE_RULE, Evaluation.REASON_VARIABLE_OVERRIDE_VARIATION).contains(reason)) return Reason.TARGETING_MATCH; + if (Evaluation.REASON_ALLOCATED.equals(reason)) return Reason.SPLIT; + if (List.of(Evaluation.REASON_DISABLED, Evaluation.REASON_VARIATION_DISABLED, Evaluation.REASON_VARIABLE_DISABLED).contains(reason)) return Reason.DISABLED; + return Reason.DEFAULT; + } + + private static ErrorCode errorCode(String reason) { + if (List.of(Evaluation.REASON_FEATURE_NOT_FOUND, Evaluation.REASON_VARIABLE_NOT_FOUND, Evaluation.REASON_NO_VARIATIONS).contains(reason)) return ErrorCode.FLAG_NOT_FOUND; + if (Evaluation.REASON_ERROR.equals(reason)) return ErrorCode.GENERAL; + return null; + } + + private static String errorMessage(Evaluation evaluation) { + if (evaluation.getError() != null) return evaluation.getError().getMessage(); + if (Evaluation.REASON_FEATURE_NOT_FOUND.equals(evaluation.getReason())) return "Feature \"" + evaluation.getFeatureKey() + "\" was not found"; + if (Evaluation.REASON_VARIABLE_NOT_FOUND.equals(evaluation.getReason())) return "Variable \"" + evaluation.getVariableKey() + "\" was not found for feature \"" + evaluation.getFeatureKey() + "\""; + if (Evaluation.REASON_NO_VARIATIONS.equals(evaluation.getReason())) return "Feature \"" + evaluation.getFeatureKey() + "\" has no variations"; + return "Featurevisor evaluation failed"; + } + + private static String variant(Evaluation evaluation) { + if (evaluation.getVariationValue() != null) return evaluation.getVariationValue(); + return evaluation.getVariation() != null ? evaluation.getVariation().getValue() : null; + } + + private static boolean matches(Object value, String expected) { + if ("boolean".equals(expected)) return value instanceof Boolean; + if ("string".equals(expected)) return value instanceof String; + if ("integer".equals(expected)) return value instanceof Number && Math.rint(((Number) value).doubleValue()) == ((Number) value).doubleValue(); + if ("number".equals(expected)) return value instanceof Number && Double.isFinite(((Number) value).doubleValue()); + return value instanceof Map || value instanceof List; + } + + private static Map normalizeMap(Map input) { + Map result = new HashMap<>(); + input.forEach((key, value) -> result.put(key, normalize(value))); + return result; + } + private static Object normalize(Object value) { + if (value instanceof Instant) return value.toString(); + if (value instanceof Map) return normalizeMap((Map) value); + if (value instanceof List) { List result = new ArrayList<>(); for (Object item : (List) value) result.add(normalize(item)); return result; } + return value; + } + private static Value toValue(Object value) throws InstantiationException { + if (value instanceof Value) return (Value) value; + if (value instanceof Map) return new Value(Structure.mapToStructure((Map) value)); + if (value instanceof List) { List result = new ArrayList<>(); for (Object item : (List) value) result.add(toValue(item)); return new Value(result); } + return new Value(value); + } + private static ProviderEvaluation typeMismatch(String key, Object fallback, String expected, ImmutableMetadata metadata) { + return error(fallback, ErrorCode.TYPE_MISMATCH, "Flag \"" + key + "\" did not resolve to a " + expected + " value", metadata); + } + private static ProviderEvaluation error(T value, ErrorCode code, String message, ImmutableMetadata metadata) { + return ProviderEvaluation.builder().value(value).reason(Reason.ERROR.name()).errorCode(code).errorMessage(message).flagMetadata(metadata).build(); + } + private static ProviderEvaluation cast(ProviderEvaluation source, T fallback, Class type) { + T value = type.isInstance(source.getValue()) ? type.cast(source.getValue()) : fallback; + return copy(source, value); + } + private static ProviderEvaluation copy(ProviderEvaluation source, T value) { + return ProviderEvaluation.builder().value(value).variant(source.getVariant()).reason(source.getReason()).errorCode(source.getErrorCode()).errorMessage(source.getErrorMessage()).flagMetadata(source.getFlagMetadata()).build(); + } + private static String nonEmpty(String value, String fallback) { return value == null || value.isEmpty() ? fallback : value; } +} diff --git a/featurevisor-openfeature/src/test/java/com/featurevisor/openfeature/FeaturevisorOpenFeatureProviderTest.java b/featurevisor-openfeature/src/test/java/com/featurevisor/openfeature/FeaturevisorOpenFeatureProviderTest.java new file mode 100644 index 0000000..21d6708 --- /dev/null +++ b/featurevisor-openfeature/src/test/java/com/featurevisor/openfeature/FeaturevisorOpenFeatureProviderTest.java @@ -0,0 +1,89 @@ +package com.featurevisor.openfeature; + +import com.featurevisor.sdk.DatafileContent; +import com.featurevisor.sdk.Featurevisor; +import com.featurevisor.sdk.FeaturevisorLogLevel; +import com.featurevisor.sdk.FeaturevisorModule; +import dev.openfeature.sdk.ErrorCode; +import dev.openfeature.sdk.ImmutableContext; +import dev.openfeature.sdk.OpenFeatureAPI; +import dev.openfeature.sdk.ProviderEvaluation; +import dev.openfeature.sdk.Value; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class FeaturevisorOpenFeatureProviderTest { + private static final String DATAFILE = """ + {"schemaVersion":"2","revision":"openfeature-test","segments":{},"features":{"checkout":{ + "bucketBy":"userId", + "variations":[{"value":"on","variables":{"title":"Hello","count":3,"ratio":1.5,"visible":true,"items":["a"],"config":{"color":"blue"},"json":"{\\\"nested\\\":true}"}}], + "variablesSchema":{"title":{"type":"string","defaultValue":"Default"},"count":{"type":"integer","defaultValue":0},"ratio":{"type":"double","defaultValue":0},"visible":{"type":"boolean","defaultValue":false},"items":{"type":"array","defaultValue":[]},"config":{"type":"object","defaultValue":{}},"json":{"type":"json","defaultValue":"{}"}}, + "force":[{"conditions":{"attribute":"userId","operator":"equals","value":"forced-user"},"enabled":true,"variation":"on"}], + "traffic":[{"key":"all","segments":"*","percentage":100000,"variation":"on"}] + }}}"""; + + private Featurevisor.FeaturevisorOptions options() throws Exception { + return new Featurevisor.FeaturevisorOptions().datafile(DatafileContent.fromJson(DATAFILE)).logLevel(FeaturevisorLogLevel.FATAL); + } + + @AfterEach void closeOpenFeature() { OpenFeatureAPI.getInstance().shutdown(); } + + @Test void resolvesEveryTypeAndMapsTargetingKey() throws Exception { + FeaturevisorOpenFeatureProvider provider = new FeaturevisorOpenFeatureProvider(options()); + ImmutableContext context = new ImmutableContext("forced-user"); + assertTrue(provider.getBooleanEvaluation("checkout", false, context).getValue()); + assertEquals("on", provider.getStringEvaluation("checkout:variation", "fallback", context).getValue()); + assertEquals("Hello", provider.getStringEvaluation("checkout:title", "fallback", context).getValue()); + assertEquals(3, provider.getIntegerEvaluation("checkout:count", 0, context).getValue()); + assertEquals(1.5, provider.getDoubleEvaluation("checkout:ratio", 0.0, context).getValue()); + assertTrue(provider.getBooleanEvaluation("checkout:visible", false, context).getValue()); + assertEquals("a", provider.getObjectEvaluation("checkout:items", new Value(new ArrayList()), context).getValue().asList().get(0).asString()); + assertEquals("blue", provider.getObjectEvaluation("checkout:config", new Value(), context).getValue().asStructure().getValue("color").asString()); + assertTrue(provider.getObjectEvaluation("checkout:json", new Value(), context).getValue().asStructure().getValue("nested").asBoolean()); + } + + @Test void handlesErrorsCustomGrammarTrackingAndLifecycle() throws Exception { + List tracked = new ArrayList<>(); + FeaturevisorOpenFeatureProvider provider = new FeaturevisorOpenFeatureProvider( + new FeaturevisorOpenFeatureProvider.Options().featurevisorOptions(options()).keySeparator("/").variationKey("$variation").onTrack((name, context, details) -> tracked.add(name))); + assertEquals("on", provider.getStringEvaluation("checkout/$variation", "fallback", ImmutableContext.EMPTY).getValue()); + assertEquals(ErrorCode.TYPE_MISMATCH, provider.getStringEvaluation("missing", "fallback", ImmutableContext.EMPTY).getErrorCode()); + ProviderEvaluation missing = provider.getBooleanEvaluation("missing", true, ImmutableContext.EMPTY); + assertTrue(missing.getValue()); + assertEquals(ErrorCode.FLAG_NOT_FOUND, missing.getErrorCode()); + provider.track("purchase", ImmutableContext.EMPTY, null); + assertEquals(List.of("purchase"), tracked); + provider.shutdown(); + } + + @Test void reportsMalformedDatafileAndWorksThroughOpenFeatureApi() throws Exception { + FeaturevisorOpenFeatureProvider malformed = new FeaturevisorOpenFeatureProvider(new Featurevisor.FeaturevisorOptions().datafileString("{").logLevel(FeaturevisorLogLevel.FATAL)); + assertEquals(ErrorCode.PARSE_ERROR, malformed.getBooleanEvaluation("checkout", false, ImmutableContext.EMPTY).getErrorCode()); + assertEquals("Could not parse datafile", malformed.getBooleanEvaluation("checkout", false, ImmutableContext.EMPTY).getErrorMessage()); + malformed.getFeaturevisor().setDatafile(DATAFILE, true); + assertTrue(malformed.getBooleanEvaluation("checkout", false, new ImmutableContext("forced-user")).getValue()); + + OpenFeatureAPI api = OpenFeatureAPI.getInstance(); + api.setProviderAndWait(new FeaturevisorOpenFeatureProvider(options())); + assertTrue(api.getClient().getBooleanValue("checkout", false, new ImmutableContext("forced-user"))); + } + + @Test void borrowsExistingFeaturevisor() throws Exception { + AtomicBoolean closed = new AtomicBoolean(false); + FeaturevisorModule module = new FeaturevisorModule("owner").close(() -> closed.set(true)); + Featurevisor.FeaturevisorOptions featurevisorOptions = options().modules(List.of(module)); + Featurevisor featurevisor = Featurevisor.createFeaturevisor(featurevisorOptions); + FeaturevisorOpenFeatureProvider provider = new FeaturevisorOpenFeatureProvider(featurevisor); + + assertSame(featurevisor, provider.getFeaturevisor()); + provider.shutdown(); + assertFalse(closed.get()); + + featurevisor.close(); + assertTrue(closed.get()); + } +} diff --git a/featurevisor-sdk/pom.xml b/featurevisor-sdk/pom.xml new file mode 100644 index 0000000..b4d0d6b --- /dev/null +++ b/featurevisor-sdk/pom.xml @@ -0,0 +1,93 @@ + + + 4.0.0 + + + com.featurevisor + featurevisor-parent + ${revision} + ../pom.xml + + + featurevisor-java + jar + + Featurevisor Java SDK + Java SDK for Featurevisor + https://github.com/featurevisor/featurevisor-java + + + scm:git:git://github.com/featurevisor/featurevisor-java.git + scm:git:ssh://github.com:featurevisor/featurevisor-java.git + https://github.com/featurevisor/featurevisor-java + HEAD + + + + + com.fasterxml.jackson.core + jackson-core + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.core + jackson-annotations + + + info.picocli + picocli + + + org.apache.commons + commons-exec + + + org.junit.jupiter + junit-jupiter + test + + + + + + + src/test/resources + + + ${project.basedir}/../conformance + conformance + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + org.codehaus.mojo + flatten-maven-plugin + + + org.codehaus.mojo + exec-maven-plugin + + + + diff --git a/src/main/java/com/featurevisor/cli/CLI.java b/featurevisor-sdk/src/main/java/com/featurevisor/cli/CLI.java similarity index 100% rename from src/main/java/com/featurevisor/cli/CLI.java rename to featurevisor-sdk/src/main/java/com/featurevisor/cli/CLI.java diff --git a/src/main/java/com/featurevisor/sdk/Allocation.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Allocation.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Allocation.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Allocation.java diff --git a/src/main/java/com/featurevisor/sdk/AssertionMatrix.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/AssertionMatrix.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/AssertionMatrix.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/AssertionMatrix.java diff --git a/src/main/java/com/featurevisor/sdk/Attribute.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Attribute.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Attribute.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Attribute.java diff --git a/src/main/java/com/featurevisor/sdk/AttributeProperty.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/AttributeProperty.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/AttributeProperty.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/AttributeProperty.java diff --git a/src/main/java/com/featurevisor/sdk/AttributeType.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/AttributeType.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/AttributeType.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/AttributeType.java diff --git a/src/main/java/com/featurevisor/sdk/Bucket.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Bucket.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Bucket.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Bucket.java diff --git a/src/main/java/com/featurevisor/sdk/BucketDeserializer.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/BucketDeserializer.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/BucketDeserializer.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/BucketDeserializer.java diff --git a/src/main/java/com/featurevisor/sdk/Bucketer.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Bucketer.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Bucketer.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Bucketer.java diff --git a/src/main/java/com/featurevisor/sdk/ChildInstance.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/ChildInstance.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/ChildInstance.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/ChildInstance.java diff --git a/src/main/java/com/featurevisor/sdk/CompareVersions.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/CompareVersions.java similarity index 98% rename from src/main/java/com/featurevisor/sdk/CompareVersions.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/CompareVersions.java index 9301f44..1987b78 100644 --- a/src/main/java/com/featurevisor/sdk/CompareVersions.java +++ b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/CompareVersions.java @@ -20,7 +20,7 @@ public class CompareVersions { * Compare two semantic version strings * @param v1 First version string * @param v2 Second version string - * @return -1 if v1 < v2, 0 if equal, 1 if v1 > v2 + * @return -1 if v1 is less than v2, 0 if equal, 1 if v1 is greater than v2 */ public static int compareVersions(String v1, String v2) { // validate input and split into segments diff --git a/src/main/java/com/featurevisor/sdk/Condition.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Condition.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Condition.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Condition.java diff --git a/src/main/java/com/featurevisor/sdk/Conditions.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Conditions.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Conditions.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Conditions.java diff --git a/src/main/java/com/featurevisor/sdk/ContextUtils.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/ContextUtils.java similarity index 94% rename from src/main/java/com/featurevisor/sdk/ContextUtils.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/ContextUtils.java index 683a66f..7340847 100644 --- a/src/main/java/com/featurevisor/sdk/ContextUtils.java +++ b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/ContextUtils.java @@ -9,7 +9,7 @@ public class ContextUtils { /** * Get a value from a context object using a dot-separated path - * @param context The context object (Map) + * @param context The context object * @param path The dot-separated path to the value * @return The value at the path, or null if not found */ diff --git a/src/main/java/com/featurevisor/sdk/DatafileContent.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/DatafileContent.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/DatafileContent.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/DatafileContent.java diff --git a/src/main/java/com/featurevisor/sdk/DatafileReader.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/DatafileReader.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/DatafileReader.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/DatafileReader.java diff --git a/src/main/java/com/featurevisor/sdk/Emitter.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Emitter.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Emitter.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Emitter.java diff --git a/src/main/java/com/featurevisor/sdk/Evaluate.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Evaluate.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Evaluate.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Evaluate.java diff --git a/src/main/java/com/featurevisor/sdk/EvaluateByBucketing.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluateByBucketing.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/EvaluateByBucketing.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluateByBucketing.java diff --git a/src/main/java/com/featurevisor/sdk/EvaluateDisabled.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluateDisabled.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/EvaluateDisabled.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluateDisabled.java diff --git a/src/main/java/com/featurevisor/sdk/EvaluateForced.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluateForced.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/EvaluateForced.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluateForced.java diff --git a/src/main/java/com/featurevisor/sdk/EvaluateNotFound.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluateNotFound.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/EvaluateNotFound.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluateNotFound.java diff --git a/src/main/java/com/featurevisor/sdk/EvaluateOptions.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluateOptions.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/EvaluateOptions.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluateOptions.java diff --git a/src/main/java/com/featurevisor/sdk/EvaluateSticky.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluateSticky.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/EvaluateSticky.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluateSticky.java diff --git a/src/main/java/com/featurevisor/sdk/EvaluatedFeature.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluatedFeature.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/EvaluatedFeature.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluatedFeature.java diff --git a/src/main/java/com/featurevisor/sdk/EvaluatedFeatures.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluatedFeatures.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/EvaluatedFeatures.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/EvaluatedFeatures.java diff --git a/src/main/java/com/featurevisor/sdk/Evaluation.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Evaluation.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Evaluation.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Evaluation.java diff --git a/src/main/java/com/featurevisor/sdk/Events.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Events.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Events.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Events.java diff --git a/src/main/java/com/featurevisor/sdk/ExpectedEvaluations.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/ExpectedEvaluations.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/ExpectedEvaluations.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/ExpectedEvaluations.java diff --git a/src/main/java/com/featurevisor/sdk/Feature.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Feature.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Feature.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Feature.java diff --git a/src/main/java/com/featurevisor/sdk/FeatureAssertion.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeatureAssertion.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/FeatureAssertion.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeatureAssertion.java diff --git a/src/main/java/com/featurevisor/sdk/FeatureChildAssertion.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeatureChildAssertion.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/FeatureChildAssertion.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeatureChildAssertion.java diff --git a/src/main/java/com/featurevisor/sdk/FeaturesDeserializer.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturesDeserializer.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/FeaturesDeserializer.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturesDeserializer.java diff --git a/src/main/java/com/featurevisor/sdk/Featurevisor.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Featurevisor.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Featurevisor.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Featurevisor.java diff --git a/src/main/java/com/featurevisor/sdk/FeaturevisorDiagnostic.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorDiagnostic.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/FeaturevisorDiagnostic.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorDiagnostic.java diff --git a/src/main/java/com/featurevisor/sdk/FeaturevisorDiagnosticHandler.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorDiagnosticHandler.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/FeaturevisorDiagnosticHandler.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorDiagnosticHandler.java diff --git a/src/main/java/com/featurevisor/sdk/FeaturevisorDiagnosticReporter.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorDiagnosticReporter.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/FeaturevisorDiagnosticReporter.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorDiagnosticReporter.java diff --git a/src/main/java/com/featurevisor/sdk/FeaturevisorLogLevel.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorLogLevel.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/FeaturevisorLogLevel.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorLogLevel.java diff --git a/src/main/java/com/featurevisor/sdk/FeaturevisorModule.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorModule.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/FeaturevisorModule.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorModule.java diff --git a/src/main/java/com/featurevisor/sdk/FeaturevisorModuleApi.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorModuleApi.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/FeaturevisorModuleApi.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorModuleApi.java diff --git a/src/main/java/com/featurevisor/sdk/FeaturevisorModuleApiFactory.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorModuleApiFactory.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/FeaturevisorModuleApiFactory.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorModuleApiFactory.java diff --git a/src/main/java/com/featurevisor/sdk/FeaturevisorModuleDiagnosticOptions.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorModuleDiagnosticOptions.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/FeaturevisorModuleDiagnosticOptions.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/FeaturevisorModuleDiagnosticOptions.java diff --git a/src/main/java/com/featurevisor/sdk/Force.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Force.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Force.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Force.java diff --git a/src/main/java/com/featurevisor/sdk/GroupSegment.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/GroupSegment.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/GroupSegment.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/GroupSegment.java diff --git a/src/main/java/com/featurevisor/sdk/GroupSegmentType.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/GroupSegmentType.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/GroupSegmentType.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/GroupSegmentType.java diff --git a/src/main/java/com/featurevisor/sdk/Helpers.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Helpers.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Helpers.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Helpers.java diff --git a/src/main/java/com/featurevisor/sdk/Logger.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Logger.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Logger.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Logger.java diff --git a/src/main/java/com/featurevisor/sdk/ModulesManager.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/ModulesManager.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/ModulesManager.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/ModulesManager.java diff --git a/src/main/java/com/featurevisor/sdk/MurmurHash.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/MurmurHash.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/MurmurHash.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/MurmurHash.java diff --git a/src/main/java/com/featurevisor/sdk/Operator.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Operator.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Operator.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Operator.java diff --git a/src/main/java/com/featurevisor/sdk/ProjectConfig.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/ProjectConfig.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/ProjectConfig.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/ProjectConfig.java diff --git a/src/main/java/com/featurevisor/sdk/PropertyType.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/PropertyType.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/PropertyType.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/PropertyType.java diff --git a/src/main/java/com/featurevisor/sdk/Range.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Range.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Range.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Range.java diff --git a/src/main/java/com/featurevisor/sdk/RangeDeserializer.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/RangeDeserializer.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/RangeDeserializer.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/RangeDeserializer.java diff --git a/src/main/java/com/featurevisor/sdk/RequiredWithVariation.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/RequiredWithVariation.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/RequiredWithVariation.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/RequiredWithVariation.java diff --git a/src/main/java/com/featurevisor/sdk/Rule.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Rule.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Rule.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Rule.java diff --git a/src/main/java/com/featurevisor/sdk/Segment.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Segment.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Segment.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Segment.java diff --git a/src/main/java/com/featurevisor/sdk/SegmentAssertion.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/SegmentAssertion.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/SegmentAssertion.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/SegmentAssertion.java diff --git a/src/main/java/com/featurevisor/sdk/StickyFeatures.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/StickyFeatures.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/StickyFeatures.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/StickyFeatures.java diff --git a/src/main/java/com/featurevisor/sdk/Test.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Test.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Test.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Test.java diff --git a/src/main/java/com/featurevisor/sdk/TestFeature.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/TestFeature.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/TestFeature.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/TestFeature.java diff --git a/src/main/java/com/featurevisor/sdk/TestResult.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/TestResult.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/TestResult.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/TestResult.java diff --git a/src/main/java/com/featurevisor/sdk/TestResultAssertion.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/TestResultAssertion.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/TestResultAssertion.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/TestResultAssertion.java diff --git a/src/main/java/com/featurevisor/sdk/TestResultAssertionError.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/TestResultAssertionError.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/TestResultAssertionError.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/TestResultAssertionError.java diff --git a/src/main/java/com/featurevisor/sdk/TestSegment.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/TestSegment.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/TestSegment.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/TestSegment.java diff --git a/src/main/java/com/featurevisor/sdk/Traffic.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Traffic.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Traffic.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Traffic.java diff --git a/src/main/java/com/featurevisor/sdk/TypeAliases.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/TypeAliases.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/TypeAliases.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/TypeAliases.java diff --git a/src/main/java/com/featurevisor/sdk/VariableKey.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/VariableKey.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/VariableKey.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/VariableKey.java diff --git a/src/main/java/com/featurevisor/sdk/VariableOverride.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/VariableOverride.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/VariableOverride.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/VariableOverride.java diff --git a/src/main/java/com/featurevisor/sdk/VariableSchema.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/VariableSchema.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/VariableSchema.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/VariableSchema.java diff --git a/src/main/java/com/featurevisor/sdk/VariableType.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/VariableType.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/VariableType.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/VariableType.java diff --git a/src/main/java/com/featurevisor/sdk/VariableValue.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/VariableValue.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/VariableValue.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/VariableValue.java diff --git a/src/main/java/com/featurevisor/sdk/Variation.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/Variation.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/Variation.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/Variation.java diff --git a/src/main/java/com/featurevisor/sdk/VariationValue.java b/featurevisor-sdk/src/main/java/com/featurevisor/sdk/VariationValue.java similarity index 100% rename from src/main/java/com/featurevisor/sdk/VariationValue.java rename to featurevisor-sdk/src/main/java/com/featurevisor/sdk/VariationValue.java diff --git a/src/test/java/com/featurevisor/cli/CLIOptionsTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/cli/CLIOptionsTest.java similarity index 100% rename from src/test/java/com/featurevisor/cli/CLIOptionsTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/cli/CLIOptionsTest.java diff --git a/src/test/java/com/featurevisor/sdk/BucketerTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/BucketerTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/BucketerTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/BucketerTest.java diff --git a/src/test/java/com/featurevisor/sdk/ChildTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/ChildTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/ChildTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/ChildTest.java diff --git a/src/test/java/com/featurevisor/sdk/ConditionsTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/ConditionsTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/ConditionsTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/ConditionsTest.java diff --git a/src/test/java/com/featurevisor/sdk/DatafileContentTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/DatafileContentTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/DatafileContentTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/DatafileContentTest.java diff --git a/src/test/java/com/featurevisor/sdk/DatafileReaderComprehensiveTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/DatafileReaderComprehensiveTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/DatafileReaderComprehensiveTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/DatafileReaderComprehensiveTest.java diff --git a/src/test/java/com/featurevisor/sdk/DatafileReaderTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/DatafileReaderTest.java similarity index 96% rename from src/test/java/com/featurevisor/sdk/DatafileReaderTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/DatafileReaderTest.java index b9ec59c..de6954b 100644 --- a/src/test/java/com/featurevisor/sdk/DatafileReaderTest.java +++ b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/DatafileReaderTest.java @@ -2,8 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import java.nio.file.Files; -import java.nio.file.Path; +import java.io.InputStream; import com.featurevisor.sdk.Allocation; import com.featurevisor.sdk.Bucket; @@ -30,10 +29,13 @@ public class DatafileReaderTest { @Test public void testSharedV3ConformanceFixture() throws Exception { - JsonNode fixture = new ObjectMapper().readTree(Files.readString(Path.of("conformance/sdk-v3.json"))); - assertEquals(1, fixture.get("version").asInt()); - assertEquals("control", fixture.get("bucketing").get("allocationExpectations").get("50000").asText()); - assertEquals("treatment", fixture.get("bucketing").get("allocationExpectations").get("50001").asText()); + try (InputStream fixtureStream = getClass().getResourceAsStream("/conformance/sdk-v3.json")) { + assertNotNull(fixtureStream); + JsonNode fixture = new ObjectMapper().readTree(fixtureStream); + assertEquals(1, fixture.get("version").asInt()); + assertEquals("control", fixture.get("bucketing").get("allocationExpectations").get("50000").asText()); + assertEquals("treatment", fixture.get("bucketing").get("allocationExpectations").get("50001").asText()); + } } private Logger logger; diff --git a/src/test/java/com/featurevisor/sdk/EmitterTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/EmitterTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/EmitterTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/EmitterTest.java diff --git a/src/test/java/com/featurevisor/sdk/EvaluateDisabledTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/EvaluateDisabledTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/EvaluateDisabledTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/EvaluateDisabledTest.java diff --git a/src/test/java/com/featurevisor/sdk/EvaluateForcedTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/EvaluateForcedTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/EvaluateForcedTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/EvaluateForcedTest.java diff --git a/src/test/java/com/featurevisor/sdk/EvaluateNotFoundTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/EvaluateNotFoundTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/EvaluateNotFoundTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/EvaluateNotFoundTest.java diff --git a/src/test/java/com/featurevisor/sdk/EvaluateStickyTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/EvaluateStickyTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/EvaluateStickyTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/EvaluateStickyTest.java diff --git a/src/test/java/com/featurevisor/sdk/EventsTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/EventsTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/EventsTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/EventsTest.java diff --git a/src/test/java/com/featurevisor/sdk/FeaturevisorTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/FeaturevisorTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/FeaturevisorTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/FeaturevisorTest.java diff --git a/src/test/java/com/featurevisor/sdk/HelpersTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/HelpersTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/HelpersTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/HelpersTest.java diff --git a/src/test/java/com/featurevisor/sdk/IndexTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/IndexTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/IndexTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/IndexTest.java diff --git a/src/test/java/com/featurevisor/sdk/JsonNodeVariableMethodsTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/JsonNodeVariableMethodsTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/JsonNodeVariableMethodsTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/JsonNodeVariableMethodsTest.java diff --git a/src/test/java/com/featurevisor/sdk/LoggerTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/LoggerTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/LoggerTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/LoggerTest.java diff --git a/src/test/java/com/featurevisor/sdk/ModulesManagerTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/ModulesManagerTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/ModulesManagerTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/ModulesManagerTest.java diff --git a/src/test/java/com/featurevisor/sdk/NamespaceGuardTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/NamespaceGuardTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/NamespaceGuardTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/NamespaceGuardTest.java diff --git a/src/test/java/com/featurevisor/sdk/TypedVariableMethodsTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/TypedVariableMethodsTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/TypedVariableMethodsTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/TypedVariableMethodsTest.java diff --git a/src/test/java/com/featurevisor/sdk/VariableOverrideParityTest.java b/featurevisor-sdk/src/test/java/com/featurevisor/sdk/VariableOverrideParityTest.java similarity index 100% rename from src/test/java/com/featurevisor/sdk/VariableOverrideParityTest.java rename to featurevisor-sdk/src/test/java/com/featurevisor/sdk/VariableOverrideParityTest.java diff --git a/pom.xml b/pom.xml index c45a62a..e725fda 100644 --- a/pom.xml +++ b/pom.xml @@ -1,20 +1,43 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.featurevisor - featurevisor-java - 0.0.1 - jar + featurevisor-parent + ${revision} + pom - Featurevisor Java SDK - Java SDK for Featurevisor + Featurevisor Java + Featurevisor Java SDK and OpenFeature provider https://github.com/featurevisor/featurevisor-java - + + featurevisor-sdk + featurevisor-openfeature + + + + 0.0.1 + 11 + 11 + 15 + 15 + UTF-8 + 2.15.2 + 5.9.2 + 4.7.5 + 1.3 + 1.20.2 + 3.11.0 + 3.0.0 + 3.3.0 + 3.5.0 + 1.5.0 + 3.5.1 + + MIT License @@ -23,7 +46,19 @@ - + + + Fahad Heylaal + Featurevisor + https://featurevisor.com + + + + + Featurevisor + https://featurevisor.com + + scm:git:git://github.com/featurevisor/featurevisor-java.git scm:git:ssh://github.com:featurevisor/featurevisor-java.git @@ -31,13 +66,11 @@ HEAD - GitHub https://github.com/featurevisor/featurevisor-java/issues - github @@ -51,180 +84,144 @@ - - 11 - 11 - 15 - 15 - UTF-8 - 2.15.2 - - true - - - - - - com.fasterxml.jackson.core - jackson-core - ${jackson.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - com.fasterxml.jackson.core - jackson-annotations - ${jackson.version} - - - - - org.junit.jupiter - junit-jupiter - 5.9.2 - test - - - - - info.picocli - picocli - 4.7.5 - - - - - org.apache.commons - commons-exec - 1.3 - - + + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + org.junit.jupiter + junit-jupiter + ${junit.version} + + + info.picocli + picocli + ${picocli.version} + + + org.apache.commons + commons-exec + ${commons-exec.version} + + + dev.openfeature + sdk + ${openfeature.version} + + + - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.11.0 - - - default-compile - compile - - compile - - - 11 - 11 - - - - default-testCompile - test-compile - - testCompile - - - 15 - 15 - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 3.0.0 - - -Dfile.encoding=UTF-8 - - + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + + default-compile + + ${maven.compiler.source} + + + + default-testCompile + + ${maven.compiler.testSource} + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + -Dfile.encoding=UTF-8 + + + + org.apache.maven.plugins + maven-source-plugin + ${maven-source-plugin.version} + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + + ${maven.compiler.source} + none + + + + attach-javadocs + + jar + + + + + + org.codehaus.mojo + flatten-maven-plugin + ${flatten-maven-plugin.version} + + true + oss + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + + + org.codehaus.mojo + exec-maven-plugin + ${exec-maven-plugin.version} + + + - - - org.apache.maven.plugins - maven-source-plugin - 3.3.0 - - - attach-sources - - jar-no-fork - - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.5.0 - - 11 - none - - - - attach-javadocs - - jar - - - - - - + org.codehaus.mojo flatten-maven-plugin - 1.5.0 - - true - oss - - - - flatten - process-resources - - flatten - - - - flatten.clean - clean - - clean - - - - - - - - - - Fahad Heylaal - Featurevisor - https://featurevisor.com - - - - - - Featurevisor - https://featurevisor.com - - - diff --git a/scripts/verify-artifacts.sh b/scripts/verify-artifacts.sh new file mode 100644 index 0000000..f6b4098 --- /dev/null +++ b/scripts/verify-artifacts.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +set -euo pipefail + +find_main_jar() { + find "$1/target" -maxdepth 1 -type f -name "$2-*.jar" \ + ! -name "*-sources.jar" \ + ! -name "*-javadoc.jar" \ + -print -quit +} + +sdk_jar="$(find_main_jar featurevisor-sdk featurevisor-java)" +provider_jar="$(find_main_jar featurevisor-openfeature featurevisor-openfeature)" + +if [[ -z "$sdk_jar" || -z "$provider_jar" ]]; then + echo "Expected SDK and provider JARs were not found" >&2 + exit 1 +fi + +if jar tf "$sdk_jar" | grep '^com/featurevisor/openfeature/' >/dev/null; then + echo "The Featurevisor SDK JAR contains OpenFeature provider classes" >&2 + exit 1 +fi + +if ! jar tf "$provider_jar" | grep '^com/featurevisor/openfeature/FeaturevisorOpenFeatureProvider.class$' >/dev/null; then + echo "The OpenFeature provider JAR does not contain its provider class" >&2 + exit 1 +fi + +if grep -q 'dev\.openfeature' featurevisor-sdk/.flattened-pom.xml; then + echo "The Featurevisor SDK published POM contains an OpenFeature dependency" >&2 + exit 1 +fi + +if ! grep -q 'featurevisor-java' featurevisor-openfeature/.flattened-pom.xml; then + echo "The provider published POM does not depend on Featurevisor Java" >&2 + exit 1 +fi + +if ! grep -q 'dev\.openfeature' featurevisor-openfeature/.flattened-pom.xml; then + echo "The provider published POM does not depend on the OpenFeature SDK" >&2 + exit 1 +fi + +for artifact in \ + featurevisor-sdk/target/featurevisor-java-*-sources.jar \ + featurevisor-sdk/target/featurevisor-java-*-javadoc.jar \ + featurevisor-openfeature/target/featurevisor-openfeature-*-sources.jar \ + featurevisor-openfeature/target/featurevisor-openfeature-*-javadoc.jar; do + if ! compgen -G "$artifact" >/dev/null; then + echo "Missing published artifact: $artifact" >&2 + exit 1 + fi +done + +echo "SDK and OpenFeature provider artifacts are isolated and complete."