diff --git a/.travis.yml b/.travis.yml index 4340bf58b4..33be442fa4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,31 +1,31 @@ sudo: false language: node_js node_js: -- '8' -- '10' + - '8' + - '10' env: - matrix: - - DATABASE_URL=postgres://postgres@localhost:5432/unleash_test TEST_DATABASE_URL=postgres://postgres@localhost:5432/unleash_test - global: - secure: HyWYh1dbUfe2yPF9ZdcdA/IVGyNWmJmpuaRvRGnnpO63/5Y0KT6/hyL6nZ4YJ7Wr/KEt4eMJBJsnzaCFtiqNA3cWyyprzXJButw0o8C6dfd/9jOleisuvdqndu92RqDKIIq2EjHVq3sd6B8uGyiOlkMsyFH57O/V+xHW8MYLnaQ= + matrix: + - DATABASE_URL=postgres://postgres@localhost:5432/unleash_test TEST_DATABASE_URL=postgres://postgres@localhost:5432/unleash_test + global: + secure: HyWYh1dbUfe2yPF9ZdcdA/IVGyNWmJmpuaRvRGnnpO63/5Y0KT6/hyL6nZ4YJ7Wr/KEt4eMJBJsnzaCFtiqNA3cWyyprzXJButw0o8C6dfd/9jOleisuvdqndu92RqDKIIq2EjHVq3sd6B8uGyiOlkMsyFH57O/V+xHW8MYLnaQ= before_install: npm install -g greenkeeper-lockfile@1 before_script: -- psql -c 'create database unleash_test;' -U postgres -- greenkeeper-lockfile-update + - psql -c 'create database unleash_test;' -U postgres + - greenkeeper-lockfile-update script: yarn run test:coverage after_script: greenkeeper-lockfile-upload -after_success: -- yarn run test:coverage-report +after_success: + - yarn run test:coverage-report notifications: - slack: - secure: MroremSKwtQkwPbrXjgs9hIqKTCDKk7bAIXXzjcS6wXC9uRaFgwFaW8oO3vBxtWa4BL44EQBLE/rboWgqFER62+XgXNgEqGZqrcJHJvby4r+dUNMPI64OZvWdIiydIYxLo8C1C4x5PqBup0xuLq8h/SBnNvA2NLgkjuvzOi+v/Q= + slack: + secure: MroremSKwtQkwPbrXjgs9hIqKTCDKk7bAIXXzjcS6wXC9uRaFgwFaW8oO3vBxtWa4BL44EQBLE/rboWgqFER62+XgXNgEqGZqrcJHJvby4r+dUNMPI64OZvWdIiydIYxLo8C1C4x5PqBup0xuLq8h/SBnNvA2NLgkjuvzOi+v/Q= addons: - postgresql: '9.4' + postgresql: '9.4' cache: - yarn: true + yarn: true deploy: - # deploy doc on master to production - - provider: script - script: bash scripts/deploy-docs.sh - on: - branch: master \ No newline at end of file + # deploy doc on master to production + - provider: script + script: bash scripts/deploy-docs.sh + on: + branch: master diff --git a/CHANGELOG.md b/CHANGELOG.md index ce5bde9d77..c1e32af44b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,29 +1,35 @@ # Changelog ## 3.1.2 + - fix(clientApi): Add namePrefix paramter to /api/client/features ## 3.1.1 + - fix(gzip): Add gzip support - fix(package): update unleash-frontend to version 3.1.3 ## 3.1.0 + - fix(package): update unleash-frontend to version 3.1.1 ## 3.0.6 + - fix(log4js): Upgrade log4js to version 3.0.3 and fix default log configuration ## 3.0.5 + - fix(package): update log4js to version 3.0.2 - fix(package): update knex to version 0.15.2 - fix(package): update yargs to version 12.0.1 - chore(readme): Update documentation - fix(package): update install to version 0.12.0 -- fix(revive): Include user information on revive +- fix(revive): Include user information on revive - chore(package): update eslint to version 5.0.0 - chore(package): update nyc to version 12.0.1 ## 3.0.4 + - feat(metrics): Expose toggle updates to prometheus - chore(package.json): Bump serve-favicon to 2.5.0 - chore(package.json): Bump joi to 13.0.3 @@ -36,31 +42,37 @@ - chore(package.json): Bump commander to 2.15.1 ## 3.0.3 + - feat(bind): Added option to bind to specific http address - fix(migration): Unleash should not start if migration fails. ## 3.0.2 -- fix(package): Update unleash-frontend to version 3.0.1 + +- fix(package): Update unleash-frontend to version 3.0.1 ## 3.0.1 + - fix(package): Update db-migrate-pg to version 0.4.0 - fix(package): update prom-client to version 11.0.0 - refactor: use body-parser bundled with express - fix(package): update express-validator to version 5.0.0 ## 3.0.0 (10.02.2018) + - All changes in all 3.0.0 alpha-releases is included in this version - fix(package): Upgrade unleash-frontend to version 3.0.0 - ## 3.0.0-alpha.10 + - chore(package.json): Bump unleash-frontend to 3.0.0-alpha.7 - fix(store): DB should not override createdAt if set. ## 3.0.0-alpha.9 + - Bugfix: more informative name validation errors ([#292](https://github.com/Unleash/unleash/pull/292)) ## 3.0.0-alpha.8 + - [Auth] User-provider ([#261](https://github.com/Unleash/unleash/issues/261)) - [Auth] Document how to secure Unleash ([#234](https://github.com/Unleash/unleash/issues/234)) - [Auth] Admin UI should handle 401 ([#232](https://github.com/Unleash/unleash/issues/232)) @@ -69,16 +81,20 @@ - [Auth] Support sign out ([#288](https://github.com/Unleash/unleash/issues/288)) ## 3.0.0-alpha.7 + - Bugfix: Should not allow creation of archived toggle #284 ## 3.0.0-alpha.6 -- Expose vresion number in /api and in user interface. + +- Expose vresion number in /api and in user interface. - Housekeeping: Upgrading a lot of dependencies ## 3.0.0-alpha.3 + - Bump unleash-frontend ## 3.0.0-alpha.2 + - Add sdkVersion in client registration - disable edit of built-in strategies - Strip uknown fields in client requests. @@ -86,66 +102,73 @@ - Add posibility to inject custom logger provider ## 3.0.0-alpha.1 + - upgrade unleash-frontend to 3.0.0-alpha.1 -- moved api endpoints to /api/admin/* and /api/client/* +- moved api endpoints to /api/admin/_ and /api/client/_ - refactored all routes to use a standalone router per file - removed v.1 legacy data support - removed v.1 legacy /features endpoint - added prettier and upgraded eslint ## 2.2.0 + - Expose hooks in main export #223 ## 2.1.7 + - Bump unleash-frontend to 2.2.6 ## 2.1.6 + - Added strategies validation when updating feature toggle - Allow node newer than 6 to run the app ## 2.1.4 + - Bump unleash-fronted to 2.2.4 ## 2.1.3 + - Bugfix for db: timestamps should be with time zone. - Bump unleash-fronted to 2.2.3 ## 2.1.2 + - Bugfix for migration: avoid multiple calls on same callback. ## 2.1.0 -- Provide a set of pre-defined activation strategies. These will automatically be defined by the migrator as long as they don't exist already. - - applicationHostname - - gradualRolloutRandom - - gradualRolloutSessionId - - gradualRolloutUserId - - remoteAddress - - userWithId + +- Provide a set of pre-defined activation strategies. These will automatically be defined by the migrator as long as they don't exist already. + - applicationHostname + - gradualRolloutRandom + - gradualRolloutSessionId + - gradualRolloutUserId + - remoteAddress + - userWithId ## 2.0.4 + - bump unleash-frontend which includes a lot of UI improvements and bug-fixes. -- Fix error message when trying to create a archived feature toggle. +- Fix error message when trying to create a archived feature toggle. ## 2.0.0 (January 2017) - Support multiple strategies. This makes it easy to use multiple activation strategies in combination. -- Client metrics. Gives details about what toggles a specific client application uses, how many times a toggle was evaluated to true / false. Everything presented in the UI. -- Client registration. This gives insight about connected clients, instances, strategies they support. +- Client metrics. Gives details about what toggles a specific client application uses, how many times a toggle was evaluated to true / false. Everything presented in the UI. +- Client registration. This gives insight about connected clients, instances, strategies they support. - Client Application overview. Based on metrics and client registrations. -- Database-migration done internally by Unleash, no external migration step required. -- Publish unleash-server to npm. +- Database-migration done internally by Unleash, no external migration step required. +- Publish unleash-server to npm. - Provide Prometheus endpoint for service metrics (response times, memory usage, etc). - A lot of bug-fixes (check commit history and issues for reference) -- Unleash-frontend as a separate repo: https://github.com/Unleash/unleash-frontend. Total rewrite of UI using react + redux + material Design. -- Unleash moved to it’s own organization: https://github.com/Unleash making it more open and allow everyone to contribute. -- Unleash-docker as a separate module: https://github.com/Unleash/unleash-docker -- Unleash binary, making it easy to install and use Unleash as a service. +- Unleash-frontend as a separate repo: https://github.com/Unleash/unleash-frontend. Total rewrite of UI using react + redux + material Design. +- Unleash moved to it’s own organization: https://github.com/Unleash making it more open and allow everyone to contribute. +- Unleash-docker as a separate module: https://github.com/Unleash/unleash-docker +- Unleash binary, making it easy to install and use Unleash as a service. - Removed all config/tuning that was specific to FINN.no usage of Unleash. **If you are migrating from 1.0.0 to 2.0.0 we recommend reading [the migration guide](https://github.com/Unleash/unleash/blob/master/docs/migration-guide.md)** - - ## 1.0.0 (January 2015) -- Initial public release +- Initial public release diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 78dacbd6a3..a35dddebf6 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -8,19 +8,19 @@ In the interest of fostering an open and welcoming environment, we as contributo Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting +- The use of sexualized language or imagery and unwelcome sexual attention or advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities @@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at unleash@finn.no. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at unleash@finn.no. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. diff --git a/README.md b/README.md index e870cfc701..362466dc06 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,46 @@ # Unleash -[![Build Status](https://travis-ci.org/Unleash/unleash.svg?branch=master)](https://travis-ci.org/Unleash/unleash) -[![Coverage Status](https://coveralls.io/repos/github/Unleash/unleash/badge.svg?branch=master)](https://coveralls.io/github/Unleash/unleash?branch=master) -[![Dependency Status](https://david-dm.org/Unleash/unleash.svg)](https://david-dm.org/Unleash/unleash) -[![devDependency Status](https://david-dm.org/Unleash/unleash/dev-status.svg)](https://david-dm.org/Unleash/unleash?type=dev) -[![Greenkeeper badge](https://badges.greenkeeper.io/Unleash/unleash.svg)](https://greenkeeper.io/) -[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) +[![Build Status](https://travis-ci.org/Unleash/unleash.svg?branch=master)](https://travis-ci.org/Unleash/unleash) [![Coverage Status](https://coveralls.io/repos/github/Unleash/unleash/badge.svg?branch=master)](https://coveralls.io/github/Unleash/unleash?branch=master) [![Dependency Status](https://david-dm.org/Unleash/unleash.svg)](https://david-dm.org/Unleash/unleash) [![devDependency Status](https://david-dm.org/Unleash/unleash/dev-status.svg)](https://david-dm.org/Unleash/unleash?type=dev) [![Greenkeeper badge](https://badges.greenkeeper.io/Unleash/unleash.svg)](https://greenkeeper.io/) [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) -Unleash is a feature toggle system, that gives you a great overview over all feature toggles across -all your applications and services. It comes with official client implementations for Java, Node.js, Go and Ruby. +Unleash is a feature toggle system, that gives you a great overview over all feature toggles across all your applications and services. It comes with official client implementations for Java, Node.js, Go and Ruby. -The main motivation for doing feature toggling is to decouple the process for deploying code to production -and releasing new features. This helps reducing risk, and allow us to easily manage which features to enable +The main motivation for doing feature toggling is to decouple the process for deploying code to production and releasing new features. This helps reducing risk, and allow us to easily manage which features to enable > Feature toggles decouple **deployment** of code from **release** of new features -This repo contains the unleash-server, which contains the admin UI and a place to ask for the status of features. -In order to make use of unleash you will also need a client implementation. +This repo contains the unleash-server, which contains the admin UI and a place to ask for the status of features. In order to make use of unleash you will also need a client implementation. Unleash UI [Online demo version available on heroku](https://unleash.herokuapp.com/#/features). ## Activation strategies -It's fine to have a system for turning stuff on and off. But some times we want more granular control, -we want to decide who to the toggle should be enabled for. This is where activation strategies comes in to -the picture. Activation strategies take arbitrary config and allows us to enable a toggle in various ways. + +It's fine to have a system for turning stuff on and off. But some times we want more granular control, we want to decide who to the toggle should be enabled for. This is where activation strategies comes in to the picture. Activation strategies take arbitrary config and allows us to enable a toggle in various ways. Common activation strategies includes: + - Active For users with a specified userId - GradualRollout to X-percent of our users - Active for our beta users -- Active only for application instances running on host x. +- Active only for application instances running on host x. Read more about activation strategies in [docs/activation-strategies.md](./docs/activation-strategies.md) ## Client implementations + We have offical SDK's for Java, Node.js, Go, Ruby and Python. And we will be happy to add implementations in other langugages written by you! These libraries makes it very easy to use Unleash in you application. -Official client SDKs: +Official client SDKs: + - [unleash/unleash-client-java](https://github.com/unleash/unleash-client-java) - [unleash/unleash-client-node](https://github.com/unleash/unleash-client-node) - [unleash/unleash-client-go](https://github.com/unleash/unleash-client-go) - [unleash/unleash-client-ruby](https://github.com/unleash/unleash-client-ruby) - [unleash/unleash-client-python](https://github.com/Unleash/unleash-client-python) -Clients written by awesome enthusiasts: :fire: +Clients written by awesome enthusiasts: :fire: + - [stiano/unleash-client-dotnet](https://github.com/stiano/unleash-client-dotnet) (.Net Core) - [onybo/unleash-client-core](https://github.com/onybo/unleash-client-core) (.Net Core) - [rarruda/unleash-client-python](https://github.com/rarruda/unleash-client-python) (Python 3) @@ -62,22 +57,19 @@ if (unleash.isEnabled("AwesomeFeature")) { } ``` - -# Running Unleash +# Running Unleash ## Requirements -You will need a __PostgreSQL__ 9.3+ database instance to be able to run Unleash. +You will need a **PostgreSQL** 9.3+ database instance to be able to run Unleash. -When starting Unleash you must specify a database URI (can be set as environment variable DATABASE_URL) -which includes a username and password, which has the rights to migrate the database. +When starting Unleash you must specify a database URI (can be set as environment variable DATABASE_URL) which includes a username and password, which has the rights to migrate the database. _Unleash_ will, at startup, check whether database migration is needed, and perform necessary migrations. -## Using Unleash +## Using Unleash -**The simplest way to get started:** -(database-url can also be set as a environment variable: DATABASE_URL) +**The simplest way to get started:** (database-url can also be set as a environment variable: DATABASE_URL) ```bash $ npm install unleash-server -g @@ -89,16 +81,19 @@ Unleash started on http://localhost:4242 You can also require Unleash as a lib (recommended) and expand it with more options. Read more about this feature in the [getting started guide](./docs/getting-started.md). ### Securing Unleash + Unleash also have extension points where you can integrate Unleash with your authentication provider (OAuth 2.0). Read more about [securing unleash](./docs/securing-unleash.md). ## Run with docker + We have made a separate project which runs unleash inside docker. Please see [unleash-docker](https://github.com/Unleash/unleash-docker) # Developer Guide -If you want to contribute to this project you are encouraged to send issue request, or provide pull-requests. -Please read the [unleash developer guide](./docs/developer-guide.md) to learn more on how you can contribute. + +If you want to contribute to this project you are encouraged to send issue request, or provide pull-requests. Please read the [unleash developer guide](./docs/developer-guide.md) to learn more on how you can contribute. # I want to learn more + - [Blog: Unleash your features gradually!](http://bytes.schibsted.com/unleash-features-gradually/) - [Presentation: Unleash your features gradually!](http://ivarconr.github.io/feature-toggles-presentation/sch-dev-lunch-2017/#1) - http://martinfowler.com/bliki/FeatureToggle.html diff --git a/app.json b/app.json index 5745107802..e44ee0260f 100644 --- a/app.json +++ b/app.json @@ -1,15 +1,15 @@ { - "name": "Unleash", - "description": "A default setup of Unleash", - "repository": "https://github.com/heroku/node-js-sample", - "logo": "https://github.com/Unleash/unleash/blob/master/docs/assets/logo.png?raw=true", - "keywords": ["node", "feature toggles", "release"], - "addons": [ - { - "plan": "heroku-postgresql", - "options": { - "version": "9.5" - } - } - ] -} \ No newline at end of file + "name": "Unleash", + "description": "A default setup of Unleash", + "repository": "https://github.com/heroku/node-js-sample", + "logo": "https://github.com/Unleash/unleash/blob/master/docs/assets/logo.png?raw=true", + "keywords": ["node", "feature toggles", "release"], + "addons": [ + { + "plan": "heroku-postgresql", + "options": { + "version": "9.5" + } + } + ] +} diff --git a/docs/activation-strategies.md b/docs/activation-strategies.md index d3bea98178..6a75664b6f 100644 --- a/docs/activation-strategies.md +++ b/docs/activation-strategies.md @@ -3,67 +3,66 @@ id: activation_strategy title: Activation Strategies --- - It is powerful to be able to turn a feature on and off instantaneously, without redeploying the application. The next level of control comes when you are able to enable a feature for specific users or enable it for a small subset of the users. We achieve this level of control with the help of activation strategies. The most simple strategy is the “default” strategy, which basically means that the feature should be enabled to everyone. -The definition of an activation strategy lives in the Unleash API and can be created via the Unleash UI. The implementation of activation strategies lives in the various client implementations. +The definition of an activation strategy lives in the Unleash API and can be created via the Unleash UI. The implementation of activation strategies lives in the various client implementations. -Unleash comes with a few common activation strategies. Some of them require the client to provide the [unleash-context](./unleash-context.md), which gives necessary context for unleash. +Unleash comes with a few common activation strategies. Some of them require the client to provide the [unleash-context](./unleash-context.md), which gives necessary context for unleash. ## default + It is the simplest activation strategy and basically means "active for everyone". ## userWithId + Active for users with a userId defined in the userIds-list. Typically I want to enable a new feature only for myself in production, before I enable it for everyone else. To achieve this we can use the “UserWithIdStrategy”. This strategy allows you to specify a list of user ids that you want to expose the new feature for. (A user id may of course be an email if that is more appropriate in your system.) **Parameters** -- userIds - *List of user ids you want the feature toggle be enabled for* + +- userIds - _List of user ids you want the feature toggle be enabled for_ ## gradualRolloutUserId -Gradually activates feature toggle for logged in users. Stickiness based on the user id. -This strategy guarantees that the same user gets the same experience every time, -across devices. It also guarantees that a user which is among the first 10% will -also be among the first 20% of the users. Thus we ensure that users get the same -experience. Even if we gradually increase the number of users who are exposed to -a particular feature. To achieve this we hash the user id and normalise the hash -value to a number between 1 and 100 with a simple modulo operator. + +Gradually activates feature toggle for logged in users. Stickiness based on the user id. This strategy guarantees that the same user gets the same experience every time, across devices. It also guarantees that a user which is among the first 10% will also be among the first 20% of the users. Thus we ensure that users get the same experience. Even if we gradually increase the number of users who are exposed to a particular feature. To achieve this we hash the user id and normalise the hash value to a number between 1 and 100 with a simple modulo operator. ![hash_and_normalise](assets/hash_and_normalise.png) -Starting from v3.x all clients should use the 32-bit [MurmurHash3](https://en.wikipedia.org/wiki/MurmurHash) algorithm to normalize values. -([issue 247](https://github.com/Unleash/unleash/issues/247)) +Starting from v3.x all clients should use the 32-bit [MurmurHash3](https://en.wikipedia.org/wiki/MurmurHash) algorithm to normalize values. ([issue 247](https://github.com/Unleash/unleash/issues/247)) **Parameters** -- percentage - *The percentage (0-100) you want to enable the feature toggle for.* -- groupId - *Used to define an activation group, which allows you to correlate rollout across feature toggles.* + +- percentage - _The percentage (0-100) you want to enable the feature toggle for._ +- groupId - _Used to define an activation group, which allows you to correlate rollout across feature toggles._ ## gradualRolloutSessionId -Gradually activates feature toggle. Stickiness based on session id. It is almost -identical to the `gradualRolloutUserId` strategy, with the exception that it works -on session ids. This makes it possible to target all users (not just logged in -users), guaranteeing that a user will get the same experience within a session. + +Gradually activates feature toggle. Stickiness based on session id. It is almost identical to the `gradualRolloutUserId` strategy, with the exception that it works on session ids. This makes it possible to target all users (not just logged in users), guaranteeing that a user will get the same experience within a session. **Parameters** -- percentage - *The percentage (0-100) you want to enable the feature toggle for.* -- groupId - *Used to define an activation group, which allows you to correlate rollout across feature toggles.* -## gradualRolloutRandom -Randomly activates the feature toggle. No stickiness. We have found this rollout strategy -very useful in some scenarios, especially when we enable a feature which is not -visible to the user. It is also the strategy we use to sample metrics and error reports. +- percentage - _The percentage (0-100) you want to enable the feature toggle for._ +- groupId - _Used to define an activation group, which allows you to correlate rollout across feature toggles._ + +## gradualRolloutRandom + +Randomly activates the feature toggle. No stickiness. We have found this rollout strategy very useful in some scenarios, especially when we enable a feature which is not visible to the user. It is also the strategy we use to sample metrics and error reports. **Parameters** -- percentage - *The percentage (0-100) you want to enable the feature toggle for.* + +- percentage - _The percentage (0-100) you want to enable the feature toggle for._ ## remoteAddress -Active for remote addresses defined in the IPs list. We sometimes use this strategy to -enable a feature only for IP's in our office network. + +Active for remote addresses defined in the IPs list. We sometimes use this strategy to enable a feature only for IP's in our office network. **Parameters** -- IPS - *List of IPs to enable the feature for.* + +- IPS - _List of IPs to enable the feature for._ ## applicationHostname + Active for client instances with a hostName in the hostNames-list. **Parameters** -- hostNames - *List of hostnames to enable the feature toggle for.* + +- hostNames - _List of hostnames to enable the feature toggle for._ diff --git a/docs/api/admin/events-api.md b/docs/api/admin/events-api.md index 48f12cd014..4742d65c94 100644 --- a/docs/api/admin/events-api.md +++ b/docs/api/admin/events-api.md @@ -20,26 +20,24 @@ Defined event types: **Response** - ```json +```json { - "version": 1, - "events":[ - { - "id":454, - "type":"feature-updated", - "createdBy":"unknown", - "createdAt":"2016-08-24T11:22:01.354Z", - "data": { - "name":"eid.bankid.mobile", - "description":"", - "strategy":"default", - "enabled":true, - "parameters":{} - }, - "diffs": [ - {"kind":"E","path":["enabled"],"lhs":false,"rhs":true} - ] - } - ] + "version": 1, + "events": [ + { + "id": 454, + "type": "feature-updated", + "createdBy": "unknown", + "createdAt": "2016-08-24T11:22:01.354Z", + "data": { + "name": "eid.bankid.mobile", + "description": "", + "strategy": "default", + "enabled": true, + "parameters": {} + }, + "diffs": [{ "kind": "E", "path": ["enabled"], "lhs": false, "rhs": true }] + } + ] } ``` diff --git a/docs/api/admin/feature-toggles-api.md b/docs/api/admin/feature-toggles-api.md index cc4f6e5474..1334c2fe19 100644 --- a/docs/api/admin/feature-toggles-api.md +++ b/docs/api/admin/feature-toggles-api.md @@ -7,12 +7,10 @@ title: /api/admin/features `GET: http://unleash.host.com/api/admin/features` -This endpoint is the one all admin ui should use to fetch all available feature toggles -from the _unleash-server_. The response returns all active feature toggles and their -current strategy configuration. A feature toggle will have _at least_ one configured strategy. -A strategy will have a `name` and `parameters` map. +This endpoint is the one all admin ui should use to fetch all available feature toggles from the _unleash-server_. The response returns all active feature toggles and their current strategy configuration. A feature toggle will have _at least_ one configured strategy. A strategy will have a `name` and `parameters` map. **Example response:** + ```json { "version": 2, @@ -53,8 +51,7 @@ A strategy will have a `name` and `parameters` map. `GET: http://unleash.host.com/api/admin/features/:featureName` -Used to fetch details about a specific featureToggle. This is mostly provded to make it easy to -debug the API and should not be used by the client implementations. +Used to fetch details about a specific featureToggle. This is mostly provded to make it easy to debug the API and should not be used by the client implementations. ```json { @@ -70,13 +67,13 @@ debug the API and should not be used by the client implementations. } ``` - ### Create a new Feature Toggle `POST: http://unleash.host.com/api/admin/features/` **Body:** - ```json + +```json { "name": "Feature.A", "description": "lorem ipsum..", @@ -90,17 +87,17 @@ debug the API and should not be used by the client implementations. } ``` -Used by the admin-dashboard to create a new feature toggles. The name **must be unique**, -otherwise you will get a _403-response_. +Used by the admin-dashboard to create a new feature toggles. The name **must be unique**, otherwise you will get a _403-response_. -Returns 200-respose if the feature toggle was created successfully. +Returns 200-respose if the feature toggle was created successfully. ### Update a Feature Toggle `PUT: http://unleash.host.com/api/admin/features/:toggleName` **Body:** - ```json + +```json { "name": "Feature.A", "description": "lorem ipsum..", @@ -114,18 +111,15 @@ Returns 200-respose if the feature toggle was created successfully. } ``` -Used by the admin dashboard to update a feature toggles. The name has to match an -existing features toggle. +Used by the admin dashboard to update a feature toggles. The name has to match an existing features toggle. -Returns 200-respose if the feature toggle was updated successfully. +Returns 200-respose if the feature toggle was updated successfully. ### Archive a Feature Toggle `DELETE: http://unleash.host.com/api/admin/features/:toggleName` -Used to archive a feature toggle. A feature toggle can never be totally be deleted, -but can be archived. This is a design decision to make sure that a old feature -toggle suddenly reappears becuase someone else re-using the same name. +Used to archive a feature toggle. A feature toggle can never be totally be deleted, but can be archived. This is a design decision to make sure that a old feature toggle suddenly reappears becuase someone else re-using the same name. ## Archive @@ -136,6 +130,7 @@ toggle suddenly reappears becuase someone else re-using the same name. Used to fetch list of archived feature toggles **Example response:** + ```json { "version": 1, @@ -162,10 +157,11 @@ Used to fetch list of archived feature toggles `POST http://unleash.host.com/api/admin/archive/revive` **Body:** - ```json + +```json { "name": "Feature.A" } ``` -Used to revive a feature toggle. +Used to revive a feature toggle. diff --git a/docs/api/admin/metrics-api.md b/docs/api/admin/metrics-api.md index feca5bbcfc..a904141f36 100644 --- a/docs/api/admin/metrics-api.md +++ b/docs/api/admin/metrics-api.md @@ -5,36 +5,24 @@ title: /api/admin/metrics # This document describes the metrics endpoint for admin ui - ### Seen-toggles `GET http://unleash.host.com/api/admin/seen-toggles` -This enpoints returns a list of applications and what toogles -unleash has seend for each application. It will only guarantee -toggles reported by client applications within the last hour, but -will in most cases remember seen-toggles for applications longer +This enpoints returns a list of applications and what toogles unleash has seend for each application. It will only guarantee toggles reported by client applications within the last hour, but will in most cases remember seen-toggles for applications longer -**Example response:** +**Example response:** ```json [ { "appName": "demo-app", - "seenToggles": [ - "add-feature-2", - "toggle-2", - "toggle-3" - ], + "seenToggles": ["add-feature-2", "toggle-2", "toggle-3"], "metricsCount": 127 }, { "appName": "demo-app-2", - "seenToggles": [ - "add-feature-2", - "toggle-2", - "toggle-3" - ], + "seenToggles": ["add-feature-2", "toggle-2", "toggle-3"], "metricsCount": 21 } ] @@ -42,22 +30,17 @@ will in most cases remember seen-toggles for applications longer **Fields:** -* **appName** - Name of the application seen by unleash-server -* **seenToggles** - array of toggles names seen by unleash-server for this application -* **metricsCount** - number of metrics counted across all toggles for this application. - +- **appName** - Name of the application seen by unleash-server +- **seenToggles** - array of toggles names seen by unleash-server for this application +- **metricsCount** - number of metrics counted across all toggles for this application. ### Feature-Toggles metrics `GET http://unleash.host.com/api/admin/metrics/feature-toggles` -This endpoint gives _last minute_ and _last hour_ metrics for all active toggles. This is based on -metrics reported by client applications. Yes is the number of times a given feature toggle -was evaluated to enabled in a client applcation, and no is the number it avaluated to false. +This endpoint gives _last minute_ and _last hour_ metrics for all active toggles. This is based on metrics reported by client applications. Yes is the number of times a given feature toggle was evaluated to enabled in a client applcation, and no is the number it avaluated to false. - - -**Example response:** +**Example response:** ```json { @@ -94,28 +77,21 @@ was evaluated to enabled in a client applcation, and no is the number it avaluat **Fields:** -* **lastHour** - Hour projection collected metrics for all feature toggles. -* **lastMinute** - Mintue projection collected metrics for all feature toggles. - +- **lastHour** - Hour projection collected metrics for all feature toggles. +- **lastMinute** - Mintue projection collected metrics for all feature toggles. ### Applications -`GET http://unleash.host.com/api/admin/applications` - -This endpoint returns a list of known applications (seen the last two days) and -a link to follow for more datails. +`GET http://unleash.host.com/api/admin/applications` +This endpoint returns a list of known applications (seen the last two days) and a link to follow for more datails. ```json { "applications": [ { "appName": "another", - "strategies": [ - "default", - "other", - "brother" - ], + "strategies": ["default", "other", "brother"], "createdAt": "2016-12-09T14:56:36.730Z", "links": { "appDetails": "/api/admin/applications/another" @@ -123,11 +99,7 @@ a link to follow for more datails. }, { "appName": "bow", - "strategies": [ - "default", - "other", - "brother" - ], + "strategies": ["default", "other", "brother"], "createdAt": "2016-12-09T14:56:36.730Z", "links": { "appDetails": "/api/admin/applications/bow" @@ -138,23 +110,16 @@ a link to follow for more datails. ``` #### Query Params -You can also specify the query param: _strategyName_, which will return all applications -implementing the given strategy. - -`GET http://unleash.host.com/api/admin/applications?strategyName=someStrategyName` - +You can also specify the query param: _strategyName_, which will return all applications implementing the given strategy. +`GET http://unleash.host.com/api/admin/applications?strategyName=someStrategyName` ### Application Details -`GET http://unleash.host.com/api/admin/applications/:appName` - -This endpoint gives insight into details about a client applcation, such as instances, -strategies implemented and seen toogles. - - +`GET http://unleash.host.com/api/admin/applications/:appName` +This endpoint gives insight into details about a client applcation, such as instances, strategies implemented and seen toogles. ```json { @@ -171,32 +136,24 @@ strategies implemented and seen toogles. "clientIp": "::ffff:127.0.0.1", "lastSeen": "2016-11-30T16:04:15.991Z", "createdAt": "2016-11-30T10:49:11.223Z" - }, + } ], "strategies": [ { "appName": "demo-app", - "strategies": [ - "default", - "extra" - ] + "strategies": ["default", "extra"] } ], - "seenToggles": [ - "add-feature-2", - "toggle-2", - "toggle-3" - ] + "seenToggles": ["add-feature-2", "toggle-2", "toggle-3"] } ``` ### Seen applications -`GET http://unleash.host.com/api/admin/seen-apps` +`GET http://unleash.host.com/api/admin/seen-apps` This endpoint gives insight into details about application seen per feature toggle. - ```json { "my-toggle": [ @@ -225,9 +182,7 @@ This endpoint gives insight into details about application seen per feature togg "createdAt": "2016-12-28T10:39:24.966Z", "updatedAt": "2017-01-06T15:32:41.932Z", "description": "our other app", - "strategies": [ - "default", - ], + "strategies": ["default"], "url": "http://example.com", "color": null, "icon": "desktop" diff --git a/docs/api/admin/strategies-api.md b/docs/api/admin/strategies-api.md index 0e4f17b432..c95617a0a6 100644 --- a/docs/api/admin/strategies-api.md +++ b/docs/api/admin/strategies-api.md @@ -3,53 +3,55 @@ id: strategies title: /api/admin/strategies --- -### Fetch Strategies +### Fetch Strategies + `GET: http://unleash.host.com/api/admin/strategies` -Used to fetch all defined strategies and their defined paramters. +Used to fetch all defined strategies and their defined paramters. **Response** - ```json +```json { - "version": 1, - "strategies": [ + "version": 1, + "strategies": [ + { + "name": "default", + "description": "Default on/off strategy.", + "parameters": [] + }, + { + "name": "userWithId", + "description": "Active for userId specified in the comma seperated 'userIds' parameter.", + "parameters": [ { - "name": "default", - "description": "Default on/off strategy.", - "parameters": [] + "name": "userIds", + "type": "list", + "description": "List of unique userIds the feature should be active for.", + "required": true + } + ] + }, + { + "name": "gradualRollout", + "description": "Gradual rollout to logged in users", + "parameters": [ + { + "name": "percentage", + "type": "percentage", + "description": "How many percent should the new feature be active for.", + "required": false }, { - "name": "userWithId", - "description": "Active for userId specified in the comma seperated 'userIds' parameter.", - "parameters": [ - { - "name": "userIds", - "type": "list", - "description": "List of unique userIds the feature should be active for.", - "required": true - } - ] - }, - { - "name": "gradualRollout", - "description": "Gradual rollout to logged in users", - "parameters": [ - { - "name": "percentage", - "type": "percentage", - "description": "How many percent should the new feature be active for.", - "required": false - }, - { - "name": "group", - "type": "string", - "description": "Group key to use when hasing the userId. Makes sure that the same user get different value for different groups", - "required": false - } - ] - }, - ]} + "name": "group", + "type": "string", + "description": "Group key to use when hasing the userId. Makes sure that the same user get different value for different groups", + "required": false + } + ] + } + ] +} ``` ### Create strategy @@ -79,8 +81,7 @@ Used to fetch all defined strategies and their defined paramters. }, ``` -Used to create a new Strategy. Name is required and must be unique. It is also required to have a parameters array, but it can be empty. - +Used to create a new Strategy. Name is required and must be unique. It is also required to have a parameters array, but it can be empty. ### Update strategy @@ -109,5 +110,4 @@ Used to create a new Strategy. Name is required and must be unique. It is also r }, ``` -Used to update a Strategy definition. Name can't be changed. -**PS! I can be dangerous to change a implemnted strategy as the implementation also might need to be changed** +Used to update a Strategy definition. Name can't be changed. **PS! I can be dangerous to change a implemnted strategy as the implementation also might need to be changed** diff --git a/docs/api/client/feature-toggles-api.md b/docs/api/client/feature-toggles-api.md index b92db8068c..d61e6407d4 100644 --- a/docs/api/client/feature-toggles-api.md +++ b/docs/api/client/feature-toggles-api.md @@ -9,23 +9,17 @@ title: /api/client/features **HEADERS:** -* UNLEASH-APPNAME: appName -* UNLEASH-INSTANCEID: instanceId +- UNLEASH-APPNAME: appName +- UNLEASH-INSTANCEID: instanceId -This endpoint is the one all clients should use to fetch all available feature toggles -from the _unleash-server_. The response returns all active feature toggles and their -current strategy configuration. A feature toggle will have _at least_ one configured strategy. -A strategy will have a `name` and `parameters` map. +This endpoint is the one all clients should use to fetch all available feature toggles from the _unleash-server_. The response returns all active feature toggles and their current strategy configuration. A feature toggle will have _at least_ one configured strategy. A strategy will have a `name` and `parameters` map. -> _Note:_ Clients should prefer the `strategies` property. -> Legacy properties (`strategy` & `parameters`) will be kept until **version 2** of the format. +> _Note:_ Clients should prefer the `strategies` property. Legacy properties (`strategy` & `parameters`) will be kept until **version 2** of the format. -This endpoint should never return anything besides a valid *20X or 304-response*. It will also -include an `Etag`-header. The value of this header can be used by clients as the value of -the `If-None-Match`-header in the request to prevent a data transfer if the client already -has the latest response locally. +This endpoint should never return anything besides a valid _20X or 304-response_. It will also include an `Etag`-header. The value of this header can be used by clients as the value of the `If-None-Match`-header in the request to prevent a data transfer if the client already has the latest response locally. **Example response:** + ```json { "version": 1, @@ -70,15 +64,13 @@ has the latest response locally. } ``` -You may limit the response by sending a `namePrefix` query-parameter. - +You may limit the response by sending a `namePrefix` query-parameter. `GET: http://unleash.host.com/api/client/features/:featureName` -Used to fetch details about a specific feature toggle. This is mainly provided to make it easy to -debug the API and should not be used by the client implementations. +Used to fetch details about a specific feature toggle. This is mainly provided to make it easy to debug the API and should not be used by the client implementations. -> _Notice_: You will not get a version property when fetching a specific feature toggle by name. +> _Notice_: You will not get a version property when fetching a specific feature toggle by name. ```json { diff --git a/docs/api/client/metrics-api.md b/docs/api/client/metrics-api.md index 5027859977..ef43012151 100644 --- a/docs/api/client/metrics-api.md +++ b/docs/api/client/metrics-api.md @@ -7,25 +7,25 @@ title: /api/client/metrics `POST: http://unleash.host.com/api/client/metrics` -Register a metrics payload with a timed bucket. +Register a metrics payload with a timed bucket. ```json { - "appName": "appName", - "instanceId": "instanceId", - "bucket": { - "start": "2016-11-03T07:16:43.572Z", - "stop": "2016-11-03T07:16:53.572Z", - "toggles": { - "toggle-name-1": { - "yes": 123, - "no": 321 - }, - "toggle-name-2": { - "yes": 111, - "no": 0 - } - } + "appName": "appName", + "instanceId": "instanceId", + "bucket": { + "start": "2016-11-03T07:16:43.572Z", + "stop": "2016-11-03T07:16:53.572Z", + "toggles": { + "toggle-name-1": { + "yes": 123, + "no": 321 + }, + "toggle-name-2": { + "yes": 111, + "no": 0 + } } + } } ``` diff --git a/docs/api/client/register-api.md b/docs/api/client/register-api.md index 4ef26ffeef..ece3f1594c 100644 --- a/docs/api/client/register-api.md +++ b/docs/api/client/register-api.md @@ -7,25 +7,24 @@ title: /api/client/register `POST: http://unleash.host.com/api/client/register` -Registers a client instance with the unleash server. The client should send all fields specified. +Registers a client instance with the unleash server. The client should send all fields specified. ```json { - "appName": "appName", - "instanceId": "instanceId", - "sdkVersion": "unleash-client-java:2.2.0", - "strategies": ["default", "some-strategy-1"], - "started": "2016-11-03T07:16:43.572Z", - "interval": 10000 + "appName": "appName", + "instanceId": "instanceId", + "sdkVersion": "unleash-client-java:2.2.0", + "strategies": ["default", "some-strategy-1"], + "started": "2016-11-03T07:16:43.572Z", + "interval": 10000 } ``` - **Fields:** -* **appName** - Name of the application seen by unleash-server -* **instanceId** - Instance id for this application (typically hostname, podId or similar) -* **sdkVersion** - Optional field that describes the sdk version (name:version) -* **strategies** - List of strategies implemented by this application -* **started** - When this client started. Should be reported as [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) time. -* **interval** - At which interval, in milliseconds, will this client be expected to send metrics +- **appName** - Name of the application seen by unleash-server +- **instanceId** - Instance id for this application (typically hostname, podId or similar) +- **sdkVersion** - Optional field that describes the sdk version (name:version) +- **strategies** - List of strategies implemented by this application +- **started** - When this client started. Should be reported as [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) time. +- **interval** - At which interval, in milliseconds, will this client be expected to send metrics diff --git a/docs/api/index.md b/docs/api/index.md index 306d7e579e..e69dc3b770 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -4,19 +4,22 @@ title: API Documentation --- ## Client API -This describes the API provided to unleash-clients. -* [Feature Toggles API](client/feature-toggles-api.md) -* [Register API](client/register-api.md) -* [Metrics API](client/metrics-api.md) +This describes the API provided to unleash-clients. + +- [Feature Toggles API](client/feature-toggles-api.md) +- [Register API](client/register-api.md) +- [Metrics API](client/metrics-api.md) ## Admin API (internal) + The internal API used by the Admin UI (unleash-frontend): -* [Feature Toggles API](admin/feature-toggles-api.md) -* [Strategies API](admin/strategies-api.md) -* [Events API](admin/events-api.md) -* [Metrics API](admin/metrics-api.md) +- [Feature Toggles API](admin/feature-toggles-api.md) +- [Strategies API](admin/strategies-api.md) +- [Events API](admin/events-api.md) +- [Metrics API](admin/metrics-api.md) ## System API's -* [Internal Backstage API](internal-backstage-api.md) + +- [Internal Backstage API](internal-backstage-api.md) diff --git a/docs/api/internal-backstage-api.md b/docs/api/internal-backstage-api.md index 2d8b57974f..7f4ae8184a 100644 --- a/docs/api/internal-backstage-api.md +++ b/docs/api/internal-backstage-api.md @@ -7,18 +7,16 @@ title: /internal-backstage/prometheus `GET http://unleash.host.com/internal-backstage/prometheus` -Unleash uses prometheus internally to collect metrics. These are -available on the given url if the `serverMetrics` option is enabled (default=true). +Unleash uses prometheus internally to collect metrics. These are available on the given url if the `serverMetrics` option is enabled (default=true). -[Read more about Prometheus](https://prometheus.io/) +[Read more about Prometheus](https://prometheus.io/) ## Annotations -Unleash will automatically count all updates for all toggles under the metric name `feature_toggle_update_total`, and the toggle name is will be set as a label value. This information can be used to create annotations in grafana for everytime a feature toggle is changed. +Unleash will automatically count all updates for all toggles under the metric name `feature_toggle_update_total`, and the toggle name is will be set as a label value. This information can be used to create annotations in grafana for everytime a feature toggle is changed. You can use this query in grafana to achive this: ``` delta(feature_toggle_update_total{toggle="Demo"}[1m]) != bool 0? ``` - diff --git a/docs/client-specification.md b/docs/client-specification.md index 67831b1e75..b4e69b4817 100644 --- a/docs/client-specification.md +++ b/docs/client-specification.md @@ -3,137 +3,115 @@ id: client_specification title: Client Specification --- - # Client Specification 1.0 -This document attempts to guide developers in implementing a Unleash Client SDK. +This document attempts to guide developers in implementing a Unleash Client SDK. ## System Overview + Unleash is comprised of three parts: - **Unleash API** - The service holding all feature toggles and their configurations. Configurations declare which activation strategies to use and which parameters they should get. - **Unleash UI** - The dashboard used to manage feature toggles, define new strategies, look at metrics, etc. - **Unleash SDK** - Used by clients to check if a feature is enabled or disabled. The SDK also collects metrics and sends them to the Unleash API. Activation Strategies are also implemented in the SDK. Unleash currently provides official SDKs for Java and Node.js -![system_overview](https://raw.githubusercontent.com/Unleash/unleash/master/docs/assets/unleash-diagram.png "System Overview") +![system_overview](https://raw.githubusercontent.com/Unleash/unleash/master/docs/assets/unleash-diagram.png 'System Overview') In order to be super fast, the client SDK caches all feature toggles and their current configuration in memory. The activation strategies are also implemented in the SDK. This makes it really fast to check if a toggle is on or off because it is just a simple function operating on local state, without the need to poll data from the database. ## The Basics -All client implementations should strive to have a simple and consistent user API. -It should be a simple method, called isEnabled, to check if a feature toggle is enabled -or not. The method should return a `boolean` value, true or false. + +All client implementations should strive to have a simple and consistent user API. It should be a simple method, called isEnabled, to check if a feature toggle is enabled or not. The method should return a `boolean` value, true or false. ```javascript -unleash.isEnabled("myAwesomeToggle") +unleash.isEnabled('myAwesomeToggle'); ``` -The basic `isEnabled` method should also accept a default value. This should be used if -the client does not know anything about that that toggle name. If the user does not specify -a default value, false should be returned for unknown feature toggles. +The basic `isEnabled` method should also accept a default value. This should be used if the client does not know anything about that that toggle name. If the user does not specify a default value, false should be returned for unknown feature toggles. **Calling unleash with default value:** -```javascript +```javascript boolean value = unleash.isEnabled("unknownFeatureToggle", false); -//value==false because default value was used. +//value==false because default value was used. ``` - - ### Implementation of isEnabled -A feature toggle is defined as: + +A feature toggle is defined as: ```json { - "name": "Feature.B", - "description": "lorem ipsum", - "enabled": true, - "strategies": [ - { - "name": "ActiveForUserWithId", - "parameters": { - "userIdList": "123,221,998" - } - }, - { - "name": "GradualRolloutRandom", - "parameters": { - "percentage": "10" - } - } - ], - "strategy": "ActiveForUserWithId", + "name": "Feature.B", + "description": "lorem ipsum", + "enabled": true, + "strategies": [ + { + "name": "ActiveForUserWithId", "parameters": { "userIdList": "123,221,998" } + }, + { + "name": "GradualRolloutRandom", + "parameters": { + "percentage": "10" + } } + ], + "strategy": "ActiveForUserWithId", + "parameters": { + "userIdList": "123,221,998" + } +} ``` A simple demo of the isEnable function in JavaScript-style (most implementation will probably be more functional): ```javascript function isEnabled(name, unleashContext = {}, defaultValue = false) { - const toggle = toggleRepository.get(name); - let enabled = false; - - if ( !toggle ) { - return defaultValue; - } else if ( ! toggle.isEnabled) { - return false; - } else { - for(let i=0;i npm run db-migrate -- create YOUR-MIGRATION-NAME ``` -All migrations require one `up` and one `down` method. +All migrations require one `up` and one `down` method. Example of a typical migration: @@ -76,17 +75,21 @@ Example of a typical migration: /* eslint camelcase: "off" */ 'use strict'; -exports.up = function (db, cb) { - db.createTable('examples', { - id: { type: 'int', primaryKey: true, notNull: true }, - created_at: { type: 'timestamp', defaultValue: 'now()' }, - }, cb); +exports.up = function(db, cb) { + db.createTable( + 'examples', + { + id: { type: 'int', primaryKey: true, notNull: true }, + created_at: { type: 'timestamp', defaultValue: 'now()' }, + }, + cb, + ); }; -exports.down = function (db, cb) { - return db.dropTable('examples', cb); +exports.down = function(db, cb) { + return db.dropTable('examples', cb); }; -``` +``` Test your migrations: @@ -95,11 +98,10 @@ Test your migrations: > npm run db-migrate -- down ``` - ## Publishing / Releasing new packages Please run `npm run nsp` nad `npm run test` checks before publishing. Run `npm run publish` to start the publishing process. -`npm run publish:dry` +`npm run publish:dry` diff --git a/docs/getting-started.md b/docs/getting-started.md index 6fa1efc5c5..c1344577cd 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -5,14 +5,14 @@ title: Getting Started ## Requirements -You will need Node.js >= 8.0.0 and a __PostreSQL__ 9.5+ database instance to be able to run Unleash. +You will need Node.js >= 8.0.0 and a **PostreSQL** 9.5+ database instance to be able to run Unleash. -When starting Unleash you must specify a database uri (can be set as environment variable DATABASE_URL) -which includes a username and password, that have rights to migrate the database. +When starting Unleash you must specify a database uri (can be set as environment variable DATABASE_URL) which includes a username and password, that have rights to migrate the database. On startup _Unleash_ will perform necessary migrations if needed. -## Start Unleash +## Start Unleash + ### 1. The simplest way to get started: ```bash @@ -23,34 +23,40 @@ Unleash started on http://localhost:4242 ``` ### 2. Or programmatically: + You can also depend on unleash ```js const unleash = require('unleash-server'); -unleash.start({ - databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash', - port: 4242 -}).then(unleash => { - console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`); -}); +unleash + .start({ + databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash', + port: 4242, + }) + .then(unleash => { + console.log( + `Unleash started on http://localhost:${unleash.app.get('port')}`, + ); + }); ``` Available unleash options includes: -- **databaseUrl** - the postgress database url to connect to. Should include username/password. +- **databaseUrl** - the postgress database url to connect to. Should include username/password. - **port** - Which port should the unleash-server bind to? - **enableLegacyRoutes** (boolean) - allows you to turn on/off support for legacy routes to support older clients. Enabled by default. -- **serverMetrics** (boolean) - Use this option to turn off prometheus metrics. -- **preHook** (function) - This is a hook if you need to provide any middlewares to express before `unleash` adds any. Express app instance is injected as first arguement. -- **preRouterHook** (function) - Use this to register custom express middlewares before the `unleash` specific routers are added. This is typically how you would register custom middlewares to handle authentication. -- **secret** (string) - Set this when you want to secure unleash. Used to encrypt the user session. +- **serverMetrics** (boolean) - Use this option to turn off prometheus metrics. +- **preHook** (function) - This is a hook if you need to provide any middlewares to express before `unleash` adds any. Express app instance is injected as first arguement. +- **preRouterHook** (function) - Use this to register custom express middlewares before the `unleash` specific routers are added. This is typically how you would register custom middlewares to handle authentication. +- **secret** (string) - Set this when you want to secure unleash. Used to encrypt the user session. - **adminAuthentication** (string) - Use this when implementing custom admin authentication [securing-unleash](./securing-unleash.md). Possible values are: - `none` - Will disable authentication altogether - - `unsecure` - (default) Will use simple cookie based authentication. UI will require the user to specify an email in order to use unleash. - - `custom` - Use this when you implement your own custom authentication logic. + - `unsecure` - (default) Will use simple cookie based authentication. UI will require the user to specify an email in order to use unleash. + - `custom` - Use this when you implement your own custom authentication logic. ### 3. Docker + You can also use the [hosted docker image](https://hub.docker.com/r/unleashorg/unleash-server/) to start the Unleash server ```sh @@ -58,36 +64,36 @@ docker run -d -e DATABASE_URL=postgres://user:pass@10.200.221.11:5432/unleash un ``` ## How do I configure the log output? - + By default, `unleash` uses [log4js](https://github.com/nomiddlename/log4js-node) to log important information. It is possible to swap out the logger provider (only when using Unleash programmatically). This enables filtering of log levels and easy redirection of output streams. - + ### What is a logger provider? - + A logger provider is a function which takes the name of a logger and returns a logger implementation. For instance, the following code snippet shows how a logger provider for the global `console` object could be written: - + ```javascript -function consoleLoggerProvider (name) { +function consoleLoggerProvider(name) { // do something with the name return { debug: console.log, info: console.log, warn: console.log, - error: console.error + error: console.error, }; } ``` - + The logger interface with its `debug`, `info`, `warn` and `error` methods expects format string support as seen in `debug` or the JavaScript `console` object. Many commonly used logging implementations cover this API, e.g. bunyan, pino or winston. - + ### How do I set a logger provider? - -Custom logger providers need to be set *before requiring the `unleash-server` module*. The following example shows how this can be done: - + +Custom logger providers need to be set _before requiring the `unleash-server` module_. The following example shows how this can be done: + ```javascript // first configure the logger provider const unleashLogger = require('unleash-server/logger'); unleashLogger.setLoggerProvider(consoleLoggerProvider); - + // then require unleash-server and continue as normal const unleash = require('unleash-server'); ``` diff --git a/docs/guides/google-auth-hook.md b/docs/guides/google-auth-hook.md index a1a19445a2..841cc6ee50 100644 --- a/docs/guides/google-auth-hook.md +++ b/docs/guides/google-auth-hook.md @@ -6,6 +6,7 @@ title: Google Auth Hook This part of the tutorial shows how to create a sign-in flow for users and integrate with Unleash server project. The implementation assumes that I am working in `localhost` with `4242` port. This is a simple `index.js` server file. + ```javascript const unleash = require('unleash-server'); @@ -15,7 +16,7 @@ if (process.env.DATABASE_URL_FILE) { unleash.start(options).then(unleash => { console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`); -});; +}); ``` ### Creating a web application client ID @@ -31,6 +32,7 @@ unleash.start(options).then(unleash => { 5. Type the **Name**. 6. Under **Authorized redirect URIs** enter the following URLs, one at a time. + ``` http://localhost:4242/api/auth/callback ``` @@ -39,58 +41,67 @@ http://localhost:4242/api/auth/callback 8. Copy the **CLIENT ID** and **CLIENT SECRET** and save them for later use. - ### Add dependencies -Add two dependencies [`passport`](https://www.npmjs.com/package/passport) and [`passport-google-oauth20`](https://www.npmjs.com/package/passport-google-oauth20) inside `index.js` file +Add two dependencies [`passport`](https://www.npmjs.com/package/passport) and [`passport-google-oauth20`](https://www.npmjs.com/package/passport-google-oauth20) inside `index.js` file + ```js const unleash = require('unleash-server'); const passport = require('passport'); const GoogleStrategy = require('passport-google-oauth20').Strategy; ``` + ### Configure the Google strategy for use by Passport.js OAuth 2-based strategies require a `verify` function which receives the credential (`accessToken`) for accessing the Google API on the user's behalf, along with the user's profile. The function must invoke `cb` with a user object, which will be set at `req.user` in route handlers after authentication. + ```js const GOOGLE_CLIENT_ID = '...'; const GOOGLE_CLIENT_SECRET = '...'; const GOOGLE_CALLBACK_URL = 'http://localhost:4242/api/auth/callback'; -passport.use(new GoogleStrategy( - { - clientID: GOOGLE_CLIENT_ID, - clientSecret: GOOGLE_CLIENT_SECRET, - callbackURL: GOOGLE_CALLBACK_URL - }, - function(accessToken, refreshToken, profile, cb) { - // Extract the minimal profile information we need from the profile object - // and connect with Unleash to get name and email. - cb(null, new unleash.User({ - name: profile.displayName, - email: profile.emails[0].value, - })); - } -)); +passport.use( + new GoogleStrategy( + { + clientID: GOOGLE_CLIENT_ID, + clientSecret: GOOGLE_CLIENT_SECRET, + callbackURL: GOOGLE_CALLBACK_URL, + }, + function(accessToken, refreshToken, profile, cb) { + // Extract the minimal profile information we need from the profile object + // and connect with Unleash to get name and email. + cb( + null, + new unleash.User({ + name: profile.displayName, + email: profile.emails[0].value, + }), + ); + }, + ), +); ``` Add `googleAdminAuth()` function and other options + ```js function googleAdminAuth(app) {} let options = { enableLegacyRoutes: false, adminAuthentication: 'custom', - preRouterHook: googleAdminAuth + preRouterHook: googleAdminAuth, }; unleash.start(options).then(unleash => { console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`); -});; +}); ``` ### In `googleAdminAuth` function Configure `passport` package. + ```js function googleAdminAuth(app) { app.use(passport.initialize()); @@ -102,32 +113,39 @@ function googleAdminAuth(app) { ``` Implement a preRouter hook for `/api/admin/login`. It's neccesary for login with Google. + ```js function googleAdminAuth(app) { // ... - app.get('/api/admin/login', passport.authenticate('google', { scope: ['profile', 'email'] })); + app.get( + '/api/admin/login', + passport.authenticate('google', { scope: ['profile', 'email'] }), + ); // ... } ``` Implement a preRouter hook for `/api/auth/callback`. It's a callback when the login is executed. + ```js function googleAdminAuth(app) { // ... - app.get('/api/auth/callback', + app.get( + '/api/auth/callback', passport.authenticate('google', { failureRedirect: '/api/admin/error-login', }), (req, res) => { // Successful authentication, redirect to your app. res.redirect('/'); - } + }, ); // ... } ``` Implement a preRouter hook for `/api/admin`. + ```js function googleAdminAuth(app) { // ... @@ -143,8 +161,9 @@ function googleAdminAuth(app) { path: '/api/admin/login', type: 'custom', message: `You have to identify yourself in order to use Unleash. Click the button and follow the instructions.`, - }) - ).end(); + }), + ) + .end(); } }); // ... @@ -152,7 +171,9 @@ function googleAdminAuth(app) { ``` ### The complete code + The `index.js` server file. + ```js 'use strict'; @@ -164,19 +185,24 @@ const GOOGLE_CLIENT_ID = '...'; const GOOGLE_CLIENT_SECRET = '...'; const GOOGLE_CALLBACK_URL = 'http://localhost:4242/api/auth/callback'; -passport.use(new GoogleStrategy( - { - clientID: GOOGLE_CLIENT_ID, - clientSecret: GOOGLE_CLIENT_SECRET, - callbackURL: GOOGLE_CALLBACK_URL - }, - function(accessToken, refreshToken, profile, cb) { - cb(null, new unleash.User({ - name: profile.displayName, - email: profile.emails[0].value, - })); - } -)); +passport.use( + new GoogleStrategy( + { + clientID: GOOGLE_CLIENT_ID, + clientSecret: GOOGLE_CLIENT_SECRET, + callbackURL: GOOGLE_CALLBACK_URL, + }, + function(accessToken, refreshToken, profile, cb) { + cb( + null, + new unleash.User({ + name: profile.displayName, + email: profile.emails[0].value, + }), + ); + }, + ), +); function googleAdminAuth(app) { app.use(passport.initialize()); @@ -184,14 +210,18 @@ function googleAdminAuth(app) { passport.serializeUser((user, done) => done(null, user)); passport.deserializeUser((user, done) => done(null, user)); - app.get('/api/admin/login', passport.authenticate('google', { scope: ['profile', 'email'] })); - app.get('/api/auth/callback', + app.get( + '/api/admin/login', + passport.authenticate('google', { scope: ['profile', 'email'] }), + ); + app.get( + '/api/auth/callback', passport.authenticate('google', { failureRedirect: '/api/admin/error-login', }), (req, res) => { res.redirect('/'); - } + }, ); app.use('/api/admin/', (req, res, next) => { @@ -205,8 +235,9 @@ function googleAdminAuth(app) { path: '/api/admin/login', type: 'custom', message: `You have to identify yourself in order to use Unleash. Click the button and follow the instructions.`, - }) - ).end(); + }), + ) + .end(); } }); } @@ -214,7 +245,7 @@ function googleAdminAuth(app) { let options = { enableLegacyRoutes: false, adminAuthentication: 'custom', - preRouterHook: googleAdminAuth + preRouterHook: googleAdminAuth, }; if (process.env.DATABASE_URL_FILE) { @@ -223,5 +254,5 @@ if (process.env.DATABASE_URL_FILE) { unleash.start(options).then(unleash => { console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`); -});; +}); ``` diff --git a/docs/migration-guide.md b/docs/migration-guide.md index 0121cf5526..c4321cbdce 100644 --- a/docs/migration-guide.md +++ b/docs/migration-guide.md @@ -3,29 +3,31 @@ id: migration_guide title: Migration Guide --- -Generally the intention is that `unleash-server` should always provide support for clients one lower major version. This should make possible to upgrade `unleash` gradually. - +Generally the intention is that `unleash-server` should always provide support for clients one lower major version. This should make possible to upgrade `unleash` gradually. ## Upgrading from v2.x to v3.x -The notable change introduced in Unleash v3.x is a strict separation of api paths for client requests and admin requests. This makes it easier to implement different authentication mechanisms for the admin UI and all unleash-clients. You can read more about [securing unleash](https://github.com/Unleash/unleash/blob/master/docs/securing-unleash.md). -The recommended approach is to first upgrade the `unleash-server` to v3 (which still supports v2 clients). After this is done you should upgrade all your clients to v3. +The notable change introduced in Unleash v3.x is a strict separation of api paths for client requests and admin requests. This makes it easier to implement different authentication mechanisms for the admin UI and all unleash-clients. You can read more about [securing unleash](https://github.com/Unleash/unleash/blob/master/docs/securing-unleash.md). + +The recommended approach is to first upgrade the `unleash-server` to v3 (which still supports v2 clients). After this is done you should upgrade all your clients to v3. After upgrading all your clients you should consider turning off legacy routes, used by v2 clients. Read more about this option in in the [gettings started guide](https://github.com/Unleash/unleash/blob/master/docs/getting-started.md#2-or-programmatically). ## Upgrading from v1.0 to v2.0 ### Caveat 1: Not used db-migrate to migrate the unleash database? + In FINN we used, for internal reasons, liquebase to migrate our database. -Because unleash from version 2.0 migrates the database internally, with db-migrate, -you need to make sure that all previous migrations for version 1 exists, so unleash -does not try to create tables that already exists. +Because unleash from version 2.0 migrates the database internally, with db-migrate, you need to make sure that all previous migrations for version 1 exists, so unleash does not try to create tables that already exists. #### How to check? -If you don't have a "migrations" table with _7 unique migrations_ you are affected by this. + +If you don't have a "migrations" table with _7 unique migrations_ you are affected by this. #### How to fix? + Before starting unleash version 2 you have to run the SQL located under `scripts/fix-migrations-version-1.sql` ### Caveat 2: databaseUrl (not database*Uri*) -Using unleash as a lib and injecting your own config? Then you should know that we changed the databaseUri config param name to **databaseUrl**. This to align it with the environment variable (DATABASE_URL), avoiding multiple names for same config param. + +Using unleash as a lib and injecting your own config? Then you should know that we changed the databaseUri config param name to **databaseUrl**. This to align it with the environment variable (DATABASE_URL), avoiding multiple names for same config param. diff --git a/docs/securing-unleash.md b/docs/securing-unleash.md index f9ca33658d..90b59b4ce6 100644 --- a/docs/securing-unleash.md +++ b/docs/securing-unleash.md @@ -3,48 +3,53 @@ id: securing_unleash title: Securing Unleash --- -The Unleash API is split in two different paths: `/api/client` and `/api/admin`. -This makes it easy to have different authentication strategy for the admin interface and the client-api used by the applications integrating with Unleash. +The Unleash API is split in two different paths: `/api/client` and `/api/admin`. This makes it easy to have different authentication strategy for the admin interface and the client-api used by the applications integrating with Unleash. ## General settings -Unleash uses an encrypted cookie to maintain a user session. This allows users to be logged in across instances of Unleash. To protect this cookie you should specify the `secret` option when starting unleash.- + +Unleash uses an encrypted cookie to maintain a user session. This allows users to be logged in across instances of Unleash. To protect this cookie you should specify the `secret` option when starting unleash.- ## Securing the Admin API -In order to secure the Admin API you have to tell Unleash that you are using a custom admin authentication and implement your authentication logic as a preHook. You should also set the secret option to a protected secret in your system. + +In order to secure the Admin API you have to tell Unleash that you are using a custom admin authentication and implement your authentication logic as a preHook. You should also set the secret option to a protected secret in your system. ```javascript const unleash = require('unleash-server'); const myCustomAdminAuth = require('./auth-hook'); -unleash.start({ - databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash', - secret: 'super-duper-secret', - adminAuthentication: 'custom', - preRouterHook: myCustomAdminAuth -}).then(unleash => { - console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`); -}); +unleash + .start({ + databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash', + secret: 'super-duper-secret', + adminAuthentication: 'custom', + preRouterHook: myCustomAdminAuth, + }) + .then(unleash => { + console.log( + `Unleash started on http://localhost:${unleash.app.get('port')}`, + ); + }); ``` -Additionally, you can trigger the admin interface to prompt the user to sign in by configuring your middleware to return a `401` status on -protected routes. The response body must contain a `message` and a `path` used to redirect the user to the proper login route. +Additionally, you can trigger the admin interface to prompt the user to sign in by configuring your middleware to return a `401` status on protected routes. The response body must contain a `message` and a `path` used to redirect the user to the proper login route. ```json { - "message": "You must be logged in to use Unleash", - "path": "/custom/login" + "message": "You must be logged in to use Unleash", + "path": "/custom/login" } ``` Examples on custom authentication hooks: + - [google-auth-hook.js](https://github.com/Unleash/unleash/blob/master/examples/google-auth-hook.js) - [basic-auth-hook.js](https://github.com/Unleash/unleash/blob/master/examples/basic-auth-hook.js) -We also have a version of Unleash deployed on Heroku which uses Google OAuth 2.0: -https://secure-unleash.herokuapp.com +We also have a version of Unleash deployed on Heroku which uses Google OAuth 2.0: https://secure-unleash.herokuapp.com ## Securing the Client API -A common way to support client access is to use pre shared secrets. This can be solved by having clients send a shared key in a http header with every client request to the Unleash API. All official Unleash clients should support this. + +A common way to support client access is to use pre shared secrets. This can be solved by having clients send a shared key in a http header with every client request to the Unleash API. All official Unleash clients should support this. In the [Java client](https://github.com/Unleash/unleash-client-java#custom-http-headers) this looks like: @@ -63,24 +68,27 @@ On the unleash server side you need to implement a preRouter hook which verifies const unleash = require('unleash-server'); const sharedSecret = '12312Random'; -unleash.start({ - databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash', - enableLegacyRoutes: false, - preRouterHook: app => { +unleash + .start({ + databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash', + enableLegacyRoutes: false, + preRouterHook: app => { app.use('/api/client', (req, res, next) => { if (req.header('authorization') !== sharedSecret) { - res.sendStatus(401); + res.sendStatus(401); } else { - next(); + next(); } }); - } -}).then(unleash => { - console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`); -}); + }, + }) + .then(unleash => { + console.log( + `Unleash started on http://localhost:${unleash.app.get('port')}`, + ); + }); ``` [client-auth-unleash.js](https://github.com/Unleash/unleash/blob/master/examples/client-auth-unleash.js) - -PS! Remember to disable legacy route by setting the `enableLegacyRoutes` option to false. This will require all your clients to be on v3.x. +PS! Remember to disable legacy route by setting the `enableLegacyRoutes` option to false. This will require all your clients to be on v3.x. diff --git a/docs/unleash-context.md b/docs/unleash-context.md index 8a6fe07379..95a13e94d9 100644 --- a/docs/unleash-context.md +++ b/docs/unleash-context.md @@ -3,10 +3,7 @@ id: unleash_context title: Unleash Context --- - -In order to standardise a few activation strategies we also needed to -standardise a unleash context, which contains some fields that varies -per requests, needed to implement the activation strategies. +In order to standardise a few activation strategies we also needed to standardise a unleash context, which contains some fields that varies per requests, needed to implement the activation strategies. The unleash context is defined by these fields: @@ -15,12 +12,8 @@ The unleash context is defined by these fields: - remoteAddress: String, - properties: Map -All fields are optional, but if they are not set you will not be able to use -certain activation strategies. +All fields are optional, but if they are not set you will not be able to use certain activation strategies. -E.g. the userWithId-strategy obviously depends on the userId field. +E.g. the userWithId-strategy obviously depends on the userId field. -The properties field is more generic and can be used to provide more abritary -data to the strategies. A common usage is to add more metadata, e.g. that the -current user is a beta user, and thus the betaUser-strategy will use this info -in its implementation. +The properties field is more generic and can be used to provide more abritary data to the strategies. A common usage is to add more metadata, e.g. that the current user is a beta user, and thus the betaUser-strategy will use this info in its implementation. diff --git a/migrations/default-strategies.json b/migrations/default-strategies.json index e2af38b2d1..2afefb52d5 100644 --- a/migrations/default-strategies.json +++ b/migrations/default-strategies.json @@ -7,71 +7,85 @@ { "name": "userWithId", "description": "Active for users with a userId defined in the userIds-list", - "parameters": [{ - "name": "userIds", - "type": "list", - "description": "", - "required": false - }] + "parameters": [ + { + "name": "userIds", + "type": "list", + "description": "", + "required": false + } + ] }, { "name": "applicationHostname", "description": "Active for client instances with a hostName in the hostNames-list.", - "parameters": [{ - "name": "hostNames", - "type": "list", - "description": "List of hostnames to enable the feature toggle for.", - "required": false - }] + "parameters": [ + { + "name": "hostNames", + "type": "list", + "description": "List of hostnames to enable the feature toggle for.", + "required": false + } + ] }, { "name": "gradualRolloutRandom", "description": "Randomly activate the feature toggle. No stickiness.", - "parameters": [{ - "name": "percentage", - "type": "percentage", - "description": "", - "required": false - }] + "parameters": [ + { + "name": "percentage", + "type": "percentage", + "description": "", + "required": false + } + ] }, { "name": "gradualRolloutSessionId", "description": "Gradually activate feature toggle. Stickiness based on session id.", - "parameters": [{ - "name": "percentage", - "type": "percentage", - "description": "", - "required": false - },{ - "name": "groupId", - "type": "string", - "description": "Used to define a activation groups, which allows you to correlate across feature toggles.", - "required": true - }] + "parameters": [ + { + "name": "percentage", + "type": "percentage", + "description": "", + "required": false + }, + { + "name": "groupId", + "type": "string", + "description": "Used to define a activation groups, which allows you to correlate across feature toggles.", + "required": true + } + ] }, { "name": "gradualRolloutUserId", "description": "Gradually activate feature toggle for logged in users. Stickiness based on user id.", - "parameters": [{ - "name": "percentage", - "type": "percentage", - "description": "", - "required": false - },{ - "name": "groupId", - "type": "string", - "description": "Used to define a activation groups, which allows you to correlate across feature toggles.", - "required": true - }] + "parameters": [ + { + "name": "percentage", + "type": "percentage", + "description": "", + "required": false + }, + { + "name": "groupId", + "type": "string", + "description": "Used to define a activation groups, which allows you to correlate across feature toggles.", + "required": true + } + ] }, { "name": "remoteAddress", "description": "Active for remote addresses defined in the IPs list.", - "parameters": [{ - "name": "IPs", - "type": "list", - "description": "List of IPs to enable the feature toggle for.", - "required": true - }] + "parameters": [ + { + "name": "IPs", + "type": "list", + "description": "List of IPs to enable the feature toggle for.", + "required": true + } + ] } ] diff --git a/test/e2e/helpers/database.json b/test/e2e/helpers/database.json index f9f59dd98d..45e849968a 100644 --- a/test/e2e/helpers/database.json +++ b/test/e2e/helpers/database.json @@ -1,113 +1,125 @@ { - "strategies": [ + "strategies": [ + { + "name": "default", + "description": "Default on or off Strategy.", + "parameters": [] + }, + { + "name": "usersWithEmail", + "description": "Active for users defined in the comma-separated emails-parameter.", + "parameters": [ { - "name": "default", - "description": "Default on or off Strategy.", - "parameters": [] - }, - { - "name": "usersWithEmail", - "description": "Active for users defined in the comma-separated emails-parameter.", - "parameters": [{ - "name": "emails", - "type": "string" - }] - } - ], - "applications": [ - { - "appName": "demo-app-1", - "strategies": ["default"] - }, - { - "appName": "demo-app-2", - "strategies": ["default", - "extra" - ], - "description": "hello" + "name": "emails", + "type": "string" } - ], - "clientInstances": [ + ] + } + ], + "applications": [ + { + "appName": "demo-app-1", + "strategies": ["default"] + }, + { + "appName": "demo-app-2", + "strategies": ["default", "extra"], + "description": "hello" + } + ], + "clientInstances": [ + { + "appName": "demo-app-1", + "instanceId": "test-1", + "strategies": ["default"], + "started": 1516026938494, + "interval": 10 + }, + { + "appName": "demo-seed-2", + "instanceId": "test-2", + "strategies": ["default"], + "started": 1516026938494, + "interval": 10 + } + ], + "features": [ + { + "name": "featureX", + "description": "the #1 feature", + "enabled": true, + "strategies": [ { - "appName": "demo-app-1", - "instanceId": "test-1", - "strategies": ["default"], - "started": 1516026938494, - "interval": 10 - }, - { - "appName": "demo-seed-2", - "instanceId": "test-2", - "strategies": ["default"], - "started": 1516026938494, - "interval": 10 + "name": "default", + "parameters": {} } - ], - "features": [ + ] + }, + { + "name": "featureY", + "description": "soon to be the #1 feature", + "enabled": false, + "strategies": [ { - "name": "featureX", - "description": "the #1 feature", - "enabled": true, - "strategies": [{ - "name": "default", - "parameters": {} - }] - }, - { - "name": "featureY", - "description": "soon to be the #1 feature", - "enabled": false, - "strategies": [{ - "name": "baz", - "parameters": { - "foo": "bar" - } - }] - }, - { - "name": "featureZ", - "description": "terrible feature", - "enabled": true, - "strategies": [{ - "name": "baz", - "parameters": { - "foo": "rab" - } - }] - }, - { - "name": "featureArchivedX", - "description": "the #1 feature", - "enabled": true, - "archived": true, - "strategies": [{ - "name": "default", - "parameters": {} - }] - }, - { - "name": "featureArchivedY", - "description": "soon to be the #1 feature", - "enabled": false, - "archived": true, - "strategies": [{ - "name": "baz", - "parameters": { - "foo": "bar" - } - }] - }, - { - "name": "featureArchivedZ", - "description": "terrible feature", - "enabled": true, - "archived": true, - "strategies": [{ - "name": "baz", - "parameters": { - "foo": "rab" - } - }] + "name": "baz", + "parameters": { + "foo": "bar" + } } - ] -} \ No newline at end of file + ] + }, + { + "name": "featureZ", + "description": "terrible feature", + "enabled": true, + "strategies": [ + { + "name": "baz", + "parameters": { + "foo": "rab" + } + } + ] + }, + { + "name": "featureArchivedX", + "description": "the #1 feature", + "enabled": true, + "archived": true, + "strategies": [ + { + "name": "default", + "parameters": {} + } + ] + }, + { + "name": "featureArchivedY", + "description": "soon to be the #1 feature", + "enabled": false, + "archived": true, + "strategies": [ + { + "name": "baz", + "parameters": { + "foo": "bar" + } + } + ] + }, + { + "name": "featureArchivedZ", + "description": "terrible feature", + "enabled": true, + "archived": true, + "strategies": [ + { + "name": "baz", + "parameters": { + "foo": "rab" + } + } + ] + } + ] +} diff --git a/test/examples/client-metrics.json b/test/examples/client-metrics.json index 327ea2b7e1..2e035a4bc5 100644 --- a/test/examples/client-metrics.json +++ b/test/examples/client-metrics.json @@ -1,18 +1,18 @@ { - "appName": "appName", - "instanceId": "instanceId", - "bucket": { - "start": "2016-11-03T07:16:43.572Z", - "stop": "2016-11-03T07:16:53.572Z", - "toggles": { - "toggle-name-1": { - "yes": 123, - "no": 321 - }, - "toggle-name-2": { - "yes": 111, - "no": 0 - } - } + "appName": "appName", + "instanceId": "instanceId", + "bucket": { + "start": "2016-11-03T07:16:43.572Z", + "stop": "2016-11-03T07:16:53.572Z", + "toggles": { + "toggle-name-1": { + "yes": 123, + "no": 321 + }, + "toggle-name-2": { + "yes": 111, + "no": 0 + } } + } } diff --git a/test/examples/client-register.json b/test/examples/client-register.json index d13c06e995..5d7a1e87c6 100644 --- a/test/examples/client-register.json +++ b/test/examples/client-register.json @@ -1,8 +1,8 @@ { - "appName": "appName", - "instanceId": "instanceId", - "sdkVersion": "test:123", - "strategies": ["default", "some-strategy-1"], - "started": "2016-11-03T07:16:43.572Z", - "interval": 10000 + "appName": "appName", + "instanceId": "instanceId", + "sdkVersion": "test:123", + "strategies": ["default", "some-strategy-1"], + "started": "2016-11-03T07:16:43.572Z", + "interval": 10000 } diff --git a/website/README.md b/website/README.md index b7490fdf7a..5db5994fdf 100644 --- a/website/README.md +++ b/website/README.md @@ -4,11 +4,11 @@ It's hosted on https://unleash.github.io/ # What's In This Document -* [Get Started in 5 Minutes](#get-started-in-5-minutes) -* [Directory Structure](#directory-structure) -* [Editing Content](#editing-content) -* [Adding Content](#adding-content) -* [Full Documentation](#full-documentation) +- [Get Started in 5 Minutes](#get-started-in-5-minutes) +- [Directory Structure](#directory-structure) +- [Editing Content](#editing-content) +- [Adding Content](#adding-content) +- [Full Documentation](#full-documentation) # Get Started in 5 Minutes @@ -18,6 +18,7 @@ It's hosted on https://unleash.github.io/ # Install dependencies $ npm install ``` + 2. Run your dev server: ```sh @@ -103,6 +104,7 @@ For more information about adding new docs, click [here](https://docusaurus.io/d 1. Add links to docs, custom pages or external links by editing the headerLinks field of `website/siteConfig.js`: `website/siteConfig.js` + ```javascript { headerLinks: [ @@ -127,6 +129,7 @@ For more information about the navigation bar, click [here](https://docusaurus.i 1. If you want your page to show up in your navigation header, you will need to update `website/siteConfig.js` to add to the `headerLinks` element: `website/siteConfig.js` + ```javascript { headerLinks: [ diff --git a/website/sidebars.json b/website/sidebars.json index 9cd9918e87..0051dfa7e4 100644 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -1,13 +1,37 @@ { "documentation": { +<<<<<<< HEAD "User documentation": ["getting_started", "client_sdk", "securing_unleash", "unleash_context", "activation_strategy", "client_specification", "migration_guide"], "Developer Guide": ["developer_guide", "database_schema", "database_backup"], +======= + "Getting Started": [ + "getting_started", + "securing_unleash", + "unleash_context", + "activation_strategy", + "client_specification", + "migration_guide" + ], + "Developer Guide": [ + "developer_guide", + "database_schema", + "database_backup" + ], +>>>>>>> chore: Fix formatting all the things "Guides": ["guides/google_auth"] }, "api": { - "Client": ["api/client/features", "api/client/register", "api/client/metrics"], - "Admin": ["api/admin/features", "api/admin/strategies", "api/admin/metrics", "api/admin/events" ], - "Internal": ["api/internal" ] - + "Client": [ + "api/client/features", + "api/client/register", + "api/client/metrics" + ], + "Admin": [ + "api/admin/features", + "api/admin/strategies", + "api/admin/metrics", + "api/admin/events" + ], + "Internal": ["api/internal"] } } diff --git a/website/static/css/custom.css b/website/static/css/custom.css index 48c844452c..10526478af 100644 --- a/website/static/css/custom.css +++ b/website/static/css/custom.css @@ -16,9 +16,9 @@ } h2.projectTitle { - color: black; + color: black; } .blockImage img { box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); -} \ No newline at end of file +}