diff --git a/data/release-notes/3-0/0-rc.yml b/data/release-notes/3-0/0-rc.yml index ab62dc23b1..d38b93195b 100644 --- a/data/release-notes/3-0/0-rc.yml +++ b/data/release-notes/3-0/0-rc.yml @@ -134,7 +134,8 @@ sections: - '`ghe-config-apply` occassionally fails with `ERROR: Failure waiting for nomad jobs to apply` until the Nomad job queue is cleared. This currently requires as admin to delete `/etc/nomad-jobs/queue`.' - When configuring a multiple replica node, the status of the replica can be incorrectly synchronized. - Customers attempting to restore a 3.0 backup to a new instance should not pre-configure the instance, as it may lead to a bad state for user logins. We recommend restoring to a fresh, unconfigured instance. - - GitHub Enterprise Server 3.0 release candidates are not yet available in the Azure marketplace. To test RC1 in staging environments, start a 2.21 or 2.22 instance, and then upgrade it with the Azure upgrade package on the download page. + - GitHub Enterprise Server 3.0 release candidates are not yet available in the Azure marketplace. To test release candidates in staging environments, start a 2.21 or 2.22 instance, and then upgrade it with the Azure upgrade package on the download page. + - The image and upgrade package download size has increased. Customers on slow internet connections may find the packages take longer to download. backups: - '{% data variables.product.prodname_ghe_server %} 3.0 requires at least [GitHub Enterprise Backup Utilities 3.0.0](https://github.com/github/backup-utils) for [Backups and Disaster Recovery](/enterprise-server@3.0/admin/configuration/configuring-backups-on-your-appliance).' diff --git a/includes/head.html b/includes/head.html index aae0ee2a4b..480c9cbc7d 100644 --- a/includes/head.html +++ b/includes/head.html @@ -23,7 +23,7 @@ /> {% endfor %} - + diff --git a/includes/scripts.html b/includes/scripts.html index 7c489813d5..1654d3dd35 100644 --- a/includes/scripts.html +++ b/includes/scripts.html @@ -1 +1 @@ - + diff --git a/layouts/dev-toc.html b/layouts/dev-toc.html index 59fe20ab5a..80c0900265 100644 --- a/layouts/dev-toc.html +++ b/layouts/dev-toc.html @@ -3,7 +3,7 @@ Docs TOC - + diff --git a/lib/built-asset-urls.js b/lib/built-asset-urls.js new file mode 100644 index 0000000000..ea2613a883 --- /dev/null +++ b/lib/built-asset-urls.js @@ -0,0 +1,23 @@ +const fs = require('fs') +const path = require('path') +const crypto = require('crypto') + +// Get an MD4 Digest Hex content hash, loosely based on Webpack `[contenthash]` +function getContentHash (absFilePath) { + const buffer = fs.readFileSync(absFilePath) + const hash = crypto.createHash('md4') + hash.update(buffer) + return hash.digest('hex') +} + +function getUrl (relFilePath) { + const absFilePath = path.join(process.cwd(), relFilePath) + return `/${relFilePath}?hash=${getContentHash(absFilePath)}` +} + +module.exports = { + main: { + js: getUrl('dist/index.js'), + css: getUrl('dist/index.css') + } +} diff --git a/middleware/context.js b/middleware/context.js index f5217852a9..3d24f94608 100644 --- a/middleware/context.js +++ b/middleware/context.js @@ -7,6 +7,7 @@ const { getVersionStringFromPath, getProductStringFromPath, getPathWithoutLangua const productNames = require('../lib/product-names') const warmServer = require('../lib/warm-server') const featureFlags = Object.keys(require('../feature-flags')) +const builtAssets = require('../lib/built-asset-urls') // Supply all route handlers with a baseline `req.context` object // Note that additional middleware in middleware/index.js adds to this context object @@ -42,5 +43,8 @@ module.exports = async function contextualize (req, res, next) { req.context.siteTree = siteTree req.context.pages = pageMap + // JS + CSS asset paths + req.context.builtAssets = builtAssets + return next() } diff --git a/tests/rendering/server.js b/tests/rendering/server.js index edb868218e..1228ecde66 100644 --- a/tests/rendering/server.js +++ b/tests/rendering/server.js @@ -4,6 +4,7 @@ const { get, getDOM, head } = require('../helpers/supertest') const { describeViaActionsOnly } = require('../helpers/conditional-runs') const path = require('path') const { loadPages } = require('../../lib/pages') +const builtAssets = require('../../lib/built-asset-urls') describe('server', () => { jest.setTimeout(60 * 1000) @@ -694,7 +695,8 @@ describe('?json query param for context debugging', () => { describe('stylesheets', () => { it('compiles and sets the right content-type header', async () => { - const res = await get('/dist/index.css') + const stylesheetUrl = builtAssets.main.css + const res = await get(stylesheetUrl) expect(res.statusCode).toBe(200) expect(res.headers['content-type']).toBe('text/css; charset=UTF-8') }) @@ -703,7 +705,8 @@ describe('stylesheets', () => { describe('client-side JavaScript bundle', () => { let res beforeAll(async (done) => { - res = await get('/dist/index.js') + const scriptUrl = builtAssets.main.js + res = await get(scriptUrl) done() })