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

add CircleCI support #68

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = {
"node": true,
"es6": true,
"browser": true,
"jest": true,
},
"parserOptions": {
"ecmaVersion": 8,
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ npm-debug.log
.vscode

frontend/.oauth_token
frontend/app.yaml
frontend/app.yaml

coverage/
55 changes: 48 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

This repo contains the frontend and backend for running Lighthouse in CI and integration with Github Pull Requests. An example web service is hosted for demo purposes.

**Note**: This repo was previously named "lighthouse-ci".
**Note**: This repo was previously named "lighthouse-ci".

## Auditing GitHub Pull Requests

> Please note: This drop in service is considered **Beta**. There are no SLAs or uptime guarantees. If you're interested in running your own CI server in a Docker container, check out [Running your own CI server](#running-your-own-ci-server).

Lighthouse can be setup as part of your CI on **Travis only**. As new pull requests come in, the **Lighthouse Bot tests the changes and reports back the new score**.
Lighthouse can be setup as part of your CI on **Travis/CircleCI only**. As new pull requests come in, the **Lighthouse Bot tests the changes and reports back the new score**.

<img width="700" alt="Run Lighthouse on Github PRs" src="https://user-images.githubusercontent.com/238208/27059055-70ba6e86-4f89-11e7-8ead-932aab0f2634.png">

Expand All @@ -25,10 +25,16 @@ First, add [lighthousebot](https://github.com/lighthousebot) as a collaborator o
[Request an API Key](https://goo.gl/forms/9BzzhHd1sKzsvyC52). API keys will eventually be
enforced and are necessary so we can contact you when there are changes to the CI system.

Once you have a key, update Travis settings by adding an `LIGHTHOUSE_API_KEY` environment variables with your key:
Once you have a key, update Travis/CircleCI settings by adding an `LIGHTHOUSE_API_KEY` environment variables with your key:

**Travis:**

<img width="875" alt="Travis LIGHTHOUSE_API_KEY env variable " src="https://user-images.githubusercontent.com/2837064/32105842-2635de42-bb2a-11e7-983a-921a802d38b3.jpg">

**CircleCI:**

<img width="875" alt="CircleCI LIGHTHOUSE_API_KEY env variable " src="https://user-images.githubusercontent.com/26760571/60830641-55653680-a1c0-11e9-91a5-17abd2a320be.png">

The `lighthousebot` script will include your key in requests made to the CI server.

### 2. Deploy the PR
Expand All @@ -37,13 +43,27 @@ We recommend deploying your PR to a real staging server instead of running a loc
A staging environment will produce realistic performance numbers that are
more representative of your production setup. The Lighthouse report will be more accurate.

**Travis:**

In `.travis.yml`, add an `after_success` that **deploys the PR's changes to a staging server**.

```bash
after_success:
- ./deploy.sh # TODO(you): deploy the PR changes to your staging server.
```

**CircleCI:**

In `.circleci/config.yml`, add a build step that **deploys the PR's changes to a staging server**.

```bash
after_success:
steps:
- run:
name: Deploy to staging
command: ./deploy.sh # TODO(you): deploy the PR changes to your staging server.
```

Since every hosting environment has different deployment setups, the implementation of `deploy.sh` is left to the reader.

> **Tip:** Using Google App Engine? Check out [`deploy_pr_gae.sh`](https://github.com/GoogleChrome/chromium-dashboard/blob/master/travis/deploy_pr_gae.sh) which shows how to install the GAE SDK and deploy PR changes programmatically.
Expand All @@ -52,7 +72,9 @@ after_success:

Install the script:

npm i --save-dev https://github.com/GoogleChromeLabs/lighthousebot
```bash
npm i --save-dev https://github.com/GoogleChromeLabs/lighthousebot
```

Add an NPM script to your `package.json`:

Expand All @@ -62,7 +84,9 @@ Add an NPM script to your `package.json`:
}
```

Next, in `.travis.yml` call [`npm run lh`][runlighthouse-link] as the last step in `after_success`:
**Travis:**

In `.travis.yml` call [`npm run lh`][runlighthouse-link] as the last step in `after_success`:

```yml
install:
Expand All @@ -72,6 +96,23 @@ after_success:
- npm run lh -- https://staging.example.com
```

**CircleCI:**

In `.circleci/config.yml` call [`npm run lh`][runlighthouse-link] as the last step in `after_success`:

```yml
install:
- npm install # make sure to install the deps when CircleCI runs.
after_success:
steps:
- run:
name: Deploy to staging
command: ./deploy.sh # TODO(you): deploy the PR changes to your staging server.
- run:
name: Start lighthouse bot
command: npm run lh -- https://staging.example.com
```

When Lighthouse is done auditing the URL, the bot will post a comment to the pull
request containing the updated scores:

Expand Down Expand Up @@ -154,7 +195,7 @@ For the backend, see [builder/README.md](https://github.com/GoogleChromeLabs/lig
Other changes, to the "Development" section:

- Create a personal OAuth token in https://github.com/settings/tokens. Drop it in `frontend/.oauth_token`.
- Add a `LIGHTHOUSE_CI_HOST` env variable to Travis settings that points to your own URL. The one where you deploy the Docker container.
- Add a `LIGHTHOUSE_CI_HOST` env variable to Travis/CircleCI settings that points to your own URL. The one where you deploy the Docker container.

## Development

Expand Down Expand Up @@ -215,7 +256,7 @@ Relevant source:
- `frontend/public/` - UI for https://lighthouse-ci.appspot.com/try.

### Bot CI server (frontend)
> Server that responds to requests from Travis.
> Server that responds to requests from Travis/CircleCI.

REST endpoints:
- `https://lighthouse-ci.appspot.com/run_on_chrome`
Expand Down
50 changes: 50 additions & 0 deletions envHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'use strict';

function isInvokedFromPr() {
return process.env.TRAVIS_EVENT_TYPE === 'pull_request' || !!process.env.CIRCLE_PULL_REQUEST;
}

function getPrInfo() {
// Travis
if (process.env.TRAVIS_PULL_REQUEST) {
return {
number: parseInt(process.env.TRAVIS_PULL_REQUEST, 10),
sha: process.env.TRAVIS_PULL_REQUEST_SHA
};
}

// CircleCI
if (process.env.CIRCLE_PULL_REQUEST) {
const pieces = process.env.CIRCLE_PULL_REQUEST.split('/');
return {
number: parseInt(pieces[pieces.length-1], 10),
sha: process.env.CIRCLE_SHA1
};
}

return {};
}

function getRepoInfo() {
// Travis
if (process.env.TRAVIS_PULL_REQUEST_SLUG) {
const repoSlug = process.env.TRAVIS_PULL_REQUEST_SLUG;
const pieces = repoSlug.split('/');
return {
owner: pieces[0],
name: pieces[1]
};
}

// CircleCI
if (process.env.CIRCLE_PROJECT_REPONAME) {
return {
owner: process.env.CIRCLE_PROJECT_USERNAME,
name: process.env.CIRCLE_PROJECT_REPONAME
};
}

return null;
}

module.exports = {isInvokedFromPr, getPrInfo, getRepoInfo};
86 changes: 86 additions & 0 deletions envHelpers.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
'use strict';
const {isInvokedFromPr, getPrInfo, getRepoInfo} = require('./envHelpers');

describe('envHelpers', () => {
beforeEach(() => {
delete process.env.TRAVIS_EVENT_TYPE;
delete process.env.TRAVIS_PULL_REQUEST;
delete process.env.TRAVIS_PULL_REQUEST_SHA;
delete process.env.TRAVIS_PULL_REQUEST_SLUG;

delete process.env.CIRCLE_PULL_REQUEST;
delete process.env.CIRCLE_SHA1;
delete process.env.CIRCLE_PROJECT_USERNAME;
delete process.env.CIRCLE_PROJECT_REPONAME;
});

describe('isInvokedFromPr', () => {
test('should return false when not invoked from Travis or CircleCI pr', () => {
expect(isInvokedFromPr()).toBe(false);

process.env.TRAVIS_EVENT_TYPE = 'non_pr_event';
expect(isInvokedFromPr()).toBe(false);
});

test('should return true when invoked from Travis pr', () => {
process.env.TRAVIS_EVENT_TYPE = 'pull_request';
expect(isInvokedFromPr()).toBe(true);
});

test('should return true when invoked from CircleCI pr', () => {
process.env.CIRCLE_PULL_REQUEST = 'https://github.com/owner_name/repo_name/pull/10';
expect(isInvokedFromPr()).toBe(true);
});
});

describe('getPrInfo', () => {
test('should return an empty object when not invoked from Travis or CircleCI', () => {
expect(getPrInfo()).toEqual({});
});

test('should return pr information when invoked from Travis', () => {
process.env.TRAVIS_PULL_REQUEST = '15';
process.env.TRAVIS_PULL_REQUEST_SHA = '00000000';

expect(getPrInfo()).toEqual({
number: 15,
sha: '00000000'
});
});

test('should return pr information when invoked from CircleCI pr', () => {
process.env.CIRCLE_PULL_REQUEST = 'https://github.com/owner_name/repo_name/pull/30';
process.env.CIRCLE_SHA1 = '33333333';

expect(getPrInfo()).toEqual({
number: 30,
sha: '33333333'
});
});
});

describe('getRepoInfo', () => {
test('should return null when not invoked from Travis or CircleCI', () => {
expect(getRepoInfo()).toBeNull();
});

test('should return repo information when invoked from Travis', () => {
process.env.TRAVIS_PULL_REQUEST_SLUG = 'owner_name/repo_name';

expect(getRepoInfo()).toEqual({
owner: 'owner_name',
name: 'repo_name'
});
});

test('should return repo information when invoked from CircleCI', () => {
process.env.CIRCLE_PROJECT_USERNAME = 'owner_name';
process.env.CIRCLE_PROJECT_REPONAME = 'repo_name';

expect(getRepoInfo()).toEqual({
owner: 'owner_name',
name: 'repo_name'
});
});
});
});
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@
"lighthousebot": "runlighthouse.js"
},
"scripts": {
"deploy": "./deploy.sh"
"deploy": "./deploy.sh",
"test": "jest",
"coverage": "jest --coverage"
},
"dependencies": {
"minimist": "^1.2.0",
"node-fetch": "^2.2.0"
},
"devDependencies": {
"eslint": "^5.6.1",
"eslint-config-google": "^0.10.0"
"eslint-config-google": "^0.10.0",
"jest": "^24.8.0"
}
}
22 changes: 10 additions & 12 deletions runlighthouse.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

const fetch = require('node-fetch'); // polyfill
const minimist = require('minimist');
const {isInvokedFromPr, getPrInfo, getRepoInfo} = require('./envHelpers');

const CI_HOST = process.env.LIGHTHOUSE_CI_HOST || 'https://lighthouse-ci.appspot.com';
const API_KEY = process.env.LIGHTHOUSE_API_KEY || process.env.API_KEY;
Expand Down Expand Up @@ -124,20 +125,15 @@ function getConfig() {
}
console.log(`Using runner: ${config.runner}`);

config.pr = {
number: parseInt(process.env.TRAVIS_PULL_REQUEST, 10),
sha: process.env.TRAVIS_PULL_REQUEST_SHA
};
const pr = getPrInfo();
config.pr = pr;

const repoSlug = process.env.TRAVIS_PULL_REQUEST_SLUG;
if (!repoSlug) {
throw new Error('This script can only be run on Travis PR requests.');
const repo = getRepoInfo();
if (!repo) {
throw new Error('This script can only be run on Travis/CircleCI PR requests.');
}

config.repo = {
owner: repoSlug.split('/')[0],
name: repoSlug.split('/')[1]
};
config.repo = repo;

return config;
}
Expand Down Expand Up @@ -181,8 +177,10 @@ function run(config) {

// Run LH if this is a PR.
const config = getConfig();
if (process.env.TRAVIS_EVENT_TYPE === 'pull_request') {
if (isInvokedFromPr()) {
run(config);
} else {
console.log('Lighthouse is not run for non-PR commits.');
}