├── .gitignore ├── README.md ├── package-lock.json ├── package.json └── src ├── index.js ├── install.js ├── templates ├── _github │ └── workflows │ │ └── gh-pages-deploy.yml └── scripts │ └── gh-pages-deploy.js ├── tools ├── helpers.js └── plugin.js └── uninstall.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .thumbs.db 3 | node_modules 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gh-pages-auto-deploy 2 | 3 | ### What does it do? 4 | Automates [Github Pages](https://help.github.com/en/github/working-with-github-pages/about-github-pages) 5 | deployment by using [Github Actions](https://help.github.com/en/actions/getting-started-with-github-actions/about-github-actions). 6 | 7 | ### How is it beneficial? 8 | Deploying an app to github pages takes some steps that you have to do every time. 9 | This extension makes deployment to github pages really easy. 10 | After you have added it in your project, everything is ready for you without doing anything else. 11 | Every time you push on `master` branch a deployment begins using github actions. 12 | 13 | ### Why would someone want to use it? 14 | Often, I create small applications and when I finish them, I want to deploy them to github pages. 15 | I had to copy paste a lot of stuff from older projects I already had set up the github pages deployment. 16 | Even the copy/paste process was taking some time, so I thought that creating an extension to automate 17 | everything would be a great idea. 18 | 19 | ## Install 20 | ```bash 21 | quasar ext add gh-pages-auto-deploy 22 | ``` 23 | Quasar CLI will retrieve it from NPM and install the extension. 24 | 25 | ## Uninstall 26 | ```bash 27 | quasar ext remove gh-pages-auto-deploy 28 | ``` 29 | 30 | ### The story - me and Quasar 31 | I am using quasar in my work for one and a half year and I really love it. 32 | I always wanted to contribute somehow to this awesome community, but I never found the time to do it. 33 | When I saw the \#Hack-a-May contest I though that I it was a great opportunity to give something small 34 | to the community who helped me so much all these months and I fall in love with it. 35 | 36 | ### The story - challenge 37 | Everything started back in 2018 where it was kinda hard for me to find the right steps to deploy 38 | a vue-cli app on github pages. So after I successfully deployed my app to github pages, I thought 39 | that would be a good idea to write an article about the steps I took to successfully deploy my app. 40 | 41 | [That article](https://medium.com/@Roli_Dori/deploy-vue-cli-3-project-to-github-pages-ebeda0705fbd) got a huge 42 | impact, and it seemed that many other people were struggling to deploy their app on GP (github pages) too. 43 | 44 | This year, I created 2 small projects, and I went to my article to read how to deploy it on GP. 45 | Even though everything worked, it took some time to follow all these steps every time I want to deploy. 46 | It was obvious I should do something to automate the deployment. 47 | 48 | After researches, I found out a way and wrote another [article](https://dev.to/rolanddoda/deploy-to-github-pages-like-a-pro-with-github-actions-4hdg) 49 | which again got a huge impact since you had to set up deployment only once and every time you push 50 | on master the app will be automatically deployed. 51 | 52 | Even though the latest article was a piece of art for me since I could automate deployment, still 53 | I always have to copy paste the code. So lately, I thought about writing a vue-cli plugin which you only 54 | had to install once to your project and everything is ready to go. 55 | 56 | I published the [vue-cli-plugin](https://github.com/Rolanddoda/vue-cli-plugin-gh-pages-auto-deploy) which works fine 57 | for my personal vue-cli projects. However, I am mentoring 2 junior developers, and we mostly use quasar for UI so that 58 | would be a great idea to not only build projects with Quasar but also add them on github and deploy them to GP. 59 | 60 | I came across to [this article](https://dev.to/quasar/hack-a-may-quasar-framework-s-community-programming-contest-3k4i) 61 | and I knew that this was a sign I should build that extension to give something small back to the awesome 62 | quasar community. 63 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quasar-app-extension-gh-pages-auto-deploy", 3 | "version": "0.4.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "cross-spawn": { 8 | "version": "7.0.2", 9 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", 10 | "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", 11 | "requires": { 12 | "path-key": "^3.1.0", 13 | "shebang-command": "^2.0.0", 14 | "which": "^2.0.1" 15 | } 16 | }, 17 | "end-of-stream": { 18 | "version": "1.4.4", 19 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 20 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 21 | "requires": { 22 | "once": "^1.4.0" 23 | } 24 | }, 25 | "execa": { 26 | "version": "4.0.0", 27 | "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.0.tgz", 28 | "integrity": "sha512-JbDUxwV3BoT5ZVXQrSVbAiaXhXUkIwvbhPIwZ0N13kX+5yCzOhUNdocxB/UQRuYOHRYYwAxKYwJYc0T4D12pDA==", 29 | "requires": { 30 | "cross-spawn": "^7.0.0", 31 | "get-stream": "^5.0.0", 32 | "human-signals": "^1.1.1", 33 | "is-stream": "^2.0.0", 34 | "merge-stream": "^2.0.0", 35 | "npm-run-path": "^4.0.0", 36 | "onetime": "^5.1.0", 37 | "signal-exit": "^3.0.2", 38 | "strip-final-newline": "^2.0.0" 39 | } 40 | }, 41 | "get-stream": { 42 | "version": "5.1.0", 43 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", 44 | "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", 45 | "requires": { 46 | "pump": "^3.0.0" 47 | } 48 | }, 49 | "human-signals": { 50 | "version": "1.1.1", 51 | "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", 52 | "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==" 53 | }, 54 | "is-stream": { 55 | "version": "2.0.0", 56 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", 57 | "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" 58 | }, 59 | "isexe": { 60 | "version": "2.0.0", 61 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 62 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" 63 | }, 64 | "merge-stream": { 65 | "version": "2.0.0", 66 | "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", 67 | "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" 68 | }, 69 | "mimic-fn": { 70 | "version": "2.1.0", 71 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", 72 | "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" 73 | }, 74 | "npm-run-path": { 75 | "version": "4.0.1", 76 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", 77 | "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", 78 | "requires": { 79 | "path-key": "^3.0.0" 80 | } 81 | }, 82 | "once": { 83 | "version": "1.4.0", 84 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 85 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 86 | "requires": { 87 | "wrappy": "1" 88 | } 89 | }, 90 | "onetime": { 91 | "version": "5.1.0", 92 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", 93 | "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", 94 | "requires": { 95 | "mimic-fn": "^2.1.0" 96 | } 97 | }, 98 | "path-key": { 99 | "version": "3.1.1", 100 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 101 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" 102 | }, 103 | "pump": { 104 | "version": "3.0.0", 105 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 106 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 107 | "requires": { 108 | "end-of-stream": "^1.1.0", 109 | "once": "^1.3.1" 110 | } 111 | }, 112 | "shebang-command": { 113 | "version": "2.0.0", 114 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 115 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 116 | "requires": { 117 | "shebang-regex": "^3.0.0" 118 | } 119 | }, 120 | "shebang-regex": { 121 | "version": "3.0.0", 122 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 123 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" 124 | }, 125 | "signal-exit": { 126 | "version": "3.0.3", 127 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", 128 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" 129 | }, 130 | "strip-final-newline": { 131 | "version": "2.0.0", 132 | "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", 133 | "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" 134 | }, 135 | "which": { 136 | "version": "2.0.2", 137 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 138 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 139 | "requires": { 140 | "isexe": "^2.0.0" 141 | } 142 | }, 143 | "wrappy": { 144 | "version": "1.0.2", 145 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 146 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quasar-app-extension-gh-pages-auto-deploy", 3 | "version": "0.4.0", 4 | "description": "Automate deployment to github pages", 5 | "author": "Roland Doda ", 6 | "license": "MIT", 7 | "main": "src/index.js", 8 | "scripts": { 9 | "release": "np --no-tests --no-yarn" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/Rolanddoda/quasar-ext-gh-pages-auto-deploy.git" 14 | }, 15 | "bugs": "", 16 | "homepage": "https://github.com/Rolanddoda/gh-pages-auto-deploy", 17 | "dependencies": { 18 | "execa": "^4.0.0" 19 | }, 20 | "engines": { 21 | "node": ">= 8.9.0", 22 | "npm": ">= 5.6.0", 23 | "yarn": ">= 1.6.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api, ctx) { 2 | 3 | } -------------------------------------------------------------------------------- /src/install.js: -------------------------------------------------------------------------------- 1 | const plugin = require('./tools/plugin') 2 | 3 | module.exports = async function (api) { 4 | api.compatibleWith('quasar', '>=1.0.0') 5 | api.compatibleWith('@quasar/app', '>=1.0.0') 6 | 7 | plugin.extendPackageJSON(api) 8 | await plugin.addPublicPathToConfig(api) 9 | await plugin.addTemplateFiles(api) 10 | api.onExitLog(` 11 | 🧾🧾 Now you only have to commit and push 🧾🧾 12 | 🔥🔥 Enjoy automatic deployment 🔥🔥 13 | 🌟🌟 Please don't forget to star the project on Github if you like this extension. 🌟🌟 14 | Project URL: https://github.com/Rolanddoda/quasar-ext-gh-pages-auto-deploy 15 | `) 16 | } 17 | -------------------------------------------------------------------------------- /src/templates/_github/workflows/gh-pages-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to github pages 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | gh-pages-deploy: 8 | name: Deploying to gh-pages 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Setup Node.js for use with actions 12 | uses: actions/setup-node@v2 13 | with: 14 | version: 12.x 15 | - name: Checkout branch 16 | uses: actions/checkout@v2 17 | 18 | - name: Clean install dependencies 19 | run: <%= cleanInstallCommand %> 20 | 21 | - name: Run deploy script 22 | run: | 23 | git config user.name "<%= username %>" && git config user.email "<%= email %>" 24 | npm run gh-pages-deploy 25 | -------------------------------------------------------------------------------- /src/templates/scripts/gh-pages-deploy.js: -------------------------------------------------------------------------------- 1 | const execa = require('execa') 2 | const emoji = require('node-emoji') 3 | const chalk = require('chalk') 4 | 5 | const firstLog = emoji.get('fast_forward') + ' ' + chalk.yellow('Building...') 6 | const secondLog = emoji.get('fast_forward') + ' ' + chalk.yellow('Pushing...') 7 | const thirdLog = emoji.get('rocket') + ' ' + chalk.green('Your app successfully deployed') + ' ' + emoji.get('rocket') 8 | 9 | ;(async () => { 10 | try { 11 | const { stdout: currentBranch } = await execa.command('git branch --show-current') 12 | await execa.command('git checkout --orphan gh-pages') 13 | console.log(firstLog) 14 | 15 | await execa.command('quasar build', { stdio: 'inherit' }) 16 | await execa.command('git --work-tree dist add --all') 17 | await execa.command('git --work-tree dist/spa commit -m "gh-pages"') 18 | console.log(secondLog) 19 | 20 | await execa.command('git push origin HEAD:gh-pages --force', { stdio: 'inherit' }) 21 | await execa.command('rm -r dist/spa') 22 | await execa.command(`git checkout -f ${currentBranch}`) 23 | await execa.command('git branch -D gh-pages') 24 | console.log(thirdLog) 25 | } catch (e) { 26 | console.log(e.message) 27 | process.exit(1) 28 | } 29 | })() 30 | -------------------------------------------------------------------------------- /src/tools/helpers.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const execa = require("execa") 3 | const path = require("path") 4 | 5 | async function getUserCredentials() { 6 | const {stdout: userName} = await execa.command('git config user.name') 7 | const {stdout: email} = await execa.command('git config user.email') 8 | return { 9 | username: userName.replace(' ', ''), 10 | email 11 | } 12 | } 13 | 14 | function getPackageManager(api) { 15 | if (fs.existsSync(api.resolve.app('package-lock.json'))) { 16 | return 'npm' 17 | } else if (fs.existsSync(api.resolve.app('yarn.lock'))) { 18 | return 'yarn' 19 | } 20 | } 21 | 22 | async function getRepoName() { 23 | try { 24 | const {stdout: repoUrl} = await execa.command('git config --get remote.origin.url') 25 | return path.basename(repoUrl).replace('.git', '') 26 | } catch (e) { 27 | throw new Error('You must add a remote before installing this plugin. Adding a remote: https://help.github.com/en/github/using-git/adding-a-remote') 28 | } 29 | } 30 | 31 | function getCleanInstallCommand(api) { 32 | const npmOrYarn = getPackageManager(api) 33 | return npmOrYarn === 'npm' ? 'npm ci' : 'yarn install --frozen-lockfile' 34 | } 35 | 36 | module.exports = { 37 | getUserCredentials, 38 | getRepoName, 39 | getCleanInstallCommand 40 | } -------------------------------------------------------------------------------- /src/tools/plugin.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const helpers = require('./helpers') 3 | 4 | function extendPackageJSON(api) { 5 | api.extendPackageJson({ 6 | scripts: { 7 | "gh-pages-deploy": "node scripts/gh-pages-deploy.js" 8 | }, 9 | "devDependencies": { 10 | "chalk": "^4.0.0", 11 | "execa": "^4.0.0", 12 | "node-emoji": "^1.10.0" 13 | } 14 | }) 15 | } 16 | 17 | async function addPublicPathToConfig(api) { 18 | const configPath = api.resolve.app('./quasar.conf.js') 19 | const config = require(configPath) 20 | if (!config.publicPath) { 21 | const repoName = await helpers.getRepoName() 22 | const {EOL} = require('os') 23 | const fileLines = fs.readFileSync(configPath, 'utf-8').split(/\r?\n/g) 24 | const returnTextIndex = fileLines.findIndex(line => line.includes('return')) 25 | const newLine = `\t\tpublicPath: process.env.NODE_ENV === "production" ? "/${repoName}/" : "/",` 26 | fileLines.splice(returnTextIndex + 1, 0, newLine) 27 | fs.writeFileSync(configPath, fileLines.join(EOL), {encoding: 'utf-8'}) 28 | } 29 | } 30 | 31 | async function addTemplateFiles (api) { 32 | const cleanInstallCommand = helpers.getCleanInstallCommand(api) 33 | const {username, email} = await helpers.getUserCredentials() 34 | api.render('../templates', {username, email, cleanInstallCommand}) 35 | } 36 | 37 | module.exports = { 38 | extendPackageJSON, 39 | addPublicPathToConfig, 40 | addTemplateFiles 41 | } -------------------------------------------------------------------------------- /src/uninstall.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | module.exports = function (api) { 4 | const ghActionPath = api.resolve.app('.github/workflows/gh-pages-deploy.yml') 5 | const ghPagesScriptPath = api.resolve.app('scripts/gh-pages-deploy.js') 6 | 7 | if (fs.existsSync(ghActionPath)) api.removePath(ghActionPath) 8 | if (fs.existsSync(ghPagesScriptPath)) api.removePath(ghPagesScriptPath) 9 | 10 | api.onExitLog(`Thanks for using this extension.`) 11 | } 12 | --------------------------------------------------------------------------------