Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Git refs/preview env guide #176

Merged
merged 7 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions guides/get-going-with-gitops.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ This endpoint happens to list out a bunch of strings in a JSON array.
The sorting algorithm previously used was slow (Bubble Sort), and we want to try something new (Quicksort).
While we feel confident in our implementation, we're going to practice caution and release the change behind a feature flag.

### The Application
### Structure

<Note>
If you want to follow along you can fork our [gitops guide
repository](https://github.com/flipt-io/flipt-gitops-guide).
repository](https://github.com/flipt-io/guides).
</Note>

```bash
Expand Down Expand Up @@ -426,7 +426,7 @@ The `flipt` binary has the sub-command `flipt validate`.
This can be used to statically validate your Flipt feature configuration files.
You can install this to run during a CI step and catch bugs before merging changes into `main`.

For GitHub, try our pre-built [Flipt Validate Action](https://github.com/marketplace/actions/flipt-validate-action).
For GitHub, try our pre-built [Flipt Setup Action](https://github.com/marketplace/actions/flipt-setup-action).

</Tip>

Expand Down Expand Up @@ -588,12 +588,11 @@ At each commit, we could've fully recreated the configuration of our entire appl

Now you have all the tools necessary to practice GitOps with your feature flags.

However, in production, your mileage may vary with the different backed types.
You might want to consider the `object` (and AWS S3 type) or the `oci` backend if your source Git repositories are large (we're working on a guide for that now).
You might want to consider the `object` or the `oci` backend if your source Git repositories are too large (we're working on a guide for that now).

The declarative storage backends currently mandate that the UI is **read-only**.
We've thoughts on how this could change in the future, but for now, this is a limitation.
You always have your editor, Git and the SCMs (GitHub, Gitlab etc) for state management in the meantime.

Each of these backends work by polling their sources (git, local directory or object store) and the interval can be configured.
Each of these backends work by polling their sources (git, oci, local directory or object store) and the interval can be configured.
Checkout the [Configuration: Storage: Declarative](/configuration/storage#declarative) for details on adjusting these intervals.
237 changes: 237 additions & 0 deletions guides/using-references.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
---
title: Evaluating with References
description: Leveraging Flipt evaluation references for preview environments.
---

## What are References in Flipt?

Check warning on line 6 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Openly.Titles] 'What are References in Flipt?' should be in sentence case Raw Output: {"message": "[Openly.Titles] 'What are References in Flipt?' should be in sentence case", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 6, "column": 4}}}, "severity": "WARNING"}

Check warning on line 6 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Microsoft.HeadingPunctuation] Don't use end punctuation in headings. Raw Output: {"message": "[Microsoft.HeadingPunctuation] Don't use end punctuation in headings.", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 6, "column": 31}}}, "severity": "WARNING"}

References are a way to pass additional information to Flipt during an evaluation request. This allows you to serve different flag states based on the reference when using our [Git backend](/configuration/storage#git).

Check warning on line 8 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Microsoft.We] Try to avoid using first-person plural like 'our'. Raw Output: {"message": "[Microsoft.We] Try to avoid using first-person plural like 'our'.", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 8, "column": 173}}}, "severity": "WARNING"}

References are especially useful when using Flipt in preview environments. You can use references to serve a different Git branch for each preview environment keeping your main branch safe from untested configurations.

## What are Preview Environments?

Check failure on line 12 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Flipt.TitleCase] 'What are Preview Environments?' should be in title case Raw Output: {"message": "[Flipt.TitleCase] 'What are Preview Environments?' should be in title case", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 12, "column": 4}}}, "severity": "ERROR"}

Check warning on line 12 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Openly.Titles] 'What are Preview Environments?' should be in sentence case Raw Output: {"message": "[Openly.Titles] 'What are Preview Environments?' should be in sentence case", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 12, "column": 4}}}, "severity": "WARNING"}

Check warning on line 12 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Microsoft.HeadingPunctuation] Don't use end punctuation in headings. Raw Output: {"message": "[Microsoft.HeadingPunctuation] Don't use end punctuation in headings.", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 12, "column": 32}}}, "severity": "WARNING"}

Preview environments are a way to create a temporary environment for a pull request. This allows you to test your changes in a production-like environment before merging your code. This is especially useful for testing changes that require a full build and deploy cycle.

In this guide, we're going to demonstrate how to leverage Flipt in preview environments to test changes in a production-like environment, without affecting your production users.

Check warning on line 16 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Openly.SentenceLength] Write short sentences (less than 25 words). Raw Output: {"message": "[Openly.SentenceLength] Write short sentences (less than 25 words).", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 16, "column": 1}}}, "severity": "WARNING"}

Check warning on line 16 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Microsoft.We] Try to avoid using first-person plural like 'we'. Raw Output: {"message": "[Microsoft.We] Try to avoid using first-person plural like 'we'.", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 16, "column": 16}}}, "severity": "WARNING"}

## What You'll Learn

Check warning on line 18 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Openly.Titles] 'What You'll Learn' should be in sentence case Raw Output: {"message": "[Openly.Titles] 'What You'll Learn' should be in sentence case", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 18, "column": 4}}}, "severity": "WARNING"}

Check warning on line 18 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Openly.FutureTense] Possible future tense. Raw Output: {"message": "[Openly.FutureTense] Possible future tense.", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 18, "column": 13}}}, "severity": "WARNING"}

In this guide you will learn how to:

Check warning on line 20 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Openly.FutureTense] Possible future tense. Raw Output: {"message": "[Openly.FutureTense] Possible future tense.", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 20, "column": 19}}}, "severity": "WARNING"}

- 🏁 Setup Flipt to work in a preview environment
- 🚀 Create a preview environment for a pull request that modifies a feature flag in our [declarative format](/configuration/storage#flag-state-configuration)
- 🌲 Add, commit, and push the change to a preview branch
- 🧪 Test the change in the preview environment
- 🎉 Merge the pull request and deploy the change to production

## Our Example Application

We're going to be making a change to our internal organization sales dashboard. This dashboard is made up of simple [React](https://reactjs.org/) frontend and a Go backend. The frontend is a single page application that makes API calls to the backend to fetch data. The backend is a **new** API that returns a list of sales performance data. The frontend will use this data to render a graph of our companies sales performance.

Because this API is new and we're not sure how it will perform, we want to test it in a production-like environment before we merge it into our main branch.

![Our example application without our new graph](/images/guides/using-references/dashboard-main.png)

We already use Flipt in our production environment, and we want to be able to use the same instance without having to deploy a new Flipt specifically for our preview environments.

We also make use of Flipt's GitOps integration to manage our feature flags in our Git repository. This allows us to manage our feature flags in a declarative format, and have them automatically synced to Flipt in the background.

<Tip>
If you're not familiar with Flipt's GitOps integration, check out our{" "}
<a href="/guides/get-going-with-gitops">GitOps guide</a> for more information.
</Tip>

### Structure

Our application lives in a directory committed to a Git repository.
For the example's sake, we assume the repository will be hosted on GitHub at `https://github.com/organization/repository.git`.

The application is made up of three directories:

- `cmd/api` - contains our Go backend API and loads the UI
- `ui` - contains our React frontend
- `pkg/performance` - contains our Flipt feature flag definition

<Note>
If you want to follow along you can fork our [guide
repository](https://github.com/flipt-io/guides).
</Note>

For the purpose of this guide, we'll mainly focus on the Go backend and the Flipt feature flag definition file.

### Go Backend

The purpose of our Go backend is two-fold:

1. Serve our React frontend
2. Serve our new API

Our new API is a simple HTTP endpoint that returns a list of sales performance data.

Because we're good engineers, we want to make sure that our new API is performant before we merge it into our main branch. To do this, we're going to use Flipt to control access to our new API.

The main bit of code that we want to guard is where we mount the `/api/performance` endpoint:

```go cmd/api/main.go
http.HandleFunc("/api/performance", func(w http.ResponseWriter, r *http.Request) {
logger := slog.With(
slog.String("namespace", "performance"),
slog.String("flag", "showPerformanceHistory"),
)

// evaluate the showPerformanceHistory features flag
result, err := flipt.Evaluation().Boolean(r.Context(), &evaluation.EvaluationRequest{
NamespaceKey: "performance",
FlagKey: "showPerformanceHistory",
EntityId: fmt.Sprintf("%x", rand.Intn(1000)),
Reference: os.Getenv("FLIPT_CLIENT_REFERENCE"),
})
if err != nil {
logger.Error("evaluating flag", "error", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

// if the flag is disabled we return that the endpoint cannot be found
if !result.Enabled {
logger.Debug("flag disabled")
http.Error(w, "path not found", http.StatusNotFound)
return
}

if err := json.NewEncoder(w).Encode(&history); err != nil {
logger.Error("parsing json", "error", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
})
```

Here you can see that we're using Flipt's Go client to evaluate the `showPerformanceHistory` feature flag. If the flag is enabled, we return the sales performance data.

Also of note, we're using the `FLIPT_CLIENT_REFERENCE` environment variable to pass in the reference to Flipt in the evaluation call. This is used to serve a different Git branch for each preview environment. We'll talk more about this later.

### Flipt Feature Flag Definition

Our feature flag definition is stored in the `pkg/performance` directory. This directory contains a single file called `features.yml`. This file contains the definition of our `showPerformanceHistory` feature flag.

```yaml pkg/performance/features.yml
namespace: performance
flags:
- key: showPerformanceHistory
name: Show Performance History Graph
type: BOOLEAN_FLAG_TYPE
enabled: false
```

<Note>
You don't have to call your file `features.yml` and you can spread your flag
definitions across multiple files. Checkout our docs on [locating flag
state](/configuration/storage#locating-flag-state) to learn more.
</Note>

## Creating Preview Environments

For this guide, we're going to use [GitHub Actions](https://github.com/features/actions) to deploy our preview environments to [Koyeb](https://www.koyeb.com/).

Check failure on line 136 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Flipt.Spelling] Check the spelling of 'Koyeb'. If the spelling is correct, add this word to the spelling exception list. Raw Output: {"message": "[Flipt.Spelling] Check the spelling of 'Koyeb'. If the spelling is correct, add this word to the spelling exception list.", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 136, "column": 129}}}, "severity": "ERROR"}

Koyeb has a nice tutorial on how to deploy a preview environment using GitHub Actions. You can find it [here](https://www.koyeb.com/tutorials/deploy-preview-environments-on-koyeb-for-github-pull-requests).

Check failure on line 138 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Flipt.Spelling] Check the spelling of 'Koyeb'. If the spelling is correct, add this word to the spelling exception list. Raw Output: {"message": "[Flipt.Spelling] Check the spelling of 'Koyeb'. If the spelling is correct, add this word to the spelling exception list.", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 138, "column": 1}}}, "severity": "ERROR"}

To get our preview environments working with Flipt, we'll need some way of passing the Git branch name to Flipt. We can do this by setting the `FLIPT_CLIENT_REFERENCE` environment variable to the Git branch name. This will allow us to serve a different Git branch for each preview environment.

To do this, we'll need to add a step to our GitHub Actions workflow that sets the `FLIPT_CLIENT_REFERENCE` environment variable to the Git branch name.

```yaml
- name: Deploy the application to Koyeb
uses: koyeb/action-git-deploy@v1
with:
app-name: "dashboard-app-preview-${{ github.head_ref }}"
service-name: ${{ github.head_ref }}
service-ports: "8081:http"
service-routes: "/:8081"
service-env: "FLIPT_CLIENT_REFERENCE=${{ github.head_ref }},FLIPT_ADDRESS=${{ secrets.FLIPT_ADDRESS }}"
docker: ghcr.io/flipt-io/dashboard-app:latest
```

Here we're also setting the `FLIPT_ADDRESS` environment variable to the address of our Flipt instance. This could also be configured in your application via a config file.

## Enabling the Flag and Pushing to a Preview Branch

Now that we have our preview environments setup, we can enable our feature flag and push our changes to a preview branch.

Check failure on line 160 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Microsoft.Contractions] Use 'we've' instead of 'we have'. Raw Output: {"message": "[Microsoft.Contractions] Use 'we've' instead of 'we have'.", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 160, "column": 10}}}, "severity": "ERROR"}

To enable our feature flag, we'll need to update our `features.yml` file to set the `enabled` field to `true`.

```yaml pkg/performance/features.yml
namespace: performance
flags:
- key: showPerformanceHistory
name: Show Performance History Graph
type: BOOLEAN_FLAG_TYPE
enabled: true
```

Now we can add, commit, and push our changes to a preview branch.

```bash
git checkout -b feature/enable-performance-history
git add pkg/performance/features.yml
git commit -m "Enable performance history"
git push origin feature/enable-performance-history
```

We'll also need to create a pull request for our preview branch. This will trigger our GitHub Actions workflow and deploy our preview environment.

## Testing the Change

Before checking on our preview environment, let's take a look at our Flipt instance. We can see that our feature flag is still showing as disabled in the UI.

This is because Flipt is configured to track the `main` branch of our Git repository by default, which is what it continues to show in the UI.

Check failure on line 188 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Openly.UnclearAntecedent] 'This is' is an unclear antecedent Raw Output: {"message": "[Openly.UnclearAntecedent] 'This is' is an unclear antecedent", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 188, "column": 1}}}, "severity": "ERROR"}

![Our feature flag is still disabled in the UI](/images/guides/using-references/flag-disabled.png)

<Tip>
In an upcoming release, we'll be adding the ability to switch between
references in the UI. This will allow you to see the state of your feature
flags in each Git branch.
</Tip>

Now that our preview environment is deployed, we can test our new API. We can view our application deployed to Koyeb from the Koyeb dashboard.

Check failure on line 198 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Flipt.Spelling] Check the spelling of 'Koyeb'. If the spelling is correct, add this word to the spelling exception list. Raw Output: {"message": "[Flipt.Spelling] Check the spelling of 'Koyeb'. If the spelling is correct, add this word to the spelling exception list.", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 198, "column": 112}}}, "severity": "ERROR"}

Check failure on line 198 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Flipt.Spelling] Check the spelling of 'Koyeb'. If the spelling is correct, add this word to the spelling exception list. Raw Output: {"message": "[Flipt.Spelling] Check the spelling of 'Koyeb'. If the spelling is correct, add this word to the spelling exception list.", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 198, "column": 127}}}, "severity": "ERROR"}

You can also view the application settings and see that the `FLIPT_CLIENT_REFERENCE` environment variable is set to the Git branch name.

![Our application settings in Koyeb](/images/guides/using-references/koyeb-settings.png)

Check failure on line 202 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Flipt.Spelling] Check the spelling of 'Koyeb'. If the spelling is correct, add this word to the spelling exception list. Raw Output: {"message": "[Flipt.Spelling] Check the spelling of 'Koyeb'. If the spelling is correct, add this word to the spelling exception list.", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 202, "column": 31}}}, "severity": "ERROR"}

Now we can click on the application URL to view our application. We can see that our new API is working and our graph is being rendered. 🎉

This means our feature flag is enabled successfully in our preview environment.

![Our example application with our new graph](/images/guides/using-references/dashboard-preview.png)

## Merging the Pull Request

Now that we've tested our new API in our preview environment, we can merge our pull request and deploy our changed flag definition to production.

Note that we don't have to make any code changes in our production application. This is because our Flipt is already configured to track the HEAD of the `main` Git branch. This means that when we merge our pull request, our application will automatically start using the new flag state.

![Our feature flag is now enabled in the UI](/images/guides/using-references/flag-enabled.png)

## Recap

In this guide, we learned how to use Flipt's GitOps integration and references to test changes in a production-like environment without affecting our production users.

Using references allowed us to serve a different Git branch for each preview environment. This means that each of our developers can test their feature flag changes in a production-like environment without affecting other developers.

There are likely many other ways to use references with Flipt. We'd love to hear how you're using references in your organization.

Check failure on line 224 in guides/using-references.mdx

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Openly.ThereIs] Don't start a sentence with 'There are' Raw Output: {"message": "[Openly.ThereIs] Don't start a sentence with 'There are'", "location": {"path": "guides/using-references.mdx", "range": {"start": {"line": 224, "column": 1}}}, "severity": "ERROR"}

### Further Considerations

References are available for all of our GET API endpoints, (e.g. [`GET /api/v1/flags`](/reference/flags/list-flags)) as well as all of our evaluation endpoints (e.g. [`POST /evaluate/v1/boolean`](/reference/evaluation/boolean-evaluation)).

We've also added support for references in all of our [server side REST SDKs](/integration/server/rest) and our [client side SDKs](/integration/client).

References currently only work with Git, and our `git` backend, like all of the declarative storage backends, mandates that the UI is **read-only**.
We have thoughts on how this could change in the future, but for now, this is a limitation.
You always have your editor, Git and the SCMs (GitHub, Gitlab etc) for state management in the meantime.

Flipt will automatically sync your feature flag definitions to Flipt in the background. Each of these backends work by polling their sources (git, oci, local directory or object store) and the interval can be configured.
Checkout the [Configuration: Storage: Declarative](/configuration/storage#declarative) for details on adjusting these intervals.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion mint.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@
"pages": [
{
"group": "User Guides",
"pages": ["guides/get-going-with-gitops"]
"pages": [
"guides/get-going-with-gitops",
"guides/using-references"
]
},
{
"group": "Operations Guides",
Expand Down
Loading