Skip to content

Commit f8e5386

Browse files
authored
feat: create OAuth token using device flow if no token was provided (#32)
1 parent ed29f37 commit f8e5386

File tree

5 files changed

+222
-7198
lines changed

5 files changed

+222
-7198
lines changed

bin/commands/run.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ const options = {
1515
"octoherd-token": {
1616
description:
1717
'Requires the "public_repo" scope for public repositories, "repo" scope for private repositories.',
18-
demandOption: true,
1918
type: "string",
2019
alias: "T",
2120
},

index.js

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import { appendFileSync } from "fs";
22

33
import { Octokit } from "@octoherd/octokit";
4+
import { createOAuthDeviceAuth } from "@octokit/auth-oauth-device";
45
import chalk from "chalk";
56
import tempy from "tempy";
7+
import clipboardy from "clipboardy";
8+
import enquirer from "enquirer";
69

710
import { cache as octokitCachePlugin } from "./lib/octokit-plugin-cache.js";
811
import { requestLog } from "./lib/octokit-plugin-request-log.js";
@@ -48,8 +51,38 @@ export async function octoherd(
4851
if (typeof octoherdCache === "string") plugins.push(octokitCachePlugin);
4952
const CliOctokit = Octokit.plugin(...plugins);
5053

54+
const authOptions = octoherdToken
55+
? { auth: octoherdToken }
56+
: {
57+
authStrategy: createOAuthDeviceAuth,
58+
auth: {
59+
// Octoherd's OAuth App
60+
clientId: "e93735961b3b72ca5c02",
61+
clientType: "oauth-app",
62+
scopes: ["repo"],
63+
async onVerification({ verification_uri, user_code }) {
64+
console.log("Open %s", verification_uri);
65+
66+
await clipboardy.write(user_code);
67+
console.log("Paste code: %s (copied to your clipboard)", user_code);
68+
69+
console.log(
70+
`\n${chalk.gray(
71+
"To avoid this prompt, pass a token with --octoherd-token or -T"
72+
)}\n`
73+
);
74+
75+
const prompt = new enquirer.Input({
76+
message: "Press <enter> when ready",
77+
});
78+
79+
await prompt.run();
80+
},
81+
},
82+
};
83+
5184
const octokit = new CliOctokit({
52-
auth: octoherdToken,
85+
...authOptions,
5386
userAgent: ["octoherd-cli", VERSION].join("/"),
5487
octoherd: {
5588
debug: octoherdDebug,
@@ -81,6 +114,10 @@ export async function octoherd(
81114
throw new Error("[octoherd] No repositories provided");
82115
}
83116

117+
// trigger OAuth Device Flow before loading repositories
118+
// It's not necessary, but a better UX
119+
await octokit.auth({ type: "oauth-user" });
120+
84121
const state = {
85122
log: console,
86123
octokit,
@@ -98,8 +135,8 @@ export async function octoherd(
98135
);
99136

100137
try {
101-
const { id, owner, name } = repository
102-
octokit.log.setContext({ repository: { id, owner, name } })
138+
const { id, owner, name } = repository;
139+
octokit.log.setContext({ repository: { id, owner, name } });
103140
await octoherdScript(octokit, repository, userOptions);
104141
} catch (error) {
105142
if (!error.cancel) throw error;

lib/octokit-plugin-request-confirm.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export function requestConfirm(octokit, { octoherd }) {
2525

2626
const { name, documentationUrl } = ENDPOINTS[route] || {};
2727

28+
if (baseUrl !== "https://api.github.com") return request(options);
2829
if (octoherd.bypassConfirms) return request(options);
2930
if (!isMutatingRequest) return request(options);
3031
if (allowAll["*"]) return request(options);

0 commit comments

Comments
 (0)