From 0f8311049dca457fe2dc3ae364f7600e0e6d7a9c Mon Sep 17 00:00:00 2001 From: Mike Brocchi Date: Thu, 2 Feb 2017 21:34:47 -0500 Subject: [PATCH] refactor(@angular/cli): removed the github pages deploy command BREAKING CHANGE: This command is being removed from the core of the CLI There are several options for deploying CLI-based applications outside the scope of this project. One of which being https://github.com/angular-buch/angular-cli-ghpages This functionality is likely to return in the form of an addon/plugin in the future --- README.md | 32 -- .../stories/deploy-github-pages.md | 30 -- packages/@angular/cli/addon/index.js | 1 - .../cli/blueprints/ng2/files/README.md | 4 - .../cli/commands/github-pages-deploy.run.ts | 272 ----------------- .../cli/commands/github-pages-deploy.ts | 90 ------ packages/@angular/cli/commands/help.ts | 3 +- .../@angular/cli/tasks/create-github-repo.ts | 92 ------ tests/acceptance/github-pages-deploy.spec.js | 285 ------------------ 9 files changed, 1 insertion(+), 808 deletions(-) delete mode 100644 docs/documentation/stories/deploy-github-pages.md delete mode 100644 packages/@angular/cli/commands/github-pages-deploy.run.ts delete mode 100644 packages/@angular/cli/commands/github-pages-deploy.ts delete mode 100644 packages/@angular/cli/tasks/create-github-repo.ts delete mode 100644 tests/acceptance/github-pages-deploy.spec.js diff --git a/README.md b/README.md index 154fb4d0b58f..9be7ec352117 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,6 @@ with NPM 3 or higher. * [Running Unit Tests](#running-unit-tests) * [Running End-to-End Tests](#running-end-to-end-tests) * [Proxy To Backend](#proxy-to-backend) -* [Deploying the App via GitHub Pages](#deploying-the-app-via-github-pages) * [Linting code](#linting-code) * [Commands autocompletion](#commands-autocompletion) * [Project assets](#project-assets) @@ -237,37 +236,6 @@ and then we edit the `package.json` file's start script to be now run it with `npm start` -### Deploying the app via GitHub Pages - -You can deploy your apps quickly via: - -```bash -ng github-pages:deploy --message "Optional commit message" -``` - -This will do the following: - -- creates GitHub repo for the current project if one doesn't exist -- rebuilds the app in production mode at the current `HEAD` -- creates a local `gh-pages` branch if one doesn't exist -- moves your app to the `gh-pages` branch and creates a commit -- edit the base tag in index.html to support GitHub Pages -- pushes the `gh-pages` branch to GitHub -- returns back to the original `HEAD` - -Creating the repo requires a token from GitHub, and the remaining functionality -relies on ssh authentication for all git operations that communicate with github.com. -To simplify the authentication, be sure to [setup your ssh keys](https://help.github.com/articles/generating-ssh-keys/). - -If you are deploying a [user or organization page](https://help.github.com/articles/user-organization-and-project-pages/), you can instead use the following command: - -```bash -ng github-pages:deploy --user-page --message "Optional commit message" -``` - -This command pushes the app to the `master` branch on the GitHub repo instead -of pushing to `gh-pages`, since user and organization pages require this. - ### Linting code diff --git a/docs/documentation/stories/deploy-github-pages.md b/docs/documentation/stories/deploy-github-pages.md deleted file mode 100644 index f062852f6b4e..000000000000 --- a/docs/documentation/stories/deploy-github-pages.md +++ /dev/null @@ -1,30 +0,0 @@ -# Deploying the app via GitHub Pages - -You can deploy your apps quickly via: - -```bash -ng github-pages:deploy --message "Optional commit message" -``` - -This will do the following: - -- creates GitHub repo for the current project if one doesn't exist -- rebuilds the app in production mode at the current `HEAD` -- creates a local `gh-pages` branch if one doesn't exist -- moves your app to the `gh-pages` branch and creates a commit -- edit the base tag in index.html to support GitHub Pages -- pushes the `gh-pages` branch to GitHub -- returns back to the original `HEAD` - -Creating the repo requires a token from GitHub, and the remaining functionality -relies on ssh authentication for all git operations that communicate with github.com. -To simplify the authentication, be sure to [setup your ssh keys](https://help.github.com/articles/generating-ssh-keys/). - -If you are deploying a [user or organization page](https://help.github.com/articles/user-organization-and-project-pages/), you can instead use the following command: - -```bash -ng github-pages:deploy --user-page --message "Optional commit message" -``` - -This command pushes the app to the `master` branch on the GitHub repo instead -of pushing to `gh-pages`, since user and organization pages require this. diff --git a/packages/@angular/cli/addon/index.js b/packages/@angular/cli/addon/index.js index cf283cc72a50..5bc9aceb51e6 100644 --- a/packages/@angular/cli/addon/index.js +++ b/packages/@angular/cli/addon/index.js @@ -32,7 +32,6 @@ module.exports = { 'version': require('../commands/version').default, 'completion': require('../commands/completion').default, 'doc': require('../commands/doc').default, - 'github-pages-deploy': require('../commands/github-pages-deploy').default, // Easter eggs. 'make-this-awesome': require('../commands/easter-egg').default, diff --git a/packages/@angular/cli/blueprints/ng2/files/README.md b/packages/@angular/cli/blueprints/ng2/files/README.md index 188342879eaa..c45be663b72c 100755 --- a/packages/@angular/cli/blueprints/ng2/files/README.md +++ b/packages/@angular/cli/blueprints/ng2/files/README.md @@ -22,10 +22,6 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github. Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). Before running the tests make sure you are serving the app via `ng serve`. -## Deploying to GitHub Pages - -Run `ng github-pages:deploy` to deploy to GitHub Pages. - ## Further help To get more help on the `angular-cli` use `ng help` or go check out the [Angular-CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/packages/@angular/cli/commands/github-pages-deploy.run.ts b/packages/@angular/cli/commands/github-pages-deploy.run.ts deleted file mode 100644 index 1e8f1211a027..000000000000 --- a/packages/@angular/cli/commands/github-pages-deploy.run.ts +++ /dev/null @@ -1,272 +0,0 @@ -const SilentError = require('silent-error'); -import denodeify = require('denodeify'); - -import { exec } from 'child_process'; -import * as chalk from 'chalk'; -import * as fs from 'fs'; -import * as fse from 'fs-extra'; -import * as path from 'path'; -import Build from '../tasks/build'; -import CreateGithubRepo from '../tasks/create-github-repo'; -import { CliConfig } from '../models/config'; -import { GithubPagesDeployOptions } from './github-pages-deploy'; - -const fsReadDir = denodeify(fs.readdir); -const fsCopy = denodeify(fse.copy); -const fsWriteFile = denodeify(fse.writeFile); - -export default function githubPagesDeployRun(options: GithubPagesDeployOptions, rawArgs: string[]) { - const ui = this.ui; - const root = this.project.root; - const execOptions = { - cwd: root - }; - - if (options.environment === '') { - if (options.target === 'development') { - options.environment = 'dev'; - } - if (options.target === 'production') { - options.environment = 'prod'; - } - } - - const projectName = this.project.pkg.name; - - const outDir = CliConfig.fromProject().config.apps[0].outDir; - const indexFilename = CliConfig.fromProject().config.apps[0].index; - - let ghPagesBranch = 'gh-pages'; - let destinationBranch = options.userPage ? 'master' : ghPagesBranch; - let initialBranch: string; - let branchErrMsg = ' You might also need to return to the initial branch manually.'; - - // declared here so that tests can stub exec - const execPromise = <(cmd: string, options?: any) => Promise>denodeify(exec); - - const buildTask = new Build({ - ui: this.ui, - cliProject: this.project, - target: options.target, - environment: options.environment, - outputPath: outDir - }); - - /** - * BaseHref tag setting logic: - * First, no value if --custom-domain is provided. - * Second, use --base-href flag value if provided. - * Else if --user-page is true, then keep baseHref default as declared in index.html. - * Otherwise auto-replace with `/${projectName}/`. - */ - let baseHref: String = null; - if (!options.customDomain) { - baseHref = options.baseHref || (options.userPage ? null : `/${projectName}/`); - } - - const buildOptions = { - target: options.target, - environment: options.environment, - outputPath: outDir, - baseHref: baseHref, - aot: options.aot, - vendorChunk: options.vendorChunk, - }; - - const createGithubRepoTask = new CreateGithubRepo({ - ui: this.ui, - project: this.project - }); - - const createGithubRepoOptions = { - projectName, - ghUsername: options.ghUsername, - ghToken: options.ghToken - }; - - return checkForPendingChanges() - .then(build) - .then(saveStartingBranchName) - .then(createGitHubRepoIfNeeded) - .then(checkoutGhPages) - .then(cleanGhPagesBranch) - .then(copyFiles) - .then(createNotFoundPage) - .then(createCustomDomainFile) - .then(addAndCommit) - .then(returnStartingBranch) - .then(pushToGitRepo) - .then(printProjectUrl) - .catch(failGracefully); - - function checkForPendingChanges() { - return execPromise('git status --porcelain') - .then((stdout: string) => { - if (/\w+/m.test(stdout)) { - let msg = 'Uncommitted file changes found! Please commit all changes before deploying.'; - return Promise.reject(new SilentError(msg)); - } - }); - } - - function build() { - if (options.skipBuild) { return Promise.resolve(); } - return buildTask.run(buildOptions); - } - - function saveStartingBranchName() { - return execPromise('git rev-parse --abbrev-ref HEAD') - .then((stdout: string) => initialBranch = stdout.replace(/\s/g, '')); - } - - function createGitHubRepoIfNeeded() { - return execPromise('git remote -v') - .then(function(stdout) { - if (!/origin\s+(https:\/\/|git@)github\.com/m.test(stdout)) { - return createGithubRepoTask.run(createGithubRepoOptions) - .then(() => generateRemoteUrl()) - .then((upstream: string) => { - // only push starting branch if it's not the destinationBranch - // this happens commonly when using github user pages, since - // they require the destination branch to be 'master' - if (destinationBranch !== initialBranch) { - execPromise(`git push -u ${upstream} ${initialBranch}`); - } - }); - } - }); - } - - function checkoutGhPages() { - return execPromise(`git checkout ${ghPagesBranch}`) - .catch(createGhPagesBranch); - } - - function createGhPagesBranch() { - return execPromise(`git checkout --orphan ${ghPagesBranch}`) - .then(() => execPromise('git rm --cached -r .', execOptions)) - .then(() => execPromise('git add .gitignore', execOptions)) - .then(() => execPromise('git clean -f -d', execOptions)) - .then(() => execPromise(`git commit -m \"initial ${ghPagesBranch} commit\"`)); - } - - function cleanGhPagesBranch() { - return execPromise('git ls-files') - .then(function (stdout) { - let files = ''; - stdout.split(/\n/).forEach(function (f) { - // skip .gitignore & 404.html - if ((f != '') && (f != '.gitignore') && (f != '404.html')) { - files = files.concat(`"${f}" `); - } - }); - return execPromise(`git rm -r ${files}`) - .catch(() => { - // Ignoring errors when trying to erase files. - }); - }); - } - - function copyFiles() { - return fsReadDir(outDir) - .then((files: string[]) => Promise.all(files.map((file) => { - if (file === '.gitignore') { - // don't overwrite the .gitignore file - return Promise.resolve(); - } - return fsCopy(path.join(outDir, file), path.join('.', file)); - }))); - } - - function createNotFoundPage() { - const indexHtml = path.join(root, indexFilename); - const notFoundPage = path.join(root, '404.html'); - return fsCopy(indexHtml, notFoundPage); - } - - function createCustomDomainFile() { - if (!options.customDomain) { - return; - } - - const cnameFile = path.join(root, 'CNAME'); - return fsWriteFile(cnameFile, options.customDomain); - } - - function addAndCommit() { - return execPromise('git add .', execOptions) - .then(() => execPromise(`git commit -m "${options.message}"`)) - .catch(() => { - let msg = 'No changes found. Deployment skipped.'; - return returnStartingBranch() - .then(() => Promise.reject(new SilentError(msg))) - .catch(() => Promise.reject(new SilentError(msg.concat(branchErrMsg)))); - }); - } - - function returnStartingBranch() { - return execPromise(`git checkout ${initialBranch}`); - } - - function pushToGitRepo() { - return generateRemoteUrl() - .then(upstream => { - return execPromise(`git push ${upstream} ${ghPagesBranch}:${destinationBranch}`); - }) - .catch((err) => returnStartingBranch() - .catch(() => Promise.reject(err) )); - } - - function printProjectUrl() { - return getUsernameFromGitOrigin() - .then((userName) => { - let url = ''; - - if (options.customDomain) { - url = `http://${options.customDomain}/`; - } else { - url = `https://${userName}.github.io/${options.userPage ? '' : (baseHref + '/')}`; - } - - ui.writeLine(chalk.green(`Deployed! Visit ${url}`)); - ui.writeLine('Github pages might take a few minutes to show the deployed site.'); - }); - } - - function failGracefully(error: Error) { - if (error && (/git clean/.test(error.message) || /Permission denied/.test(error.message))) { - ui.writeLine(error.message); - let msg = 'There was a permissions error during git file operations, ' + - 'please close any open project files/folders and try again.'; - msg += `\nYou might also need to return to the ${initialBranch} branch manually.`; - return Promise.reject(new SilentError(msg.concat(branchErrMsg))); - } else { - return Promise.reject(error); - } - } - - function generateRemoteUrl(): Promise { - if (createGithubRepoOptions.ghToken && createGithubRepoOptions.ghUsername) { - return Promise.resolve(`https://${createGithubRepoOptions.ghToken}@github.com/` + - `${createGithubRepoOptions.ghUsername}/${createGithubRepoOptions.projectName}.git`); - } - - if (createGithubRepoOptions.ghToken && !createGithubRepoOptions.ghUsername) { - return getUsernameFromGitOrigin() - .then(username => { - return Promise.resolve(`https://${createGithubRepoOptions.ghToken}@github.com/` + - `${username}/${createGithubRepoOptions.projectName}.git`); - }); - } - - return Promise.resolve('origin'); - } - - function getUsernameFromGitOrigin(): Promise { - return execPromise('git remote -v') - .then((stdout) => { - let match = stdout.match(/origin\s+(?:https:\/\/|git@)github\.com(?:\:|\/)([^\/]+)/m); - return match[1].toLowerCase(); - }); - } -} diff --git a/packages/@angular/cli/commands/github-pages-deploy.ts b/packages/@angular/cli/commands/github-pages-deploy.ts deleted file mode 100644 index b5e60638e07f..000000000000 --- a/packages/@angular/cli/commands/github-pages-deploy.ts +++ /dev/null @@ -1,90 +0,0 @@ -const Command = require('../ember-cli/lib/models/command'); -import { oneLine } from 'common-tags'; - -export interface GithubPagesDeployOptions { - message?: string; - target?: string; - environment?: string; - userPage?: boolean; - skipBuild?: boolean; - ghToken?: string; - ghUsername?: string; - baseHref?: string; - customDomain?: string; - aot?: boolean; - vendorChunk?: boolean; -} - -const GithubPagesDeployCommand = Command.extend({ - name: 'github-pages:deploy', - aliases: ['gh-pages:deploy'], - description: oneLine` - Build the test app for production, commit it into a git branch, - setup GitHub repo and push to it - `, - works: 'insideProject', - - availableOptions: [ - { - name: 'message', - type: String, - default: 'new gh-pages version', - description: 'The commit message to include with the build, must be wrapped in quotes.' - }, { - name: 'target', - type: String, - default: 'production', - aliases: ['t', { 'dev': 'development' }, { 'prod': 'production' }] - }, { - name: 'environment', - type: String, - default: '', - aliases: ['e'] - }, { - name: 'user-page', - type: Boolean, - default: false, - description: 'Deploy as a user/org page' - }, { - name: 'skip-build', - type: Boolean, - default: false, - description: 'Skip building the project before deploying' - }, { - name: 'gh-token', - type: String, - default: '', - description: 'GitHub token' - }, { - name: 'gh-username', - type: String, - default: '', - description: 'GitHub username' - }, { - name: 'base-href', - type: String, - default: null, - aliases: ['bh'] - }, { - name: 'custom-domain', - type: String, - default: null, - aliases: ['cd'], - description: 'Custom domain for Github Pages' - }, { - name: 'aot', - type: Boolean, - default: false, - }, { - name: 'vendor-chunk', - type: Boolean, - default: false, - }], - - run: function(options: GithubPagesDeployOptions, rawArgs: string[]) { - return require('./github-pages-deploy.run').default.call(this, options, rawArgs); - } -}); - - -export default GithubPagesDeployCommand; diff --git a/packages/@angular/cli/commands/help.ts b/packages/@angular/cli/commands/help.ts index 5a00ff6b0de4..e0906d063ffc 100644 --- a/packages/@angular/cli/commands/help.ts +++ b/packages/@angular/cli/commands/help.ts @@ -7,8 +7,7 @@ const lookupCommand = require('../ember-cli/lib/cli/lookup-command'); const commandsToIgnore = [ 'easter-egg', - 'destroy', - 'github-pages-deploy' // errors because there is no base github-pages command + 'destroy' ]; const HelpCommand = Command.extend({ diff --git a/packages/@angular/cli/tasks/create-github-repo.ts b/packages/@angular/cli/tasks/create-github-repo.ts deleted file mode 100644 index 554d38396671..000000000000 --- a/packages/@angular/cli/tasks/create-github-repo.ts +++ /dev/null @@ -1,92 +0,0 @@ -import * as denodeify from 'denodeify'; -const Task = require('../ember-cli/lib/models/task'); -const SilentError = require('silent-error'); -import { exec } from 'child_process'; -import * as https from 'https'; -import { oneLine } from 'common-tags'; - - -export default Task.extend({ - run: function(commandOptions: any) { - const ui = this.ui; - let promise: Promise; - - // declared here so that tests can stub exec - const execPromise = denodeify(exec); - - if (/.+/.test(commandOptions.ghToken) && /\w+/.test(commandOptions.ghUsername)) { - promise = Promise.resolve({ - ghToken: commandOptions.ghToken, - ghUsername: commandOptions.ghUsername - }); - } else { - ui.writeLine(); - ui.writeLine(oneLine` - In order to deploy this project via GitHub Pages, we must first create a repository for it. - `); - ui.writeLine(oneLine` - It\'s safer to use a token than to use a password so you will need to create one - `); - ui.writeLine('Go to the following page and click "Generate new token".'); - ui.writeLine('https://github.com/settings/tokens\n'); - ui.writeLine('Choose "public_repo" as scope and then click "Generate token".\n'); - promise = ui.prompt([ - { - name: 'ghToken', - type: 'input', - message: oneLine` - Please enter GitHub token you just created - (used only once to create the repo): - `, - validate: function(token: string) { - return /.+/.test(token); - } - }, { - name: 'ghUsername', - type: 'input', - message: 'and your GitHub user name:', - validate: function(userName: string) { - return /\w+/.test(userName); - } - }]); - } - - return promise - .then((answers) => { - return new Promise(function(resolve, reject) { - const postData = JSON.stringify({ - 'name': commandOptions.projectName - }); - - const req = https.request({ - hostname: 'api.github.com', - port: 443, - path: '/user/repos', - method: 'POST', - headers: { - 'Authorization': `token ${answers.ghToken}`, - 'Content-Type': 'application/json', - 'Content-Length': postData.length, - 'User-Agent': 'angular-cli-github-pages' - } - }); - - req.on('response', function(response: any) { - if (response.statusCode === 201) { - resolve(execPromise(oneLine` - git remote add origin - git@github.com:${answers.ghUsername}/${commandOptions.projectName}.git - `)); - } else { - reject(new SilentError(oneLine` - Failed to create GitHub repo. Error: ${response.statusCode} ${response.statusMessage} - `)); - } - }); - - req.write(postData); - req.end(); - }); - }); - } -}); diff --git a/tests/acceptance/github-pages-deploy.spec.js b/tests/acceptance/github-pages-deploy.spec.js deleted file mode 100644 index 032ad3e9eaeb..000000000000 --- a/tests/acceptance/github-pages-deploy.spec.js +++ /dev/null @@ -1,285 +0,0 @@ -/*eslint-disable no-console */ -'use strict'; - -var ng = require('../helpers/ng'); -var tmp = require('../helpers/tmp'); -var Promise = require('@angular/cli/ember-cli/lib/ext/promise'); -var fs = require('fs'); -var path = require('path'); -var chai = require('chai'); -var sinon = require('sinon'); -var ExecStub = require('../helpers/exec-stub'); -var https = require('https'); -var SilentError = require('silent-error'); - -const expect = chai.expect; -const fsWriteFile = Promise.denodeify(fs.writeFile); -const fsMkdir = Promise.denodeify(fs.mkdir); - -describe('Acceptance: ng github-pages:deploy', function() { - let execStub; - let project = 'foo', - initialBranch = 'master', - ghPagesBranch = 'gh-pages', - message = 'new gh-pages version', - remote = 'origin git@github.com:username/project.git (fetch)'; - - function setupDist() { - return fsMkdir('./dist') - .then(() => { - let indexHtml = path.join(process.cwd(), 'dist', 'index.html'); - let indexData = `project\n`; - return fsWriteFile(indexHtml, indexData, 'utf8'); - }); - } - - beforeEach(function() { - this.timeout(10000); - return tmp.setup('./tmp') - .then(() => process.chdir('./tmp')) - .then(() => ng(['new', project, '--skip-npm'])) - .then(() => setupDist()) - .finally(() => execStub = new ExecStub()); - }); - - afterEach(function() { - this.timeout(10000); - return tmp.teardown('./tmp') - .then(() => expect(execStub.hasFailed()).to.be.false) - .then(() => expect(execStub.hasEmptyStack()).to.be.true) - .finally(() => execStub.restore()); - }); - - it('should fail with uncommited changes', function() { - this.timeout(10000); - execStub.addExecSuccess('git status --porcelain', 'M dir/file.ext'); - return ng(['github-pages:deploy', '--skip-build']) - .then(() => { - throw new SilentError('Should fail with uncommited changes but passing.'); - }, (ret) => { - expect(ret.name).to.equal('SilentError'); - expect(ret.isSilentError).to.equal(true); - }); - }); - - it('should deploy with defaults to existing remote', function () { - execStub.addExecSuccess('git status --porcelain') - .addExecSuccess('git rev-parse --abbrev-ref HEAD', initialBranch) - .addExecSuccess('git remote -v', remote) - .addExecSuccess(`git checkout ${ghPagesBranch}`) - .addExecSuccess('git ls-files') - .addExecSuccess('git rm -r ') - .addExecSuccess('git add .') - .addExecSuccess(`git commit -m "${message}"`) - .addExecSuccess(`git checkout ${initialBranch}`) - .addExecSuccess(`git push origin ${ghPagesBranch}:${ghPagesBranch}`) - .addExecSuccess('git remote -v', remote); - - return ng(['github-pages:deploy', '--skip-build']); - }); - - it('should deploy with token and username', function () { - let token = 'token', - username = 'bar'; - - execStub.addExecSuccess('git status --porcelain') - .addExecSuccess('git rev-parse --abbrev-ref HEAD', initialBranch) - .addExecSuccess('git remote -v', remote) - .addExecSuccess(`git checkout ${ghPagesBranch}`) - .addExecSuccess('git ls-files') - .addExecSuccess('git rm -r ') - .addExecSuccess('git add .') - .addExecSuccess(`git commit -m "${message}"`) - .addExecSuccess(`git checkout ${initialBranch}`) - .addExecSuccess(`git push https://${token}@github.com/${username}/${project}.git ${ghPagesBranch}:${ghPagesBranch}`) - .addExecSuccess('git remote -v', remote); - - return ng(['github-pages:deploy', '--skip-build', `--gh-token=${token}`, `--gh-username=${username}`]); - }) - - it('should deploy with token only', function () { - let token = 'token'; - - execStub.addExecSuccess('git status --porcelain') - .addExecSuccess('git rev-parse --abbrev-ref HEAD', initialBranch) - .addExecSuccess('git remote -v', remote) - .addExecSuccess(`git checkout ${ghPagesBranch}`) - .addExecSuccess('git ls-files') - .addExecSuccess('git rm -r ') - .addExecSuccess('git add .') - .addExecSuccess(`git commit -m "${message}"`) - .addExecSuccess(`git checkout ${initialBranch}`) - .addExecSuccess('git remote -v', remote) - .addExecSuccess(`git push https://${token}@github.com/username/${project}.git ${ghPagesBranch}:${ghPagesBranch}`) - .addExecSuccess('git remote -v', remote); - - return ng(['github-pages:deploy', '--skip-build', `--gh-token=${token}`]); - }); - - it('should deploy with changed defaults', function() { - let userPageBranch = 'master', - message = 'not new gh-pages version'; - - execStub.addExecSuccess('git status --porcelain') - .addExecSuccess('git rev-parse --abbrev-ref HEAD', initialBranch) - .addExecSuccess('git remote -v', remote) - .addExecSuccess(`git checkout ${ghPagesBranch}`) - .addExecSuccess('git ls-files') - .addExecSuccess('git rm -r ') - .addExecSuccess('git add .') - .addExecSuccess(`git commit -m "${message}"`) - .addExecSuccess(`git checkout ${initialBranch}`) - .addExecSuccess(`git push origin ${ghPagesBranch}:${userPageBranch}`) - .addExecSuccess('git remote -v', remote); - - return ng(['github-pages:deploy', '--skip-build', `--message=${message}`, '--user-page']); - }); - - it('should create branch if needed', function() { - execStub.addExecSuccess('git status --porcelain') - .addExecSuccess('git rev-parse --abbrev-ref HEAD', initialBranch) - .addExecSuccess('git remote -v', remote) - .addExecError(`git checkout ${ghPagesBranch}`) - .addExecSuccess(`git checkout --orphan ${ghPagesBranch}`) - .addExecSuccess('git rm --cached -r .') - .addExecSuccess('git add .gitignore') - .addExecSuccess('git clean -f -d') - .addExecSuccess(`git commit -m \"initial ${ghPagesBranch} commit\"`) - .addExecSuccess('git ls-files') - .addExecSuccess('git rm -r ') - .addExecSuccess('git add .') - .addExecSuccess(`git commit -m "${message}"`) - .addExecSuccess(`git checkout ${initialBranch}`) - .addExecSuccess(`git push origin ${ghPagesBranch}:${ghPagesBranch}`) - .addExecSuccess('git remote -v', remote); - - return ng(['github-pages:deploy', '--skip-build']); - }); - - it('should create repo if needed', function() { - let noRemote = '', - token = 'token', - username = 'username'; - - execStub.addExecSuccess('git status --porcelain') - .addExecSuccess('git rev-parse --abbrev-ref HEAD', initialBranch) - .addExecSuccess('git remote -v', noRemote) - .addExecSuccess(`git remote add origin git@github.com:${username}/${project}.git`) - .addExecSuccess(`git push -u https://${token}@github.com/${username}/${project}.git ${initialBranch}`) - .addExecSuccess(`git checkout ${ghPagesBranch}`) - .addExecSuccess('git ls-files') - .addExecSuccess('git rm -r ') - .addExecSuccess('git add .') - .addExecSuccess(`git commit -m "${message}"`) - .addExecSuccess(`git checkout ${initialBranch}`) - .addExecSuccess(`git push https://${token}@github.com/${username}/${project}.git ${ghPagesBranch}:${ghPagesBranch}`) - .addExecSuccess('git remote -v', remote); - - var httpsStub = sinon.stub(https, 'request', httpsRequestStubFunc); - - function httpsRequestStubFunc(req) { - let responseCb; - - let expectedPostData = JSON.stringify({ - 'name': project - }); - - let expectedReq = { - hostname: 'api.github.com', - port: 443, - path: '/user/repos', - method: 'POST', - headers: { - 'Authorization': `token ${token}`, - 'Content-Type': 'application/json', - 'Content-Length': expectedPostData.length, - 'User-Agent': 'angular-cli-github-pages' - } - } - - expect(req).to.eql(expectedReq); - - return { - on: (event, cb) => responseCb = cb, - write: (postData) => expect(postData).to.eql(expectedPostData), - end: () => responseCb({ statusCode: 201 }) - } - } - - return ng(['github-pages:deploy', '--skip-build', `--gh-token=${token}`, - `--gh-username=${username}`]) - .then(() => httpsStub.restore()); - }); - - it('should stop deploy if create branch fails', function() { - let noRemote = '', - token = 'token', - username = 'username'; - - execStub.addExecSuccess('git status --porcelain') - .addExecSuccess('git rev-parse --abbrev-ref HEAD', initialBranch) - .addExecSuccess('git remote -v', noRemote); - - var httpsStub = sinon.stub(https, 'request', httpsRequestStubFunc); - - function httpsRequestStubFunc(req) { - let responseCb; - - let expectedPostData = JSON.stringify({ - 'name': project - }); - - let expectedReq = { - hostname: 'api.github.com', - port: 443, - path: '/user/repos', - method: 'POST', - headers: { - 'Authorization': `token ${token}`, - 'Content-Type': 'application/json', - 'Content-Length': expectedPostData.length, - 'User-Agent': 'angular-cli-github-pages' - } - } - - expect(req).to.eql(expectedReq); - - return { - on: (event, cb) => responseCb = cb, - write: (postData) => expect(postData).to.eql(expectedPostData), - end: () => responseCb({ statusCode: 401, statusMessage: 'Unauthorized' }) - } - } - - return ng(['github-pages:deploy', '--skip-build', `--gh-token=${token}`, - `--gh-username=${username}`]) - .then(() => { - throw new SilentError('Should not pass the deploy.'); - }, (ret) => { - expect(ret.name).to.equal('SilentError'); - expect(ret.isSilentError).to.equal(true); - }) - .then(() => httpsStub.restore()); - }); - - it('should fail gracefully when checkout has permissions failure', function() { - execStub.addExecSuccess('git status --porcelain') - .addExecSuccess('git rev-parse --abbrev-ref HEAD', initialBranch) - .addExecSuccess('git remote -v', remote) - .addExecSuccess(`git checkout ${ghPagesBranch}`) - .addExecSuccess('git ls-files') - .addExecSuccess('git rm -r ') - .addExecSuccess('git add .') - .addExecSuccess(`git commit -m "${message}"`) - .addExecError(`git checkout ${initialBranch}`, 'error: cannot stat \'src/client\': Permission denied'); - - return ng(['github-pages:deploy', '--skip-build']) - .then(() => { - throw new SilentError('Should not pass the deploy.'); - }, (ret) => { - expect(ret.name).to.equal('SilentError'); - expect(ret.isSilentError).to.equal(true); - expect(ret.message).to.contain('There was a permissions error'); - }); - }); -});