2015-12-11 22:36:42 +03:00
|
|
|
[![Build Status](https://travis-ci.org/mozilla/addons-linter.svg?branch=master)](https://travis-ci.org/mozilla/addons-linter)
|
|
|
|
[![Coverage Status](https://coveralls.io/repos/mozilla/addons-linter/badge.svg?branch=master&service=github)](https://coveralls.io/github/mozilla/addons-linter?branch=master)
|
|
|
|
[![Dependency Status](https://david-dm.org/mozilla/addons-linter.svg)](https://david-dm.org/mozilla/addons-linter)
|
|
|
|
[![devDependency Status](https://david-dm.org/mozilla/addons-linter/dev-status.svg)](https://david-dm.org/mozilla/addons-linter#info=devDependencies)
|
|
|
|
[![npm version](https://badge.fury.io/js/addons-linter.svg)](https://badge.fury.io/js/addons-linter)
|
2015-09-16 19:43:49 +03:00
|
|
|
|
2015-12-11 22:36:42 +03:00
|
|
|
# addons-linter
|
2015-09-16 19:28:28 +03:00
|
|
|
|
2015-12-11 22:36:42 +03:00
|
|
|
The Add-ons Linter, JS edition.
|
2015-09-16 19:28:28 +03:00
|
|
|
|
2015-12-11 22:36:42 +03:00
|
|
|
Here is the [canonical list of rules](http://mozilla.github.io/addons-linter/) we're working from.
|
2015-10-29 23:17:15 +03:00
|
|
|
|
2015-10-22 03:10:08 +03:00
|
|
|
## Usage
|
|
|
|
|
|
|
|
### Command Line
|
|
|
|
|
2015-12-11 22:36:42 +03:00
|
|
|
You need node.js to use the add-ons linter.
|
2015-10-22 03:10:08 +03:00
|
|
|
|
2015-12-11 22:36:42 +03:00
|
|
|
To validate your add-on locally, install the linter from
|
2015-10-22 03:10:08 +03:00
|
|
|
[npm](http://nodejs.org/):
|
|
|
|
|
|
|
|
```
|
2015-12-11 22:36:42 +03:00
|
|
|
# Install globally so you can use the linter from any directory on
|
2015-11-04 22:12:02 +03:00
|
|
|
# your machine.
|
2015-12-11 22:36:42 +03:00
|
|
|
npm install -g addons-linter
|
2015-10-22 03:10:08 +03:00
|
|
|
```
|
|
|
|
|
2015-12-11 22:36:42 +03:00
|
|
|
After installation, run the linter and direct it to your add-on file:
|
2015-10-22 03:10:08 +03:00
|
|
|
|
|
|
|
```
|
2016-06-30 21:40:37 +03:00
|
|
|
addons-linter my-addon.zip
|
2015-10-22 03:10:08 +03:00
|
|
|
```
|
|
|
|
|
2015-11-21 03:57:13 +03:00
|
|
|
Alternatively you can point it at a directory:
|
|
|
|
|
|
|
|
```
|
2015-12-11 22:36:42 +03:00
|
|
|
addons-linter my/package/dir
|
2015-11-21 03:57:13 +03:00
|
|
|
```
|
|
|
|
|
2015-12-11 22:36:42 +03:00
|
|
|
The addons-linter will check your add-on and show you errors, warnings,
|
2015-10-22 03:10:08 +03:00
|
|
|
and friendly messages for your add-on. If you want more info on the options
|
|
|
|
you can enable/disable for the command-line app, use the `--help` option:
|
|
|
|
|
|
|
|
```
|
2015-12-11 22:36:42 +03:00
|
|
|
addons-linter --help
|
2015-10-22 03:10:08 +03:00
|
|
|
```
|
|
|
|
|
2017-03-04 08:36:12 +03:00
|
|
|
### Import Linter API into another NodeJS application
|
|
|
|
|
|
|
|
```js
|
|
|
|
import linter from 'addons-linter';
|
|
|
|
|
|
|
|
const sourceDir = process.cwd();
|
|
|
|
|
|
|
|
const linter = linter.createInstance({
|
|
|
|
config: {
|
|
|
|
// This mimics the first command line argument from yargs,
|
|
|
|
// which should be the directory to the extension.
|
|
|
|
_: [sourceDir],
|
|
|
|
logLevel: process.env.VERBOSE ? 'debug' : 'fatal',
|
|
|
|
stack: Boolean(process.env.VERBOSE),
|
|
|
|
pretty: false,
|
|
|
|
warningsAsErrors: false,
|
|
|
|
metadata: false,
|
|
|
|
output: 'none',
|
|
|
|
boring: false,
|
|
|
|
selfHosted: false,
|
|
|
|
// Lint only the selected files
|
|
|
|
// scanFile: ['path/...', ...]
|
|
|
|
//
|
|
|
|
// Exclude files:
|
|
|
|
shouldScanFile: (fileName) => true,
|
|
|
|
},
|
|
|
|
// This prevent the linter to exit the nodejs application
|
|
|
|
runAsBinary: false,
|
|
|
|
});
|
|
|
|
|
|
|
|
linter.run()
|
|
|
|
.then((linterResults) => ...)
|
|
|
|
.catch((err) => console.error("addons-linter failure: ", err));
|
|
|
|
```
|
|
|
|
|
|
|
|
`linter.output` is composed by the following properties (the same of the 'json' report type):
|
|
|
|
|
|
|
|
```js
|
|
|
|
{
|
|
|
|
metadata: {...},
|
|
|
|
summary: {
|
|
|
|
error, notice, warning,
|
|
|
|
},
|
|
|
|
scanFile,
|
|
|
|
count,
|
|
|
|
error: [{
|
|
|
|
type: "error",
|
|
|
|
code, message, description,
|
|
|
|
column, file, line
|
|
|
|
}, ...],
|
|
|
|
warning: [...],
|
|
|
|
notice: [...]
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2015-10-20 18:19:20 +03:00
|
|
|
## Development
|
|
|
|
|
2015-12-11 22:36:42 +03:00
|
|
|
If you'd like to help us develop the addons-linter, that's great! It's
|
2015-10-22 03:10:08 +03:00
|
|
|
pretty easy to get started, you just need node.js installed on your machine.
|
|
|
|
|
2015-10-24 01:58:44 +03:00
|
|
|
### Quick Start
|
|
|
|
|
|
|
|
If you have node.js installed, here's the quick start to getting
|
|
|
|
your development dependencies installed and building the binary:
|
|
|
|
|
|
|
|
```
|
2015-12-11 22:36:42 +03:00
|
|
|
git clone https://github.com/mozilla/addons-linter.git
|
|
|
|
cd addons-linter
|
2015-10-24 01:58:44 +03:00
|
|
|
npm install
|
|
|
|
npm start
|
|
|
|
# Leave running to watch for changes or cancel to stop watching.
|
2016-06-30 21:40:37 +03:00
|
|
|
bin/addons-linter my-addon.zip
|
2015-10-24 01:58:44 +03:00
|
|
|
```
|
|
|
|
|
2015-10-20 18:19:20 +03:00
|
|
|
### Required node version
|
2015-10-13 18:22:47 +03:00
|
|
|
|
2015-12-11 22:36:42 +03:00
|
|
|
addons-linter requires node.js v0.12.x or greater. Using nvm is probably the
|
2015-10-22 02:55:08 +03:00
|
|
|
easiest way to manage multiple node versions side by side. See
|
2015-10-13 18:22:47 +03:00
|
|
|
[nvm on github](https://github.com/creationix/nvm) for more details.
|
|
|
|
|
2015-10-20 18:19:20 +03:00
|
|
|
### Install dependencies
|
2015-09-16 19:28:28 +03:00
|
|
|
|
2015-09-25 18:45:49 +03:00
|
|
|
Install dependencies with [npm](http://nodejs.org/):
|
2015-09-16 19:28:28 +03:00
|
|
|
|
2015-09-25 18:45:49 +03:00
|
|
|
```
|
|
|
|
npm install
|
|
|
|
```
|
|
|
|
|
|
|
|
Dependencies are automatically kept up-to-date using [greenkeeper](http://greenkeeper.io/).
|
|
|
|
|
2015-10-22 02:55:08 +03:00
|
|
|
### npm scripts and grunt tasks
|
2015-10-21 14:17:27 +03:00
|
|
|
|
2015-10-22 02:55:08 +03:00
|
|
|
Run basic automation tasks via npm scripts (e.g. `npm test`).
|
|
|
|
These don't need `grunt-cli` installed globally.
|
2015-10-21 14:17:27 +03:00
|
|
|
|
2015-10-22 02:55:08 +03:00
|
|
|
#### npm scripts
|
2015-10-21 14:17:27 +03:00
|
|
|
|
|
|
|
| Script | Description |
|
|
|
|
|--------------|-----------------------------------------------------------|
|
|
|
|
| npm test | Runs the tests |
|
|
|
|
| npm start | Builds the lib and watches for changes |
|
2015-10-28 14:46:51 +03:00
|
|
|
| npm run build| Builds the lib (used by Travis) |
|
2015-10-21 14:17:27 +03:00
|
|
|
|
2015-10-22 02:55:08 +03:00
|
|
|
If you install `grunt-cli` globally then you can run other tasks.
|
2015-10-21 14:17:27 +03:00
|
|
|
|
|
|
|
```
|
|
|
|
npm install -g grunt-cli
|
|
|
|
```
|
|
|
|
|
|
|
|
From the grunt docs:
|
|
|
|
|
|
|
|
> The job of the Grunt CLI is simple: run the version of Grunt which has
|
|
|
|
been installed next to a Gruntfile. This allows multiple versions of
|
|
|
|
Grunt to be installed on the same machine simultaneously.
|
|
|
|
|
|
|
|
#### Grunt tasks
|
|
|
|
|
2015-10-23 18:59:39 +03:00
|
|
|
| Script | Description |
|
|
|
|
|------------------------|--------------------------------------------------|
|
|
|
|
| grunt test | Runs the tests |
|
|
|
|
| grunt test-no-coverage | Runs the tests (without coverage) |
|
2015-10-23 21:27:59 +03:00
|
|
|
| grunt build | Builds the lib |
|
|
|
|
| grunt start | Builds the lib and watches for changes |
|
2015-10-23 18:59:39 +03:00
|
|
|
| grunt eslint | Lints the files with eslint (Run in grunt test) |
|
2015-10-21 14:17:27 +03:00
|
|
|
|
|
|
|
|
|
|
|
### Building and watching for changes
|
|
|
|
|
2015-10-22 02:55:08 +03:00
|
|
|
You can run `npm start` to build the library and then rebuild on file changes.
|
2015-10-21 14:17:27 +03:00
|
|
|
|
2015-12-11 22:36:42 +03:00
|
|
|
Once you build the library you can use the CLI in `bin/addons-linter`.
|
2015-10-21 14:17:27 +03:00
|
|
|
|
2015-10-20 18:19:20 +03:00
|
|
|
### Testing
|
2015-09-25 18:45:49 +03:00
|
|
|
|
2015-10-21 14:17:27 +03:00
|
|
|
Tests use `grunt` but don't require global `grunt`. Just run `npm test`.
|
|
|
|
|
|
|
|
#### Coverage
|
|
|
|
|
|
|
|
We're looking to maintain coverage at 100%. Use the coverage data in the
|
2015-10-22 02:55:08 +03:00
|
|
|
test output to work out what lines aren't covered and ensure they're covered.
|
2015-10-21 14:17:27 +03:00
|
|
|
|
|
|
|
#### Testing and promises
|
|
|
|
|
2015-10-22 02:55:08 +03:00
|
|
|
Tests using promises should return the promise. This removes the need to call
|
|
|
|
`done()` in your tests:
|
2015-09-25 18:45:49 +03:00
|
|
|
|
2015-10-21 14:17:27 +03:00
|
|
|
```javascript
|
2015-10-22 02:55:08 +03:00
|
|
|
it('should do something promise-y', () => {
|
2015-10-21 14:17:27 +03:00
|
|
|
return somePromiseCall()
|
|
|
|
.then(() => {
|
|
|
|
// Assert stuff here.
|
|
|
|
});
|
|
|
|
})
|
2015-09-25 18:45:49 +03:00
|
|
|
```
|
2015-10-21 14:17:27 +03:00
|
|
|
|
|
|
|
To test for rejection you can use this pattern:
|
|
|
|
|
|
|
|
```javascript
|
2015-11-03 19:16:00 +03:00
|
|
|
import { unexpectedSuccess } from './helpers';
|
2015-10-22 22:37:31 +03:00
|
|
|
...
|
2015-10-21 14:17:27 +03:00
|
|
|
it('should reject because of x', () => {
|
|
|
|
return somePromiseCall()
|
2015-10-22 22:37:31 +03:00
|
|
|
.then(unexpectedSuccess)
|
2015-10-21 14:17:27 +03:00
|
|
|
.catch((err) => {
|
|
|
|
// make assertions about err here.
|
|
|
|
});
|
|
|
|
})
|
2015-09-25 18:45:49 +03:00
|
|
|
```
|
2015-10-16 14:58:22 +03:00
|
|
|
|
2015-10-21 14:17:27 +03:00
|
|
|
#### Assertions and testing APIs
|
|
|
|
|
2015-10-22 02:55:08 +03:00
|
|
|
`assert`, `describe`, `it`, `beforeEach`, and `afterEach` are
|
|
|
|
available in tests by default–you don't need to import anything
|
|
|
|
for those to work.
|
2015-10-21 14:17:27 +03:00
|
|
|
|
|
|
|
We're using chai for assertions [see the Chai docs for the API
|
|
|
|
available](http://chaijs.com/api/assert/)
|
|
|
|
|
2015-10-20 18:19:20 +03:00
|
|
|
### Logging
|
2015-10-16 14:58:22 +03:00
|
|
|
|
|
|
|
We use [bunyan](https://github.com/trentm/node-bunyan) for logging:
|
|
|
|
|
|
|
|
* By default logging is off (level is set to 'fatal') .
|
|
|
|
* Logging in tests can be enabled using an env var e.g: `LOG_LEVEL=debug grunt test`
|
|
|
|
* Logging on the cli can be enabled with `--log-level [level]`.
|
|
|
|
* Bunyan by default logs JSON. If you want the json to be pretty printed
|
|
|
|
pipe anything that logs into `bunyan` e.g. `LOG_LEVEL=debug grunt test
|
|
|
|
| node_modules/bunyan/bin/bunyan`
|
2015-10-20 18:19:20 +03:00
|
|
|
|
|
|
|
|
|
|
|
## Architecture
|
|
|
|
|
2015-12-11 22:36:42 +03:00
|
|
|
In a nutshell the way the linter works is to take an add-on
|
2015-10-20 18:19:20 +03:00
|
|
|
package, extract the metadata from the xpi (zip) format and then
|
|
|
|
process the files it finds through various content scanners.
|
|
|
|
|
2015-12-11 22:36:42 +03:00
|
|
|
![Architecture diagram](https://raw.github.com/mozilla/addons-linter/master/docs/diagrams/addon-linter-flow.png)
|
2015-10-20 19:20:43 +03:00
|
|
|
|
2015-10-20 18:19:20 +03:00
|
|
|
### Scanners
|
|
|
|
|
2015-10-22 02:55:08 +03:00
|
|
|
Each file-type has a scanner. For example: CSS files use `CSSScanner`;
|
|
|
|
Javascript files use `JavaScriptScanner`. Each scanner looks at relevant
|
2015-10-20 18:19:20 +03:00
|
|
|
files and passes each file through a parser which then hands off to
|
2015-10-22 02:55:08 +03:00
|
|
|
a set of rules that look for specific things.
|
2015-10-20 18:19:20 +03:00
|
|
|
|
|
|
|
### Rules
|
|
|
|
|
2015-10-22 02:55:08 +03:00
|
|
|
Rules get exported via a single function in a single file. A rule can
|
2015-10-20 18:19:20 +03:00
|
|
|
have private functions it uses internally, but rule code should not depend
|
2015-10-22 02:55:08 +03:00
|
|
|
on another rule file and each rule file should export one rule.
|
2015-10-20 18:19:20 +03:00
|
|
|
|
|
|
|
Each rule function is passed data from the scanner in order to carry
|
|
|
|
out the specific checks for that rule it returns a list of objects which
|
|
|
|
are then made into message objects and are passed to the Collector.
|
|
|
|
|
|
|
|
### Collector
|
|
|
|
|
2015-10-22 02:55:08 +03:00
|
|
|
The Collector is an in-memory store for all validation message objects
|
|
|
|
"collected" as the contents of the package are processed.
|
2015-10-20 18:19:20 +03:00
|
|
|
|
|
|
|
### Messages
|
|
|
|
|
|
|
|
Each message has a code which is also its key. It has a message which
|
|
|
|
is a short outline of what the message represents, and a description
|
|
|
|
which is more detail into why that message was logged. The type of
|
|
|
|
the message is set as messages are added so that if necessary the
|
|
|
|
same message could be an error *or* a warning for example.
|
|
|
|
|
|
|
|
### Output
|
|
|
|
|
2015-12-11 22:36:42 +03:00
|
|
|
Lastly when the processing is complete the linter will output
|
2015-10-20 18:19:20 +03:00
|
|
|
the collected data as text or JSON.
|
2015-10-28 14:46:51 +03:00
|
|
|
|
|
|
|
## Deploys
|
|
|
|
|
|
|
|
We deploy to npm automatically using TravisCI. To release a new version,
|
|
|
|
increment the version in `package.json` and create a PR. Make sure your
|
|
|
|
version number conforms to the [semver][] format eg: `0.2.1`.
|
|
|
|
|
|
|
|
After merging the PR, [create a new release][new release] with the same tag
|
|
|
|
name as your new version. Once the build passes it will deploy. Magic! ✨
|
|
|
|
|
2015-12-11 22:36:42 +03:00
|
|
|
[new release]: https://github.com/mozilla/addons-linter/releases/new
|
2015-10-28 14:46:51 +03:00
|
|
|
[semver]: http://semver.org/
|