Skip to content

Commit

Permalink
Merge pull request #9299 from poikilotherm/9297-feature-flags
Browse files Browse the repository at this point in the history
9297 feature flags
  • Loading branch information
kcondon authored Mar 20, 2023
2 parents a9a8311 + 612eae6 commit 308d5e3
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 1 deletion.
14 changes: 14 additions & 0 deletions doc/sphinx-guides/source/developers/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,17 @@ always like ``dataverse.<scope/....>.newname...=old.property.name``. Note this d
aliases.

Details can be found in ``edu.harvard.iq.dataverse.settings.source.AliasConfigSource``

Adding a Feature Flag
^^^^^^^^^^^^^^^^^^^^^

Some parts of our codebase might be opt-in only. Experimental or optional feature previews can be switched on using our
usual configuration mechanism, a JVM setting.

Feature flags are implemented in the enumeration ``edu.harvard.iq.dataverse.settings.FeatureFlags``, which allows for
convenient usage of it anywhere in the codebase. When adding a flag, please add it to the enum, think of a default
status, add some Javadocs about the flagged feature and add a ``@since`` tag to make it easier to identify when a flag
has been introduced.

We want to maintain a list of all :ref:`feature flags <feature-flags>` in the :ref:`configuration guide <feature-flags>`,
please add yours to the list.
26 changes: 26 additions & 0 deletions doc/sphinx-guides/source/installation/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2153,6 +2153,32 @@ See also these related database settings:
- :ref:`:Authority`
- :ref:`:Shoulder`

.. _feature-flags:

Feature Flags
-------------

Certain features might be deactivated because they are experimental and/or opt-in previews. If you want to enable these,
please find all known feature flags below. Any of these flags can be activated using a boolean value
(case-insensitive, one of "true", "1", "YES", "Y", "ON") for the setting.

.. list-table::
:widths: 35 50 15
:header-rows: 1
:align: left

* - Flag Name
- Description
- Default status
* - Example flag
- Replace this with something real
- ``Off``

**Note:** Can be set via any `supported MicroProfile Config API source`_, e.g. the environment variable
``DATAVERSE_FEATURE_XXX``.



.. _:ApplicationServerSettings:

Application Server Settings
Expand Down
1 change: 0 additions & 1 deletion doc/sphinx-guides/source/installation/oidc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,3 @@ configuration option. For details, see :doc:`config`.
.. hint::
In contrast to our :doc:`oauth2`, you can use multiple providers by creating distinct configurations enabled by
the same technology and without modifying the Dataverse Software code base (standards for the win!).

78 changes: 78 additions & 0 deletions src/main/java/edu/harvard/iq/dataverse/settings/FeatureFlags.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package edu.harvard.iq.dataverse.settings;

import java.util.Objects;

/**
* <p>
* This enum holds so-called "feature flags" aka "feature gates", etc. It can be used throughout the application
* to avoid activating or using experimental functionality or feature previews that are opt-in.
* </p><p>
* The current implementation reuses {@link JvmSettings} to interpret any
* <a href="https://download.eclipse.org/microprofile/microprofile-config-3.0/microprofile-config-spec-3.0.html#_built_in_converters">boolean values</a>
* (true == case-insensitive one of "true", "1", "YES", "Y", "ON") and hook into the usual settings system
* (any MicroProfile Config Source available).
* </p><p>
* If you add any new flags, please add it here, think of a default status, add some Javadocs about the flagged
* feature and add a "@since" tag to make it easier to identify when a flag has been introduced.
* </p><p>
* When removing a flag because of a feature being removed, drop the entry. When a feature matures, drop the flag,
* too! Flags are not meant to be switches for configuration!
* </p>
*
* @see <a href="https://guides.dataverse.org/en/latest/installation/config.html#feature-flags">Configuration Guide</a>
* @see <a href="https://guides.dataverse.org/en/latest/developers/configuration.html#adding-a-feature-flag">Developer Guide</a>
*/
public enum FeatureFlags {

/* None yet - please add the first here. Example code with JavaDoc example:
*
* /**
* * Your (short) description of what will happen when enabling here.
* * @apiNote Raise flag by setting "dataverse.feature.flag-name"
* * @since Dataverse 5.13
* * /
* DESCRIPTIVE_NAME_HERE("flag-name"),
*
*/

// This is used for testing only, thus no documentation! Might be removed when adding the first real flag
// and replace it in the unit test!
TEST_MODE("test_mode"),

;

final String flag;
final boolean defaultStatus;

/**
* Construct a flag with default status "off".
*
* @param flag This flag name will be used to create a scoped String with {@link JvmSettings#FEATURE_FLAG},
* making it available as "dataverse.feature.${flag}".
*/
FeatureFlags(String flag) {
this(flag, false);
}

/**
* Construct a flag.
* @param flag This flag name will be used to create a scoped String with {@link JvmSettings#FEATURE_FLAG},
* making it available as "dataverse.feature.${flag}".
* @param defaultStatus A sensible default should be given here. Probably this will be "false" for most
* experimental feature previews.
*/
FeatureFlags(String flag, boolean defaultStatus) {
Objects.requireNonNull(flag);
this.flag = flag;
this.defaultStatus = defaultStatus;
}

/**
* Determine the status of this flag via {@link JvmSettings}.
* @return True or false, depending on the configuration or {@link #defaultStatus} if not found.
*/
public boolean enabled() {
return JvmSettings.FEATURE_FLAG.lookupOptional(Boolean.class, flag).orElse(defaultStatus);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ public enum JvmSettings {
SCOPE_API(PREFIX, "api"),
API_SIGNING_SECRET(SCOPE_API, "signing-secret"),

// FEATURE FLAGS SETTINGS
SCOPE_FLAGS(PREFIX, "feature"),
// This is a special placeholder-type setting entry, to be filled in by FeatureFlag entries during lookup.
// Avoids adding flag entries twice.
FEATURE_FLAG(SCOPE_FLAGS),

;

private static final String SCOPE_SEPARATOR = ".";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package edu.harvard.iq.dataverse.settings;

import edu.harvard.iq.dataverse.util.testing.JvmSetting;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class FeatureFlagsTest {

@Test
void testFlagDisabled() {
assertFalse(FeatureFlags.TEST_MODE.enabled());
}

@Test
@JvmSetting(key = JvmSettings.FEATURE_FLAG, value = "on", varArgs = "test_mode")
void testFlagEnabled() {
assertTrue(FeatureFlags.TEST_MODE.enabled());
}

}

0 comments on commit 308d5e3

Please sign in to comment.