diff --git a/.github/workflows/csharp.yml b/.github/workflows/csharp.yml
index b55407af..1650a685 100644
--- a/.github/workflows/csharp.yml
+++ b/.github/workflows/csharp.yml
@@ -75,7 +75,7 @@ jobs:
- name: Restore dependencies
run: dotnet restore OptimizelySDK.NetStandard16/OptimizelySDK.NetStandard16.csproj
- name: Build & strongly name assemblies
- run: dotnet build OptimizelySDK.NetStandard16/OptimizelySDK.NetStandard16.csproj /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=D:\a\csharp-sdk\csharp-sdk\keypair.snk -c Release
+ run: dotnet build OptimizelySDK.NetStandard16/OptimizelySDK.NetStandard16.csproj /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=$(pwd)/keypair.snk -c Release
netStandard20:
name: Build Standard 2.0
@@ -98,7 +98,7 @@ jobs:
- name: Restore dependencies
run: dotnet restore OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj
- name: Build & strongly name assemblies
- run: dotnet build OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=D:\a\csharp-sdk\csharp-sdk\keypair.snk -c Release
+ run: dotnet build OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=$(pwd)/keypair.snk -c Release
integration_tests:
name: Run Integration Tests
@@ -106,7 +106,6 @@ jobs:
uses: optimizely/csharp-sdk/.github/workflows/integration_test.yml@master
secrets:
CI_USER_TOKEN: ${{ secrets.CI_USER_TOKEN }}
- TRAVIS_COM_TOKEN: ${{ secrets.TRAVIS_COM_TOKEN }}
fullstack_production_suite:
name: Run Performance Tests
@@ -116,4 +115,3 @@ jobs:
FULLSTACK_TEST_REPO: ProdTesting
secrets:
CI_USER_TOKEN: ${{ secrets.CI_USER_TOKEN }}
- TRAVIS_COM_TOKEN: ${{ secrets.TRAVIS_COM_TOKEN }}
diff --git a/.github/workflows/csharp_release.yml b/.github/workflows/csharp_release.yml
index cd80b0b2..80461161 100644
--- a/.github/workflows/csharp_release.yml
+++ b/.github/workflows/csharp_release.yml
@@ -3,6 +3,7 @@
on:
release:
types: [ published ] # Trigger on published pre-releases and releases
+ workflow_dispatch:
jobs:
variables:
@@ -33,13 +34,13 @@ jobs:
runs-on: windows-2019 # required version for Framework 4.0
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
ref: ${{ needs.variables.outputs.tag }}
- name: Add msbuild to PATH
- uses: microsoft/setup-msbuild@v1
+ uses: microsoft/setup-msbuild@v2
- name: Setup NuGet
- uses: NuGet/setup-nuget@v1
+ uses: nuget/setup-nuget@v2
- name: Restore NuGet packages
run: nuget restore ./OptimizelySDK.NETFramework.sln
- name: Build and strongly name assemblies
@@ -57,11 +58,11 @@ jobs:
runs-on: windows-latest
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
ref: ${{ needs.variables.outputs.tag }}
- name: Setup .NET
- uses: actions/setup-dotnet@v2
+ uses: actions/setup-dotnet@v4
- name: Restore dependencies
run: dotnet restore OptimizelySDK.NetStandard16/OptimizelySDK.NetStandard16.csproj
- name: Build and strongly name assemblies
@@ -79,11 +80,11 @@ jobs:
runs-on: windows-latest
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
ref: ${{ needs.variables.outputs.tag }}
- name: Setup .NET
- uses: actions/setup-dotnet@v2
+ uses: actions/setup-dotnet@v4
- name: Restore dependencies
run: dotnet restore OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj
- name: Build and strongly name Standard 2.0 project
diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml
index cf9a96b3..b56cc881 100644
--- a/.github/workflows/integration_test.yml
+++ b/.github/workflows/integration_test.yml
@@ -9,8 +9,6 @@ on:
secrets:
CI_USER_TOKEN:
required: true
- TRAVIS_COM_TOKEN:
- required: true
jobs:
test:
runs-on: ubuntu-latest
@@ -19,8 +17,8 @@ jobs:
with:
# You should create a personal access token and store it in your repository
token: ${{ secrets.CI_USER_TOKEN }}
- repository: 'optimizely/travisci-tools'
- path: 'home/runner/travisci-tools'
+ repository: 'optimizely/ci-helper-tools'
+ path: 'home/runner/ci-helper-tools'
ref: 'master'
- name: set SDK Branch if PR
env:
@@ -28,14 +26,12 @@ jobs:
if: ${{ github.event_name == 'pull_request' }}
run: |
echo "SDK_BRANCH=$HEAD_REF" >> $GITHUB_ENV
- echo "TRAVIS_BRANCH=$HEAD_REF" >> $GITHUB_ENV
- name: set SDK Branch if not pull request
env:
REF_NAME: ${{ github.ref_name }}
if: ${{ github.event_name != 'pull_request' }}
run: |
echo "SDK_BRANCH=$REF_NAME" >> $GITHUB_ENV
- echo "TRAVIS_BRANCH=$REF_NAME" >> $GITHUB_ENV
- name: Trigger build
env:
SDK: csharp
@@ -51,9 +47,8 @@ jobs:
PULL_REQUEST_SHA: ${{ github.event.pull_request.head.sha }}
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
UPSTREAM_SHA: ${{ github.sha }}
- TOKEN: ${{ secrets.TRAVIS_COM_TOKEN }}
EVENT_MESSAGE: ${{ github.event.message }}
HOME: 'home/runner'
run: |
echo "$GITHUB_CONTEXT"
- home/runner/travisci-tools/trigger-script-with-status-update.sh
+ home/runner/ci-helper-tools/trigger-script-with-status-update.sh
diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml
index b60e311d..54ba8165 100644
--- a/.github/workflows/sonarqube.yml
+++ b/.github/workflows/sonarqube.yml
@@ -9,21 +9,21 @@ jobs:
runs-on: windows-latest
steps:
- name: Set up JDK 11
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v4
with:
java-version: 1.11
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Cache SonarCloud packages
- uses: actions/cache@v1
+ uses: actions/cache@v4
with:
path: ~\sonar\cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache SonarCloud scanner
id: cache-sonar-scanner
- uses: actions/cache@v1
+ uses: actions/cache@v4
with:
path: .\.sonar\scanner
key: ${{ runner.os }}-sonar-scanner
diff --git a/OptimizelySDK.DemoApp/Scripts/README.md b/OptimizelySDK.DemoApp/Scripts/README.md
index ff1e9551..12510e26 100644
--- a/OptimizelySDK.DemoApp/Scripts/README.md
+++ b/OptimizelySDK.DemoApp/Scripts/README.md
@@ -7,7 +7,6 @@
-
@@ -34,7 +33,7 @@ to make it possible to position it near a given reference element.
The engine is completely modular and most of its features are implemented as **modifiers**
(similar to middlewares or plugins).
-The whole code base is written in ES2015 and its features are automatically tested on real browsers thanks to [SauceLabs](https://saucelabs.com/) and [TravisCI](https://travis-ci.org/).
+The whole code base is written in ES2015 and its features are automatically tested on real browsers thanks to [SauceLabs](https://saucelabs.com/).
Popper.js has zero dependencies. No jQuery, no LoDash, nothing.
It's used by big companies like [Twitter in Bootstrap v4](https://getbootstrap.com/), [Microsoft in WebClipper](https://github.com/OneNoteDev/WebClipper) and [Atlassian in AtlasKit](https://aui-cdn.atlassian.com/atlaskit/registry/).
diff --git a/OptimizelySDK.Tests/OptimizelyTest.cs b/OptimizelySDK.Tests/OptimizelyTest.cs
index 5dab3aec..0adb57ec 100644
--- a/OptimizelySDK.Tests/OptimizelyTest.cs
+++ b/OptimizelySDK.Tests/OptimizelyTest.cs
@@ -339,6 +339,12 @@ public void TestDecisionNotificationSentWhenSendFlagDecisionsFalseAndFeature()
{
"decisionEventDispatched", true
},
+ {
+ "experimentId", "7718750065"
+ },
+ {
+ "variationId", "7713030086"
+ }
}))), Times.Once);
EventDispatcherMock.Verify(dispatcher => dispatcher.DispatchEvent(It.IsAny()),
Times.Once);
@@ -405,6 +411,12 @@ public void TestDecisionNotificationSentWhenSendFlagDecisionsTrueAndFeature()
{
"decisionEventDispatched", true
},
+ {
+ "experimentId", "7718750065"
+ },
+ {
+ "variationId", "7713030086"
+ }
}))), Times.Once);
EventDispatcherMock.Verify(dispatcher => dispatcher.DispatchEvent(It.IsAny()),
Times.Once);
@@ -476,6 +488,12 @@ public void TestDecisionNotificationNotSentWhenSendFlagDecisionsFalseAndRollout(
{
"decisionEventDispatched", false
},
+ {
+ "experimentId", experiment.Id
+ },
+ {
+ "variationId", variation.Id
+ }
}))), Times.Once);
EventDispatcherMock.Verify(dispatcher => dispatcher.DispatchEvent(It.IsAny()),
Times.Never);
@@ -547,6 +565,12 @@ public void TestDecisionNotificationSentWhenSendFlagDecisionsTrueAndRollout()
{
"decisionEventDispatched", true
},
+ {
+ "experimentId", experiment.Id
+ },
+ {
+ "variationId", variation.Id
+ }
}))), Times.Once);
EventDispatcherMock.Verify(dispatcher => dispatcher.DispatchEvent(It.IsAny()),
Times.Once);
@@ -2361,8 +2385,7 @@ public void
Assert.AreEqual(expectedValue, variableValue);
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"Got variable value ""{variableValue}"" for variable ""{variableKey
- }"" of feature flag ""{featureKey}""."));
+ $@"Got variable value ""{variableValue}"" for variable ""{variableKey}"" of feature flag ""{featureKey}""."));
}
[Test]
@@ -2406,8 +2429,7 @@ public void
Assert.AreEqual(expectedValue, variableValue);
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"Got variable value ""{variableValue}"" for variable ""{variableKey
- }"" of feature flag ""{featureKey}""."));
+ $@"Got variable value ""{variableValue}"" for variable ""{variableKey}"" of feature flag ""{featureKey}""."));
}
[Test]
@@ -2439,8 +2461,7 @@ public void
Assert.AreEqual(expectedValue, variableValue);
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"Feature ""{featureKey}"" is not enabled for user {TestUserId
- }. Returning the default variable value ""{variableValue}""."));
+ $@"Feature ""{featureKey}"" is not enabled for user {TestUserId}. Returning the default variable value ""{variableValue}""."));
}
[Test]
@@ -2484,8 +2505,7 @@ public void
Assert.AreEqual(expectedValue, variableValue);
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"Feature ""{featureKey}"" is not enabled for user {TestUserId
- }. Returning the default variable value ""{variableValue}""."));
+ $@"Feature ""{featureKey}"" is not enabled for user {TestUserId}. Returning the default variable value ""{variableValue}""."));
}
[Test]
@@ -2515,8 +2535,7 @@ public void
Assert.AreEqual(expectedValue, variableValue);
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"Got variable value ""true"" for variable ""{variableKey}"" of feature flag ""{
- featureKey}""."));
+ $@"Got variable value ""true"" for variable ""{variableKey}"" of feature flag ""{featureKey}""."));
}
[Test]
@@ -2562,8 +2581,7 @@ public void
Assert.AreEqual(expectedStringValue, variableValue.GetValue("string_var"));
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"Got variable value ""{variableValue}"" for variable ""{variableKey
- }"" of feature flag ""{featureKey}""."));
+ $@"Got variable value ""{variableValue}"" for variable ""{variableKey}"" of feature flag ""{featureKey}""."));
}
[Test]
@@ -2609,8 +2627,7 @@ public void
Assert.AreEqual(expectedStringValue, variableValue.GetValue("string_var"));
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"Got variable value ""{variableValue}"" for variable ""{variableKey
- }"" of feature flag ""{featureKey}""."));
+ $@"Got variable value ""{variableValue}"" for variable ""{variableKey}"" of feature flag ""{featureKey}""."));
}
[Test]
@@ -2654,8 +2671,7 @@ public void
Assert.AreEqual(expectedValue, variableValue);
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"Got variable value ""{variableValue}"" for variable ""{variableKey
- }"" of feature flag ""{featureKey}""."));
+ $@"Got variable value ""{variableValue}"" for variable ""{variableKey}"" of feature flag ""{featureKey}""."));
}
[Test]
@@ -2684,8 +2700,7 @@ public void
variableKey, TestUserId, null);
Assert.AreEqual(expectedValue, variableValue);
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"Feature ""{featureKey}"" is not enabled for user {TestUserId
- }. Returning the default variable value ""true""."));
+ $@"Feature ""{featureKey}"" is not enabled for user {TestUserId}. Returning the default variable value ""true""."));
}
[Test]
@@ -2728,8 +2743,7 @@ public void
Assert.AreEqual(expectedValue, variableValue);
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"Feature ""{featureKey}"" is not enabled for user {TestUserId
- }. Returning the default variable value ""{variableValue}""."));
+ $@"Feature ""{featureKey}"" is not enabled for user {TestUserId}. Returning the default variable value ""{variableValue}""."));
}
[Test]
@@ -2758,8 +2772,7 @@ public void
Assert.AreEqual(expectedValue, variableValue);
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"User ""{TestUserId}"" is not in any variation for feature flag ""{featureKey
- }"", returning default value ""{variableValue}""."));
+ $@"User ""{TestUserId}"" is not in any variation for feature flag ""{featureKey}"", returning default value ""{variableValue}""."));
}
#endregion Feature Toggle Tests
@@ -2822,8 +2835,7 @@ public void TestGetFeatureVariableValueForTypeGivenFeatureKeyOrVariableKeyNotFou
LoggerMock.Verify(l =>
l.Log(LogLevel.ERROR, $@"Feature key ""{featureKey}"" is not in datafile."));
LoggerMock.Verify(l => l.Log(LogLevel.ERROR,
- $@"No feature variable was found for key ""{variableKey
- }"" in feature flag ""double_single_variable_feature""."));
+ $@"No feature variable was found for key ""{variableKey}"" in feature flag ""double_single_variable_feature""."));
}
// Should return null and log error message when variable type is invalid.
@@ -2851,17 +2863,13 @@ public void TestGetFeatureVariableValueForTypeGivenInvalidVariableType()
"string_single_variable_feature", "json_var", TestUserId, null, variableTypeInt));
LoggerMock.Verify(l => l.Log(LogLevel.ERROR,
- $@"Variable is of type ""double"", but you requested it as type ""{variableTypeBool
- }""."));
+ $@"Variable is of type ""double"", but you requested it as type ""{variableTypeBool}""."));
LoggerMock.Verify(l => l.Log(LogLevel.ERROR,
- $@"Variable is of type ""boolean"", but you requested it as type ""{
- variableTypeDouble}""."));
+ $@"Variable is of type ""boolean"", but you requested it as type ""{variableTypeDouble}""."));
LoggerMock.Verify(l => l.Log(LogLevel.ERROR,
- $@"Variable is of type ""integer"", but you requested it as type ""{
- variableTypeString}""."));
+ $@"Variable is of type ""integer"", but you requested it as type ""{variableTypeString}""."));
LoggerMock.Verify(l => l.Log(LogLevel.ERROR,
- $@"Variable is of type ""string"", but you requested it as type ""{variableTypeInt
- }""."));
+ $@"Variable is of type ""string"", but you requested it as type ""{variableTypeInt}""."));
}
[Test]
@@ -2913,8 +2921,7 @@ public void TestGetFeatureVariableValueForTypeGivenFeatureFlagIsNotEnabledForUse
Assert.AreEqual(expectedValue, variableValue);
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"Feature ""{featureKey}"" is not enabled for user {TestUserId
- }. Returning the default variable value ""{variableValue}""."));
+ $@"Feature ""{featureKey}"" is not enabled for user {TestUserId}. Returning the default variable value ""{variableValue}""."));
}
// Should return default value and log message when feature is enabled for the user
@@ -2954,9 +2961,7 @@ public void
Assert.AreEqual(expectedValue, variableValue);
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"Variable ""{variableKey
- }"" is not used in variation ""control"", returning default value ""{expectedValue
- }""."));
+ $@"Variable ""{variableKey}"" is not used in variation ""control"", returning default value ""{expectedValue}""."));
}
// Should return variable value from variation and log message when feature is enabled for the user
@@ -2994,8 +2999,7 @@ public void
Assert.AreEqual(expectedValue, variableValue);
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"Got variable value ""{variableValue}"" for variable ""{variableKey
- }"" of feature flag ""{featureKey}""."));
+ $@"Got variable value ""{variableValue}"" for variable ""{variableKey}"" of feature flag ""{featureKey}""."));
}
// Verify that GetFeatureVariableValueForType returns correct variable value for rollout rule.
@@ -3149,8 +3153,7 @@ public void TestIsFeatureEnabledGivenFeatureFlagIsEnabledAndUserIsNotBeingExperi
// SendImpressionEvent() does not get called.
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"The user ""{TestUserId}"" is not being experimented on feature ""{featureKey
- }""."), Times.Once);
+ $@"The user ""{TestUserId}"" is not being experimented on feature ""{featureKey}""."), Times.Once);
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
$@"Feature flag ""{featureKey}"" is enabled for user ""{TestUserId}""."));
@@ -3183,8 +3186,7 @@ public void TestIsFeatureEnabledGivenFeatureFlagIsEnabledAndUserIsBeingExperimen
// SendImpressionEvent() gets called.
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"The user ""{TestUserId}"" is not being experimented on feature ""{featureKey
- }""."), Times.Never);
+ $@"The user ""{TestUserId}"" is not being experimented on feature ""{featureKey}""."), Times.Never);
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
$@"Feature flag ""{featureKey}"" is enabled for user ""{TestUserId}""."));
@@ -3218,8 +3220,7 @@ public void TestIsFeatureEnabledGivenFeatureFlagIsNotEnabledAndUserIsBeingExperi
// SendImpressionEvent() gets called.
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
- $@"The user ""{TestUserId}"" is not being experimented on feature ""{featureKey
- }""."), Times.Never);
+ $@"The user ""{TestUserId}"" is not being experimented on feature ""{featureKey}""."), Times.Never);
LoggerMock.Verify(l => l.Log(LogLevel.INFO,
$@"Feature flag ""{featureKey}"" is not enabled for user ""{TestUserId}""."));
diff --git a/OptimizelySDK.Tests/OptimizelyUserContextTest.cs b/OptimizelySDK.Tests/OptimizelyUserContextTest.cs
index 76d0d8b8..21ae10db 100644
--- a/OptimizelySDK.Tests/OptimizelyUserContextTest.cs
+++ b/OptimizelySDK.Tests/OptimizelyUserContextTest.cs
@@ -1081,6 +1081,12 @@ public void TestDecisionNotification()
{
"decisionEventDispatched", true
},
+ {
+ "experimentId", "122235"
+ },
+ {
+ "variationId", "122236"
+ },
};
var userAttributes = new UserAttributes
diff --git a/OptimizelySDK/Optimizely.cs b/OptimizelySDK/Optimizely.cs
index b1766985..99cbdaaf 100644
--- a/OptimizelySDK/Optimizely.cs
+++ b/OptimizelySDK/Optimizely.cs
@@ -1000,7 +1000,8 @@ ProjectConfig projectConfig
)
{
var userId = user.GetUserId();
-
+ string experimentId = null;
+ string variationId = null;
var flagEnabled = false;
if (flagDecision.Variation != null)
{
@@ -1008,8 +1009,12 @@ ProjectConfig projectConfig
{
flagEnabled = true;
}
+ variationId = flagDecision.Variation.Id;
+ }
+ if (flagDecision.Experiment != null)
+ {
+ experimentId = flagDecision.Experiment.Id;
}
-
Logger.Log(LogLevel.INFO,
$"Feature \"{flagKey}\" is enabled for user \"{userId}\"? {flagEnabled}");
@@ -1062,6 +1067,8 @@ ProjectConfig projectConfig
{ "ruleKey", ruleKey },
{ "reasons", reasonsToReport },
{ "decisionEventDispatched", decisionEventDispatched },
+ { "experimentId", experimentId },
+ { "variationId", variationId },
};
NotificationCenter.SendNotifications(NotificationCenter.NotificationType.Decision,
diff --git a/README.md b/README.md
index f6b04d5c..9de4ddc7 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Optimizely C# SDK

-[](https://travis-ci.org/optimizely/csharp-sdk)
+
[](https://www.nuget.org/packages/Optimizely.SDK/)
[](http://www.apache.org/licenses/LICENSE-2.0)