Skip to content

Commit 3b6f4cf

Browse files
authored
feat: OpenFeature provider for Java (#4)
1 parent 5e223a3 commit 3b6f4cf

107 files changed

Lines changed: 885 additions & 253 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/checks.yml

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,55 @@ name: Checks
22

33
on:
44
push:
5-
branches: ["**"]
5+
branches:
6+
- main
7+
pull_request:
8+
9+
permissions:
10+
contents: read
11+
12+
concurrency:
13+
group: checks-${{ github.workflow }}-${{ github.ref }}
14+
cancel-in-progress: true
615

716
jobs:
8-
ci:
17+
checks:
918
runs-on: ubuntu-latest
10-
11-
strategy:
12-
matrix:
13-
java-version: [24]
19+
timeout-minutes: 15
1420

1521
steps:
16-
- name: Checkout code
17-
uses: actions/checkout@v4
18-
19-
- name: Set up JDK ${{ matrix.java-version }}
20-
uses: actions/setup-java@v4
21-
with:
22-
java-version: ${{ matrix.java-version }}
23-
distribution: "temurin"
24-
cache: "maven"
22+
- name: Check out repository
23+
uses: actions/checkout@v6
2524

26-
- name: Cache Maven packages
27-
uses: actions/cache@v4
25+
- name: Set up Java
26+
uses: actions/setup-java@v5
2827
with:
29-
path: ~/.m2
30-
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
31-
restore-keys: ${{ runner.os }}-m2
28+
java-version: "24"
29+
distribution: temurin
30+
cache: maven
3231

33-
- name: Build with Maven
34-
run: mvn clean compile package -DskipTests
32+
- name: Build and test Maven reactor
33+
run: mvn --batch-mode clean verify
3534

36-
- name: Test
37-
run: mvn test
35+
- name: Verify published artifact boundaries
36+
run: bash scripts/verify-artifacts.sh
3837

39-
- uses: actions/setup-node@v4
38+
- name: Set up Node.js
39+
uses: actions/setup-node@v7
4040
with:
41-
node-version-file: ".nvmrc"
41+
node-version-file: .nvmrc
4242

43-
- name: Setup Featurevisor example-1 project
43+
- name: Set up Featurevisor example-1 project
4444
run: |
4545
mkdir example-1
46-
(cd example-1 && npx @featurevisor/cli@2.x init --example=1)
47-
(cd example-1 && npm install)
48-
(cd example-1 && npx featurevisor test)
46+
cd example-1
47+
npx --yes @featurevisor/cli@3 init --example=1
48+
npm install
49+
npx featurevisor build
50+
npx featurevisor test --onlyFailures
4951
5052
- name: Run Featurevisor project tests against Java SDK
51-
run: mvn exec:java -Dexec.mainClass="com.featurevisor.cli.CLI" -Dexec.args="test --projectDirectoryPath=example-1"
53+
run: >-
54+
mvn --batch-mode -pl featurevisor-sdk exec:java
55+
-Dexec.mainClass=com.featurevisor.cli.CLI
56+
-Dexec.args="test --projectDirectoryPath=example-1 --onlyFailures"

.github/workflows/publish.yml

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,49 +5,45 @@ on:
55
tags:
66
- "v*"
77

8+
permissions:
9+
contents: read
10+
packages: write
11+
12+
concurrency:
13+
group: publish-${{ github.ref }}
14+
cancel-in-progress: false
15+
816
jobs:
917
publish:
1018
runs-on: ubuntu-latest
11-
12-
permissions:
13-
contents: read
14-
packages: write
19+
timeout-minutes: 15
1520

1621
steps:
17-
- name: Checkout code
18-
uses: actions/checkout@v4
19-
with:
20-
fetch-depth: 0 # Required for flatten-maven-plugin to work with Git tags
22+
- name: Check out repository
23+
uses: actions/checkout@v6
2124

22-
- name: Set up JDK 24 and Maven
23-
uses: actions/setup-java@v4
25+
- name: Set up Java and Maven publishing
26+
uses: actions/setup-java@v5
2427
with:
2528
java-version: "24"
26-
distribution: "temurin"
27-
cache: "maven"
29+
distribution: temurin
30+
cache: maven
31+
server-id: github
32+
server-username: GITHUB_ACTOR
33+
server-password: GITHUB_TOKEN
2834

2935
- name: Extract version from Git tag
3036
id: version
37+
shell: bash
3138
run: |
32-
VERSION=${GITHUB_REF#refs/tags/v}
33-
echo "version=$VERSION" >> $GITHUB_OUTPUT
34-
echo "Extracted version: $VERSION"
39+
version="${GITHUB_REF_NAME#v}"
40+
echo "version=$version" >> "$GITHUB_OUTPUT"
41+
echo "Publishing Featurevisor Java $version"
3542
36-
- name: Update version in pom.xml
37-
run: |
38-
# Cross-platform sed command that works on both Linux and macOS
39-
if [[ "$OSTYPE" == "darwin"* ]]; then
40-
# macOS (BSD sed)
41-
sed -i '' "/<artifactId>featurevisor-java<\/artifactId>/,/<version>/ s/<version>.*<\/version>/<version>${{ steps.version.outputs.version }}<\/version>/" pom.xml
42-
else
43-
# Linux (GNU sed)
44-
sed -i "/<artifactId>featurevisor-java<\/artifactId>/,/<version>/ s/<version>.*<\/version>/<version>${{ steps.version.outputs.version }}<\/version>/" pom.xml
45-
fi
46-
47-
cat pom.xml | grep '<version>'
48-
49-
- name: Build and Publish
43+
- name: Build, test, and publish all artifacts
5044
env:
5145
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52-
run: |
53-
mvn clean deploy -DskipTests
46+
run: >-
47+
mvn --batch-mode
48+
-Drevision=${{ steps.version.outputs.version }}
49+
clean deploy

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2025 Fahad Heylaal (https://fahad19.com)
3+
Copyright (c) 2026 Fahad Heylaal (https://fahad19.com)
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

Makefile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: install build test test-example-1 setup-monorepo update-monorepo setup-golang-sdk update-golang-sdk setup-references update-references
1+
.PHONY: install build test verify-artifacts test-example-1 setup-monorepo update-monorepo setup-golang-sdk update-golang-sdk setup-references update-references
22

33
install:
44
mvn install
@@ -9,9 +9,13 @@ build:
99
test:
1010
mvn test
1111

12+
verify-artifacts:
13+
mvn package
14+
bash scripts/verify-artifacts.sh
15+
1216
test-example-1:
1317
mvn test
14-
mvn exec:java -Dexec.mainClass="com.featurevisor.cli.CLI" -Dexec.args="test --projectDirectoryPath=../featurevisor/examples/example-1 --onlyFailures"
18+
mvn -pl featurevisor-sdk exec:java -Dexec.mainClass="com.featurevisor.cli.CLI" -Dexec.args="test --projectDirectoryPath=../featurevisor/examples/example-1 --onlyFailures"
1519

1620
##
1721
# Monorepo

README.md

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ This SDK supports Featurevisor v3 behavior and v2 datafiles. Generated datafiles
4646
- [Registering modules](#registering-modules)
4747
- [Child instance](#child-instance)
4848
- [Close](#close)
49+
- [OpenFeature](#openfeature)
4950
- [CLI usage](#cli-usage)
5051
- [Test](#test)
5152
- [Benchmark](#benchmark)
@@ -78,7 +79,7 @@ For finding GitHub Package (public package):
7879

7980
### Dependency
8081

81-
Add Featurevisor Java SDK as a dependency with your desired version:
82+
Add the Featurevisor Java SDK as a dependency with your desired version:
8283

8384
```xml
8485
<dependencies>
@@ -834,6 +835,56 @@ Learn more about assessing distribution [here](https://featurevisor.com/docs/cli
834835
$ 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"
835836
```
836837

838+
## OpenFeature
839+
840+
The OpenFeature provider is published as a separate artifact. Applications that use only `com.featurevisor:featurevisor-java` receive no provider classes or OpenFeature dependency.
841+
842+
Add the provider with the same version as the Featurevisor Java SDK:
843+
844+
```xml
845+
<dependency>
846+
<groupId>com.featurevisor</groupId>
847+
<artifactId>featurevisor-openfeature</artifactId>
848+
<version>FEATUREVISOR_VERSION</version>
849+
</dependency>
850+
```
851+
852+
The provider artifact depends on the matching Featurevisor Java SDK and the compatible official OpenFeature SDK, so no additional dependency is required.
853+
854+
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.
855+
856+
```java
857+
import com.featurevisor.openfeature.FeaturevisorOpenFeatureProvider;
858+
import com.featurevisor.sdk.Featurevisor;
859+
import dev.openfeature.sdk.ImmutableContext;
860+
import dev.openfeature.sdk.OpenFeatureAPI;
861+
862+
var provider = new FeaturevisorOpenFeatureProvider(
863+
new Featurevisor.FeaturevisorOptions().datafile(datafileContent)
864+
);
865+
866+
var api = OpenFeatureAPI.getInstance();
867+
api.setProviderAndWait(provider);
868+
869+
var client = api.getClient();
870+
boolean enabled = client.getBooleanValue("checkout", false, new ImmutableContext("user-123"));
871+
```
872+
873+
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.
874+
875+
OpenFeature's targeting key maps to `userId` by default. `targetingKeyField`, `keySeparator`, and `variationKey` on `FeaturevisorOpenFeatureProvider.Options` can customize the mapping.
876+
877+
You can also reuse an existing Featurevisor instance:
878+
879+
```java
880+
Featurevisor featurevisor = Featurevisor.createFeaturevisor(featurevisorOptions);
881+
var provider = new FeaturevisorOpenFeatureProvider(featurevisor);
882+
```
883+
884+
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.
885+
886+
See the [OpenFeature provider guide](https://featurevisor.com/docs/sdks/openfeature/) for resolution reasons, errors, metadata, tracking, lifecycle, and providers for other languages.
887+
837888
<!-- FEATUREVISOR_DOCS_END -->
838889

839890
## Development of this package
@@ -852,11 +903,22 @@ $ mvn install
852903
$ mvn test
853904
```
854905

906+
The repository is a Maven reactor with two published libraries:
907+
908+
- `com.featurevisor:featurevisor-java`
909+
- `com.featurevisor:featurevisor-openfeature`
910+
911+
To verify their published JAR and POM boundaries locally:
912+
913+
```bash
914+
$ make verify-artifacts
915+
```
916+
855917
### Releasing
856918

857919
- Manually create a new release on [GitHub](https://github.com/featurevisor/featurevisor-java/releases)
858920
- Tag it with a prefix of `v`, like `v1.0.0`
859-
- GitHub Actions is set up to automatically publish the package to [GitHub Packages](https://github.com/orgs/featurevisor/packages?repo_name=featurevisor-java)
921+
- GitHub Actions publishes the parent POM, Java SDK, and OpenFeature provider to [GitHub Packages](https://github.com/orgs/featurevisor/packages?repo_name=featurevisor-java)
860922

861923
## License
862924

featurevisor-openfeature/pom.xml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>com.featurevisor</groupId>
9+
<artifactId>featurevisor-parent</artifactId>
10+
<version>${revision}</version>
11+
<relativePath>../pom.xml</relativePath>
12+
</parent>
13+
14+
<artifactId>featurevisor-openfeature</artifactId>
15+
<packaging>jar</packaging>
16+
17+
<name>Featurevisor OpenFeature Provider for Java</name>
18+
<description>OpenFeature provider for the Featurevisor Java SDK</description>
19+
<url>https://github.com/featurevisor/featurevisor-java</url>
20+
21+
<scm>
22+
<connection>scm:git:git://github.com/featurevisor/featurevisor-java.git</connection>
23+
<developerConnection>scm:git:ssh://github.com:featurevisor/featurevisor-java.git</developerConnection>
24+
<url>https://github.com/featurevisor/featurevisor-java</url>
25+
<tag>HEAD</tag>
26+
</scm>
27+
28+
<dependencies>
29+
<dependency>
30+
<groupId>com.featurevisor</groupId>
31+
<artifactId>featurevisor-java</artifactId>
32+
<version>${project.version}</version>
33+
</dependency>
34+
<dependency>
35+
<groupId>dev.openfeature</groupId>
36+
<artifactId>sdk</artifactId>
37+
</dependency>
38+
<dependency>
39+
<groupId>com.fasterxml.jackson.core</groupId>
40+
<artifactId>jackson-databind</artifactId>
41+
</dependency>
42+
<dependency>
43+
<groupId>org.junit.jupiter</groupId>
44+
<artifactId>junit-jupiter</artifactId>
45+
<scope>test</scope>
46+
</dependency>
47+
</dependencies>
48+
49+
<build>
50+
<plugins>
51+
<plugin>
52+
<groupId>org.apache.maven.plugins</groupId>
53+
<artifactId>maven-compiler-plugin</artifactId>
54+
</plugin>
55+
<plugin>
56+
<groupId>org.apache.maven.plugins</groupId>
57+
<artifactId>maven-surefire-plugin</artifactId>
58+
</plugin>
59+
<plugin>
60+
<groupId>org.apache.maven.plugins</groupId>
61+
<artifactId>maven-source-plugin</artifactId>
62+
</plugin>
63+
<plugin>
64+
<groupId>org.apache.maven.plugins</groupId>
65+
<artifactId>maven-javadoc-plugin</artifactId>
66+
</plugin>
67+
<plugin>
68+
<groupId>org.codehaus.mojo</groupId>
69+
<artifactId>flatten-maven-plugin</artifactId>
70+
</plugin>
71+
</plugins>
72+
</build>
73+
</project>

0 commit comments

Comments
 (0)