Skip to content

Crown-Commercial-Service/digitalmarketplace-utils

Folders and files

NameName
Last commit message
Last commit date

Latest commit

d8e4490 · Sep 7, 2018
Sep 7, 2018
Sep 26, 2017
Sep 7, 2018
Mar 16, 2018
Apr 20, 2018
Mar 15, 2018
Sep 7, 2018
Nov 27, 2017
Aug 30, 2018
Apr 26, 2018
Sep 3, 2018
Sep 25, 2017
Sep 5, 2018
Aug 24, 2018
Jan 19, 2018
Sep 7, 2018

Repository files navigation

Digital Marketplace utils

Coverage Status Requirements Status

What's in here?

  • Digital Marketplace API clients
  • Formatting utilities for Digital Marketplace
  • Digital Marketplace logging for Flask using JSON Logging
  • Utility functions/libraries for Amazon S3, Mailchimp/Mandrill, Cloudwatch
  • Helper code for Flask configuration
  • A formed version of Flask Feature Flags

Logging from applications

When logging from applications you should write your message as a format string and pass any required arguments to the log method in the extra named argument. This allows our logging to use them as separate fields in our JSON logs making it much easier to search and aggregate on them.

logger.info("the user {user_id} did the thing '{thing}'", extra={
    'user_id': user_id, 'thing': thing
})

Note that apart from not getting the benefit, passing the formatted message can be dangerous. User generated content may be passed, unescaped to the .format method.

Using FeatureFlags

Hide not-ready-to-ship features until they're ready.

Basic implementation

# config.py

class Config(object):
  FEATURE_FLAGS_THING = enabled_since('2015-10-08')
# main/views.py

from .. import flask_featureflags

@main.route('/')
def index():
	return render_template("index.html")

@main.route('/shiny-new-thing')
@flask_featureflags.is_active_feature('THING', redirect_to='/')
def shiny_new_thing():
	return render_template("shiny_new_thing.html")
<!-- templates/index.html -->

<p>Content</p>
{% if 'THING' is active_feature %}
	<a href="{{ url_for('.shiny_new_thing') }}">Check out this cool thing!</a>
{% endif %}

Documentation

Documentation for the extension lives here.

Deviations from source code

  1. Only Inline Flags are recognized.

    # Do this
    FEATURE_FLAGS_THING = True
    
    # Not this
    FEATURE_FLAGS: {
    	'thing': True
    }
  2. get_flags()

    Returns all of the flags and their values set in our config file (for the current environment), but it doesn't know which ones exist elsewhere in the code. If you define a flag in the code that isn't in the config file, it will throw an error but only once you come across it.

    Hit up the /_status endpoint of each app to see which flags are being used (if any).

  3. enabled_since('yyyy-mm-dd')

    Super simple way of tracking how long flags have been turned on. Flags are considered active if they return any truthy value, so by assigning them a date string (ideally, one corresponding to the current date), we'll know when they were activated.

    Accuracy of dates will depend on cognizant developers and vigilant code reviewers.

Versioning

Releases of this project follow semantic versioning, ie

Given a version number MAJOR.MINOR.PATCH, increment the:

  • MAJOR version when you make incompatible API changes,
  • MINOR version when you add functionality in a backwards-compatible manner, and
  • PATCH version when you make backwards-compatible bug fixes.

To make a new version:

  • update the version in the dmutils/__init__.py file
  • if you are making a major change, also update the change log;

When the pull request is merged a Jenkins job will be run to tag the new version.