Skip to content

Commit 108901d

Browse files
authored
Merge pull request #1974 from gitgitgadget/re-architecture-token-handling
Re architecture token handling
2 parents b80b25b + ae860c0 commit 108901d

File tree

6 files changed

+73
-15
lines changed

6 files changed

+73
-15
lines changed

lib/ci-helper.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export class CIHelper {
3737
protected testing: boolean;
3838
private gggNotesUpdated: boolean;
3939
private mail2CommitMapUpdated: boolean;
40+
private notesPushToken: string | undefined;
4041
protected maxCommitsExceptions: string[];
4142

4243
public constructor(workDir: string, skipUpdate?: boolean, gggConfigDir = ".") {
@@ -53,6 +54,13 @@ export class CIHelper {
5354
this.urlRepo = `${this.urlBase}${this.config.repo.name}/`;
5455
}
5556

57+
public setAccessToken(repositoryOwner: string, token: string): void {
58+
this.github.setAccessToken(repositoryOwner, token);
59+
if (this.config.repo.owner === repositoryOwner) {
60+
this.notesPushToken = token;
61+
}
62+
}
63+
5664
/*
5765
* Given a commit that was contributed as a patch via GitGitGadget (i.e.
5866
* a commit with a Message-ID recorded in `refs/notes/gitgitgadget`),
@@ -243,7 +251,7 @@ export class CIHelper {
243251
}
244252
}
245253
if (result) {
246-
await this.notes.push(this.urlRepo);
254+
await this.pushNotesRef();
247255
}
248256
return result;
249257
}
@@ -408,7 +416,7 @@ export class CIHelper {
408416
}
409417

410418
if (notesUpdated || optionsUpdated) {
411-
await this.notes.push(this.urlRepo);
419+
await this.pushNotesRef();
412420
}
413421

414422
return [notesUpdated, optionsUpdated];
@@ -568,7 +576,7 @@ export class CIHelper {
568576
};
569577

570578
try {
571-
const gitGitGadget = await GitGitGadget.get(this.gggConfigDir, this.workDir);
579+
const gitGitGadget = await GitGitGadget.get(this.gggConfigDir, this.workDir, this.notesPushToken);
572580
if (!gitGitGadget.isUserAllowed(comment.author)) {
573581
throw new Error(`User ${comment.author} is not yet permitted to use ${this.config.app.displayName}`);
574582
}
@@ -774,7 +782,7 @@ export class CIHelper {
774782
await this.github.addPRComment(prKey, redacted);
775783
};
776784

777-
const gitGitGadget = await GitGitGadget.get(this.gggConfigDir, this.workDir);
785+
const gitGitGadget = await GitGitGadget.get(this.gggConfigDir, this.workDir, this.notesPushToken);
778786
if (!pr.hasComments && !gitGitGadget.isUserAllowed(pr.author)) {
779787
const welcome = (await readFile("res/WELCOME.md")).toString().replace(/\${username}/g, pr.author);
780788
await this.github.addPRComment(prKey, welcome);
@@ -806,7 +814,7 @@ export class CIHelper {
806814
this.config.mailrepo.branch,
807815
);
808816
if (await mailArchiveGit.processMails(prFilter)) {
809-
await this.notes.push(this.urlRepo);
817+
await this.pushNotesRef();
810818
return true;
811819
}
812820
return false;
@@ -878,7 +886,7 @@ export class CIHelper {
878886
if (optionsChanged) {
879887
console.log(`Changed options:\n${toPrettyJSON(options)}`);
880888
await this.notes.set("", options, true);
881-
await this.notes.push(this.urlRepo);
889+
await this.pushNotesRef();
882890
}
883891

884892
return optionsChanged;
@@ -933,4 +941,8 @@ export class CIHelper {
933941
this.mail2CommitMapUpdated = true;
934942
}
935943
}
944+
945+
private async pushNotesRef(): Promise<void> {
946+
await this.notes.push(this.urlRepo, this.notesPushToken);
947+
}
936948
}

lib/git-notes.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,16 @@ type TemporaryNoteIndex = {
1919
};
2020

2121
export class GitNotes {
22-
public async push(url: string) {
22+
public async push(url: string, token: string | undefined = undefined): Promise<void> {
23+
const auth = !token
24+
? []
25+
: [
26+
"-c",
27+
`http.extraheader=Authorization: Basic ${Buffer.from(`x-access-token:${token}`).toString("base64")}`,
28+
];
2329
for (const backoff of [50, 500, 2000, 5000, 20000, 0]) {
2430
try {
25-
await git(["push", url, "--", `${this.notesRef}`], {
31+
await git([...auth, "push", url, "--", `${this.notesRef}`], {
2632
workDir: this.workDir,
2733
});
2834
} catch (e) {

lib/gitgitgadget.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export class GitGitGadget {
3636
return workDir;
3737
}
3838

39-
public static async get(gitGitGadgetDir: string, workDir?: string): Promise<GitGitGadget> {
39+
public static async get(gitGitGadgetDir: string, workDir?: string, notesPushToken?: string): Promise<GitGitGadget> {
4040
if (!workDir) {
4141
workDir = await this.getWorkDir(gitGitGadgetDir);
4242
}
@@ -76,6 +76,7 @@ export class GitGitGadget {
7676
allowedUsers,
7777
{ smtpHost, smtpOpts, smtpPass, smtpUser },
7878
publishTagsAndNotesToRemote,
79+
notesPushToken,
7980
);
8081
}
8182

@@ -98,13 +99,15 @@ export class GitGitGadget {
9899
protected readonly smtpOptions: ISMTPOptions;
99100

100101
protected readonly publishTagsAndNotesToRemote: string;
102+
private readonly publishToken: string | undefined;
101103

102104
protected constructor(
103105
notes: GitNotes,
104106
options: IGitGitGadgetOptions,
105107
allowedUsers: Set<string>,
106108
smtpOptions: ISMTPOptions,
107109
publishTagsAndNotesToRemote: string,
110+
publishToken?: string,
108111
) {
109112
if (!notes.workDir) {
110113
throw new Error("Could not determine Git worktree");
@@ -117,6 +120,7 @@ export class GitGitGadget {
117120
this.smtpOptions = smtpOptions;
118121

119122
this.publishTagsAndNotesToRemote = publishTagsAndNotesToRemote;
123+
this.publishToken = publishToken;
120124
}
121125

122126
public isUserAllowed(user: string): boolean {
@@ -240,7 +244,7 @@ export class GitGitGadget {
240244
}
241245

242246
protected async pushNotesRef(): Promise<void> {
243-
await this.notes.push(this.publishTagsAndNotesToRemote);
247+
await this.notes.push(this.publishTagsAndNotesToRemote, this.publishToken);
244248

245249
// re-read options
246250
[this.options, this.allowedUsers] = await GitGitGadget.readOptions(this.notes);
@@ -280,6 +284,7 @@ export class GitGitGadget {
280284
this.publishTagsAndNotesToRemote,
281285
pr.pullRequestURL,
282286
new Date(),
287+
this.publishToken,
283288
);
284289
if (!options.noUpdate) {
285290
await this.pushNotesRef();

lib/github-glue.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export class GitHubGlue {
5757
protected authenticated?: string;
5858
protected owner: string;
5959
protected repo: string;
60+
private tokens: Map<string, string> = new Map();
6061

6162
public constructor(workDir: string, owner: string, repo: string) {
6263
this.owner = owner;
@@ -472,12 +473,19 @@ export class GitHubGlue {
472473
}
473474
}
474475

476+
public setAccessToken(repositoryOwner: string, token: string): void {
477+
this.tokens.set(repositoryOwner, token);
478+
}
479+
475480
protected async ensureAuthenticated(repositoryOwner: string): Promise<void> {
476481
if (repositoryOwner !== this.authenticated) {
477-
const infix = repositoryOwner === "gitgitgadget" ? "" : `.${repositoryOwner}`;
478-
const tokenKey = `gitgitgadget${infix}.githubToken`;
479-
const tokenVar = tokenKey.toUpperCase().replace(/\./, "_");
480-
const token = process.env[tokenVar] ? process.env[tokenVar] : await gitConfig(tokenKey);
482+
let token = this.tokens.get(repositoryOwner);
483+
if (!token) {
484+
const infix = repositoryOwner === "gitgitgadget" ? "" : `.${repositoryOwner}`;
485+
const tokenKey = `gitgitgadget${infix}.githubToken`;
486+
const tokenVar = tokenKey.toUpperCase().replace(/\./, "_");
487+
token = process.env[tokenVar] ? process.env[tokenVar] : await gitConfig(tokenKey);
488+
}
481489
if (!token) {
482490
throw new Error(`Need a GitHub token for ${repositoryOwner}`);
483491
}

lib/patch-series.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,7 @@ export class PatchSeries {
555555
publishTagsAndNotesToRemote?: string,
556556
pullRequestURL?: string,
557557
forceDate?: Date,
558+
publishToken?: string,
558559
): Promise<IPatchSeriesMetadata | undefined> {
559560
let globalOptions: IGitGitGadgetOptions | undefined;
560561
if (this.options.dryRun) {
@@ -822,8 +823,20 @@ export class PatchSeries {
822823
if (this.options.dryRun) {
823824
logger.log("Would publish tag");
824825
} else {
826+
const auth = [];
827+
if (publishToken) {
828+
auth.push(
829+
"-c",
830+
[
831+
`http.extraheader=Authorization:`,
832+
`Basic`,
833+
Buffer.from(`x-access-token:${publishToken}`).toString("base64"),
834+
].join(" "),
835+
);
836+
}
837+
825838
logger.log("Publishing tag");
826-
await git(["push", publishTagsAndNotesToRemote, `refs/tags/${tagName}`], {
839+
await git([...auth, "push", publishTagsAndNotesToRemote, `refs/tags/${tagName}`], {
827840
workDir: this.notes.workDir,
828841
});
829842
}

script/misc-helper.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,27 +72,38 @@ const commandOptions = commander.opts<ICommanderOptions>();
7272

7373
const ci = new CIHelper(await getGitGitWorkDir(), commandOptions.skipUpdate, commandOptions.gitgitgadgetWorkDir);
7474

75+
const configureNotesPushToken = async (): Promise<void> => {
76+
const token = await gitConfig("gitgitgadget.githubToken");
77+
if (!token) {
78+
throw new Error("No token configured for gitgitgadget.githubToken");
79+
}
80+
ci.setAccessToken("gitgitgadget", token);
81+
};
82+
7583
const argv = commander.args;
7684
commander = new Command().version("1.0.0");
7785
commander
7886
.usage("[options] command")
7987
.command("update-open-prs")
8088
.description("Update GitGitGadget's idea of what PRs are open")
8189
.action(async () => {
90+
await configureNotesPushToken();
8291
const result = await ci.updateOpenPrs();
8392
console.log(`Updated notes: ${result}`);
8493
});
8594
commander
8695
.command("update-commit-mappings")
8796
.description("Determine which commits correspond to which open PRs")
8897
.action(async () => {
98+
await configureNotesPushToken();
8999
const result = await ci.updateCommitMappings();
90100
console.log(`Updated notes: ${result}`);
91101
});
92102
commander
93103
.command("handle-open-prs")
94104
.description("Handle open PRs, i.e. look whether they have been integrated into upstream Git")
95105
.action(async () => {
106+
await configureNotesPushToken();
96107
const options = await ci.getGitGitGadgetOptions();
97108
if (!options.openPRs) {
98109
throw new Error("No open PRs?");
@@ -437,6 +448,7 @@ const commandOptions = commander.opts<ICommanderOptions>();
437448
"Handle a comment on a Pull Request",
438449
async (repositoryOwner: string, commentID: string) => {
439450
if (repositoryOwner === undefined) repositoryOwner = config.repo.owner;
451+
await configureNotesPushToken();
440452
await ci.handleComment(repositoryOwner, parseInt(commentID, 10));
441453
},
442454
true,
@@ -447,6 +459,7 @@ const commandOptions = commander.opts<ICommanderOptions>();
447459
"handle-pr-push",
448460
"Handle a push to a Pull Request",
449461
async (repositoryOwner: string, prNumber: string) => {
462+
await configureNotesPushToken();
450463
await ci.handlePush(repositoryOwner, parseInt(prNumber, 10));
451464
},
452465
true,
@@ -456,6 +469,7 @@ const commandOptions = commander.opts<ICommanderOptions>();
456469
.command("handle-new-mails")
457470
.description("Handle new mails in the mail archive")
458471
.action(async () => {
472+
await configureNotesPushToken();
459473
const mailArchiveGitDir = await getVar("loreGitDir", commandOptions.gitgitgadgetWorkDir);
460474

461475
if (!mailArchiveGitDir) {

0 commit comments

Comments
 (0)