Skip to content

Commit

Permalink
Setup publishing to AMO (#180)
Browse files Browse the repository at this point in the history
* Setup publishing to AMO

* Fix notifications-service-test

* Push minimium browser requirements, drop CSS

* Drop babel, partially fix requesting permissions

* Release on cron, triggered builds, and on tags

* Fix permissions forever

  - Remove on tags for Travis build

  - Rename option `newTabAlways` to `reuseTabs`

  - Move permissions requests to options

  - Remove some tests and respective dependencies

  - Fix failing tests

* Extract out options syncing

* Fix error propagation

* Update options screenshot

* Delay showing successive notifications on Firefox
  • Loading branch information
notlmn committed Jun 16, 2019
1 parent ed9f3d4 commit f42c6f5
Show file tree
Hide file tree
Showing 22 changed files with 192 additions and 224 deletions.
4 changes: 4 additions & 0 deletions .travis.yml
Expand Up @@ -8,4 +8,8 @@ deploy:
skip_cleanup: true
script: npm run release
on:
# Create a new release
# On cron jobs, or
# When triggered via "Trigger build" on https://travis-ci.org/sindresorhus/refined-github/
branch: master
condition: (($TRAVIS_EVENT_TYPE = api) || ($TRAVIS_EVENT_TYPE = cron && $(git rev-list -n 1 --since=\"26 hours ago\" master)))
Binary file modified media/screenshot-options.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
51 changes: 30 additions & 21 deletions package.json
Expand Up @@ -3,37 +3,42 @@
"scripts": {
"lint": "npm run lint:css && npm run lint:js",
"lint:js": "xo",
"lint:css": "stylelint source/*.css",
"lint-fix": "npm run lint:css -- --fix",
"lint:css": "stylelint source/**/*.css",
"lint-fix": "npm run lint:css -- --fix && npm run lint:js -- --fix",
"test": "npm run lint && npm run test:js && npm run build",
"test:js": "ava",
"build": "webpack --mode=production",
"watch": "webpack --mode=development --watch",
"release": "npm run build && npm run update-version && webstore upload --source=distribution --auto-publish",
"update-version": "VERSION=$(utc-version); echo $VERSION; dot-json distribution/manifest.json version $VERSION"
"prerelease:version": "VERSION=$(utc-version); echo $VERSION; dot-json distribution/manifest.json version $VERSION",
"prerelease:source-url": "echo https://github.com/sindresorhus/refined-github/tree/\"${TRAVIS_COMMIT:-$VERSION}\" > distribution/SOURCE_URL",
"release": "npm-run-all build prerelease:* release:*",
"release:cws": "webstore upload --source=distribution --auto-publish",
"release:amo": "web-ext-submit --source-dir distribution"
},
"dependencies": {
"delay": "^4.3.0",
"webext-options-sync": "^0.16.0",
"webextension-polyfill": "^0.4.0"
},
"devDependencies": {
"ava": "^1.4.1",
"babel-core": "^6.26.3",
"babel-loader": "^8.0.5",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
"ava": "^2.1.0",
"chrome-webstore-upload-cli": "^1.2.0",
"copy-webpack-plugin": "^5.0.2",
"copy-webpack-plugin": "^5.0.3",
"dot-json": "^1.1.0",
"esm": "^3.2.22",
"esm": "^3.2.25",
"lodash.merge": "^4.6.1",
"moment": "^2.24.0",
"p-immediate": "^3.1.0",
"npm-run-all": "^4.1.5",
"sinon": "^7.3.2",
"sinon-chrome": "^3.0.1",
"stylelint": "^10.0.1",
"stylelint-config-xo": "^0.14.0",
"terser-webpack-plugin": "^1.2.3",
"utc-version": "^1.1.0",
"webext-options-sync": "^0.15.5",
"webextension-polyfill": "^0.4.0",
"webpack": "^4.30.0",
"webpack-cli": "^3.3.1",
"stylelint": "^10.1.0",
"stylelint-config-xo": "^0.15.0",
"terser-webpack-plugin": "^1.3.0",
"utc-version": "^2.0.1",
"web-ext": "^3.0.0",
"web-ext-submit": "^3.0.0",
"webpack": "^4.33.0",
"webpack-cli": "^3.3.4",
"xo": "^0.24.0"
},
"ava": {
Expand All @@ -58,13 +63,17 @@
{
"varsIgnorePattern": "^h$"
}
]
],
"no-await-in-loop": 1
},
"globals": [
"browser"
]
},
"stylelint": {
"extends": "stylelint-config-xo"
"extends": "stylelint-config-xo",
"rules": {
"declaration-no-important": null
}
}
}
22 changes: 15 additions & 7 deletions readme.md
@@ -1,10 +1,20 @@
# Notifier for GitHub [![Build Status](https://travis-ci.org/sindresorhus/notifier-for-github.svg?branch=master)](https://travis-ci.org/sindresorhus/notifier-for-github)

[link-cws]: https://chrome.google.com/webstore/detail/notifier-for-github/lmjdlojahmbbcodnpecnjnmlddbkjhnn "Version published on Chrome Web Store"
[link-amo]: https://addons.mozilla.org/en-US/firefox/addon/nfg/ "Version published on Mozilla Add-ons"

> Browser extension - Displays your GitHub notifications unread count
It checks for new GitHub notifications every minute.


## Install

- [**Chrome** extension][link-cws] [<img valign="middle" src="https://img.shields.io/chrome-web-store/v/lmjdlojahmbbcodnpecnjnmlddbkjhnn.svg?label=%20">][link-cws]
- [**Firefox** add-on][link-amo] [<img valign="middle" src="https://img.shields.io/amo/v/nfg.svg?label=%20">][link-amo]
- **Opera** extension: Use [this Opera extension](https://addons.opera.com/en/extensions/details/download-chrome-extension-9/) to install the Chrome version.


## Highlights

- Desktop notifications
Expand All @@ -13,15 +23,13 @@ It checks for new GitHub notifications every minute.

*Make sure to add a token in the options.*

![](media/screenshot.png)
![](media/screenshot-options.png)

## Screenshots

## Install
### Notification count
![](media/screenshot.png)

- [**Chrome** extension](https://chrome.google.com/webstore/detail/notifier-for-github/lmjdlojahmbbcodnpecnjnmlddbkjhnn)
- **Firefox** add-on: Use [this](https://addons.mozilla.org/en-US/firefox/addon/chrome-store-foxified/) to enable installing Chrome extensions and then install [Notifier for GitHub](https://chrome.google.com/webstore/detail/notifier-for-github/lmjdlojahmbbcodnpecnjnmlddbkjhnn)
- **Opera** extension: Use [this](https://addons.opera.com/en/extensions/details/download-chrome-extension-9/) to enable installing Chrome extensions and then install [Notifier for GitHub](https://chrome.google.com/webstore/detail/notifier-for-github/lmjdlojahmbbcodnpecnjnmlddbkjhnn)
### Options
![](media/screenshot-options.png)


## Permissions
Expand Down
32 changes: 10 additions & 22 deletions source/background.js
@@ -1,29 +1,14 @@
import OptionsSync from 'webext-options-sync';
import optionsStorage from './options-storage';
import localStore from './lib/local-store';
import {openTab} from './lib/tabs-service';
import {queryPermission} from './lib/permissions-service';
import {getNotificationCount, getTabUrl} from './lib/api';
import {renderCount, renderError, renderWarning} from './lib/badge';
import {checkNotifications, openNotification} from './lib/notifications-service';
import {isChrome} from './util';

const syncStore = new OptionsSync();

new OptionsSync().define({
defaults: {
token: '',
rootUrl: 'https://api.github.com/',
playNotifSound: false,
showDesktopNotif: false,
onlyParticipating: false,
newTabAlways: false
},
migrations: [
OptionsSync.migrations.removeUnused
]
});

function scheduleNextAlarm(interval) {
const intervalSetting = localStore.get('interval') || 60;
async function scheduleNextAlarm(interval) {
const intervalSetting = await localStore.get('interval') || 60;
const intervalValue = interval || 60;

if (intervalSetting !== intervalValue) {
Expand All @@ -41,7 +26,7 @@ async function handleLastModified(newLastModified) {

// Something has changed since we last accessed, display any new notificaitons
if (newLastModified !== lastModified) {
const {showDesktopNotif, playNotifSound} = await syncStore.getAll();
const {showDesktopNotif, playNotifSound} = await optionsStorage.getAll();
if (showDesktopNotif === true || playNotifSound === true) {
await checkNotifications(lastModified);
}
Expand Down Expand Up @@ -72,7 +57,7 @@ function handleOfflineStatus() {
async function update() {
if (navigator.onLine) {
try {
updateNotificationCount();
await updateNotificationCount();
} catch (error) {
handleError(error);
}
Expand Down Expand Up @@ -123,7 +108,10 @@ function init() {
browser.runtime.onMessage.addListener(onMessage);
browser.runtime.onInstalled.addListener(handleInstalled);

browser.permissions.onAdded.addListener(addNotificationHandler);
// Chrome specific API
if (isChrome()) {
browser.permissions.onAdded.addListener(addNotificationHandler);
}

browser.browserAction.onClicked.addListener(handleBrowserActionClick);

Expand Down
31 changes: 16 additions & 15 deletions source/lib/api.js
@@ -1,9 +1,7 @@
import OptionsSync from 'webext-options-sync';

const syncStore = new OptionsSync();
import optionsStorage from '../options-storage';

export async function getHostname() {
const {rootUrl} = await syncStore.getAll();
const {rootUrl} = await optionsStorage.getAll();

if (/(^(https:\/\/)?(api\.)?github\.com)/.test(rootUrl)) {
return 'github.com';
Expand All @@ -13,14 +11,14 @@ export async function getHostname() {
}

export async function getTabUrl() {
const {onlyParticipating} = await syncStore.getAll();
const {onlyParticipating} = await optionsStorage.getAll();
const useParticipating = onlyParticipating ? '/participating' : '';

return `https://${await getHostname()}/notifications${useParticipating}`;
}

export async function getApiUrl() {
const {rootUrl} = await syncStore.getAll();
const {rootUrl} = await optionsStorage.getAll();

if (/(^(https:\/\/)?(api\.)?github\.com)/.test(rootUrl)) {
return 'https://api.github.com';
Expand All @@ -36,7 +34,7 @@ export async function getParsedUrl(endpoint, params) {
}

export async function getHeaders() {
const {token} = await syncStore.getAll();
const {token} = await optionsStorage.getAll();

if (!(/[a-z\d]{40}/.test(token))) {
throw new Error('missing token');
Expand Down Expand Up @@ -64,19 +62,22 @@ export async function makeApiRequest(endpoint, params) {
}

if (status >= 400) {
return Promise.reject(new Error(`client error: ${status} ${response.statusText}`));
return Promise.reject(new Error('client error'));
}

const json = await response.json();

return {
headers,
json
};
try {
const json = await response.json();
return {
headers,
json
};
} catch (error) {
return Promise.reject(new Error('parse error'));
}
}

export async function getNotificationResponse({maxItems = 100, lastModified = ''} = {}) {
const {onlyParticipating} = await syncStore.getAll();
const {onlyParticipating} = await optionsStorage.getAll();
const params = {
per_page: maxItems // eslint-disable-line camelcase
};
Expand Down
17 changes: 5 additions & 12 deletions source/lib/defaults.js
@@ -1,11 +1,3 @@
export const defaults = new Map([
['rootUrl', 'https://api.github.com/'],
['oauthToken', ''],
['useParticipatingCount', false],
['interval', 60],
['title', 'Notifier for GitHub']
]);

export const notificationReasons = new Map([
['subscribed', 'You are watching the repository'],
['manual', 'You are subscribed to this thread'],
Expand All @@ -20,13 +12,14 @@ export const notificationReasons = new Map([
export const errorTitles = new Map([
['missing token', 'Missing access token, please create one and enter it in Options'],
['server error', 'You have to be connected to the Internet'],
['data format error', 'Unable to find count'],
['client error', 'Invalid token, enter a valid one'],
['parse error', 'Unable to handle server response'],
['default', 'Unknown error']
]);

export const errorSymbols = new Map([
['missing token', 'X'],
['client error', '!'],
['default', '?']
]);

Expand All @@ -41,8 +34,8 @@ export const warningSymbols = new Map([
]);

export const colors = new Map([
['default', [65, 131, 196, 255]],
['error', [166, 41, 41, 255]],
['default', [3, 102, 214, 255]],
['error', [203, 36, 49, 255]],
['warning', [245, 159, 0, 255]]
]);

Expand Down Expand Up @@ -78,4 +71,4 @@ export function getNotificationReasonText(reason) {
return notificationReasons.get(reason) || '';
}

export const defaultTitle = defaults.get('title');
export const defaultTitle = 'Notifier for GitHub';
12 changes: 6 additions & 6 deletions source/lib/notifications-service.js
@@ -1,11 +1,10 @@
import OptionsSync from 'webext-options-sync';
import delay from 'delay';
import optionsStorage from '../options-storage';
import {makeApiRequest, getNotifications, getTabUrl, getHostname} from './api';
import {getNotificationReasonText} from './defaults';
import {openTab} from './tabs-service';
import localStore from './local-store';

const syncStore = new OptionsSync();

function getLastReadForNotification(notification) {
// Extract the specific fragment URL for a notification
// This allows you to directly jump to a specif comment as if you were using
Expand Down Expand Up @@ -102,9 +101,10 @@ export async function showNotifications(notifications) {
const notificationId = `github-notifier-${notification.id}`;
const notificationObject = getNotificationObject(notification);

browser.notifications.create(notificationId, notificationObject);
await browser.notifications.create(notificationId, notificationObject);
await localStore.set(notificationId, notification);

localStore.set(notificationId, notification);
await delay(50);
}
}

Expand All @@ -116,7 +116,7 @@ export async function playNotificationSound() {

export async function checkNotifications(lastModified) {
const notifications = await getNotifications({lastModified});
const {showDesktopNotif, playNotifSound} = await syncStore.getAll();
const {showDesktopNotif, playNotifSound} = await optionsStorage.getAll();

if (playNotifSound && notifications.length > 1) {
await playNotificationSound();
Expand Down
22 changes: 10 additions & 12 deletions source/lib/permissions-service.js
@@ -1,19 +1,17 @@
export async function queryPermission(permission) {
const granted = await browser.permissions.contains({permissions: [permission]});

if (browser.runtime.lastError) {
throw new Error(browser.runtime.lastError);
try {
return browser.permissions.contains({permissions: [permission]});
} catch (error) {
console.log(error);
return false;
}

return granted;
}

export async function requestPermission(permission) {
const granted = await browser.permissions.request({permissions: [permission]});

if (browser.runtime.lastError) {
throw new Error(browser.runtime.lastError);
try {
return browser.permissions.request({permissions: [permission]});
} catch (error) {
console.log(error);
return false;
}

return granted;
}

0 comments on commit f42c6f5

Please sign in to comment.