Verified Commit c754db9b authored by Aral Balkan's avatar Aral Balkan
Browse files

Build script and version command now support alpha and beta builds

parent ddc338a2
node_modules
dist
.nyc_output
manifest.json
......@@ -16,6 +16,7 @@ const childProcess = require('child_process')
const { compile } = require('nexe')
const minimist = require('minimist')
const package = require('../package.json')
const moment = require('moment')
const cpuArchitecture = os.arch()
// Parse the commandline arguments.
......@@ -23,7 +24,7 @@ const commandLineOptions = minimist(process.argv.slice(2), {boolean: true})
// Display help on syntax error or if explicitly requested.
if (commandLineOptions._.length !== 0 || commandLineOptions.h || commandLineOptions.help) {
console.log('\n Usage: npm run build [--deploy] [--all] [--install]\n')
console.log('\n Usage: npm run build [--deploy] [--all] [--install] [--alpha] [--beta]\n')
process.exit()
}
......@@ -33,19 +34,41 @@ if (cpuArchitecture !== 'x64' && cpuArchitecture !== 'arm') {
process.exit()
}
const releaseType = commandLineOptions.alpha ? 'alpha' : (commandLineOptions.beta ? 'beta' : '')
const releaseTypeName = releaseType === '' ? 'release': releaseType
const releaseSuffix = releaseType === '' ? '' : `-${releaseType}`
const nodeVersion = process.version.slice(1)
// Get the version from the npm package configuration.
const version = package.version
function presentBinaryVersion (binaryVersion) {
const m = moment(binaryVersion, 'YYYYMMDDHHmmss')
return `${m.format('MMMM Do YYYY')} at ${m.format('HH:mm:ss')}`
}
const binaryVersion = moment(new Date()).format('YYYYMMDDHHmmss')
const sourceVersion = package.version
const binaryName = 'site'
const windowsBinaryName = `${binaryName}.exe`
console.log(`\n ⚙ Site.js: building native binaries for Site.js version ${version} (bundling Node version ${nodeVersion})\n`)
console.log(`\n ⚙️ Site.js build started on ${presentBinaryVersion(binaryVersion)}.\n
Build type : ${releaseTypeName}
Binary version: ${binaryVersion}
Source version: ${sourceVersion}
Node version : ${nodeVersion}\n`)
// Write out the manifest file. This will be included in the build so that the binary knows what type of release it is.
// This allows it to modify its behaviour at runtime (e.g., auto-update from beta releases if it’s a beta release).
const manifest = {
binaryVersion,
sourceVersion,
releaseType: releaseTypeName
}
fs.writeFileSync('manifest.json', JSON.stringify(manifest), 'utf-8')
const linuxX64Directory = path.join('dist', 'linux', version)
const linuxArmDirectory = path.join('dist', 'linux-arm', version)
const macOsDirectory = path.join('dist', 'macos', version)
const windowsDirectory = path.join('dist', 'windows', version)
const linuxX64Directory = path.join('dist', `linux${releaseSuffix}`, binaryVersion)
const linuxArmDirectory = path.join('dist', `linux-arm${releaseSuffix}`, binaryVersion)
const macOsDirectory = path.join('dist', `macos${releaseSuffix}`, binaryVersion)
const windowsDirectory = path.join('dist', `windows${releaseSuffix}`, binaryVersion)
fs.mkdirSync(linuxX64Directory, {recursive: true})
fs.mkdirSync(linuxArmDirectory, {recursive: true})
......@@ -64,10 +87,12 @@ const binaryPaths = {
'win32': windowsBinaryPath
}
// Note 1: Linux on ARM doesn’t have a target as we build Node from source.
// Note 2: Ensure that a Nexe build exists for the Node version you’re running as that is
// what will be used. This is by design as you should be testing with the Node
// version that you’re deploying with.
// Note: Ensure that a Nexe build exists for the Node version you’re running as that is
// ===== what will be used. This is by design as you should be deploying with the Node
// version that you’re developing and testing with. Pre-built Nexe base images are
// downloaded from our own remote repository, not from the official Nexe releases
// (so we can include platforms – like ARM – that aren’t covered yet by the
// official releases).
const remote = 'https://sitejs.org/nexe/'
const linuxX64Target = `linux-x64-${nodeVersion}`
const linuxArmTarget = `linux-arm-${nodeVersion}`
......@@ -96,7 +121,7 @@ if (platform === 'linux' && cpuArchitecture === 'arm') { currentPlatformBinaryPa
// Common resources.
const resources = [
'package.json', // Used to get the app’s version at runtime.
'manifest.json', // App-specific metadata generated by this build script (version, etc.)
'bin/commands/*', // Conditionally required based on command-line argument.
// nexe@next does not appear to be making use of the pkg→assets setting in
......@@ -329,7 +354,7 @@ async function build () {
// We use tar and gzip here instead of zip as unzip is not a standard
// part of Linux distributions whereas tar and gzip are. We do not use
// gzip directly as that does not maintain the executable flag on the binary.
const zipFileName = `${version}.tar.gz`
const zipFileName = `${binaryVersion}.tar.gz`
const mainSourceDirectory = path.join(__dirname, '..')
const linuxX64WorkingDirectory = path.join(mainSourceDirectory, linuxX64Directory)
const linuxArmWorkingDirectory = path.join(mainSourceDirectory, linuxArmDirectory)
......@@ -391,7 +416,7 @@ async function build () {
// Write out a dynamic route with the latest version into the site. That endpoint will be used by the
// auto-update feature to decide whether it needs to update.
console.log(' • Adding dynamic version endpoint to Site.js web site.')
const versionRoute = `module.exports = (request, response) => { response.end('${package.version}') }\n`
const versionRoute = `module.exports = (request, response) => { response.end('${binaryVersion}') }\n`
fs.writeFileSync(pathToDynamicVersionRoute, versionRoute, {encoding: 'utf-8'})
// Update the install file and deploy them to the Site.js web site.
......@@ -402,7 +427,7 @@ async function build () {
//
const linuxAndMacOSInstallScriptFile = path.join(mainSourceDirectory, 'script', 'install')
let linuxAndMacOSInstallScript = fs.readFileSync(linuxAndMacOSInstallScriptFile, 'utf-8')
linuxAndMacOSInstallScript = linuxAndMacOSInstallScript.replace(/\d+\.\d+\.\d+/g, package.version)
linuxAndMacOSInstallScript = linuxAndMacOSInstallScript.replace(/\d+\.\d+\.\d+/g, binaryVersion)
fs.writeFileSync(linuxAndMacOSInstallScriptFile, linuxAndMacOSInstallScript)
fs.copyFileSync(linuxAndMacOSInstallScriptFile, pathToLinuxAndMacOSInstallationScriptFileOnWebSite)
......@@ -412,7 +437,7 @@ async function build () {
//
const windowsInstallScriptFile = path.join(mainSourceDirectory, 'script', 'windows')
let windowsInstallScript = fs.readFileSync(windowsInstallScriptFile, 'utf-8')
windowsInstallScript = windowsInstallScript.replace(/\d+\.\d+\.\d+/g, package.version)
windowsInstallScript = windowsInstallScript.replace(/\d+\.\d+\.\d+/g, binaryVersion)
fs.writeFileSync(windowsInstallScriptFile, windowsInstallScript)
fs.copyFileSync(windowsInstallScriptFile, pathToWindowsInstallationScriptFileOnWebSite)
......
......@@ -18,43 +18,38 @@
//
////////////////////////////////////////////////////////////////////////////////
const https = require('@small-tech/https')
const fs = require('fs-extra')
const path = require('path')
const os = require('os')
const fs = require('fs-extra')
const path = require('path')
const os = require('os')
const childProcess = require('child_process')
const https = require('@small-tech/https')
const expressWebSocket = require('@small-tech/express-ws')
const Hugo = require('@small-tech/node-hugo')
const instant = require('@small-tech/instant')
const crossPlatformHostname = require('@small-tech/cross-platform-hostname')
const clr = require('./lib/clr')
const express = require('express')
const bodyParser = require('body-parser')
const expressWebSocket = require('@small-tech/express-ws')
const helmet = require('helmet')
const morgan = require('morgan')
const enableDestroy = require('server-destroy')
const Graceful = require('node-graceful')
const httpProxyMiddleware = require('http-proxy-middleware')
const instant = require('@small-tech/instant')
const Hugo = require('@small-tech/node-hugo')
const cli = require('./bin/lib/cli')
const serve = require('./bin/commands/serve')
const chokidar = require('chokidar')
const decache = require('decache')
const childProcess = require('child_process')
const getRoutes = require('@small-tech/web-routes-from-files')
const Stats = require('./lib/Stats')
const errors = require('./lib/errors')
const getRoutes = require('@small-tech/web-routes-from-files')
const Graceful = require('node-graceful')
const express = require('express')
const bodyParser = require('body-parser')
const helmet = require('helmet')
const httpProxyMiddleware = require('http-proxy-middleware')
const enableDestroy = require('server-destroy')
const moment = require('moment')
const morgan = require('morgan')
const chokidar = require('chokidar')
const decache = require('decache')
const clr = require('./lib/clr')
const cli = require('./bin/lib/cli')
const serve = require('./bin/commands/serve')
const Stats = require('./lib/Stats')
const errors = require('./lib/errors')
class Site {
static #appNameAndVersionAlreadyLogged = false
static #manifest = null
static get HUGO_LOGO () {
return `${clr('🅷', 'magenta')} ${clr('🆄', 'blue')} ${clr('🅶', 'green')} ${clr('🅾', 'yellow')} `
}
......@@ -79,12 +74,17 @@ class Site {
return
}
if (!Site.appNameAndVersionAlreadyLogged && !process.argv.includes('--dont-log-app-name-and-version')) {
if (!Site.#appNameAndVersionAlreadyLogged && !process.argv.includes('--dont-log-app-name-and-version')) {
let prefix1 = compact ? ' 💕 ' : ' 💕 '
let prefix2 = compact ? ' ' : ' '
this.readAndCacheManifest()
let message = [
`\n${prefix1}Site.js v${Site.versionNumber()} ${clr(`(running on Node ${process.version})`, 'italic')}\n\n`,
`\n${prefix1}Site.js ${this.humanReadableReleaseType()}\n\n`,
`${prefix2}Build : ${clr(this.humanReadableVersion(), 'green')}\n`,
`${prefix2}Engine: ${clr(`Node.js ${process.version}`, 'green')}\n`,
`${prefix2}Source: ${clr(`https://source.small-tech.org/site.js/app/tags/${this.#manifest.sourceVersion}`, 'cyan')}\n\n`,
`${prefix2}╔═══════════════════════════════════════════╗\n`,
`${prefix2}║ Like this? Fund us! ║\n`,
`${prefix2}║ ║\n`,
......@@ -95,16 +95,49 @@ class Site {
console.log(message)
Site.appNameAndVersionAlreadyLogged = true
Site.#appNameAndVersionAlreadyLogged = true
}
}
// Calculate and cache version number from package.json on first call.
static readAndCacheManifest () {
this.#manifest = JSON.parse(fs.readFileSync(path.join(__dirname, './manifest.json'), 'utf-8'))
}
// Return the binary version.
static versionNumber () {
if (Site._versionNumber === null) {
Site._versionNumber = JSON.parse(fs.readFileSync(path.join(__dirname, './package.json'), 'utf-8')).version
if (this.#manifest === null) {
this.readAndCacheManifest()
}
return this.#manifest.binaryVersion
}
static humanReadableVersion () {
if (this.#manifest === null) {
this.readAndCacheManifest()
}
const m = moment(this.#manifest.binaryVersion, 'YYYYMMDDHHmmss')
return `${m.format('MMMM Do, YYYY')} at ${m.format('HH:mm:ss')}`
}
static humanReadableReleaseType () {
if (this.#manifest === null) {
this.readAndCacheManifest()
}
switch(this.#manifest.releaseType) {
case 'alpha': return clr(`\n
█████  ██  ██████  ██  ██  █████ 
██   ██ ██  ██   ██ ██  ██ ██   ██ 
███████ ██  ██████  ███████ ███████ 
██   ██ ██  ██      ██   ██ ██   ██ 
██  ██ ███████ ██  ██  ██ ██  ██`, 'red')
case 'beta': return clr(`\n
██████  ███████ ████████  █████ 
██   ██ ██         ██    ██   ██ 
██████  █████  ██  ███████ 
██   ██ ██     ██  ██   ██ 
██████  ███████  ██  ██  ██`, 'yellow')
default: return ''
}
return Site._versionNumber
}
// Default error pages.
......@@ -1113,7 +1146,5 @@ class Site {
}
}
Site.appNameAndVersionAlreadyLogged = false
Site._versionNumber = null
module.exports = Site
......@@ -16,6 +16,12 @@
"build": "node bin/build.js",
"deploy": "bin/build.js --deploy",
"install-locally": "node bin/build.js --install",
"build-alpha": "node bin/build.js --alpha",
"deploy-alpha": "bin/build.js --deploy --alpha",
"install-locally-alpha": "node bin/build.js --install --alpha",
"build-beta": "node bin/build.js --beta",
"deploy-beta": "bin/build.js --deploy --beta",
"install-locally-beta": "node bin/build.js --install --beta",
"test": "QUIET=true tape test/*.js | tap-spec",
"coverage": "QUIET=true nyc tape test/*.js | tap-nyc"
},
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment