mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-09 14:22:27 +02:00
feat: allow GIT_USER env var to be unset if SSH is used (#5840)
* feat: allow GIT_USER env var to be unset if SSH is used * fix: packages/docusaurus/src/commands/deploy.ts Co-authored-by: Joshua Chen <sidachen2003@gmail.com> * feat: allow user to specify deploymentBranch property in docusaurus.config.js (#5841) * feat: allow user to specify deploymentBranch property in docusaurus.config.js * docs: remove extra backtick * docs: fix broken code block * docs: fix i18n routes to feature requests (#5843) * docs: fix i18n routes to feature requests * Add redirect rules * feat: allow GIT_USER env var to be unset if SSH is used * fix: packages/docusaurus/src/commands/deploy.ts Co-authored-by: Joshua Chen <sidachen2003@gmail.com> * fix: avoid escaping hyphen in regex * Refactor * Update deployment.mdx * Make SSH higher priority * Only infer but not override * Add tests * Fix tests * Fix Co-authored-by: Joshua Chen <sidachen2003@gmail.com>
This commit is contained in:
parent
ecce576bbc
commit
f5732e7589
7 changed files with 166 additions and 151 deletions
|
@ -26,8 +26,16 @@ This command generates static content into the `build` directory and can be serv
|
||||||
|
|
||||||
### Deployment
|
### Deployment
|
||||||
|
|
||||||
|
Using SSH:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ GIT_USER=<Your GitHub username> USE_SSH=true yarn deploy
|
$ USE_SSH=true yarn deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
Not using SSH:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ GIT_USER=<Your GitHub username> yarn deploy
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
|
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
|
||||||
|
|
|
@ -26,8 +26,16 @@ This command generates static content into the `build` directory and can be serv
|
||||||
|
|
||||||
### Deployment
|
### Deployment
|
||||||
|
|
||||||
|
Using SSH:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ GIT_USER=<Your GitHub username> USE_SSH=true yarn deploy
|
$ USE_SSH=true yarn deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
Not using SSH:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ GIT_USER=<Your GitHub username> yarn deploy
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
|
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {buildUrl} from '../buildRemoteBranchUrl';
|
|
||||||
|
|
||||||
describe('remoteeBranchUrl', () => {
|
|
||||||
test('should build a normal ssh url', async () => {
|
|
||||||
const url = buildUrl(
|
|
||||||
'github.com',
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
'facebook',
|
|
||||||
'docusaurus',
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
expect(url).toEqual('git@github.com:facebook/docusaurus.git');
|
|
||||||
});
|
|
||||||
test('should build a ssh url with port', async () => {
|
|
||||||
const url = buildUrl(
|
|
||||||
'github.com',
|
|
||||||
'422',
|
|
||||||
undefined,
|
|
||||||
'facebook',
|
|
||||||
'docusaurus',
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
expect(url).toEqual('ssh://git@github.com:422/facebook/docusaurus.git');
|
|
||||||
});
|
|
||||||
test('should build a normal http url', async () => {
|
|
||||||
const url = buildUrl(
|
|
||||||
'github.com',
|
|
||||||
undefined,
|
|
||||||
'user:pass',
|
|
||||||
'facebook',
|
|
||||||
'docusaurus',
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
expect(url).toEqual('https://user:pass@github.com/facebook/docusaurus.git');
|
|
||||||
});
|
|
||||||
test('should build a normal http url', async () => {
|
|
||||||
const url = buildUrl(
|
|
||||||
'github.com',
|
|
||||||
'5433',
|
|
||||||
'user:pass',
|
|
||||||
'facebook',
|
|
||||||
'docusaurus',
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
expect(url).toEqual(
|
|
||||||
'https://user:pass@github.com:5433/facebook/docusaurus.git',
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
62
packages/docusaurus/src/commands/__tests__/deploy.test.ts
Normal file
62
packages/docusaurus/src/commands/__tests__/deploy.test.ts
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {buildSshUrl, buildHttpsUrl, hasSSHProtocol} from '../deploy';
|
||||||
|
|
||||||
|
describe('remoteBranchUrl', () => {
|
||||||
|
test('should build a normal ssh url', () => {
|
||||||
|
const url = buildSshUrl('github.com', 'facebook', 'docusaurus');
|
||||||
|
expect(url).toEqual('git@github.com:facebook/docusaurus.git');
|
||||||
|
});
|
||||||
|
test('should build a ssh url with port', () => {
|
||||||
|
const url = buildSshUrl('github.com', 'facebook', 'docusaurus', '422');
|
||||||
|
expect(url).toEqual('ssh://git@github.com:422/facebook/docusaurus.git');
|
||||||
|
});
|
||||||
|
test('should build a normal http url', () => {
|
||||||
|
const url = buildHttpsUrl(
|
||||||
|
'user:pass',
|
||||||
|
'github.com',
|
||||||
|
'facebook',
|
||||||
|
'docusaurus',
|
||||||
|
);
|
||||||
|
expect(url).toEqual('https://user:pass@github.com/facebook/docusaurus.git');
|
||||||
|
});
|
||||||
|
test('should build a normal http url', () => {
|
||||||
|
const url = buildHttpsUrl(
|
||||||
|
'user:pass',
|
||||||
|
'github.com',
|
||||||
|
'facebook',
|
||||||
|
'docusaurus',
|
||||||
|
'5433',
|
||||||
|
);
|
||||||
|
expect(url).toEqual(
|
||||||
|
'https://user:pass@github.com:5433/facebook/docusaurus.git',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('hasSSHProtocol', () => {
|
||||||
|
test('should recognize explicit SSH protocol', () => {
|
||||||
|
const url = 'ssh://git@github.com:422/facebook/docusaurus.git';
|
||||||
|
expect(hasSSHProtocol(url)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should recognize implied SSH protocol', () => {
|
||||||
|
const url = 'git@github.com:facebook/docusaurus.git';
|
||||||
|
expect(hasSSHProtocol(url)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not recognize HTTPS with credentials', () => {
|
||||||
|
const url = 'https://user:pass@github.com/facebook/docusaurus.git';
|
||||||
|
expect(hasSSHProtocol(url)).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not recognize plain HTTPS URL', () => {
|
||||||
|
const url = 'https://github.com:5433/facebook/docusaurus.git';
|
||||||
|
expect(hasSSHProtocol(url)).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,50 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function buildUrl(
|
|
||||||
githubHost: string,
|
|
||||||
githubPort: string | undefined,
|
|
||||||
gitCredentials: string | undefined,
|
|
||||||
organizationName: string,
|
|
||||||
projectName: string,
|
|
||||||
useSSH: boolean | undefined,
|
|
||||||
): string {
|
|
||||||
return useSSH
|
|
||||||
? buildSshUrl(githubHost, organizationName, projectName, githubPort)
|
|
||||||
: buildHttpsUrl(
|
|
||||||
gitCredentials,
|
|
||||||
githubHost,
|
|
||||||
organizationName,
|
|
||||||
projectName,
|
|
||||||
githubPort,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildSshUrl(
|
|
||||||
githubHost: string,
|
|
||||||
organizationName: string,
|
|
||||||
projectName: string,
|
|
||||||
githubPort: string | undefined,
|
|
||||||
) {
|
|
||||||
if (githubPort) {
|
|
||||||
return `ssh://git@${githubHost}:${githubPort}/${organizationName}/${projectName}.git`;
|
|
||||||
}
|
|
||||||
return `git@${githubHost}:${organizationName}/${projectName}.git`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildHttpsUrl(
|
|
||||||
gitCredentials: string | undefined,
|
|
||||||
githubHost: string,
|
|
||||||
organizationName: string,
|
|
||||||
projectName: string,
|
|
||||||
githubPort: string | undefined,
|
|
||||||
) {
|
|
||||||
if (githubPort) {
|
|
||||||
return `https://${gitCredentials}@${githubHost}:${githubPort}/${organizationName}/${projectName}.git`;
|
|
||||||
}
|
|
||||||
return `https://${gitCredentials}@${githubHost}/${organizationName}/${projectName}.git`;
|
|
||||||
}
|
|
|
@ -13,7 +13,6 @@ import build from './build';
|
||||||
import {BuildCLIOptions} from '@docusaurus/types';
|
import {BuildCLIOptions} from '@docusaurus/types';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import {buildUrl} from './buildRemoteBranchUrl';
|
|
||||||
|
|
||||||
// GIT_PASS env variable should not appear in logs
|
// GIT_PASS env variable should not appear in logs
|
||||||
function obfuscateGitPass(str: string) {
|
function obfuscateGitPass(str: string) {
|
||||||
|
@ -38,6 +37,43 @@ function shellExecLog(cmd: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildSshUrl(
|
||||||
|
githubHost: string,
|
||||||
|
organizationName: string,
|
||||||
|
projectName: string,
|
||||||
|
githubPort?: string,
|
||||||
|
): string {
|
||||||
|
if (githubPort) {
|
||||||
|
return `ssh://git@${githubHost}:${githubPort}/${organizationName}/${projectName}.git`;
|
||||||
|
}
|
||||||
|
return `git@${githubHost}:${organizationName}/${projectName}.git`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildHttpsUrl(
|
||||||
|
gitCredentials: string,
|
||||||
|
githubHost: string,
|
||||||
|
organizationName: string,
|
||||||
|
projectName: string,
|
||||||
|
githubPort?: string,
|
||||||
|
): string {
|
||||||
|
if (githubPort) {
|
||||||
|
return `https://${gitCredentials}@${githubHost}:${githubPort}/${organizationName}/${projectName}.git`;
|
||||||
|
}
|
||||||
|
return `https://${gitCredentials}@${githubHost}/${organizationName}/${projectName}.git`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasSSHProtocol(sourceRepoUrl: string): boolean {
|
||||||
|
try {
|
||||||
|
if (new URL(sourceRepoUrl).protocol === 'ssh:') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch {
|
||||||
|
// Fails when there isn't a protocol
|
||||||
|
return /^([\w-]+@)?[\w.-]+:[\w./_-]+(\.git)?/.test(sourceRepoUrl); // git@github.com:facebook/docusaurus.git
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default async function deploy(
|
export default async function deploy(
|
||||||
siteDir: string,
|
siteDir: string,
|
||||||
cliOptions: Partial<BuildCLIOptions> = {},
|
cliOptions: Partial<BuildCLIOptions> = {},
|
||||||
|
@ -63,15 +99,32 @@ This behavior can have SEO impacts and create relative link issues.
|
||||||
throw new Error('Git not installed or on the PATH!');
|
throw new Error('Git not installed or on the PATH!');
|
||||||
}
|
}
|
||||||
|
|
||||||
const gitUser = process.env.GIT_USER;
|
// Source repo is the repo from where the command is invoked
|
||||||
if (!gitUser) {
|
const sourceRepoUrl = shell
|
||||||
throw new Error('Please set the GIT_USER environment variable!');
|
.exec('git config --get remote.origin.url', {silent: true})
|
||||||
}
|
.stdout.trim();
|
||||||
|
|
||||||
// The branch that contains the latest docs changes that will be deployed.
|
// The source branch; defaults to the currently checked out branch
|
||||||
const currentBranch =
|
const sourceBranch =
|
||||||
process.env.CURRENT_BRANCH ||
|
process.env.CURRENT_BRANCH ||
|
||||||
shell.exec('git rev-parse --abbrev-ref HEAD').stdout.trim();
|
shell.exec('git rev-parse --abbrev-ref HEAD', {silent: true}).stdout.trim();
|
||||||
|
|
||||||
|
const gitUser = process.env.GIT_USER;
|
||||||
|
|
||||||
|
let useSSH =
|
||||||
|
process.env.USE_SSH !== undefined &&
|
||||||
|
process.env.USE_SSH.toLowerCase() === 'true';
|
||||||
|
|
||||||
|
if (!gitUser && !useSSH) {
|
||||||
|
// If USE_SSH is unspecified: try inferring from repo URL
|
||||||
|
if (process.env.USE_SSH === undefined && hasSSHProtocol(sourceRepoUrl)) {
|
||||||
|
useSSH = true;
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
'Please set the GIT_USER environment variable, or explicitly specify USE_SSH instead!',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const organizationName =
|
const organizationName =
|
||||||
process.env.ORGANIZATION_NAME ||
|
process.env.ORGANIZATION_NAME ||
|
||||||
|
@ -107,8 +160,7 @@ This behavior can have SEO impacts and create relative link issues.
|
||||||
// Organization deploys looks like:
|
// Organization deploys looks like:
|
||||||
// - Git repo: https://github.com/<organization>/<organization>.github.io
|
// - Git repo: https://github.com/<organization>/<organization>.github.io
|
||||||
// - Site url: https://<organization>.github.io
|
// - Site url: https://<organization>.github.io
|
||||||
const isGitHubPagesOrganizationDeploy =
|
const isGitHubPagesOrganizationDeploy = projectName.includes('.github.io');
|
||||||
projectName.indexOf('.github.io') !== -1;
|
|
||||||
if (
|
if (
|
||||||
isGitHubPagesOrganizationDeploy &&
|
isGitHubPagesOrganizationDeploy &&
|
||||||
!process.env.DEPLOYMENT_BRANCH &&
|
!process.env.DEPLOYMENT_BRANCH &&
|
||||||
|
@ -127,38 +179,39 @@ You can also set the deploymentBranch property in docusaurus.config.js .`);
|
||||||
process.env.GITHUB_HOST || siteConfig.githubHost || 'github.com';
|
process.env.GITHUB_HOST || siteConfig.githubHost || 'github.com';
|
||||||
const githubPort = process.env.GITHUB_PORT || siteConfig.githubPort;
|
const githubPort = process.env.GITHUB_PORT || siteConfig.githubPort;
|
||||||
|
|
||||||
const gitPass: string | undefined = process.env.GIT_PASS;
|
let remoteBranch: string;
|
||||||
let gitCredentials = `${gitUser}`;
|
if (useSSH) {
|
||||||
if (gitPass) {
|
remoteBranch = buildSshUrl(
|
||||||
gitCredentials = `${gitCredentials}:${gitPass}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const useSSH = process.env.USE_SSH;
|
|
||||||
const remoteBranch = buildUrl(
|
|
||||||
githubHost,
|
githubHost,
|
||||||
githubPort,
|
|
||||||
gitCredentials,
|
|
||||||
organizationName,
|
organizationName,
|
||||||
projectName,
|
projectName,
|
||||||
useSSH !== undefined && useSSH.toLowerCase() === 'true',
|
githubPort,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
const gitPass = process.env.GIT_PASS;
|
||||||
|
const gitCredentials = gitPass ? `${gitUser!}:${gitPass}` : gitUser!;
|
||||||
|
remoteBranch = buildHttpsUrl(
|
||||||
|
gitCredentials,
|
||||||
|
githubHost,
|
||||||
|
organizationName,
|
||||||
|
projectName,
|
||||||
|
githubPort,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`${chalk.cyan('Remote branch:')} ${obfuscateGitPass(remoteBranch)}`,
|
`${chalk.cyan('Remote branch:')} ${obfuscateGitPass(remoteBranch)}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check if this is a cross-repo publish.
|
// Check if this is a cross-repo publish.
|
||||||
const currentRepoUrl = shell
|
const crossRepoPublish = !sourceRepoUrl.endsWith(
|
||||||
.exec('git config --get remote.origin.url')
|
|
||||||
.stdout.trim();
|
|
||||||
const crossRepoPublish = !currentRepoUrl.endsWith(
|
|
||||||
`${organizationName}/${projectName}.git`,
|
`${organizationName}/${projectName}.git`,
|
||||||
);
|
);
|
||||||
|
|
||||||
// We don't allow deploying to the same branch unless it's a cross publish.
|
// We don't allow deploying to the same branch unless it's a cross publish.
|
||||||
if (currentBranch === deploymentBranch && !crossRepoPublish) {
|
if (sourceBranch === deploymentBranch && !crossRepoPublish) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`You cannot deploy from this branch (${currentBranch}).` +
|
`You cannot deploy from this branch (${sourceBranch}).` +
|
||||||
'\nYou will need to checkout to a different branch!',
|
'\nYou will need to checkout to a different branch!',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,19 +138,12 @@ By default, GitHub Pages runs published files through [Jekyll](https://jekyllrb.
|
||||||
|
|
||||||
### Environment settings {#environment-settings}
|
### Environment settings {#environment-settings}
|
||||||
|
|
||||||
Specify the Git user as an environment variable.
|
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `GIT_USER` | The username for a GitHub account that **has push access to the deployment repo**. For your own repositories, this will usually be your GitHub username. |
|
| `USE_SSH` | Set to `true` to use SSH instead of the default HTTPS for the connection to the GitHub repo. If the source repo URL is an SSH URL (e.g. `git@github.com:facebook/docusaurus.git`), `USE_SSH` is inferred to be `true`. |
|
||||||
|
| `GIT_USER` | The username for a GitHub account that **has push access to the deployment repo**. For your own repositories, this will usually be your GitHub username. Required if not using SSH, and ignored otherwise. |
|
||||||
Optional parameters, also set as environment variables:
|
| `GIT_PASS` | Personal access token of the git user (specified by `GIT_USER`), to facilitate non-interactive deployment (e.g. continuous deployment) |
|
||||||
|
|
||||||
| Name | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `USE_SSH` | Set to `true` to use SSH instead of the default HTTPS for the connection to the GitHub repo. |
|
|
||||||
| `CURRENT_BRANCH` | The source branch. Usually, the branch will be `main` or `master`, but it could be any branch except for `gh-pages`. If nothing is set for this variable, then the current branch from which `docusaurus deploy` is invoked will be used. |
|
| `CURRENT_BRANCH` | The source branch. Usually, the branch will be `main` or `master`, but it could be any branch except for `gh-pages`. If nothing is set for this variable, then the current branch from which `docusaurus deploy` is invoked will be used. |
|
||||||
| `GIT_PASS` | Personal access token of the `git` user (specified by `GIT_USER`), to facilitate non-interactive deployment (e.g. continuous deployment) |
|
|
||||||
|
|
||||||
GitHub enterprise installations should work in the same manner as github.com; you only need to set the organization's GitHub Enterprise host as an environment variable:
|
GitHub enterprise installations should work in the same manner as github.com; you only need to set the organization's GitHub Enterprise host as an environment variable:
|
||||||
|
|
||||||
|
@ -362,7 +355,6 @@ jobs:
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
env:
|
env:
|
||||||
USE_SSH: true
|
USE_SSH: true
|
||||||
GIT_USER: git
|
|
||||||
run: |
|
run: |
|
||||||
git config --global user.email "actions@github.com"
|
git config --global user.email "actions@github.com"
|
||||||
git config --global user.name "gh-actions"
|
git config --global user.name "gh-actions"
|
||||||
|
@ -492,7 +484,6 @@ trigger:
|
||||||
- yarn deploy
|
- yarn deploy
|
||||||
environment:
|
environment:
|
||||||
USE_SSH: true
|
USE_SSH: true
|
||||||
GIT_USER: $DRONE_COMMIT_AUTHOR
|
|
||||||
GITHUB_PRIVATE_KEY:
|
GITHUB_PRIVATE_KEY:
|
||||||
from_secret: git_deploy_private_key
|
from_secret: git_deploy_private_key
|
||||||
```
|
```
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue