Retire try.html and create new dev + prod builds (#1194)

- Followup from #1163
- Retire try.html
- Separate build config for dev and production
    - Move config for badge examples into the JS build
- Move the prod transform into npm scripts
    - In the future this could be handled using a bundler plugin
- make website builds production build as before
- Run the production build in CI to make sure it’s working
- Build the frontend on Heroku
This commit is contained in:
Paul Melnikow
2017-10-28 14:02:45 -04:00
committed by GitHub
parent cf14ab1464
commit bde4d925f2
18 changed files with 162 additions and 4136 deletions
+1
View File
@@ -17,6 +17,7 @@ before_script:
script:
- npm run lint
- npm run test:js
- npm run build:production
jobs:
include:
+7 -6
View File
@@ -13,15 +13,16 @@ endif
favicon:
node gh-badge.js '' '' '#bada55' .png > favicon.png
website:
@mkdir -p build && \
node_modules/.bin/babel-node frontend/render-badge-examples && \
cat frontend/fragments/try-header.html build/badge-examples-fragment.html frontend/fragments/try-footer.html > try.html && \
cat try.html | $(SED) "s,(<img src=\")(/[^\"\?]+)\",\1https://img.shields.io\2?maxAge=2592000\"," \
footer-production-transform:
@$(SED) "s,(<img src=\")(/[^\"\?]+)\",\1https://img.shields.io\2?maxAge=2592000\"," \
frontend/fragments/try-footer.html \
| $(SED) "s,(<img src=\")(/[^\"\?]+\?[^\"]+)\",\1https://img.shields.io\2\&maxAge=2592000\"," \
| $(SED) "s,<span id='imgUrlPrefix'>,&https://img.shields.io," \
| $(SED) "s,var origin = '';,var origin = 'https://img.shields.io';," \
| $(SED) "s,<style>,<!-- WARNING: THIS FILE WAS GENERATED FROM try.html -->\\"$(NEWLINE)"<style>," > index.html
> build/try-footer.html
website:
npm run build:production
deploy: deploy-s0 deploy-s1 deploy-s2 deploy-gh-pages
+4 -3
View File
@@ -27,7 +27,7 @@ continuous integration services, package registries, distributions, app
stores, social networks, code coverage services, and code analysis services.
Every month it serves over 470 million images.
In addition to hosting the shields.io home page and server code, this monorepo
In addition to hosting the shields.io frontend and server code, this monorepo
hosts an [NPM library for generating badges][gh-badges], and the badge design
specification.
@@ -118,8 +118,9 @@ Development
1. Install Node 6 or later. You can use the [package manager][] of your choice.
2. Clone this repository.
3. Run `npm install` to install the dependencies.
4. Run `node server 1111 localhost` to start the server.
5. Open `http://localhost:1111/try.html` to view the home page.
4. Run `npm run build` to build the frontend.
5. Run `npm start` to start the server.
6. Open `http://[::]:8080/` to view the home page.
[package manager]: https://nodejs.org/en/download/package-manager/
+10 -1
View File
@@ -10,7 +10,16 @@
"website": "https://shields.io/",
"repository": "https://github.com/badges/shields",
"logo": "http://shields.io/favicon.png",
"success_url": "/try.html",
"env": {
"INFOSITE": {
"description": "The home page.",
"value": "/"
},
"NPM_CONFIG_PRODUCTION": {
"description": "Configure whether devDependencies are installed (they are needed for the build).",
"value": "false"
}
},
"formation": {
"web": {
"quantity": 1,
+23 -17
View File
@@ -27,17 +27,19 @@ I suppose you have [git](https://git-scm.com/) installed.
If you do not, install it and learn about the [Github workflow](http://try.github.io/).
1. [Fork][fork] this repository.
2. Clone the fork
2. Clone the fork
`git clone git@github.com:YOURGITHUBUSERNAME/shields.git`
3. `cd shields`
4. Install npm and other required packages (Ubuntu 16.10)
4. Install npm and other required packages (Ubuntu 16.10)
`sudo apt-get install npm nodejs-legacy curl imagemagick`
5. Install all packages
5. Install all packages
`npm install`
6. Run the server
6. Build the frontend
`npm run build`
6. Run the server
`npm start`
7. Visit the website to check the badges get loaded slowly:
[http://[::1]:8080/try.html](http://[::1]/try.html)
7. Visit the website to check the badges get loaded slowly:
[http://[::1]:8080/](http://[::1]/)
(3) Open an Issue
-----------------
@@ -203,17 +205,21 @@ This has something to do with [private/secret.json](https://github.com/badges/sh
Once you are done implementing your badge, you can add it to the collection on [shields.io](http://shields.io/).
First, we make it visible on [http://[::1]:8080/try.html][try].
Edit [try.html][tryhtml] in the right section (Build, Downloads, ...) and add your badge:
First, we make it visible locally at [http://[::1]:8080/][home]. Edit
[lib/all-badge-examples.js][allbadges] in the right category (Build,
Downloads, ...) and add your badge:
```
<tr><th data-keywords='test badge keywords for google'>Test Badge from the tutorial</th>
<td><img src='/test/subject/STATUS.svg' alt=''/></td>
<td><code>https://img.shields.io/test/subject/STATUS.svg</code></td>
</tr>
```js
{
title: 'Test Badge from the tutorial',
keywords: [
'some-search-keyword'
],
previewUri: '/test/subject/STATUS.svg',
},
```
Save, restart and you can see it [locally][try].
Save, run `npm run build`, and you can see it [locally][home].
## (4.4) Write Tests
@@ -235,7 +241,7 @@ Please follow it to include tests on your pull-request.
## (5) Create a Pull Request
You have implemented changes in `server.js` and `try.html`.
You have implemented changes in `server.js` and `lib/all-badge-examples.js`.
These changes shall go live on shields.io.
To do that, [create a pull-request](https://help.github.com/articles/creating-a-pull-request/).
By doing this, your changes are made public to the shields team.
@@ -257,9 +263,9 @@ These files can also be of help for creating your own badge.
[example-issue]: https://github.com/badges/shields/issues/886
[fork]: https://github.com/badges/shields/fork
[format]: INSTALL.md#format
[try]: http://[::1]:8080/try.html
[home]: http://[::1]:8080/
[server]: ../server.js
[tryhtml]: ../try.html
[allbadges]: ../lib/all-badge-examples.js
[edit]: https://github.com/badges/shields/edit/master/doc/TUTORIAL.md
[add-pr]: https://github.com/badges/shields/issues?utf8=%E2%9C%93&q=is%3Aissue%20in%3Atitle%20add%20
[new-badge]: https://github.com/badges/shields/pulls?q=is%3Apr+label%3Anew-badge
+6 -8
View File
@@ -22,13 +22,11 @@ npm install # You may need sudo for this.
[package manager]: https://nodejs.org/en/download/package-manager/
Build the index
---------------
Build the "real" index page:
Build the frontend
------------------
```sh
make website
BASE_URL=https://your-server.example.com npm run build:production
```
@@ -50,7 +48,7 @@ node server 8080
The root gets redirected to https://shields.io.
For testing purposes, you can go to `http://localhost/try.html`.
For testing purposes, you can go to `http://localhost/`.
Heroku
@@ -93,11 +91,11 @@ $ docker run --rm -p 8080:80 --env-file shields.env --name shields shields
> gh-badges@1.1.2 start /usr/src/app
> node server.js
http://[::1]:80/try.html
http://[::1]/
```
Assuming Docker is running locally, you should be able to get to the
application at http://localhost:8080/try.html.
application at http://localhost:8080/.
If you run Docker in a virtual machine (such as boot2docker or Docker Machine)
then you will need to replace `localhost` with the IP address of that virtual
+17 -4
View File
@@ -1,7 +1,20 @@
'use strict';
const url = require('url');
// const URL = url.URL; // Requires Node 7+.
const { URL } = require('whatwg-url');
const React = require('react');
function resolvePreviewUri (uri, baseUri, isProductionBuild) {
if (isProductionBuild) {
const parsed = new URL(uri, baseUri);
parsed.searchParams.set('maxAge', 2592000);
return parsed.toString();
} else {
return uri;
}
}
const Badge = (props) => {
const attrs = {};
if (props.documentation) {
@@ -11,9 +24,9 @@ const Badge = (props) => {
attrs['data-keywords'] = props.keywords.join(' ');
}
const previewImage = props.previewUri
? (<img src={props.previewUri} alt="" />)
? (<img src={resolvePreviewUri(props.previewUri, props.baseUri, props.isProductionBuild)} alt="" />)
: '\u00a0'; // non-breaking space
const exampleUri = `https://img.shields.io${props.exampleUri || props.previewUri}`;
const exampleUri = url.resolve(props.baseUri, props.exampleUri || props.previewUri);
return (
<tr><th {... attrs}>{ props.title }:</th>
@@ -28,7 +41,7 @@ const Category = (props) => (
<h3 id={props.category.id}>{ props.category.name }</h3>
<table className='badge'><tbody>
{
props.examples.map((badgeData, i) => (<Badge key={i} {...badgeData} />))
props.examples.map((badgeData, i) => (<Badge key={i} {...badgeData} baseUri={props.baseUri} isProductionBuild={props.isProductionBuild} />))
}
</tbody></table>
</div>
@@ -37,7 +50,7 @@ const Category = (props) => (
const BadgeExamples = (props) => (
<div>
{
props.examples.map((categoryData, i) => (<Category key={i} {...categoryData} />))
props.examples.map((categoryData, i) => (<Category key={i} {...categoryData} baseUri={props.baseUri} isProductionBuild={props.isProductionBuild} />))
}
</div>
);
-17
View File
@@ -1,17 +0,0 @@
#!/bin/bash
rm ../lib/all-badge-examples.js
cat >../lib/all-badge-examples.js <<HERE
'use strict';
const allBadgeExamples =
HERE
cat ../all-badges.json >> ../lib/all-badge-examples.js
sed -Ei '' -e 's/\"([a-zA-Z]+)\":/\1:/' ../lib/all-badge-examples.js
sed -Ei '' -e "s/\"/\'/g" ../lib/all-badge-examples.js
cat >>../lib/all-badge-examples.js <<HERE
module.exports = allBadgeExamples;
HERE
-50
View File
@@ -1,50 +0,0 @@
// Generate a JSON file from try.html with the initial badge example data.
'use strict';
const fs = require('fs');
const path = require('path');
const cheerio = require('cheerio');
const inputPath = path.join(__dirname, '..', 'try.html');
const html = fs.readFileSync(inputPath);
const $ = cheerio.load(html);
const sectionHeaders = $('h3');
const sections = [];
$('table.badge').each((i, table) => {
const category = {
id: sectionHeaders.eq(i).attr('id'),
name: sectionHeaders.eq(i).text().trim(),
};
const examples = [];
$(table).find('tr').each((i, row) => {
const th = $(row).find('th');
const keywordsAttr = th.attr('data-keywords');
const previewUri = $(row).find('img').attr('src');
const exampleUri = $(row).find('code').text().replace(/^https:\/\/img\.shields\.io/, '');
const rowData = {
title: th.text().trim().replace(/:$/, ''),
previewUri,
keywords: keywordsAttr ? keywordsAttr.split(' ') : undefined,
documentation: th.attr('data-doc'),
};
if (exampleUri !== previewUri) {
rowData.exampleUri = exampleUri;
}
examples.push(rowData);
})
sections.push({ category, examples });
})
const outputPath = path.join(__dirname, '..', 'all-badges.json');
fs.writeFileSync(outputPath, JSON.stringify(sections, 0, 2));
File diff suppressed because it is too large Load Diff
+5 -1
View File
@@ -2,6 +2,7 @@
const fs = require('fs');
const path = require('path');
const envFlag = require('node-env-flag');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const pretty = require('pretty');
@@ -11,8 +12,11 @@ const BadgeExamples = require('./badge-examples');
// const badgeExampleData = JSON.parse(fs.readFileSync(inputPath));
const badgeExampleData = require('../lib/all-badge-examples');
const baseUri = process.env.BASE_URL || 'https://img.shields.io';
const isProductionBuild = envFlag(process.env.PRODUCTION_BUILD, false);
const fragment = ReactDOMServer.renderToStaticMarkup(
<BadgeExamples examples={badgeExampleData} />);
<BadgeExamples examples={badgeExampleData} {...{baseUri, isProductionBuild}} />);
const outputPath = path.join(__dirname, '..', 'build', 'badge-examples-fragment.html');
fs.writeFileSync(outputPath, pretty(fragment));
+65
View File
@@ -4568,6 +4568,12 @@
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
"dev": true
},
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
"integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
"dev": true
},
"lolex": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/lolex/-/lolex-2.1.3.tgz",
@@ -4927,6 +4933,31 @@
}
}
},
"node-env-flag": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/node-env-flag/-/node-env-flag-0.1.0.tgz",
"integrity": "sha1-vn1DxRHCeBqg+GiOfY9Cb3WSS8U=",
"dev": true,
"requires": {
"chai": "4.1.2"
},
"dependencies": {
"chai": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz",
"integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=",
"dev": true,
"requires": {
"assertion-error": "1.0.2",
"check-error": "1.0.2",
"deep-eql": "3.0.1",
"get-func-name": "2.0.0",
"pathval": "1.1.0",
"type-detect": "4.0.3"
}
}
}
},
"node-fetch": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
@@ -8204,6 +8235,40 @@
"integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ=",
"dev": true
},
"whatwg-url": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.3.0.tgz",
"integrity": "sha512-rM+hE5iYKGPAOu05mIdJR47pYSR2vDzfrTEFRc/S8D3L60yW8BuXmUJ7Kog7x/DrokFN7JNaHKadpzjouKRRAw==",
"dev": true,
"requires": {
"lodash.sortby": "4.7.0",
"tr46": "1.0.1",
"webidl-conversions": "4.0.2"
},
"dependencies": {
"punycode": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz",
"integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=",
"dev": true
},
"tr46": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
"integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
"dev": true,
"requires": {
"punycode": "2.1.0"
}
},
"webidl-conversions": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
"dev": true
}
}
},
"whatwg-url-compat": {
"version": "0.6.5",
"resolved": "https://registry.npmjs.org/whatwg-url-compat/-/whatwg-url-compat-0.6.5.tgz",
+12 -3
View File
@@ -52,8 +52,14 @@
"test:services:pr:run": "mocha --delay service-tests/runner/cli.js --stdin < pull-request-services.log",
"test:services:pr": "npm run test:services:pr:prepare && npm run test:services:pr:run",
"test": "npm run lint && npm run test:js",
"build": "make website",
"start": "node server 8080 ::"
"prebuild:examples": "mkdirp build",
"build:examples": "node_modules/.bin/babel-node frontend/render-badge-examples",
"build:copy-fragments": "cp frontend/fragments/try-header.html frontend/fragments/try-footer.html build/",
"build:concat": "cat build/try-header.html build/badge-examples-fragment.html build/try-footer.html > index.html",
"build": "npm run build:examples && npm run build:copy-fragments && npm run build:concat",
"build:production": "PRODUCTION_BUILD=true npm run build:examples && npm run build:copy-fragments && make footer-production-transform && npm run build:concat",
"heroku-postbuild": "npm run build",
"start": "INFOSITE=/ node server 8080 ::"
},
"bin": {
"badge": "./gh-badge.js"
@@ -93,8 +99,10 @@
"is-svg": "^2.1.0",
"lodash.difference": "^4.5.0",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"mocha": "^4.0.1",
"nock": "^9.0.13",
"node-env-flag": "^0.1.0",
"node-fetch": "^1.6.3",
"nyc": "^11.2.1",
"opn-cli": "^3.1.0",
@@ -105,7 +113,8 @@
"read-all-stdin-sync": "^1.0.5",
"rimraf": "^2.6.2",
"semver-regex": "^1.0.0",
"sinon": "^4.0.1"
"sinon": "^4.0.1",
"whatwg-url": "^6.3.0"
},
"engines": {
"node": ">= 6",
-1
View File
@@ -1 +0,0 @@
../try.html
+9 -7
View File
@@ -19,7 +19,7 @@ var tryUrl = require('url').format({
protocol: secureServer ? 'https' : 'http',
hostname: bindAddress,
port: serverPort,
pathname: 'try.html',
pathname: '/',
});
var log = require('./lib/log.js');
var badge = require('./lib/badge.js');
@@ -7261,9 +7261,11 @@ function(data, match, end, ask) {
}
});
// Redirect the root to the website.
camp.route(/^\/$/, function(data, match, end, ask) {
ask.res.statusCode = 302;
ask.res.setHeader('Location', infoSite);
ask.res.end();
});
if (infoSite !== '/') {
// Redirect the root to the website.
camp.route(/^\/$/, function(data, match, end, ask) {
ask.res.statusCode = 302;
ask.res.setHeader('Location', infoSite);
ask.res.end();
});
}
+2 -2
View File
@@ -173,7 +173,7 @@ runner.
Here's the output:
```
http://localhost:1111/try.html
http://localhost:1111/
Travis CI
build status on default branch
@@ -197,7 +197,7 @@ t.create('build status on named branch')
```
```
http://localhost:1111/try.html
http://localhost:1111/
Travis CI
build status on default branch
+1 -1
View File
@@ -1,7 +1,7 @@
# Base URL for redirects etc.
BASE_URL=http://localhost:8080
# Where your homepage is
INFOSITE=http://localhost:8080/try.html
INFOSITE=http://localhost:8080/
# GitHub settings
GITHUB_URL=https://api.github.com
-2769
View File
File diff suppressed because it is too large Load Diff