diff --git a/.github/workflows/sdk-spec.yml b/.github/workflows/sdk-spec.yml new file mode 100644 index 0000000..7ad90ac --- /dev/null +++ b/.github/workflows/sdk-spec.yml @@ -0,0 +1,17 @@ +name: SDK spec + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + sdk-spec: + # Keep the ref in `uses:` and `spec-ref` in sync. + uses: Flagsmith/sdk-spec/.github/workflows/run-spec.yml@v0.3.0 + with: + spec-ref: v0.3.0 + language: java diff --git a/renovate.json b/renovate.json index b7a5f2e..b1830e2 100644 --- a/renovate.json +++ b/renovate.json @@ -4,6 +4,15 @@ "ignorePresets": [":semanticPrefixFixDepsChoreOthers"], "semanticCommitType": "deps", "git-submodules": { "enabled": true }, + "customManagers": [ + { + "customType": "regex", + "managerFilePatterns": ["/^\\.github/workflows/sdk-spec\\.yml$/"], + "matchStrings": ["spec-ref: (?v[\\d.]+)"], + "depNameTemplate": "Flagsmith/sdk-spec", + "datasourceTemplate": "github-tags" + } + ], "packageRules": [ { "matchUpdateTypes": [ @@ -23,6 +32,11 @@ "matchManagers": ["git-submodules"], "versioning": "semver-coerced", "enabled": true + }, + { + "matchPackageNames": ["Flagsmith/sdk-spec"], + "groupName": "SDK spec", + "enabled": true } ] } diff --git a/sdk-spec/Dockerfile b/sdk-spec/Dockerfile new file mode 100644 index 0000000..4b5e7ed --- /dev/null +++ b/sdk-spec/Dockerfile @@ -0,0 +1,24 @@ +# Runs this SDK, built from source, under the Flagsmith SDK behavioural spec. +# docker build -f sdk-spec/Dockerfile --build-context harness=/harness/java . +FROM docker.io/library/maven:3.9-eclipse-temurin-11 AS build + +WORKDIR /sdk +COPY pom.xml lombok.config ./ +COPY src/main ./src/main +RUN mvn --batch-mode --no-transfer-progress \ + -Dmaven.test.skip=true -Dcheckstyle.skip=true -Djacoco.skip=true -Dmaven.source.skip=true \ + package dependency:copy-dependencies -DincludeScope=runtime -DoutputDirectory=target/lib \ + && cp target/flagsmith-java-client-*.jar target/lib/ + +COPY --from=harness Harness.java /harness/Harness.java +COPY sdk-spec/Steps.java ./sdk-spec/Steps.java +RUN javac -cp "target/lib/*" -d target/classes-spec /harness/Harness.java sdk-spec/Steps.java + +FROM docker.io/library/eclipse-temurin:11-jre + +WORKDIR /sdk +COPY --from=build /sdk/target/lib ./lib +COPY --from=build /sdk/target/classes-spec ./classes +COPY sdk-spec/Steps.java ./sdk-spec/Steps.java + +ENTRYPOINT ["java", "-XX:TieredStopAtLevel=1", "-cp", "classes:lib/*", "Harness", "sdk-spec/Steps.java"] diff --git a/sdk-spec/Steps.java b/sdk-spec/Steps.java new file mode 100644 index 0000000..f5d80d4 --- /dev/null +++ b/sdk-spec/Steps.java @@ -0,0 +1,50 @@ +import com.flagsmith.FlagsmithClient; +import com.flagsmith.exceptions.FlagsmithClientError; +import com.flagsmith.models.BaseFlag; +import com.flagsmith.models.Flags; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Steps for the Flagsmith SDK behavioural spec: https://github.com/Flagsmith/sdk-spec + * + *

Each method implements the Gherkin step in the comment above it. + */ +public class Steps { + + /** A flag in the shape the spec expects. */ + public static class SpecFlag { + public final String feature; + public final boolean enabled; + public final Object value; + + SpecFlag(BaseFlag flag) { + feature = flag.getFeatureName(); + enabled = flag.getEnabled(); + value = flag.getValue(); + } + } + + static List asSpecFlags(Flags flags) { + return flags.getAllFlags().stream().map(SpecFlag::new).collect(Collectors.toList()); + } + + // Create the SDK client + static FlagsmithClient createClient(String environmentKey, String apiUrl) { + return FlagsmithClient.newBuilder().setApiKey(environmentKey).withApiUrl(apiUrl).build(); + } + + // When the application gets the environment flags + static List getEnvironmentFlags(FlagsmithClient flagsmith) + throws FlagsmithClientError { + return asSpecFlags(flagsmith.getEnvironmentFlags()); + } + + // When the application gets the flags for identity "{identifier}" with traits: + static List getIdentityFlags( + FlagsmithClient flagsmith, String identifier, Map traits) + throws FlagsmithClientError { + return asSpecFlags(flagsmith.getIdentityFlags(identifier, traits)); + } +}