|
| 1 | +/* eslint-disable @typescript-eslint/no-var-requires */ |
| 2 | +const deployInfo = require('./getDeployInfo')(); |
| 3 | +const { execSync } = require('node:child_process'); |
| 4 | +const fs = require('node:fs'); |
| 5 | +const path = require('node:path'); |
| 6 | + |
| 7 | +/* Constants / Config */ |
| 8 | + |
| 9 | +/** keep ".git", ".github", "website" and "scripts" */ |
| 10 | +const keepRegex = /^(?:\.git|website|scripts|versions)/; |
| 11 | +/** Regex to filter and get versions output from git ls-tree */ |
| 12 | +const versionsFilter = /^versions\/(\d+\.x|beta)\/?$/; |
| 13 | +/** Which branch to deploy to */ |
| 14 | +const pagesBranch = 'gh-pages'; |
| 15 | +/** As who should the deploy commit be made as */ |
| 16 | +const commiterInfo = { |
| 17 | + name: 'github-pages-deploy', |
| 18 | + email: '<>', |
| 19 | +}; |
| 20 | +/** Commit message to use, from commit will be automatically added */ |
| 21 | +const commitMessage = `Deploying to ${pagesBranch}`; |
| 22 | + |
| 23 | +/** |
| 24 | + * This Script should not be run outside of a CI or a testing directory |
| 25 | + */ |
| 26 | + |
| 27 | +function main() { |
| 28 | + // ensure this script is not accidentally run |
| 29 | + if (process.env['CI'] !== 'true') { |
| 30 | + console.log( |
| 31 | + 'No CI detected, refusing to run\n' + |
| 32 | + 'Make sure you are running this script in a copy and set Environment Variable CI to true' |
| 33 | + ); |
| 34 | + |
| 35 | + process.exit(1); |
| 36 | + } |
| 37 | + |
| 38 | + // ensure the gh-pages branch exists and is up-to-date |
| 39 | + execSync(`git fetch origin ${pagesBranch}:${pagesBranch}`, { stdio: 'inherit' }); |
| 40 | + |
| 41 | + // setup commiter info |
| 42 | + execSync(`git config user.name "${commiterInfo.name}"`, { stdio: 'inherit' }); |
| 43 | + execSync(`git config user.email "${commiterInfo.email}"`, { stdio: 'inherit' }); |
| 44 | + |
| 45 | + console.log('\nInstall & Build of website\n'); |
| 46 | + |
| 47 | + // make sure everything is correctly installed |
| 48 | + execSync('yarn --cwd ./website install', { stdio: 'inherit' }); |
| 49 | + |
| 50 | + // build the website |
| 51 | + execSync('yarn --cwd ./website build', { stdio: 'inherit' }); |
| 52 | + |
| 53 | + console.log('\nSwitching Branches\n'); |
| 54 | + |
| 55 | + // ensure there is nothing blocking from changing branches |
| 56 | + execSync('git add -A', { stdio: 'inherit' }); |
| 57 | + execSync('git stash push', { stdio: 'inherit' }); |
| 58 | + |
| 59 | + // works because "website" does not exist on the gh-pages branch |
| 60 | + execSync(`git checkout ${pagesBranch}`, { stdio: 'inherit' }); |
| 61 | + |
| 62 | + console.log('\nRemoving & Moving build\n'); |
| 63 | + |
| 64 | + // create deployAs directory, if not empty |
| 65 | + if (!!deployInfo.deployPath) { |
| 66 | + fs.mkdirSync(deployInfo.deployPath, { recursive: true }); |
| 67 | + } |
| 68 | + |
| 69 | + // remove everything except from the "keep" regex |
| 70 | + const deployCleanDir = path.join('.', deployInfo.deployPath); |
| 71 | + for (const entry of fs.readdirSync(deployCleanDir)) { |
| 72 | + if (entry.match(keepRegex)) { |
| 73 | + continue; |
| 74 | + } |
| 75 | + |
| 76 | + const rmPath = path.join(deployCleanDir, entry); |
| 77 | + |
| 78 | + console.log('rm', rmPath); // always log what is removed |
| 79 | + fs.rmSync(rmPath, { recursive: true }); |
| 80 | + } |
| 81 | + |
| 82 | + // move all files from "website/build" to "deployAs" |
| 83 | + const websiteDir = 'website/build'; |
| 84 | + for (const entry of fs.readdirSync(websiteDir)) { |
| 85 | + if (entry.match(keepRegex)) { |
| 86 | + console.error('Website build contained entry from keep. Skipping! entry:', entry); |
| 87 | + continue; |
| 88 | + } |
| 89 | + |
| 90 | + const from = path.join(websiteDir, entry); |
| 91 | + const to = path.join(deployInfo.deployPath, entry); |
| 92 | + console.log('rename', from, '->', to); // always log what is renamed |
| 93 | + fs.renameSync(from, to); |
| 94 | + } |
| 95 | + |
| 96 | + // remove website |
| 97 | + fs.rmSync('website', { recursive: true }); |
| 98 | + |
| 99 | + // generate versions.json file |
| 100 | + const versions = generateVersions(); |
| 101 | + fs.writeFileSync('versions.json', JSON.stringify(versions)); |
| 102 | + |
| 103 | + console.log('\nCommiting Changes\n'); |
| 104 | + |
| 105 | + // add stage all changes |
| 106 | + execSync('git add *', { stdio: 'inherit' }); |
| 107 | + |
| 108 | + let commitmsg = commitMessage; |
| 109 | + const githubSHA = process.env['GITHUB_SHA']; |
| 110 | + |
| 111 | + if (githubSHA) { |
| 112 | + commitmsg += ` from @ ${githubSHA}`; |
| 113 | + } |
| 114 | + |
| 115 | + // commit the changes |
| 116 | + execSync(`git commit -m "${commitmsg}"`, { stdio: 'inherit' }); |
| 117 | + |
| 118 | + // refuse to push changes when not being in a CI (even if CI=true) for local testing |
| 119 | + if (!githubSHA) { |
| 120 | + console.log( |
| 121 | + 'Refusing to push changes, because not in a CI (missing evironment variable "GITHUB_SHA")' |
| 122 | + ); |
| 123 | + process.exit(2); |
| 124 | + } |
| 125 | + |
| 126 | + console.log('\nPushing Changes\n'); |
| 127 | + |
| 128 | + execSync(`git push --set-upstream origin ${pagesBranch}`, { stdio: 'inherit' }); |
| 129 | +} |
| 130 | + |
| 131 | +main(); |
| 132 | + |
| 133 | +/** |
| 134 | + * Generate the versions.json file |
| 135 | + * @returns Object with keys sorted so that "beta" is first and otherwise the highest number descending |
| 136 | + */ |
| 137 | +function generateVersions() { |
| 138 | + console.log('\nGenerating Versions\n'); |
| 139 | + |
| 140 | + const versions_map = new Map(); |
| 141 | + |
| 142 | + try { |
| 143 | + // get existing versions.json file to include version that to merge them |
| 144 | + const pagesVersions = execSync(`git show ${pagesBranch}:versions.json`).toString(); |
| 145 | + |
| 146 | + const parsed = JSON.parse(pagesVersions); |
| 147 | + |
| 148 | + if (Array.isArray(parsed)) { |
| 149 | + throw new Error('versions.json is a array, expected object'); |
| 150 | + } |
| 151 | + |
| 152 | + for (const [key, path] of Object.entries(parsed)) { |
| 153 | + versions_map.set(key, path); |
| 154 | + } |
| 155 | + } catch (err) { |
| 156 | + console.log('failed to get existing versions.json:', err); |
| 157 | + } |
| 158 | + |
| 159 | + // get all existing versions from the gh-pages branch and merge them with existing versions.json |
| 160 | + const versions_tree = execSync(`git ls-tree --name-only ${pagesBranch} versions/`); |
| 161 | + |
| 162 | + // parse all versions from the git output |
| 163 | + for (const line of versions_tree.toString().split('\n')) { |
| 164 | + const caps = versionsFilter.exec(line); |
| 165 | + |
| 166 | + if (caps) { |
| 167 | + versions_map.set(caps[1], line); |
| 168 | + continue; |
| 169 | + } |
| 170 | + |
| 171 | + // ignore a empty line (to log no warning) |
| 172 | + if (line.length === 0) { |
| 173 | + continue; |
| 174 | + } |
| 175 | + |
| 176 | + console.log('no match found for version line:', line); |
| 177 | + } |
| 178 | + |
| 179 | + // always add the current version |
| 180 | + versions_map.set(deployInfo.deployName, deployInfo.deployPath); |
| 181 | + |
| 182 | + // sort the versions so that named branches are at specific places and numbers are highest descending |
| 183 | + const versions = Array.from(versions_map.entries()).sort(([versionA], [versionB]) => { |
| 184 | + if (versionA === 'beta' && versionB === 'beta') { |
| 185 | + return 0; |
| 186 | + } |
| 187 | + if (versionA === 'beta') { |
| 188 | + return -1; |
| 189 | + } |
| 190 | + if (versionB === 'beta') { |
| 191 | + return 1; |
| 192 | + } |
| 193 | + |
| 194 | + const parsedA = parseInt(versionA.split('.')[0]); |
| 195 | + const parsedB = parseInt(versionB.split('.')[0]); |
| 196 | + |
| 197 | + return parsedB - parsedA; |
| 198 | + }); |
| 199 | + |
| 200 | + return Object.fromEntries(versions); |
| 201 | +} |
0 commit comments