Skip to content

Commit c32fc8d

Browse files
committed
Use a non-blocking message when not signed in
1 parent ec1bcc5 commit c32fc8d

File tree

4 files changed

+58
-17
lines changed

4 files changed

+58
-17
lines changed

src/api/handleSamlError.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
import {Octokit} from "@octokit/rest";
2-
import {getSession} from "../auth/auth";
2+
import {AuthenticationSession} from "vscode";
3+
4+
import {newSession} from "../auth/auth";
35
import {logDebug} from "../log";
46
import {getClient} from "./api";
57

6-
export async function handleSamlError<T>(request: (client: Octokit) => Promise<T>): Promise<T> {
8+
export async function handleSamlError<T>(
9+
session: AuthenticationSession,
10+
request: (client: Octokit) => Promise<T>
11+
): Promise<T> {
712
try {
8-
const session = await getSession();
913
const client = getClient(session.accessToken);
1014
return await request(client);
1115
} catch (error) {
1216
if ((error as Error).message.includes("Resource protected by organization SAML enforcement.")) {
1317
logDebug("SAML error, re-authenticating");
14-
const session = await getSession(
18+
const session = await newSession(
1519
"Your organization is protected by SAML enforcement. Please sign-in again to continue."
1620
);
1721
const client = getClient(session.accessToken);

src/auth/auth.ts

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,56 @@ import * as vscode from "vscode";
33
const AUTH_PROVIDER_ID = "github";
44
const DEFAULT_SCOPES = ["repo", "workflow"];
55

6+
let signInPrompted = false;
7+
8+
const SESSION_ERROR = "Could not get token from the GitHub authentication provider. \nPlease sign-in and allow access.";
9+
610
/**
7-
* Retrieves a session from the GitHub authentication provider
8-
* @param forceMessage Force a new session with a prompt to the user
11+
* Creates a session from the GitHub authentication provider
12+
* @param forceMessage Prompt to the user when forcing a new session
913
* @returns A {@link vscode.AuthenticationSession}
1014
*/
11-
export async function getSession(forceMessage?: string): Promise<vscode.AuthenticationSession> {
12-
// forceNewSession and createIfNone are mutually exclusive
13-
const options: vscode.AuthenticationGetSessionOptions = forceMessage
14-
? {forceNewSession: {detail: forceMessage}}
15-
: {createIfNone: true};
16-
const existingSession = await vscode.authentication.getSession(AUTH_PROVIDER_ID, getScopes(), options);
15+
export async function newSession(forceMessage: string): Promise<vscode.AuthenticationSession> {
16+
const session = await getSessionInternal(forceMessage);
17+
if (session) {
18+
return session;
19+
}
20+
throw new Error(SESSION_ERROR);
21+
}
1722

18-
if (!existingSession) {
19-
throw new Error("Could not get token from the GitHub authentication provider. \nPlease sign-in and allow access.");
23+
/**
24+
* Retrieves a session from the GitHub authentication provider or prompts the user to sign in
25+
* @returns A {@link vscode.AuthenticationSession} or undefined
26+
*/
27+
export async function getSession(): Promise<vscode.AuthenticationSession | undefined> {
28+
const session = await getSessionInternal(false);
29+
if (session || signInPrompted) {
30+
return session;
2031
}
2132

22-
return existingSession;
33+
signInPrompted = true;
34+
const signInAction = "Sign in to GitHub";
35+
const result = await vscode.window.showInformationMessage(
36+
"Sign in to GitHub to access your repositories and GitHub Actions workflows.",
37+
signInAction
38+
);
39+
if (result === signInAction) {
40+
return await getSessionInternal(true);
41+
}
42+
throw new Error(SESSION_ERROR);
43+
}
44+
45+
async function getSessionInternal(forceNewMessage: string): Promise<vscode.AuthenticationSession | undefined>;
46+
async function getSessionInternal(createIfNone: boolean): Promise<vscode.AuthenticationSession | undefined>;
47+
async function getSessionInternal(
48+
createOrForceMessage: string | boolean = false
49+
): Promise<vscode.AuthenticationSession | undefined> {
50+
// forceNewSession and createIfNone are mutually exclusive
51+
const options: vscode.AuthenticationGetSessionOptions =
52+
typeof createOrForceMessage === "string"
53+
? {forceNewSession: {detail: createOrForceMessage}}
54+
: {createIfNone: createOrForceMessage};
55+
return await vscode.authentication.getSession(AUTH_PROVIDER_ID, getScopes(), options);
2356
}
2457

2558
function getScopes(): string[] {

src/git/repository.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,13 @@ export async function getGitHubContext(): Promise<GitHubContext | undefined> {
163163
logDebug("Found protocol infos", protocolInfos.length.toString());
164164

165165
const session = await getSession();
166+
if (!session) {
167+
// User is not signed in, getSession will prompt them to sign in
168+
return undefined;
169+
}
166170
const username = session.account.label;
167171

168-
const repos = await handleSamlError(async (client: Octokit) => {
172+
const repos = await handleSamlError(session, async (client: Octokit) => {
169173
return await Promise.all(
170174
protocolInfos.map(async (protocolInfo): Promise<GitHubRepoContext> => {
171175
logDebug("Getting infos for repository", protocolInfo.url);

src/workflow/languageServer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export async function initLanguageServer(context: vscode.ExtensionContext) {
2424

2525
const ghContext = await getGitHubContext();
2626
const initializationOptions: InitializationOptions = {
27-
sessionToken: session.accessToken,
27+
sessionToken: session?.accessToken,
2828
userAgent: userAgent,
2929
repos: ghContext?.repos.map(repo => ({
3030
id: repo.id,

0 commit comments

Comments
 (0)