Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds deploy process for custom Spoke Clients #1237

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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ example/imported/
.certs/
certs/
.env
.ret.credentials
release/spoke-linux
release/spoke-macos
release/spoke-win.exe
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@

**[Spoke Documentation](https://hubs.mozilla.com/docs/spoke-creating-projects.html)**

## Deploying custom client for Hubs Cloud

If you are deploying a custom client, copy your .ret.credentials file from your Hubs folder to this directory. If you do not have one yet, from your Hubs directory run `npm run login` and move the resulting credentials to your Spoke directory. You should then be able to run `npm run deploy` to deploy your custom Spoke.


## Features

:telescope: **Discover**: Explore images, videos, and 3D models from around the web, all without opening up a new tab. With media integrations from Sketchfab and Google Poly, you'll be on your way to creating a scene in no time.
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"integration-tests": "concurrently --success \"first\" --kill-others \"ava ./test/integration\" \"yarn test-server\"",
"update-test-snapshots": "concurrently --success \"first\" --kill-others \"ava -u\" \"yarn test-server\"",
"storybook": "start-storybook",
"deploy": "node -r esm -r @babel/register ./scripts/deploy.js",
"deploy-storybook": "storybook-to-ghpages"
},
"esm": {
Expand Down Expand Up @@ -102,6 +103,7 @@
"recharts": "^1.8.5",
"styled-components": "4.4.0",
"styled-icons": "^8.4.2",
"tar": "^6.1.11",
"three": "https://github.com/MozillaReality/three.js.git#0f9b0024725f0dd917caa54c2934a4ba1fc12c4f",
"three-mesh-bvh": "^0.1.4",
"troika-three-text": "^0.44.0",
Expand Down
123 changes: 123 additions & 0 deletions scripts/deploy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { createReadStream, readFileSync, existsSync, unlinkSync } from "fs";
import { exec } from "child_process";
import rmdir from "rimraf";
import tar from "tar";
import ora from "ora";
import FormData from "form-data";
import fetch from "node-fetch";

if (!existsSync(".ret.credentials")) {
console.log(
"Not logged in, so cannot deploy. To log in, run npm run login on a Hubs and copy the .ret.credentials file into this folder."
);
process.exit(0);
}

const { host, token } = JSON.parse(readFileSync(".ret.credentials"));
console.log(`Deploying to ${host}.`);
const step = ora({ indent: 2 }).start();

const getTs = (() => {
const p = n => (n < 10 ? `0${n}` : n);
return () => {
const d = new Date();
return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}${p(d.getHours())}${p(d.getMinutes())}${p(
d.getSeconds()
)}`;
};
})();

(async () => {
const headers = {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
};

const res = await fetch(`https://${host}/api/ita/configs/spoke`, { headers });
const spokeConfig = await res.json();
const buildEnv = {};
for (const [k, v] of Object.entries(spokeConfig.general)) {
buildEnv[k.toUpperCase()] = v;
}

const version = getTs();

buildEnv.BUILD_VERSION = `1.0.0.${version}`;
buildEnv.ITA_SERVER = "";
buildEnv.POSTGREST_SERVER = "";

const env = Object.assign(process.env, buildEnv);

for (const d in ["./dist"]) {
rmdir(d, err => {
if (err) {
console.error(err);
process.exit(1);
}
});
}

step.text = "Building Spoke.";

await new Promise((resolve, reject) => {
exec("yarn", {}, err => {
if (err) reject(err);
resolve();
});
});

await new Promise((resolve, reject) => {
exec("yarn build", { env }, err => {
if (err) reject(err);
resolve();
});
});

step.text = "Preparing Deploy.";

step.text = "Packaging Build.";
await tar.c({ gzip: true, C: "dist", file: "_build.tar.gz" }, ["."]);
step.text = `Uploading Build ${buildEnv.BUILD_VERSION}.`;

let uploadedUrl;

const runUpload = async attempt => {
if (attempt > 3) {
throw new Error("Upload failed.");
}

const formData = new FormData();
formData.append("media", createReadStream("_build.tar.gz"));
formData.append("promotion_mode", "with_token");

try {
const res = await fetch(`https://${host}/api/v1/media`, { method: "POST", body: formData });
const payload = await res.json();
const url = new URL(payload.origin);
url.searchParams.set("token", payload.meta.access_token);
uploadedUrl = url.toString();
} catch (e) {
console.log(e);
step.text = `Upload failed. Retrying attempt #${attempt + 1}/3`;
await runUpload(attempt + 1);
}
};

await runUpload(0);
unlinkSync("_build.tar.gz");

step.text = "Build uploaded, deploying.";

// Wait for S3 flush, kind of a hack.
await new Promise(res => setTimeout(res, 5000));

await fetch(`https://${host}/api/ita/deploy/spoke`, {
headers,
method: "POST",
body: JSON.stringify({ url: uploadedUrl, version })
});

step.text = `Deployed to ${host}.`;
step.succeed();
process.exit(0);
})();
49 changes: 49 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3767,6 +3767,11 @@ chownr@^1.1.1:
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6"
integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==

chownr@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==

chrome-trace-event@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4"
Expand Down Expand Up @@ -6160,6 +6165,13 @@ fs-minipass@^1.2.5:
dependencies:
minipass "^2.2.1"

fs-minipass@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
dependencies:
minipass "^3.0.0"

fs-readdir-recursive@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27"
Expand Down Expand Up @@ -8936,13 +8948,28 @@ minipass@^2.2.1, minipass@^2.3.5:
safe-buffer "^5.1.2"
yallist "^3.0.0"

minipass@^3.0.0:
version "3.1.6"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.6.tgz#3b8150aa688a711a1521af5e8779c1d3bb4f45ee"
integrity sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==
dependencies:
yallist "^4.0.0"

minizlib@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614"
integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==
dependencies:
minipass "^2.2.1"

minizlib@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
dependencies:
minipass "^3.0.0"
yallist "^4.0.0"

mississippi@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022"
Expand Down Expand Up @@ -8987,6 +9014,11 @@ mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
dependencies:
minimist "0.0.8"

mkdirp@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==

mocha@^6.1.4:
version "6.2.0"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.0.tgz#f896b642843445d1bb8bca60eabd9206b8916e56"
Expand Down Expand Up @@ -12968,6 +13000,18 @@ tar@^4:
safe-buffer "^5.1.2"
yallist "^3.0.3"

tar@^6.1.11:
version "6.1.11"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621"
integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==
dependencies:
chownr "^2.0.0"
fs-minipass "^2.0.0"
minipass "^3.0.0"
minizlib "^2.1.1"
mkdirp "^1.0.3"
yallist "^4.0.0"

telejson@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/telejson/-/telejson-2.2.2.tgz#d61d721d21849a6e4070d547aab302a9bd22c720"
Expand Down Expand Up @@ -14332,6 +14376,11 @@ yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==

yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==

yargs-parser@13.0.0:
version "13.0.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b"
Expand Down