Skip to content
This repository has been archived by the owner on Oct 14, 2020. It is now read-only.

[develop] Start of version 5 - WebExtension Experiments #120

Merged
merged 50 commits into from
Apr 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
3909b4e
Fix the division between dependencies and devDependencies in package.…
motin Mar 9, 2018
ea27ed2
Removed path as dependency (since it is a core package, we should not…
motin Mar 10, 2018
c7777fe
Updated package-lock.json
motin Apr 3, 2018
3e1f545
Npm run format (prettier + eslint --fix + fixpack)
motin Mar 10, 2018
af564c7
Results of npm run format
motin Mar 10, 2018
08ce53e
Version bump to 5.0.0-alpha1
motin Mar 23, 2018
10b430f
Imported js that should be part of study utils rather than the templa…
motin Mar 23, 2018
f882fe9
Using the same eslint configuration as the template (from https://git…
motin Mar 24, 2018
f718c53
Npm run format + linting
motin Mar 24, 2018
efae1b0
Moved make_xpi script to test-addon folder (since it it only used to …
motin Mar 24, 2018
7c0a77c
Inactivated functional tests for now (will be restored after refactor…
motin Mar 24, 2018
0a473ee
Not: Using add-on in package description
motin Mar 24, 2018
1ac3e3f
Cleaned up npm run build / lint commands
motin Mar 24, 2018
f33f312
Build produces a web extensions api js file instead of ShieldUtils.js…
motin Mar 24, 2018
efdbf5c
Package.json nits
motin Mar 24, 2018
d72e3ce
Smaller test clean-up
motin Mar 24, 2018
96188af
Legacy test add-on removed, webextension-based test add-on inserted
motin Mar 24, 2018
6ca70e2
Importing study utils and study utils bootstrap jsm modules via webpa…
motin Mar 24, 2018
7e3ebab
Minor clean-up in src/index.js
motin Mar 24, 2018
c7c1faa
Smaller clean-up in background.js
motin Mar 26, 2018
879dbd0
Renamed config to studyConfig
motin Mar 26, 2018
2e2fc1f
Moved study config from privileged scope to web extension background …
motin Mar 26, 2018
087bf7c
Formatting
motin Mar 26, 2018
aa3b891
Renamed study util js files to match variable names
motin Mar 26, 2018
f4e6c85
Bundle command to reflect that it is no longer necessary to bundle an…
motin Mar 26, 2018
c67c13a
Moved schema-related files to own folder
motin Mar 26, 2018
05b0506
Synchronized names for studySetup variables (was called studySteup, c…
motin Mar 26, 2018
10dea47
Moved web extension api related parts to a separate folder
motin Mar 26, 2018
d9b5ae4
Moved out jsonschema + sampling to separate files. Changed exposed "s…
motin Mar 26, 2018
533291f
Made room for more web extension apis
motin Mar 26, 2018
243b440
Added the prefs api from https://github.com/gregglind/shield-study-we…
motin Mar 26, 2018
228266b
Restored build + moved webpack to where it is used + made a bash scri…
motin Mar 26, 2018
c6c8f75
Formatting
motin Mar 26, 2018
317657b
Added the test utils from the template repo
motin Mar 27, 2018
6758125
Added test for: should be able to access shieldUtils WebExtensions AP…
motin Mar 27, 2018
4f79eda
Test add-on ignores APIs that are bundled from shield-studies-addon-u…
motin Mar 27, 2018
7d04c3c
Formatting
motin Mar 27, 2018
98182dc
Synced example study test utils and test-addon test utils + split tes…
motin Mar 28, 2018
ff31a48
Formatting + a minor grammar nit
motin Mar 29, 2018
4c6242c
Cleaned up background script, clarified extension page and let execut…
motin Mar 29, 2018
7da6b5e
Moved test-addon into example folder and shield-study-helper-addon in…
motin Mar 29, 2018
4b23202
Updated the readme to reflect version 5
motin Mar 29, 2018
6adda92
Corrected npm install command in readme (should be installed as runti…
motin Mar 29, 2018
cb990d2
Changed webextension api namespace from shieldUtils to study
motin Apr 2, 2018
4e01d6e
Smaller improvements
motin Apr 2, 2018
6c69c09
Updated package-lock.json
motin Apr 3, 2018
ffd015a
Restored npm run test after test add-on path change
motin Apr 3, 2018
fd82f92
Smaller method and variable refactoring
motin Apr 3, 2018
41f0679
Added browser.study.deterministicVariation and browser.study.startup …
motin Apr 3, 2018
beda8c2
Removed webExtensionMsg schema since no longer relevant
motin Apr 3, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:

- run:
name: webpack and eslint
command: npm run dist
command: npm run build

- run:
name: Build .XPI
Expand Down
7 changes: 7 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# do not lint/format generated artifacts
dist/
package-lock.json
# makes sure that eslintrc.js gets linted/formatted
!.eslintrc.js
# don't lint/format package.json since npm install formats it differently by default
package.json
47 changes: 33 additions & 14 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,52 @@
/* eslint-env node */

"use strict";

// All Mozilla specific rules and environments at:
// http://firefox-source-docs.mozilla.org/tools/lint/linters/eslint-plugin-mozilla.html

module.exports = {
env: {
"node": true
es6: true,
},
extends: [
"eslint:recommended",
// list of rules at: https://dxr.mozilla.org/mozilla-central/source/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js
"plugin:mozilla/recommended",
],

plugins: [
"mozilla",
"json"
overrides: [
{
files: "src/**",
env: {
browser: true,
webextensions: true,
},
},
],

parserOptions: {
ecmaVersion: 8,
sourceType: "module",
ecmaFeatures: {
jsx: false,
experimentalObjectRestSpread: true,
},
},
plugins: ["json", "mozilla"],
root: true,
rules: {
"babel/new-cap": "off",
"comma-dangle": ["error", "always-multiline"],
"eqeqeq": "error",
"indent": ["warn", 2, {SwitchCase: 1}],
"mozilla/no-aArgs": "warn",
"mozilla/balanced-listeners": 0,
"mozilla/balanced-listeners": "off",
"comma-dangle": ["error", "always-multiline"],
eqeqeq: "error",
indent: ["warn", 2, { SwitchCase: 1 }],
"no-console": "warn",
"no-debugger": "warn",
"no-shadow": ["error"],
"no-var": "error",
"no-shadow": "error",
"no-unused-vars": "error",
"prefer-const": "warn",
"semi": ["error", "always"],
"require-jsdoc": "warn",
"prefer-spread": "error",
semi: ["error", "always"],
"valid-jsdoc": "warn",
"max-len": ["warn", 80],
},
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,3 @@ node_modules
*.xpi
*.tgz
*.*.swp
dist/
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ RUN apt-get update -y && \
apt-get install -y zip firefox xvfb nodejs xsel git ssh openbox && \
npm install -g [email protected]

ENV PATH="/shield-study-utils/node_modules/.bin:$PATH"
ENV PATH="/shield-study-addon-utils/node_modules/.bin:$PATH"
90 changes: 61 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,24 @@

[![Build Status](https://travis-ci.org/mozilla/shield-studies-addon-utils.svg?branch=master)](https://travis-ci.org/mozilla/shield-studies-addon-utils)

A Firefox JavaScript module to be bundled with shield study add-ons (as `StudyUtils.jsm`). Provides these capabilities:
APIs and tooling that allows add-on developers to build [Shield/Pioneer](https://wiki.mozilla.org/Firefox/Shield/Shield_Studies) ([Normandy](https://wiki.mozilla.org/Firefox/Shield#Normandy_-_User_Profile_Matching_and_Recipe_Deployment)) study add-ons efficiently.

1. **Suggest variation for a client** (Deterministically! i.e. based on a hash of non-PII user info, they will always get assigned to the same branch every time the study launches)
2. **Report study lifecycle data** using Telemetry
3. **Report feature interaction and success data** using Telemetry
4. **Registers/uregisters the study as an active experiment** (By annotating the Telemetry Environment, marking the user as special in the `main` ping).
5. **Validates schema for study config**
6. **Handles study endings** (endStudy method bundles lots of tasks in one, including appending survey URLs specified in Config.jsm with query strings/sending the user to a survey and uninstalling the add-on)

The pings end up in the `shield-study` and `shield-study-addon` Telemetry buckets for faster analysis.

Allows add-on developers to build [Shield Study](https://wiki.mozilla.org/Firefox/Shield/Shield_Studies) ([Normandy](https://wiki.mozilla.org/Firefox/Shield#Normandy_-_User_Profile_Matching_and_Recipe_Deployment)) compatible add-ons without having to think very much.

## What You are Building
## Overview

* You are building a [legacy add-on](https://developer.mozilla.org/Add-ons/Legacy_add_ons). To deploy these after 57, you will need the magic special signing.
* Shield study add-ons can not be based on Web Extensions [yet](https://github.com/mozilla/shield-studies-addon-utils/issues/45).
* Jetpack / addon-sdk is not at all supported since v4 of this utils library.
* `webExtensionApis` - Firefox WebExtension Experiments APIs providing capabilities for study add-ons that are yet not available in the built-in WebExtension APIs
* `testUtils` - Test utils (helper classes to write functional/unit tests for your study add-on)
* `examples` - Tested and verified example add-ons using the WebExtension Experiments APIs and test utils

## Get started

Check out [mozilla/shield-studies-addon-template/](https://github.com/mozilla/shield-studies-addon-template/) to get started with an example study where shield-studies-addon-utils is already installed and configured.

## Installing the `StudyUtils.jsm` in your add-on
## Installing the utils in your add-on

```
npm install --save-dev shield-studies-addon-utils
npm install --save shield-studies-addon-utils
```

Copy `dist/StudyUtils.jsm` to your `addon` source directory, where it will be zipped up.

## Engineering and Process

* [Shield article on Mozilla Wiki](https://wiki.mozilla.org/Firefox/Shield)
Expand All @@ -46,24 +33,69 @@ Copy `dist/StudyUtils.jsm` to your `addon` source directory, where it will be zi
* [Long, rambling engineering docs](./docs/engineering.md)
* Come to slack: #shield

## WebExtension APIs

### `browser.study.*`

Provides these capabilities:

1. **Suggest variation for a client** (Deterministically! i.e. based on a hash of non-PII user info, they will always get assigned to the same branch every time the study launches)
2. **Report study lifecycle data** using Telemetry
3. **Report feature interaction and success data** using Telemetry
4. **Registers/unregisters the study as an active experiment** (By annotating the Telemetry Environment, marking the user as special in the `main` ping).
5. **Validates schema for study config**
6. **Handles study endings** (endStudy method bundles lots of tasks in one, including appending survey URLs specified in Config.jsm with query strings/sending the user to a survey and uninstalling the add-on)

To use, copy `webExtensionApis/study/api.js` and `webExtensionApis/study/schema.json` to your add-on's source directory under `privileged/study`, then add-the following to your add-on's manifest.json:

```
"experiment_apis": {
"study": {
"schema": "./privileged/study/schema.json",
"parent": {
"scopes": ["addon_parent"],
"script": "./privileged/study/api.js",
"paths": [["study"]]
}
}
},
```

#### Data processing pipelines

Depending on which data processing pipeline the study add-on is configured to use, the pings end up in different destinations:

* `shield-parquet` - The pings end up in the `shield-study` and `shield-study-addon` Telemetry buckets for faster analysis.
* `pioneer` - The pings are encrypted and end up in the Pioneer processing pipeline
* `custom-telemetry-events` - The pings end up in the ordinary destination for custom telemetry events

To use, copy and adjust the files as per the `study` API above.

### `browser.prefs.*`

Allows your web extension add-on to set and read preferences.

## What You are Building

* You are building . To deploy these after 57, you will need the magic special signing.
* Shield study add-ons can not be based on Web Extensions [yet](https://github.com/mozilla/shield-studies-addon-utils/issues/45).

## Gotchas, Opinions, Side Effects, and Misfeatures

1. No handling of 'timers'. No saved state at all (including the variation name), unless you handle it yourself.

2. No 'running' pings in v4 (yet).

3. User disable also uninstalls (and cleans up).

## Development on the Utils

* open an issue
* hack and file a PR
* Open an issue
* Hack and file a PR

## History of major versions

* v5: (In development) API exposed as a Web Extension Experiment
* v5: (In development) API exposed as a Web Extension Experiment. Minimal viable add-on example added. Test coverage improved. Test utils added.
* v4.1: Improved utils for common cases
* v4: First `.jsm` release. Uses packet format for PACKET version 3.
* v4: First `.jsm` release for shipping studies as [legacy add-ons](https://developer.mozilla.org/Add-ons/Legacy_add_ons). Used packet format for PACKET version 3. (Jetpack / addon-sdk is not at all supported since v4 of this utils library)
* v3: Attempt to formalize on `shield-study` PACKET version 3. Jetpack based. Prototype used for `raymak/page-reload`. All work abandoned, and no formal npm release in this series. Work done at `v3-shield-packet-format` branch. LAST JETPACK (addon-sdk) RELEASE.
* v2: Code refactor to es6 `class` with event models. Added cli tooling. Packet format is still arbitrary and per-study. Jetpack based. Last used in studies in Q2 2017.
* v1: Initial work and thinking. Telemetry packets are rather arbitrary. Jetpack based.
Expand All @@ -72,6 +104,6 @@ Copy `dist/StudyUtils.jsm` to your `addon` source directory, where it will be zi

Repositories that should not be used as templates for new studies:

<https://github.com/gregglind/template-shield-study> - The incubation repo for the updated structure and contents of this repo, ported to the official template in late 2017.
<https://github.com/benmiroglio/shield-study-embedded-webextension-hello-world-example> - A repository that was created in 2017 to help new Shield/Pioneer engineers to quickly get up and running with a Shield add-on, built upon an older and much more verbose add-on template. It's documentation has been ported to the official template repo.
<https://github.com/johngruen/shield-template> - Despite its name, this repo is for static amo consent pages and does not contain any template for Shield studies
* <https://github.com/gregglind/template-shield-study> - The incubation repo for the updated structure and contents of the template repo, ported to the official template in late 2017.
* <https://github.com/benmiroglio/shield-study-embedded-webextension-hello-world-example> - A repository that was created in 2017 to help new Shield/Pioneer engineers to quickly get up and running with a Shield add-on, built upon an older and much more verbose add-on template. It's documentation has been ported to the official template repo.
* <https://github.com/johngruen/shield-template> - Despite its name, this repo is for static amo consent pages and does not contain any template for Shield studies
26 changes: 0 additions & 26 deletions bin/make_xpi.sh

This file was deleted.

22 changes: 22 additions & 0 deletions examples/test-addon/bin/bundle-shield-studies-addon-utils.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash

# fail on any error
set -o errexit

# always run from the repository root directory
script_path=`dirname $0`
cd "$script_path/../../../"

# paths
WEBEXTAPIS_PATH="webExtensionApis"
ADDON_SRC_PATH="examples/test-addon/src"

# bundle the study web extension experiment
mkdir -p $ADDON_SRC_PATH/privileged/study
cp $WEBEXTAPIS_PATH/study/api.js $ADDON_SRC_PATH/privileged/study/api.js
cp $WEBEXTAPIS_PATH/study/schema.json $ADDON_SRC_PATH/privileged/study/schema.json

# bundle the prefs web extension experiment
mkdir -p $ADDON_SRC_PATH/privileged/prefs
cp $WEBEXTAPIS_PATH/prefs/api.js $ADDON_SRC_PATH/privileged/prefs/api.js
cp $WEBEXTAPIS_PATH/prefs/schema.json $ADDON_SRC_PATH/privileged/prefs/schema.json
2 changes: 2 additions & 0 deletions examples/test-addon/dist/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!*.gitignore
84 changes: 84 additions & 0 deletions examples/test-addon/src/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/* eslint no-console:off */
/* global studySetup */

"use strict";

class Study {
constructor(variation) {}

// Will run only during first install attempt
// Use web extension experiments to get whatever prefs, add-ons,
// telemetry, anything necessary for the check
static async isEligible() {
//browser.prefs.get('my.favorite.pref');
return true;
}

// Expiration checks should be implemented in a very reliable way by
// the add-on since Normandy does not handle study expiration in a reliable manner
static async hasExpired() {
return false;
}
}

/**
* Fired when the extension is first installed, when the extension is updated
* to a new version, and when the browser is updated to a new version.
* @param details
*/
function handleInstalled(details) {
console.log(
"The 'handleInstalled' event was fired.",
details.reason,
details,
);
}

/**
* Fired when a profile that has this extension installed first starts up.
* This event is not fired when a private browsing/incognito profile is started.
*/
async function handleStartup() {
console.log("The 'handleStartup' event was fired.", arguments);
}

// todo: on shutdown
// Run shutdown-related non-privileged code

browser.runtime.onStartup.addListener(handleStartup);
browser.runtime.onInstalled.addListener(handleInstalled);

async function initiateStudy() {
// Set dynamic study configuration flags
studySetup.eligible = await Study.isEligible();
studySetup.expired = await Study.hasExpired();
// Ensure we have configured study and are supposed to run our feature
await browser.study.configure(studySetup);
// Run the startup study checks
await browser.study.startup();
// Read the active study variation
const { variation } = await browser.study.info();
// Initiate our study-specific background logic
new Study(variation);
}

// Since this is a test-addon, we don't initiate any code directly, but wait
// for events sent by tests. This allows us to control and test the execution
// properly.
browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log("request", request);
if (request === "test:initiateStudy") {
initiateStudy();
}
});

// The tests that probe the web extensions APIs directly rely on an extension
// page opening up in a new window/tab.
// For more information, see shield-studies-addon-utils/testUtils/executeJs.js
const createData = {
type: "detached_panel",
url: "extension-page-for-tests/index.html",
width: 500,
height: 500,
};
const creating = browser.windows.create(createData);
31 changes: 31 additions & 0 deletions examples/test-addon/src/extension-page-for-tests/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<link rel="stylesheet" type="text/css" href="chrome://browser/content/extension.css">
<style>

body {
margin: 1em;
}

</style>
</head>
<body>

<h1>Shield Study Utils Test Add-on</h1>
<p>This is an extension page for shield-studies-addon-utils/test-addon</p>

<p>This add-on initiates no background logic on it's own, so that the tests
can test each lifecycle event in isolation.</p>

<p>For manual testing, use the buttons below to run the code
corresponding to each lifecycle event.</p>

<p>
<button id="initiateStudy-button" class="button-style">initiateStudy</button>
</p>

<script src="./page.js"></script>
</body>
</html>
Loading