Skip to content
Merged
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
Binary file added docs/images/circleCiGithubToken.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/circleCiSetUpProject.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 52 additions & 6 deletions docs/userGuide/deployingTheSite.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ You can override the default deployment settings %%(e.g., repo/branch to deploy)
### Deploying to GitHub Pages via CI Tools
**You can setup CI Tools to automatically build and deploy your site on GitHub Pages every time your GitHub repo is updated.**

<panel header="#### Generating a Github Personal Access Token" type="seamless" expanded>

With the exception of Github Actions, a Github Personal Access Token with **repo** permissions is required for deploying your MarkBind site to Github Pages via CI tools.

You may refer to Github's documentation on [how to generate a Github Personal Access Token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/#creating-a-token). Ensure that you have enabled **repo** permissions as shown from the screenshot below. Take note of the generated token - you will not be able to see it again once you navigate away from the page.
<include src="screenshot.md" boilerplate var-alt="GitHub Token Repo Permissions" var-file="githubTokenRepoPermissions.png" inline />
</panel>

<panel header="#### Deploying via Github Actions" type="seamless" expanded>

To instruct [Github Actions](https://docs.github.com/en/actions) to build and deploy the site when you push to the repository, add a Github Actions workflow file in your project repo at the location `<PROJECT_ROOT>/.github/workflows/deploy.yml` A sample workflow file is provided below:
Expand Down Expand Up @@ -92,7 +100,7 @@ jobs:

<box type="info">

The sample `deploy.yml` workflow above uses the [default Github Token secret](https://docs.github.com/en/actions/reference/authentication-in-a-workflow) that is generated automatically for each Github Actions workflow. You may also use a Github Personal Access Token in place of the default Github Token. For steps on setting up your Github Personal Access Token, you may refer to the [setup instructions for Travis CI](#configuring-your-repository-in-travis-ci).
The sample `deploy.yml` workflow above uses the [default Github Token secret](https://docs.github.com/en/actions/reference/authentication-in-a-workflow) that is generated automatically for each Github Actions workflow. You may also use a [Github Personal Access Token](#generating-a-github-personal-access-token) in place of the default Github Token.
</box>

Once you have created the file, commit and push the file to your repo. Github Actions should start to build and deploy your markbind site. You can verify this by visiting `www.github.com/<org|username>/<repo>/actions`.
Expand Down Expand Up @@ -137,9 +145,7 @@ Since May 2018, Travis CI has been [undergoing migration to `travis-ci.com`](htt

##### Configuring your repository in Travis CI

1. [Generate a GitHub personal access token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/#creating-a-token) with **repo** permissions. Take note of the generated token - you will not be able to see it again once you navigate away from the page.
<include src="screenshot.md" boilerplate var-alt="GitHub Token Repo Permissions" var-file="githubTokenRepoPermissions.png" inline />
1. [Add an environment variable in Travis CI](https://docs.travis-ci.com/user/environment-variables/#defining-variables-in-repository-settings) named `GITHUB_TOKEN`, with the value set to the personal access token generated in the previous step. ==Ensure that _Display value in the build log_ is set to _Off_.==
1. [Add an environment variable in Travis CI](https://docs.travis-ci.com/user/environment-variables/#defining-variables-in-repository-settings) named `GITHUB_TOKEN`, with the value set to your [generated Github Personal Access Token](#generating-a-github-personal-access-token). ==Ensure that _Display value in the build log_ is set to _Off_.==
<include src="screenshot.md" boilerplate var-alt="Add GITHUB_TOKEN" var-file="travisGithubToken.png" inline />
1. Add a `.travis.yml` file to instruct Travis CI to build and deploy the site when you push to the repository. An example `.travis.yml` file that can accomplish this is given below:
```yaml
Expand Down Expand Up @@ -207,8 +213,7 @@ The `repo` value can be changed to your specific repository as desired.

##### Configuring your repository in AppVeyor CI

1. [Generate a Github personal access token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/#creating-a-token) with **repo permissions**.
<include src="screenshot.md" boilerplate var-alt="GitHub Token Repo Permissions" var-file="githubTokenRepoPermissions.png" inline />
1. Ensure that you have generated a [Github Personal Access token with **repo** permissions](#generating-a-github-personal-access-token).
1. Navigate to the project settings page of your repository in AppVeyor CI.
1. On the left menu, click on __Environment__.
1. Under the heading __Environment variables__, add a custom environment variable named `GITHUB_TOKEN`, with the value set to the personal access token that was generated in the first step. ==Ensure that you toggle variable encryption by clicking on the padlock.==
Expand Down Expand Up @@ -236,6 +241,47 @@ build: off

Commit and push `appveyor.yml` to your github repository. Thereafter, AppVeyor CI should begin to run the build script. You are able to view the current build status by clicking on your repository in the [AppVeyor projects page](https://ci.appveyor.com/projects). Once the build succeeds, you should be able to view your Markbind site, after a few seconds, at `http://<username|org>.github.io/<repo>` e.g., http://se-edu.github.io/se-book.

</panel>

<panel header="#### Deploying via Circle CI" type="seamless" expanded>

##### Adding your repository to Circle CI
1. Ensure that you have generated a [Github Personal Access Token with **repo** permissions](#generating-a-github-personal-access-token).
1. Sign in to [Circle CI](https://circleci.com/) using your Github account.
1. In the projects dashboard, click on the `Set Up Project` button beside the repo containing your Markbind site.
<include src="screenshot.md" boilerplate var-alt="Set Up Project in Circle CI" var-file="circleCiSetUpProject.png" inline />

##### Configuring your repository in Circle CI
1. Once you have set up your project, click on the `Project Settings` button.
2. On the left, click on the `Environment Variables` tab and add a custom Environment Variable, `GITHUB_TOKEN`, which contains the value of your Github Personal Access Token.
<include src="screenshot.md" boilerplate var-alt="Add Github Token in Circle CI" var-file="circleCiGithubToken.png" inline />
3. Commit and push a `config.yml` file to the repo containg your Markbind Site that instructs Circle CI to build and deploy your Markbind site to Github Pages whenever you push to your repository. Ensure that the `config.yml` file is located in the `<PROJECT_ROOT>/.circleci/` directory. A sample `config.yml` file is shown below:
```
jobs:
Build-And-Deploy:
docker:
- image: 'cimg/base:stable'
steps:
- checkout
- node/install:
node-version: "10"
npm-version: "6"
install-yarn: false
- run: node --version
- run: npm i -g markbind-cli
- run: markbind build
- run: markbind deploy --ci
version: 2.1
orbs:
node: circleci/node@4.1.0
workflows:
Deploy-Markbind-Site:
jobs:
- Build-And-Deploy
```
After you have pushed the `config.yml` file to your remote repo, you should see Circle CI starting to run the Deploy job in your projects dashboard. Once it is successful, you should be able to view your Markbind site at `http://<username|org>.github.io/<repo>`.

For more information on customizing your build script, you may refer to [Circle CI Config Reference Document](https://circleci.com/docs/2.0/configuration-reference/#section=configuration).
</panel>
<hr>

Expand Down
34 changes: 18 additions & 16 deletions packages/core/src/Site/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,7 @@ class Site {
const options = {};
options.branch = this.siteConfig.deploy.branch || defaultDeployConfig.branch;
options.message = this.siteConfig.deploy.message || defaultDeployConfig.message;
options.message = options.message.concat(' [skip ci]');
options.repo = this.siteConfig.deploy.repo || defaultDeployConfig.repo;

if (ciTokenVar) {
Expand All @@ -1153,38 +1154,36 @@ class Site {
let repoSlug;

if (process.env.TRAVIS) {
if (options.repo) {
repoSlug = Site.extractRepoSlug(options.repo);
} else {
repoSlug = process.env.TRAVIS_REPO_SLUG;
}
repoSlug = Site.extractRepoSlug(options.repo, process.env.TRAVIS_REPO_SLUG);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice workaround! 👍


options.user = {
name: 'Deployment Bot',
email: 'deploy@travis-ci.org',
};
} else if (process.env.APPVEYOR) {
if (options.repo) {
repoSlug = Site.extractRepoSlug(options.repo);
} else {
repoSlug = process.env.APPVEYOR_REPO_NAME;
}
repoSlug = Site.extractRepoSlug(options.repo, process.env.APPVEYOR_REPO_NAME);

options.user = {
name: 'AppVeyorBot',
email: 'deploy@appveyor.com',
};
} else if (process.env.GITHUB_ACTIONS) {
if (options.repo) {
repoSlug = Site.extractRepoSlug(options.repo);
} else {
repoSlug = process.env.GITHUB_REPOSITORY;
}
repoSlug = Site.extractRepoSlug(options.repo, process.env.GITHUB_REPOSITORY);

options.user = {
name: 'github-actions',
email: 'github-actions@github.com',
};
} else if (process.env.CIRCLECI) {
repoSlug = Site.extractRepoSlug(
options.repo,
`${process.env.CIRCLE_PROJECT_USERNAME}/${process.env.CIRCLE_PROJECT_REPONAME}`,
);

options.user = {
name: 'circleci-bot',
email: 'deploy@circleci.com',
};
} else {
throw new Error('-c/--ci should only be run in CI environments.');
}
Expand All @@ -1199,7 +1198,10 @@ class Site {
/**
* Extract repo slug from user-specified repo URL so that we can include the access token
*/
static extractRepoSlug(repo) {
static extractRepoSlug(repo, ciRepoSlug) {
if (!repo) {
return ciRepoSlug;
}
const repoSlugRegex = /github\.com[:/]([\w-]+\/[\w-.]+)\.git$/;
const repoSlugMatch = repoSlugRegex.exec(repo);
if (!repoSlugMatch) {
Expand Down
60 changes: 43 additions & 17 deletions packages/core/test/unit/Site.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ test('Site deploys with default settings', async () => {
expect(ghpages.options)
.toEqual({
branch: 'gh-pages',
message: 'Site Update.',
message: 'Site Update. [skip ci]',
repo: '',
remote: 'origin',
});
Expand All @@ -256,7 +256,7 @@ test('Site deploys with custom settings', async () => {
expect(ghpages.options)
.toEqual({
branch: 'master',
message: 'Custom Site Update.',
message: 'Custom Site Update. [skip ci]',
repo: 'https://github.com/USER/REPO.git',
remote: 'origin',
});
Expand Down Expand Up @@ -289,22 +289,34 @@ describe('Site deploy with various CI environments', () => {
delete process.env.APPVEYOR_REPO_NAME;
delete process.env.GITHUB_ACTIONS;
delete process.env.GITHUB_REPOSITORY;
delete process.env.CIRCLECI;
delete process.env.CIRCLE_PROJECT_USERNAME;
delete process.env.CIRCLE_PROJECT_REPONAME;
});

afterAll(() => {
// Restore the original environment at the end of deploy Travis tests
process.env = { ...OLD_ENV };
});

/* eslint-disable max-len */
test.each([
['TRAVIS', 'TRAVIS_REPO_SLUG', { name: 'Deployment Bot', email: 'deploy@travis-ci.org' }],
['APPVEYOR', 'APPVEYOR_REPO_NAME', { name: 'AppVeyorBot', email: 'deploy@appveyor.com' }],
['GITHUB_ACTIONS', 'GITHUB_REPOSITORY', { name: 'github-actions', email: 'github-actions@github.com' }],
['TRAVIS', { reposlug: 'TRAVIS_REPO_SLUG' }, { name: 'Deployment Bot', email: 'deploy@travis-ci.org' }],
['APPVEYOR', { reposlug: 'APPVEYOR_REPO_NAME' }, { name: 'AppVeyorBot', email: 'deploy@appveyor.com' }],
['GITHUB_ACTIONS', { reposlug: 'GITHUB_REPOSITORY' }, { name: 'github-actions', email: 'github-actions@github.com' }],
['CIRCLECI', { username: 'CIRCLE_PROJECT_USERNAME', reponame: 'CIRCLE_PROJECT_REPONAME' }, { name: 'circleci-bot', email: 'deploy@circleci.com' }],
])('Site deploy -c/--ci deploys with default settings',
/* eslint-enable max-len */
async (ciIdentifier, repoSlugIdentifier, deployBotUser) => {
process.env[ciIdentifier] = true;
process.env[repoSlugIdentifier] = 'GENERIC_USER/GENERIC_REPO';
process.env.GITHUB_TOKEN = 'githubToken';
const genericRepoSlug = 'GENERIC_USER/GENERIC_REPO';
if (repoSlugIdentifier.reposlug) {
process.env[repoSlugIdentifier.reposlug] = genericRepoSlug;
} else {
process.env[repoSlugIdentifier.username] = 'GENERIC_USER';
process.env[repoSlugIdentifier.reponame] = 'GENERIC_REPO';
}

const json = {
...PAGE_NJK,
Expand All @@ -315,20 +327,25 @@ describe('Site deploy with various CI environments', () => {
const site = new Site('./', '_site');
await site.deploy(true);
expect(ghpages.options.repo)
// eslint-disable-next-line max-len
.toEqual(`https://x-access-token:${process.env.GITHUB_TOKEN}@github.com/${process.env[repoSlugIdentifier]}.git`);
.toEqual(`https://x-access-token:${process.env.GITHUB_TOKEN}@github.com/${genericRepoSlug}.git`);
expect(ghpages.options.user).toEqual(deployBotUser);
});

test.each([
['TRAVIS', 'TRAVIS_REPO_SLUG'],
['APPVEYOR', 'APPVEYOR_REPO_NAME'],
['GITHUB_ACTIONS', 'GITHUB_REPOSITORY'],
['TRAVIS', { reposlug: 'TRAVIS_REPO_SLUG' }],
['APPVEYOR', { reposlug: 'APPVEYOR_REPO_NAME' }],
['GITHUB_ACTIONS', { reposlug: 'GITHUB_REPOSITORY' }],
['CIRCLECI', { username: 'CIRCLE_PROJECT_USERNAME', reponame: 'CIRCLE_PROJECT_REPONAME' }],
])('Site deploy -c/--ci deploys with custom GitHub repo',
async (ciIdentifier, repoSlugIdentifier) => {
process.env[ciIdentifier] = true;
process.env[repoSlugIdentifier] = 'GENERIC_USER/GENERIC_REPO';
process.env.GITHUB_TOKEN = 'githubToken';
if (repoSlugIdentifier.reposlug) {
process.env[repoSlugIdentifier.reposlug] = 'GENERIC_USER/GENERIC_REPO';
} else {
process.env[repoSlugIdentifier.username] = 'GENERIC_USER';
process.env[repoSlugIdentifier.reponame] = 'GENERIC_REPO';
}

const customRepoConfig = JSON.parse(SITE_JSON_DEFAULT);
customRepoConfig.deploy.repo = 'https://github.com/USER/REPO.git';
Expand All @@ -345,14 +362,21 @@ describe('Site deploy with various CI environments', () => {
});

test.each([
['TRAVIS', 'TRAVIS_REPO_SLUG'],
['APPVEYOR', 'APPVEYOR_REPO_NAME'],
['GITHUB_ACTIONS', 'GITHUB_REPOSITORY'],
['TRAVIS', { reposlug: 'TRAVIS_REPO_SLUG' }],
['APPVEYOR', { reposlug: 'APPVEYOR_REPO_NAME' }],
['GITHUB_ACTIONS', { reposlug: 'GITHUB_REPOSITORY' }],
['CIRCLECI', { username: 'CIRCLE_PROJECT_USERNAME', reponame: 'CIRCLE_PROJECT_REPONAME' }],
])('Site deploy -c/--ci deploys to correct repo when .git is in repo name',
async (ciIdentifier, repoSlugIdentifier) => {
process.env[ciIdentifier] = true;
process.env[repoSlugIdentifier] = 'GENERIC_USER/GENERIC_REPO.github.io';
process.env.GITHUB_TOKEN = 'githubToken';
const genericRepoSlug = 'GENERIC_USER/GENERIC_REPO.github.io';
if (repoSlugIdentifier.reposlug) {
process.env[repoSlugIdentifier.reposlug] = genericRepoSlug;
} else {
process.env[repoSlugIdentifier.username] = 'GENERIC_USER';
process.env[repoSlugIdentifier.reponame] = 'GENERIC_REPO.github.io';
}

const json = {
...PAGE_NJK,
Expand All @@ -364,7 +388,7 @@ describe('Site deploy with various CI environments', () => {
await site.deploy(true);
expect(ghpages.options.repo)
// eslint-disable-next-line max-len
.toEqual(`https://x-access-token:${process.env.GITHUB_TOKEN}@github.com/${process.env[repoSlugIdentifier]}.git`);
.toEqual(`https://x-access-token:${process.env.GITHUB_TOKEN}@github.com/${genericRepoSlug}.git`);
});

test('Site deploy -c/--ci should not deploy if not in CI environment', async () => {
Expand All @@ -386,6 +410,7 @@ describe('Site deploy with various CI environments', () => {
['TRAVIS'],
['APPVEYOR'],
['GITHUB_ACTIONS'],
['CIRCLECI'],
])('Site deploy -c/--ci should not deploy without authentication token', async (ciIdentifier) => {
process.env[ciIdentifier] = true;

Expand All @@ -405,6 +430,7 @@ describe('Site deploy with various CI environments', () => {
['TRAVIS'],
['APPVEYOR'],
['GITHUB_ACTIONS'],
['CIRCLECI'],
])('Site deploy -c/--ci should not deploy if custom repository is not on GitHub', async (ciIdentifier) => {
process.env[ciIdentifier] = true;
process.env.GITHUB_TOKEN = 'githubToken';
Expand Down