import { Notice, Plugin, TFile } from "obsidian"; import { DEFAULT_SETTINGS, JekyllPublishSettings } from "./settings"; import { JekyllPublishSettingTab } from "./SettingsTab"; import { ModalResult, PublishModal } from "./PublishModal"; import { ChildProcessGitClient } from "./git"; import { publish } from "./publish"; export default class JekyllPublishPlugin extends Plugin { settings!: JekyllPublishSettings; async onload() { await this.loadSettings(); this.addSettingTab(new JekyllPublishSettingTab(this.app, this)); this.addCommand({ id: "publish-current-note", name: "Publish current note to Jekyll", checkCallback: (checking) => { const file = this.app.workspace.getActiveFile(); if (!file) return false; if (!checking) void this.openPublishModal(file); return true; }, }); } async loadSettings() { this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); } async saveSettings() { await this.saveData(this.settings); } private async openPublishModal(file: TFile) { const noteText = await this.app.vault.read(file); new PublishModal(this.app, this.settings, noteText, file.basename, (r) => void this.runPublish(noteText, r) ).open(); } private async runPublish(noteText: string, r: ModalResult) { if (!this.settings.remoteUrl.trim()) { new Notice("Jekyll Publish: set a remote URL in settings first."); return; } try { // Credentials are handled entirely by the user's system git: its // configured credential helper (Git Credential Manager on Windows, // osxkeychain on macOS, libsecret on Linux) for https:// URLs, or the // ssh-agent / key for ssh:// URLs. The plugin stores nothing and sets // GIT_TERMINAL_PROMPT=0 (in ChildProcessGitClient) so git fails fast // with a clear message instead of hanging when no helper is available. const git = new ChildProcessGitClient(); const result = await publish( { noteText, ...r }, this.settings, git, (linktext) => this.resolveImage(linktext) ); const warn = result.unresolved.length ? ` (${result.unresolved.length} image(s) unresolved)` : ""; new Notice(`Published ${result.postPath} with ${result.imageCount} image(s)${warn}`); } catch (e) { new Notice(`Publish failed: ${withCredentialHint((e as Error).message)}`, 12000); } } private async resolveImage(linktext: string): Promise { const dest = this.app.metadataCache.getFirstLinkpathDest(linktext, ""); if (!dest) return null; const ab = await this.app.vault.readBinary(dest); return Buffer.from(ab); } } /** * When git fails for an authentication reason, append guidance pointing the * user at their system credential helper / ssh setup, since the plugin * deliberately does not store or prompt for credentials itself. */ function withCredentialHint(message: string): string { const authPattern = /could not read (Username|Password)|terminal prompts disabled|Authentication failed|Permission denied|access denied|fatal: Authentication|no email was given|Author identity unknown/i; if (authPattern.test(message)) { return ( `${message}\n\n` + "Git could not authenticate or identify you. For an https:// URL, set up a " + "git credential helper (e.g. Git Credential Manager). For an ssh:// URL, make " + "sure your SSH key/agent is configured. You can also set an author name/email " + "in the plugin settings." ); } return message; }