Skip to content

Commit

Permalink
feat: Support Github Enterprise by allowing custom Github hostname (#129
Browse files Browse the repository at this point in the history
)

Add settings `apiHostname` (defaults to `api.github.com`) and `--gitHostname` (defaults to `github.com`)
  • Loading branch information
cjskillingstad authored and sorenlouv committed May 9, 2019
1 parent b130d55 commit 5d3947b
Show file tree
Hide file tree
Showing 21 changed files with 262 additions and 57 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ The above commands will start an interactive prompt. You can use the `arrow keys
| --------------- | ----------------------------------------- | ------------------------ |
| --accessToken | Github access token | string |
| --all | Show all commits | boolean (default: false) |
| --apiHostname | Hostname for the Github API | string |
| --branch | Branch to backport to | string |
| --gitHostname | Hostname for Github | string |
| --labels | Pull request labels | string |
| --multiple | Backport multiple commits and/or branches | boolean |
| --prDescription | Description to be added to pull request | string |
Expand Down
20 changes: 20 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,23 @@ CLI: `--prTitle "My PR Title"`
Text that will be added to the pull request body.

CLI: `--prDescription "skip-ci"`

#### `gitHostname`

Hostname for Github.

Example: `github.my-private-company.com`

Default: `github.com`

CLI: `--gitHostname "github.my-private-company.com"`

#### `apiHostname`

Hostname for the Github API.

Example: `api.github.my-private-company.com`

Default: `api.github.com`

CLI: `--apiHostname "api.github.my-private-company.com"`
12 changes: 12 additions & 0 deletions src/options/cliArgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,23 @@ export function getOptionsFromCliArgs(
description: 'List all commits',
type: 'boolean'
})
.option('apiHostname', {
default: configOptions.apiHostname,
description: 'Hostname for the Github API',
type: 'string'
})
.option('branches', {
default: [] as string[],
description: 'Branch(es) to backport to',
type: 'array',
alias: 'branch',
string: true // ensure `6.0` is not coerced to `6`
})
.option('gitHostname', {
default: configOptions.gitHostname,
description: 'Hostname for Github',
type: 'string'
})
.option('labels', {
default: configOptions.labels,
description: 'Pull request labels',
Expand Down Expand Up @@ -78,8 +88,10 @@ export function getOptionsFromCliArgs(
return {
accessToken: cliArgs.accessToken,
all: cliArgs.all,
apiHostname: cliArgs.apiHostname,
branchChoices: configOptions.branchChoices,
branches: cliArgs.branches,
gitHostname: cliArgs.gitHostname,
labels: cliArgs.labels,
multiple: cliArgs.multiple,
multipleBranches: cliArgs.multipleBranches || cliArgs.multiple,
Expand Down
2 changes: 2 additions & 0 deletions src/options/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export async function getOptionsFromConfigFiles() {
all: false,
labels: [] as string[],
prTitle: '[{baseBranch}] {commitMessages}',
gitHostname: 'github.com',
apiHostname: 'api.github.com',

// options from config files
...globalConfig,
Expand Down
2 changes: 2 additions & 0 deletions src/options/config/globalConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ interface GlobalConfig {

// the following are overwritable by project config:
all?: boolean;
apiHostname?: string;
gitHostname?: string;
multiple?: boolean;
multipleCommits?: boolean;
multipleBranches?: boolean;
Expand Down
4 changes: 4 additions & 0 deletions src/options/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ function getErrorMessage({
export function validateOptions({
accessToken,
all,
apiHostname,
branchChoices,
branches,
gitHostname,
labels,
multiple,
multipleBranches,
Expand Down Expand Up @@ -79,9 +81,11 @@ export function validateOptions({
return {
accessToken,
all,
apiHostname,
branchChoices,
branches,
labels,
gitHostname,
multiple,
multipleBranches,
multipleCommits,
Expand Down
24 changes: 18 additions & 6 deletions src/services/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,29 +42,38 @@ export function deleteRepo({
function getRemoteUrl({
owner,
repoName,
accessToken
accessToken,
gitHostname
}: {
owner: string;
repoName: string;
accessToken: string;
gitHostname: string;
}) {
return `https://${accessToken}@github.com/${owner}/${repoName}.git`;
return `https://${accessToken}@${gitHostname}/${owner}/${repoName}.git`;
}

export function cloneRepo({
owner,
repoName,
accessToken,
callback
callback,
gitHostname
}: {
owner: string;
repoName: string;
accessToken: string;
callback: (progress: string) => void;
gitHostname: string;
}) {
return new Promise((resolve, reject) => {
const execProcess = childProcess.exec(
`git clone ${getRemoteUrl({ accessToken, owner, repoName })} --progress`,
`git clone ${getRemoteUrl({
accessToken,
owner,
repoName,
gitHostname
})} --progress`,
{ cwd: getRepoOwnerPath(owner), maxBuffer: 100 * 1024 * 1024 },
error => {
if (error) {
Expand Down Expand Up @@ -110,19 +119,22 @@ export async function addRemote({
owner,
repoName,
username,
accessToken
accessToken,
gitHostname
}: {
owner: string;
repoName: string;
username: string;
accessToken: string;
gitHostname: string;
}) {
try {
await exec(
`git remote add ${username} ${getRemoteUrl({
accessToken,
owner: username,
repoName
repoName,
gitHostname
})}`,
{
cwd: getRepoPath(owner, repoName)
Expand Down
44 changes: 29 additions & 15 deletions src/services/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ function getCommitMessage(message: string) {
export async function fetchCommitsByAuthor(
owner: string,
repoName: string,
author: string | null
author: string | null,
apiHostname: string
): Promise<Commit[]> {
const query: GithubQuery = {
access_token: accessToken,
Expand All @@ -44,7 +45,7 @@ export async function fetchCommitsByAuthor(

try {
const res: AxiosResponse<GithubCommit[]> = await axios(
`https://api.github.com/repos/${owner}/${repoName}/commits?${querystring.stringify(
`https://${apiHostname}/repos/${owner}/${repoName}/commits?${querystring.stringify(
query
)}`
);
Expand All @@ -54,7 +55,12 @@ export async function fetchCommitsByAuthor(
return {
message: getCommitMessage(commit.commit.message),
sha,
pullNumber: await fetchPullRequestNumberBySha(owner, repoName, sha)
pullNumber: await fetchPullRequestNumberBySha(
owner,
repoName,
sha,
apiHostname
)
};
});

Expand All @@ -67,11 +73,12 @@ export async function fetchCommitsByAuthor(
export async function fetchCommitBySha(
owner: string,
repoName: string,
sha: string
sha: string,
apiHostname: string
): Promise<Commit> {
try {
const res: AxiosResponse<GithubSearch<GithubCommit>> = await axios(
`https://api.github.com/search/commits?q=hash:${sha}%20repo:${owner}/${repoName}&per_page=1&access_token=${accessToken}`,
`https://${apiHostname}/search/commits?q=hash:${sha}%20repo:${owner}/${repoName}&per_page=1&access_token=${accessToken}`,
{
headers: {
Accept: 'application/vnd.github.cloak-preview'
Expand All @@ -88,7 +95,8 @@ export async function fetchCommitBySha(
const pullNumber = await fetchPullRequestNumberBySha(
owner,
repoName,
fullSha
fullSha,
apiHostname
);

return {
Expand All @@ -104,11 +112,12 @@ export async function fetchCommitBySha(
async function fetchPullRequestNumberBySha(
owner: string,
repoName: string,
commitSha: string
commitSha: string,
apiHostname: string
): Promise<number> {
try {
const res: AxiosResponse<GithubSearch<GithubIssue>> = await axios(
`https://api.github.com/search/issues?q=repo:${owner}/${repoName}+${commitSha}+base:master&access_token=${accessToken}`
`https://${apiHostname}/search/issues?q=repo:${owner}/${repoName}+${commitSha}+base:master&access_token=${accessToken}`
);
return get(res.data.items[0], 'number');
} catch (e) {
Expand All @@ -119,11 +128,12 @@ async function fetchPullRequestNumberBySha(
export async function createPullRequest(
owner: string,
repoName: string,
payload: ReturnType<typeof getPullRequestPayload>
payload: ReturnType<typeof getPullRequestPayload>,
apiHostname: string
) {
try {
const res: AxiosResponse<GithubIssue> = await axios.post(
`https://api.github.com/repos/${owner}/${repoName}/pulls?access_token=${accessToken}`,
`https://${apiHostname}/repos/${owner}/${repoName}/pulls?access_token=${accessToken}`,
payload
);
return {
Expand All @@ -139,11 +149,12 @@ export async function addLabelsToPullRequest(
owner: string,
repoName: string,
pullNumber: number,
labels: string[]
labels: string[],
apiHostname: string
) {
try {
return await axios.post(
`https://api.github.com/repos/${owner}/${repoName}/issues/${pullNumber}/labels?access_token=${accessToken}`,
`https://${apiHostname}/repos/${owner}/${repoName}/issues/${pullNumber}/labels?access_token=${accessToken}`,
labels
);
} catch (e) {
Expand All @@ -154,11 +165,12 @@ export async function addLabelsToPullRequest(
export async function verifyAccessToken(
owner: string,
repoName: string,
accessToken: string
accessToken: string,
apiHostname: string
) {
try {
return await axios.head(
`https://api.github.com/repos/${owner}/${repoName}?access_token=${accessToken}`
`https://${apiHostname}/repos/${owner}/${repoName}?access_token=${accessToken}`
);
} catch (e) {
const error = e as GithubApiError;
Expand All @@ -175,7 +187,7 @@ export async function verifyAccessToken(
throw new HandledError(
`Please check your access token and make sure it is valid`
);
default:
case 404:
if (grantedScopes === requiredScopes) {
throw new HandledError(
`The repository "${owner}/${repoName}" doesn't exist`
Expand All @@ -185,6 +197,8 @@ export async function verifyAccessToken(
throw new HandledError(
`You do not have access to the repository "${owner}/${repoName}". Please make sure your access token has the required scopes.\n\nRequired scopes: ${requiredScopes}\nAccess token scopes: ${grantedScopes}`
);
default:
throw e.message;
}
}
}
Expand Down
24 changes: 19 additions & 5 deletions src/steps/doBackportVersions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export function doBackportVersions(
username: string,
labels: string[],
prTitle: string,
prDescription: string | undefined
prDescription: string | undefined,
apiHostname: string
) {
return sequentially(branches, async branch => {
try {
Expand All @@ -37,7 +38,8 @@ export function doBackportVersions(
username,
labels,
prTitle,
prDescription
prDescription,
apiHostname
);
log(`View pull request: ${pullRequest.html_url}`);
} catch (e) {
Expand All @@ -59,7 +61,8 @@ export async function doBackportVersion(
username: string,
labels: string[] = [],
prTitle: string,
prDescription: string | undefined
prDescription: string | undefined,
apiHostname: string
) {
const featureBranch = getFeatureBranchName(baseBranch, commits);
const refValues = commits.map(commit => getReferenceLong(commit)).join(', ');
Expand Down Expand Up @@ -98,9 +101,20 @@ export async function doBackportVersion(
prTitle,
prDescription
);
const pullRequest = await createPullRequest(owner, repoName, payload);
const pullRequest = await createPullRequest(
owner,
repoName,
payload,
apiHostname
);
if (labels.length > 0) {
await addLabelsToPullRequest(owner, repoName, pullRequest.number, labels);
await addLabelsToPullRequest(
owner,
repoName,
pullRequest.number,
labels,
apiHostname
);
}
return pullRequest;
});
Expand Down
Loading

0 comments on commit 5d3947b

Please sign in to comment.