// // Instance and token management: sign in, sign out, test, add, remove. // const config = require("../util/config.js"); const credentials = require("../gitea/credentials.js"); const selection = require("./selection.js"); const ui = require("../ui.js"); const TOKEN_HELP = "Create one in Gitea under Settings → Applications → Access Tokens with " + "repository, issue, and Actions read scopes (plus write scopes for reviews, " + "secrets, and variables)."; /** Picks the instance a command applies to, prompting only when ambiguous. */ async function resolveInstance(argument, prompt) { const node = selection.selectedNode(argument); if (node && node.data && node.data.baseUrl) return node.data.baseUrl; const repo = node && node.repo ? node.repo : null; if (repo) return repo.baseUrl; const urls = config.instances(); if (!urls.length) { ui.warn("No Gitea instance is configured. Open the extension preferences first."); return null; } if (urls.length === 1) return urls[0]; return await ui.choose(urls, { placeholder: prompt }); } function register(store, refresh) { nova.commands.register("gitea.setToken", async (argument) => { const baseUrl = await resolveInstance(argument, "Set a token for which instance?"); if (!baseUrl) return; const token = await ui.input(`Personal access token for ${baseUrl}`, { placeholder: "Access token", prompt: TOKEN_HELP, secure: true, }); if (!token) return; try { credentials.setToken(baseUrl, token.trim()); } catch (error) { ui.error(`Could not save the token to the Keychain: ${error.message || error}`); return; } store.router.invalidate(); const api = store.router.apiFor(baseUrl); try { const [version, user] = await Promise.all([api.version(), api.currentUser()]); ui.info(`Signed in to ${baseUrl} as ${user.login} (Gitea ${version}).`); } catch (error) { ui.error(`Token saved, but ${baseUrl} rejected it: ${error.message || error}`); } await refresh({ rediscover: true }); }); nova.commands.register("gitea.clearToken", async (argument) => { const baseUrl = await resolveInstance(argument, "Sign out of which instance?"); if (!baseUrl) return; if (!(await ui.confirm(`Remove the stored token for ${baseUrl}?`, "Sign Out"))) return; credentials.removeToken(baseUrl); store.router.invalidate(); ui.info(`Signed out of ${baseUrl}.`); await refresh({ rediscover: true }); }); nova.commands.register("gitea.testConnection", async (argument) => { const baseUrl = await resolveInstance(argument, "Test which instance?"); if (!baseUrl) return; if (!credentials.hasToken(baseUrl)) { ui.warn(`No token stored for ${baseUrl}. Run “Set Token…” first.`); return; } const api = store.router.apiFor(baseUrl); try { const [version, user] = await Promise.all([api.version(), api.currentUser()]); ui.info(`${baseUrl} is reachable — Gitea ${version}, signed in as ${user.login}.`); } catch (error) { ui.error(`${baseUrl} failed: ${error.message || error}`); } await refresh(); }); nova.commands.register("gitea.addInstance", async () => { const entered = await ui.input("Add a Gitea instance", { placeholder: "https://gitea.example.com", prompt: "Repositories are routed to an instance by matching their git remote host.", }); if (!entered) return; const baseUrl = config.normalizeBaseUrl(entered); if (!baseUrl) { ui.warn("That does not look like a URL."); return; } if (config.instances().includes(baseUrl)) { ui.info(`${baseUrl} is already configured.`); return; } const extra = nova.config.get("gitea.instances", "array") || []; config.setInstances([...extra, baseUrl]); store.router.invalidate(); if (await ui.confirm(`Added ${baseUrl}. Set a token for it now?`, "Set Token")) { await nova.commands.invoke("gitea.setToken", { kind: "instance", data: { baseUrl } }); } else { await refresh({ rediscover: true }); } }); nova.commands.register("gitea.removeInstance", async (argument) => { const extra = nova.config.get("gitea.instances", "array") || []; if (!extra.length) { ui.info("The default instance is set in preferences and cannot be removed here."); return; } const node = selection.selectedNode(argument); let baseUrl = node && node.data ? node.data.baseUrl : null; if (!baseUrl || !extra.includes(baseUrl)) { baseUrl = await ui.choose(extra, { placeholder: "Remove which instance?" }); } if (!baseUrl) return; if (!(await ui.confirm(`Remove ${baseUrl} and its stored token?`, "Remove"))) return; credentials.removeToken(baseUrl); config.setInstances(extra.filter((url) => url !== baseUrl)); store.router.invalidate(); await refresh({ rediscover: true }); }); nova.commands.register("gitea.openPreferences", () => { nova.openConfig(); }); } exports.register = register; exports.resolveInstance = resolveInstance;