When developing new features for the site, it may be necessary to have several incremental PRs to be merged into master. However, within these incremental PRs, it is possible that a release onto production may happen, containing this in-progress work. While one could put a warning of “do not use” for the feature, and hope instructors (or students) do not click on it, potentially breaking the system, it is better to utilize “Feature Flags”. The flags can be used to hide a feature, giving access to developers, as well as setting up a course to alpha or beta test a feature that is not quite ready for full production.
Feature flags are stored and handled within the Config model, and utilizes the following logic to determine if a flag is enabled:
- If
debugging_enabled
inconfig/database.json
is True, then all feature flags are considered on. - If
feature_flags
object exists in courseconfig.json
, then check if requested flag exists in the object and is set to true (e.g.flag: true
).
Otherwise, the flag is considered off.
E.g: To enable a feature flag in a course named sample edit the file:
/var/local/submitty/courses/f20/sample/config/config.json
To include a top level JSON object named feature flags, each feature flag is a string that can either be true or false. Set a flag to true to enable it for that course.
Example partial config:
{
"feature_flags" : {
"submitty_ocr" : true,
"foo" : false
},
/* Rest of config below */
To utilize checking a flag, the following methods are available:
- Twig Template
- Controller Annotation
- PHP Code
Twig Template
Within twig, you can use the function feature_flag_enabled(string $flag): bool
. For example, for
gating on flag foo:
{% if feature_flag_enabled('foo') %}
{# show feature foo #}
{% endif %}
Controller Annotation
To gate a controller, or just a method, you can utilize the @FeatureFlag
annotation. This annotation
is to be put in the docblock of a controller or method and it accepts a single string argument, the
name of the flag. An example of usage would be:
use app\libraries\routers\FeatureFlag;
/**
* @FeatureFlag("foo")
*/
class Bar {}
or for a function:
use app\libraries\routers\FeatureFlag;
class Bar {
/**
* @FeatureFlag("foo")
*/
public function bar() {}
// this function is available always
public function baz() {}
}
PHP Code
For the PHP code, the config model makes available the function
checkFeatureFlagEnabled(string $flag): bool
. For example, if we wanted to gate on feature flag “foo” within
a controller, we might do:
if ($this->core->getConfig()->checkFeatureFlagEnabled('foo')) {
// show feature foo
}