Updated deployment process
This commit is contained in:
parent
ba166fc7f0
commit
0eeb87cd7b
8 changed files with 150 additions and 137 deletions
36
deploy.sh
36
deploy.sh
|
|
@ -1,42 +1,22 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Edit these variables before deploying
|
# Edit these variables before deploying
|
||||||
DOMAIN="os.prozilla.dev"
|
|
||||||
COMMIT_MESSAGE="Deployed build to GitHub Pages"
|
COMMIT_MESSAGE="Deployed build to GitHub Pages"
|
||||||
REPO_URL="https://github.com/Prozilla/ProzillaOS"
|
REPO_URL="https://github.com/Prozilla/ProzillaOS"
|
||||||
|
|
||||||
# ------- You don't need to edit anything below this line -------
|
# ------- You don't need to edit anything below this line -------
|
||||||
|
|
||||||
echo -e "Domain: \e[0;36m$DOMAIN\e[0m"
|
echo -e "\e[0;33mDeploying to GitHub Pages...\e[0m"
|
||||||
|
|
||||||
|
domain=$(cat dist/CNAME)
|
||||||
|
|
||||||
|
echo -e "Domain: \e[0;36m$domain\e[0m"
|
||||||
echo -e "Commit message: \e[0;36m$COMMIT_MESSAGE\e[0m"
|
echo -e "Commit message: \e[0;36m$COMMIT_MESSAGE\e[0m"
|
||||||
echo -e "Repository: \e[0;36m$REPO_URL\e[0m\n"
|
echo -e "Repository: \e[0;36m$REPO_URL\e[0m"
|
||||||
|
|
||||||
echo -e "\e[0;33mConfiguring routing...\e[0m"
|
|
||||||
echo $DOMAIN > dist/CNAME
|
|
||||||
cp dist/index.html dist/404.html
|
|
||||||
|
|
||||||
# Use template and pages data to generate index.html files
|
|
||||||
input="tmp/pages.csv"
|
|
||||||
template="tmp/template.html"
|
|
||||||
while IFS=";" read -r app_id app_name app_description
|
|
||||||
do
|
|
||||||
path="dist/$app_id/index.html"
|
|
||||||
echo -e "- dist/\e[0;36m$app_id/index.html\e[0m"
|
|
||||||
|
|
||||||
mkdir -p "dist/$app_id"
|
|
||||||
cp $template $path
|
|
||||||
|
|
||||||
# Fill template
|
|
||||||
sed -i "s/_APP_NAME/$app_name/g" $path
|
|
||||||
sed -i "s/_APP_DESCRIPTION/$app_description/g" $path
|
|
||||||
sed -i "s/_APP_ID/$app_id/g" $path
|
|
||||||
done < <(tail -n +2 $input)
|
|
||||||
rm -r tmp
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
echo -e "\e[0;33mDeploying to GitHub Pages...\e[0m"
|
if gh-pages -x -d dist -m $COMMIT_MESSAGE -r $REPO_URL ; then
|
||||||
if gh-pages -d dist -m $COMMIT_MESSAGE -r $REPO_URL ; then
|
echo -e "\e[0;32m✓ Successfully deployed to \e[0;36mhttps://$domain/\e[0m"
|
||||||
echo -e "\e[0;32m✓ Successfully deployed to \e[0;36mhttps://$DOMAIN/\e[0m"
|
|
||||||
else
|
else
|
||||||
echo -e "\e[0;31mFailed to deploy\e[0m"
|
echo -e "\e[0;31mFailed to deploy\e[0m"
|
||||||
fi
|
fi
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
<meta name="apple-mobile-web-app-title" content="ProzillaOS">
|
<meta name="apple-mobile-web-app-title" content="ProzillaOS">
|
||||||
<meta name="application-name" content="ProzillaOS">
|
<meta name="application-name" content="ProzillaOS">
|
||||||
<meta name="msapplication-TileColor" content="#0d1114">
|
<meta name="msapplication-TileColor" content="#0d1114">
|
||||||
<meta name="theme-color" content="#4DFFE1">
|
<meta name="theme-color" content="#4D9CFF">
|
||||||
|
|
||||||
<!-- Open Graph -->
|
<!-- Open Graph -->
|
||||||
<meta property="og:title" content="ProzillaOS | Web-based Operating System"/>
|
<meta property="og:title" content="ProzillaOS | Web-based Operating System"/>
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
<meta name="twitter:title" content="ProzillaOS | Web-based Operating System"/>
|
<meta name="twitter:title" content="ProzillaOS | Web-based Operating System"/>
|
||||||
<meta name="twitter:description" content="ProzillaOS is an open-source web-based operating system inspired by Ubuntu Linux and Windows made with React.js by Prozilla."/>
|
<meta name="twitter:description" content="ProzillaOS is an open-source web-based operating system inspired by Ubuntu Linux and Windows made with React.js by Prozilla."/>
|
||||||
<meta name="twitter:card" content="summary_large_image"/>
|
<meta name="twitter:card" content="summary_large_image"/>
|
||||||
<meta name="twitter:image" content="/assets/banner-logo-title.png?v=2"/>
|
<meta name="twitter:image" content="https://os.prozilla.dev/assets/banner-logo-title.png?v=2"/>
|
||||||
<meta name="twitter:url" content="https://os.prozilla.dev/">
|
<meta name="twitter:url" content="https://os.prozilla.dev/">
|
||||||
|
|
||||||
<!-- Fonts -->
|
<!-- Fonts -->
|
||||||
|
|
@ -53,7 +53,7 @@
|
||||||
"mainEntity": [
|
"mainEntity": [
|
||||||
{
|
{
|
||||||
"@type": "Question",
|
"@type": "Question",
|
||||||
"name": "Is ProzillaOS open source?",
|
"name": "Is ProzillaOS open-source?",
|
||||||
"acceptedAnswer": {
|
"acceptedAnswer": {
|
||||||
"@type": "Answer",
|
"@type": "Answer",
|
||||||
"text": "Yes, the source code for ProzillaOS is hosted on <a href=\"https://github.com/Prozilla/ProzillaOS\">GitHub</a>."
|
"text": "Yes, the source code for ProzillaOS is hosted on <a href=\"https://github.com/Prozilla/ProzillaOS\">GitHub</a>."
|
||||||
|
|
@ -70,6 +70,8 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- Inserted tags -->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run ProzillaOS.</noscript>
|
<noscript>You need to enable JavaScript to run ProzillaOS.</noscript>
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "vite --port 3000 --host",
|
"start": "vite --port 3000 --host",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"serve": "vite preview",
|
"serve": "vite preview --port 8080 --host",
|
||||||
"predeploy": "npm run build && npm run prep",
|
"predeploy": "npm run build && npm run stage",
|
||||||
"deploy": "sh deploy.sh",
|
"stage": "node --no-warnings --loader ts-node/esm ./src/tools/stage",
|
||||||
"prep": "node --no-warnings --loader ts-node/esm ./src/tools/prep"
|
"deploy": "sh deploy.sh"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
|
|
||||||
This is ProzillaOS, a web-based operating system made with React.js by [Prozilla](https://prozilla.dev/).
|
This is ProzillaOS, a web-based operating system made with React.js by [Prozilla](https://prozilla.dev/).
|
||||||
|
|
||||||
## Open Source
|
## Open-source
|
||||||
|
|
||||||
ProzillaOS is [open source](https://github.com/Prozilla/ProzillaOS)! Feel free to fork this project and create your own OS or share feedback by creating an issue on the GitHub page.
|
ProzillaOS is [open-source](https://github.com/Prozilla/ProzillaOS)! Feel free to fork this project and create your own OS or share feedback by creating an issue on the GitHub page.
|
||||||
|
|
||||||
## Support ProzillaOS
|
## Support ProzillaOS
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
# https://www.robotstxt.org/robotstxt.html
|
|
||||||
User-agent: *
|
|
||||||
Disallow:
|
|
||||||
Sitemap: https://os.prozilla.dev/sitemap.xml
|
|
||||||
|
|
@ -2,7 +2,8 @@ import { ANSI } from "./apps/terminal.config";
|
||||||
|
|
||||||
export const NAME = "ProzillaOS";
|
export const NAME = "ProzillaOS";
|
||||||
export const TAG_LINE = "Web-based Operating System";
|
export const TAG_LINE = "Web-based Operating System";
|
||||||
export const BASE_URL = "https://os.prozilla.dev/";
|
export const DOMAIN = "os.prozilla.dev";
|
||||||
|
export const BASE_URL = `https://${DOMAIN}/`;
|
||||||
|
|
||||||
export const ASCII_LOGO = `
|
export const ASCII_LOGO = `
|
||||||
:.
|
:.
|
||||||
|
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
import fs from "node:fs";
|
|
||||||
import { APP_DESCRIPTIONS, APP_NAMES, APPS } from "../config/apps.config";
|
|
||||||
import { ANSI } from "../config/apps/terminal.config";
|
|
||||||
import { BASE_URL, NAME, TAG_LINE } from "../config/branding.config";
|
|
||||||
import { WALLPAPERS } from "../config/desktop.config";
|
|
||||||
|
|
||||||
const PATH_TO_SITEMAP = "dist/sitemap.xml";
|
|
||||||
const PATH_TO_PAGES = "tmp/pages.csv";
|
|
||||||
const PATH_TO_INDEX = "dist/index.html";
|
|
||||||
const PATH_TO_TEMPLATE = "tmp/template.html";
|
|
||||||
|
|
||||||
function generateSitemap() {
|
|
||||||
const date = new Date();
|
|
||||||
const lastModified = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
|
|
||||||
|
|
||||||
const images = WALLPAPERS.map((path) => `
|
|
||||||
<image:image>
|
|
||||||
<image:loc>${BASE_URL.slice(0, -1) + path}</image:loc>
|
|
||||||
</image:image>`
|
|
||||||
);
|
|
||||||
|
|
||||||
const pages = Object.values(APPS).map((appId) => `
|
|
||||||
<url>
|
|
||||||
<loc>${BASE_URL + appId}</loc>
|
|
||||||
<lastmod>${lastModified}</lastmod>
|
|
||||||
</url>`
|
|
||||||
);
|
|
||||||
|
|
||||||
const sitemap = `
|
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE xml>
|
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
|
||||||
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
|
|
||||||
<url>
|
|
||||||
<loc>${BASE_URL}</loc>
|
|
||||||
<lastmod>${lastModified}</lastmod>
|
|
||||||
${images.join("")}
|
|
||||||
</url>
|
|
||||||
${pages.join("")}
|
|
||||||
</urlset>`;
|
|
||||||
|
|
||||||
return sitemap.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
function generatePageRecords() {
|
|
||||||
const records = ["id;name;description"];
|
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(APPS)) {
|
|
||||||
const id = value;
|
|
||||||
const name = (Object.keys(APP_NAMES).includes(key) ? APP_NAMES[key] : id) as string;
|
|
||||||
const description = (Object.keys(APP_DESCRIPTIONS).includes(key) ? APP_DESCRIPTIONS[key] : TAG_LINE) as string;
|
|
||||||
|
|
||||||
records.push(`${id};${name};${description}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return records.join("\n") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
function generatePageTemplate() {
|
|
||||||
let html = fs.readFileSync(PATH_TO_INDEX, "utf-8");
|
|
||||||
|
|
||||||
const titleRegex = /(?<=(<title>|<meta property="og:title" content="|<meta name="twitter:title" content="))(([a-zA-Z|-]|\s)+)(?=(<\/title>|"\/?>))/g;
|
|
||||||
html = html.replaceAll(titleRegex, `_APP_NAME | ${NAME}`);
|
|
||||||
|
|
||||||
const descriptionRegex = /(?<=(<meta name="description" content="|<meta property="og:description" content="|<meta name="twitter:description" content="))(([a-zA-Z-.]|\s)+)(?=("\/?>))/g;
|
|
||||||
html = html.replaceAll(descriptionRegex, "_APP_DESCRIPTION");
|
|
||||||
|
|
||||||
const canonicalRegex = /(?<=(<link rel="canonical" href="|<meta name="twitter:url" content="|<meta property="og:url" content="))(http(s)?:\/\/[a-zA-Z-.]+\/)(?=("\/?>))/g;
|
|
||||||
html = html.replaceAll(canonicalRegex, `${BASE_URL}_APP_ID`);
|
|
||||||
|
|
||||||
const faqRegex = /<!-- FAQ -->.*?<script type="application\/ld\+json">.*?<\/script>/gs;
|
|
||||||
html = html.replaceAll(faqRegex, "");
|
|
||||||
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const steps: [string, () => string][] = [
|
|
||||||
[PATH_TO_SITEMAP, generateSitemap],
|
|
||||||
[PATH_TO_TEMPLATE, generatePageTemplate],
|
|
||||||
[PATH_TO_PAGES, generatePageRecords],
|
|
||||||
];
|
|
||||||
|
|
||||||
steps.forEach(([path, generateContent]) => {
|
|
||||||
const directory = path.substring(0, path.lastIndexOf("/"));
|
|
||||||
if (directory != "" && !fs.existsSync(directory)){
|
|
||||||
fs.mkdirSync(directory, { recursive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFileSync(path, generateContent(), { flag: "w+" });
|
|
||||||
console.log(`${ANSI.fg.green}✓ Generated ${path}${ANSI.reset}`);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
129
src/tools/stage.ts
Normal file
129
src/tools/stage.ts
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
import fs from "node:fs";
|
||||||
|
import { APP_DESCRIPTIONS, APP_NAMES, APPS } from "../config/apps.config";
|
||||||
|
import { ANSI } from "../config/apps/terminal.config";
|
||||||
|
import { BASE_URL, DOMAIN, NAME, TAG_LINE } from "../config/branding.config";
|
||||||
|
import { WALLPAPERS } from "../config/desktop.config";
|
||||||
|
|
||||||
|
const BUILD_DIR = "dist";
|
||||||
|
|
||||||
|
const PATHS = {
|
||||||
|
sitemapXml: BUILD_DIR + "/sitemap.xml",
|
||||||
|
robotsTxt: BUILD_DIR + "/robots.txt",
|
||||||
|
indexHtml: BUILD_DIR + "/index.html",
|
||||||
|
cname: BUILD_DIR + "/CNAME",
|
||||||
|
};
|
||||||
|
|
||||||
|
function generateSitemapXml() {
|
||||||
|
const date = new Date();
|
||||||
|
const lastModified = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
|
||||||
|
|
||||||
|
const images = WALLPAPERS.map((path) => `
|
||||||
|
<image:image>
|
||||||
|
<image:loc>${BASE_URL.slice(0, -1) + path}</image:loc>
|
||||||
|
</image:image>`
|
||||||
|
);
|
||||||
|
|
||||||
|
const pages = Object.values(APPS).map((appId) => `
|
||||||
|
<url>
|
||||||
|
<loc>${BASE_URL + appId}</loc>
|
||||||
|
<lastmod>${lastModified}</lastmod>
|
||||||
|
</url>`
|
||||||
|
);
|
||||||
|
|
||||||
|
const sitemap = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE xml>
|
||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||||
|
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
|
||||||
|
<url>
|
||||||
|
<loc>${BASE_URL}</loc>
|
||||||
|
<lastmod>${lastModified}</lastmod>
|
||||||
|
${images.join("")}
|
||||||
|
</url>
|
||||||
|
${pages.join("")}
|
||||||
|
</urlset>`;
|
||||||
|
|
||||||
|
return sitemap.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateRobotsTxt() {
|
||||||
|
const sitemapUrl = BASE_URL + PATHS.sitemapXml.replace(BUILD_DIR + "/", "");
|
||||||
|
|
||||||
|
return `# https://www.robotstxt.org/robotstxt.html
|
||||||
|
User-agent: *
|
||||||
|
Disallow:
|
||||||
|
Sitemap: ${sitemapUrl}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateCname() {
|
||||||
|
return DOMAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To avoid GitHub pages rendering certain pages that are only defined by React router as a 404 page,
|
||||||
|
* we copy the content of our index file to the 404 page, letting React router properly handle routing on every page
|
||||||
|
*/
|
||||||
|
function generate404Page(template: string) {
|
||||||
|
const path = `${BUILD_DIR}/404.html`;
|
||||||
|
fs.writeFileSync(path, template, { flag: "w+" });
|
||||||
|
console.log(`- ${ANSI.fg.cyan}${path}${ANSI.reset}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateAppPages(template: string) {
|
||||||
|
for (const [key, value] of Object.entries(APPS)) {
|
||||||
|
const appId = value;
|
||||||
|
const appName = Object.keys(APP_NAMES).includes(key) ? APP_NAMES[key] as string : appId;
|
||||||
|
const appDescription = Object.keys(APP_DESCRIPTIONS).includes(key) ? APP_DESCRIPTIONS[key] as string : TAG_LINE;
|
||||||
|
|
||||||
|
if (appId === "index") {
|
||||||
|
console.log("Invalid app ID found: " + appId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let html = template;
|
||||||
|
|
||||||
|
const titleRegex = /(?<=(<title>|<meta property="og:title" content="|<meta name="twitter:title" content="))(([a-zA-Z|-]|\s)+)(?=(<\/title>|"\/?>))/g;
|
||||||
|
html = html.replaceAll(titleRegex, `${appName} | ${NAME}`);
|
||||||
|
|
||||||
|
const descriptionRegex = /(?<=(<meta name="description" content="|<meta property="og:description" content="|<meta name="twitter:description" content="))(([a-zA-Z-.]|\s)+)(?=("\/?>))/g;
|
||||||
|
html = html.replaceAll(descriptionRegex, appDescription);
|
||||||
|
|
||||||
|
const canonicalRegex = /(?<=(<link rel="canonical" href="|<meta name="twitter:url" content="|<meta property="og:url" content="))(http(s)?:\/\/[a-zA-Z-.]+\/)(?=("\/?>))/g;
|
||||||
|
html = html.replaceAll(canonicalRegex, BASE_URL + appId);
|
||||||
|
|
||||||
|
const faqRegex = /<!-- FAQ -->.*?<script type="application\/ld\+json">.*?<\/script>/gs;
|
||||||
|
html = html.replaceAll(faqRegex, "");
|
||||||
|
|
||||||
|
const path = `${BUILD_DIR}/${appId}.html`;
|
||||||
|
fs.writeFileSync(path, html, { flag: "w+" });
|
||||||
|
console.log(`- ${ANSI.fg.cyan}${path}${ANSI.reset}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log(`${ANSI.fg.yellow}Staging build...${ANSI.reset}`);
|
||||||
|
|
||||||
|
const files: [string, () => string][] = [
|
||||||
|
[PATHS.sitemapXml, generateSitemapXml],
|
||||||
|
[PATHS.robotsTxt, generateRobotsTxt],
|
||||||
|
[PATHS.cname, generateCname],
|
||||||
|
];
|
||||||
|
|
||||||
|
files.forEach(([path, generateContent]) => {
|
||||||
|
const directory = path.substring(0, path.lastIndexOf("/"));
|
||||||
|
if (directory != "" && !fs.existsSync(directory)){
|
||||||
|
fs.mkdirSync(directory, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(path, generateContent(), { flag: "w+" });
|
||||||
|
console.log(`- ${ANSI.fg.cyan}${path}${ANSI.reset}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`\n${ANSI.fg.yellow}Generating pages...${ANSI.reset}`);
|
||||||
|
const template = fs.readFileSync(PATHS.indexHtml, "utf-8");
|
||||||
|
generate404Page(template);
|
||||||
|
generateAppPages(template);
|
||||||
|
console.log(`\n${ANSI.fg.green}✓ Staging complete${ANSI.reset}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue