CHANGELOG.md

# Changelog

<!-- %% CHANGELOG_ENTRIES %% -->

## Unreleased

## 3.0.0
**WARNING: BREAKING CHANGE**
Users relying on propagated overrides for variants will be affected by this
update.

### Highlights

* Updated get_variant/2 to support the official Unleash API's strategy variants
  while maintaining compatibility with feature variants.
* API interface remains unchanged.
* Removed support for propagated overrides for variants.

### Details

The official Unleash API has deprecated feature variants in favor of strategy
variants. We've adapted our implementation to align with this change while
ensuring backward compatibility.

#### Why we removed propagated overrides for variants

* Supporting propagated overrides for strategy variants would require knowledge
  of the specific strategy where each variant is defined.
* This would significantly complicate both the overrides header schema and
  implementation.
* The existing implementation for feature variants overrides lacked robust
  support for creating overrides with payloads.

This architectural decision balances API modernization with maintaining a clean
implementation.

## 2.1.0
* Restore Fresha-specific behaviour of automatically populating a custom
  context property `"namespace"` from the environment variable `UNLEASH_NAMESPACE`.
* Remove references to Mojito. It has been swapped out for Req in version 1.10.0.

## 2.0.0 - 2024-08-15

### Highlights
#### New API & Upgrade Guide
**WARNING: BREAKING CHANGES!**

The main APIs of the SDK have been restructured for safety, clarity and expressiveness,
and the main utilities to do feature checks are now the two macros `enabled?/2` and `get_variant/2`,
which feature a keyword-based call signature.

Old usage:
```elixir
Unleash.enabled?(:my_flag)
# Second argument here is the "default" (fallback if feature is missing)
Unleash.enabled?("another_flag", false)
# Second argument here is the context that gets passed to feature activation strategy evaluation
Unleash.enabled?(:flag_three, %{user_id: "user-123"})
# 3-arity clause
Unleash.enabled?("flag_four", %{}, true)
```

New usage:
```elixir
# You have to require the `Unleash.Macros` module.
# In this example we alias it to `Unleash` to make it nicer, but you do you.
require Unleash.Macros, as: Unleash

Unleash.enabled?(:my_flag)
# Explicit named arguments avoid ambiguous calls and allow extra
# options to be introduced in the future.
Unleash.enabled?("another_flag", fallback: false)
Unleash.enabled?(:flag_three, context: %{user_id: "user-123"})
# Note that you can pass the keyword arguments in any order
Unleash.enabled?("flag_four", fallback: true, context: %{})

# Overrides have to be explicitly allowed when evaluating a feature or they will be ignored.
Unleash.enabled?("flag_five", fallback: nil, allow_overrides: true)
```

The macros allow us to check at compile-time what options are provided and emit compilation warnings in case of unsupported ones,
and do other compile-time checks to ensure the clarity and correctness of feature flags checks.
Additionally, by using the macros you can swap out the underlying runtime implementation,
for example to use a mock one in tests. See the updated [README](./README.md).

Note that this means the names (not values!) of the parameters must be passed as compile-time constants.
This is not valid:

```elixir
def my_function(feature_check_options) do
  # Opts is a local variable at compile-time
  Unleash.enabled?(:some_flag, feature_check_options)
end

# Opts is an expression at compile time
Unleash.enabled?(:some_flag, if(some_condition(), do: [], else: [fallback: ]))
```

But don't worry, you're very unlikely to incur in this case in normal usage.
Even if you do, you will get a helpful compilation error explaining the problem
and how to address it.

In edge cases where you can't use the macros, which should be quite unlikely,
you can use directly the equivalent functions in `Unleash.Runtime`. 

### Added 
* Two new macros `Unleash.Macros.enabled?/1,2` and `Unleash.Macros.get_variant/1,2`,
  which are now the main methods to check a feature flag.
* the `Unleash` module now defines a behaviour for Runtime implementations.
  This can be used to define Mox/Hammox mocks and, combined with the next point,
  facilitates testing. See the testing section on the [README](./README.md).
* the actual runtime implementation (and `Application`) has been moved to `Unleash.Runtime`.
  The Runtime can be swapped via compile-time config.

### Changed
* It is now possible to pass `nil` as a fallback value to `enabled?/2` and `get_variant/2`,
    which allows you to customise how you handle missing feature flags.
* For extra safety, overrides are now "opt-in".
  You have to explicitly tell Unleash to consider them, when checking for a feature/variant,
  by passing the option `allow_overrides: true`.
* The `find_in_context/2` function has been moved to `Unleash.Context.find/2`.

### Removed
* The following functions have been removed:
  - `Unleash.is_enabled/1,2,3`
  - `Unleash.enabled?/1,2,3`
  - `Unleash.get_variant/1,2,3`
  
### Improved
* Improved documentation and tests throughout
* Improved type specs
* Updated and reworded README.

## 1.16.0 - 2024-08-08

### Highlights
#### gRPC Interceptors

This release introduces gRPC interceptors that seamlessly enable the propagation mechanism
within your gRPC-based applications.

It includes four interceptors:

- `Unleash.Propagation.GRPC.ContextServerInterceptor`
- `Unleash.Propagation.GRPC.ContextClientInterceptor`
- `Unleash.Propagation.GRPC.ImpressionsServerInterceptor`
- `Unleash.Propagation.GRPC.ImpressionsClientInterceptor`

The first two interceptors are responsible for the propagation of context and overrides.  
The server interceptor automatically extracts the incoming Unleash context and feature overrides,
which are then considered during feature evaluations within the context of request handling.  
The client interceptor propagates context and overrides further when invoking downstream gRPC services.

The latter two interceptors handle the propagation of feature impressions.  
The server interceptor initiates an impressions tracking session during request handling and automatically returns the generated impressions when sending the gRPC response.  
Meanwhile, the client interceptor reads impressions returned by downstream gRPC services and merges them with the locally generated impressions.

### Added
* gRPC interceptors for the Propagation mechanism.

### Fixed
* Changes to test setup helpers which should strongly reduce the flakiness of the tests.

## 1.15.0 - 2024-08-06

### Highlights

#### Impression Tracking

This release introduces a new propagation mechanism to track
[impressions](https://docs.getunleash.io/reference/impression-data) generated
within a tracking session, which typically corresponds to a logical execution unit, such as a request handler.
These tracked impressions can be retrieved, for instance, to be sent back to the caller in a response header.

It includes a new Plug, `track_impression/2`, which can be seamlessly integrated into your router or pipeline
to handle this process for you.

### Added
* Impressions tracking core functionality: `Unleash.Propagation.track_impressions/0`,
  `Unleash.Propagation.record_impression/2`, `Unleash.Propagation.impressions/0`
* Impressions tracking Plug: `Unleash.Propagation.Plugs.track_impressions/1,2`

## 1.14.0 - 2024-07-29

* Add `Unleash.Propagation.Serialization.serialize_context!/1` and
  `Unleash.Propagation.Serialization.serialize_overrides!/1`.

  These new methods can be invoked by users of the SDK to futher propagate context
  and overrides when sending requests to downstream services.

## 1.13.0 - 2024-07-29
* Introduce the Propagation mechanism

  The propagation mechanism allows to set overrides and context values that will be considered
  whenever a feature state is evaluated (via `enabled/3` or `get_variant/3`) in the current
  or descendant processes.
  The SDK includes two new Plugs that can be used in your Plug-based application
  to automatically extracts overrides and context out of incoming HTTP request headers
  and store them in the Propagation mechanism.

* Support for both string keys and atom keys in context `properties`.

  Previously the SDK would expect a context's `:properties` field to be a map with atom keys.
  (though this expectation wasn't enforced nor specified anywhere).

  With the new propagation mechanism, arbitrary properties can be set from HTTP requests.
  The SDK stores them as string keys instead of doing a potentially dangerous
  runtime conversion of dynamic data to atoms.

  **This is a potentially breaking change if your application relied on properties
  with string values being ignored by the SDK** (which is unlikely).

  A new function `Unleash.find_in_context/2` has been introduced to consistently
  lookup values in a context, which handles fallback to `:properties` and the string/atom dichotomy.

## 1.12.0 - 2024-07-23
* Tune retry behaviour of HTTP requests to Unleash API server.
  They are now only retried once after 50ms, instead of the default `Req` behaviour of retrying 3 times after 1s, 2s, 4s.
* Silence warnings on `Req` retries.
* Log an error when failing to contact the Unleash API server (after retry).

## 1.11.0 - 2024-07-19
* Avoid failing and crashing in case of missing or invalid bootstrap/backup file.
* Load bootstrap/backup file synchronously on startup.
* Do not read the backup file on server errrors. Keep using the local cache instead, which we assume to be in-sync with the backup file, as they bot get udpated whenever we obtain fresh features from the server.


## 1.10.2 - 2024-06-19
* Add `namespace` to context

## 1.10.1 - 2024-06-19
* Fix caseInsensitve

## 1.10.0 - 2024-05-20
* replace Mojito with Req

## 1.9.2 - 2023-01-25
* Update dependencies
* Add version, date, number comparison

## 1.9.0 - 2023-01-25

* add: Telemetry events for `Unleash.Client` [!28](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/28)
* add: Telemetry events for `Unleash.enabled?` [!29](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/29)
* add: Telemetry events for `Unleash.get_variant` [!30](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/30)
* add: Telemetry events for `Unleash.Repo` [!31](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/31)
* add: Telemetry events for metrics pushed to server [!33](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/33)
* remove: Logger calls [!37](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/36)

Thanks [Jekri Orlina](https://gitlab.com/jekku) and [Sam Hutchings](https://gitlab.com/samhutchings) for telemetry
adoption.


## 1.8.3 - 2022-05-31

* fix: Avoid crash when mojito connect is closed for the metrics client
  [!26](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/26) Thanks [John Bell](https://gitlab.com/johnabell)!
* fix: Feature flag without variants cause FunctionClause Error
  [!25](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/25) Thanks
  [Ulisses Almeida](https://gitlab.com/ulissesalmeida)


## 1.8.2
* fix `Unleash.Metrics.add_metrics` ccrash for unrecorded feature_toggle [!24](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/24) Thanks [calvin-kargo](https://gitlab.com/calvin-kargo)!

## 1.8.1
* fix Unleash.Metrics to provide proper start_link/1 behaviour [!23](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/23) Thanks [calvinsadewa](https://gitlab.com/calvin-kargo)!

## 1.8.0

* Use ETS cache to store features rather than Genserver state
  [!22](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/22) Thanks
  [Maximilien Rothier Bautzer](https://gitlab.com/cachemoi)

## 1.7.2
* Disabled flags should not produce an active variant [!20](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/20) Thanks [Daniel Cooper](https://gitlab.com/danielcooper)

## 1.7.1
* Handle unexpected mojito_response messages [!19](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/19) Thanks [Daniel Cooper](https://gitlab.com/danielcooper)

## 1.7.0
* Also transform the member in a list query [!17](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/17) Thanks [Daniel Cooper](https://gitlab.com/danielcooper)!
* Update mojito to current [!18](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/18) Thanks [Daniel Cooper](https://gitlab.com/danielcooper)!

## 1.6.0
* Add Flexible Rollout Strategy [!12](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/12)
* Support Constraints for Feature Flags [!14](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/14)
* Avoid using Mix.env at runtime [!16](https://gitlab.com/afontaine/unleash_ex/-/merge_requests/16) Thanks [Daniel Cooper](https://gitlab.com/danielcooper)!

## 1.5.0
* Add ability to fetch all feature flag names [decfa826](https://gitlab.com/afontaine/unleash_ex/commit/decfa826fca2d656a61f8e77c29138ea28214473)

## 1.4.1
* Suport Running With Distillery [!10](https://gitlab.com/afontaine/unleash_ex/merge_requests/10) Thanks [Thomas Chandler](https://gitlab.com/thomaschandler)!
* Use cached features when unexpected response received from Unleash server [!11](https://gitlab.com/afontaine/unleash_ex/merge_requests/11) Thanks [Thomas Chandler](https://gitlab.com/thomaschandler)!

## 1.4.0
* Add Support for Capturing Metrics on Variants [!7](https://gitlab.com/afontaine/unleash_ex/merge_requests/7)

## 1.3.1
* Fix Missing Content-Type for Posting Metrics [89d073cf](https://gitlab.com/afontaine/unleash_ex/commit/89d073cf6e507816259c8481b9510c56db672deb)

## 1.3.0
* Fix Variant Serialization to JSON [e5f4fd3c](https://gitlab.com/afontaine/unleash_ex/commit/e5f4fd3cece12810afbe789c122404e9169bd1ef)
* Use Mojito to Pool HTTP Connections [e5f4fd3c](https://gitlab.com/afontaine/unleash_ex/commit/e5f4fd3cece12810afbe789c122404e9169bd1ef)

## 1.2.0
* Add Variant Support [!5](https://gitlab.com/afontaine/unleash_ex/merge_requests/5)
* Fix ETag Usage [f30b80bf](https://gitlab.com/afontaine/unleash_ex/commit/f30b80bf931f56f5de908ca738977c2e540155e4)

## 1.1.0
* Add Optional `Plug` Module [!6](https://gitlab.com/afontaine/unleash_ex/merge_requests/6)

## 1.0.0
* Implement Client Specification Tests [!4](https://gitlab.com/afontaine/unleash_ex/merge_requests/4)

## 0.2.0

* Add E-Tag Caching Support [!1](https://gitlab.com/afontaine/unleash_ex/merge_requests/1)
* Send the Library Version when Registering Client [!2](https://gitlab.com/afontaine/unleash_ex/merge_requests/2)
* Add Checks for a Retry Limit [!3](https://gitlab.com/afontaine/unleash_ex/merge_requests/3)

## 0.1.0

* Initial release