package main import ( "fmt" "io" "os" "github.com/spf13/cobra" "sourcecraft.dev/bigbes/confluence-md-utilities/api" "sourcecraft.dev/bigbes/confluence-md-utilities/converter" "sourcecraft.dev/bigbes/confluence-md-utilities/template" ) var ( pushMessage string pushRaw bool pushTemplate bool pushMarkerStart string pushMarkerEnd string ) var pushCmd = &cobra.Command{ Use: "push [input.md]", Short: "Push local Markdown to a Confluence page", Long: `Convert a local Markdown file to Confluence storage format and update the page at the given URL. By default, the entire page body is replaced with the converted content. With --template, the current page body is preserved as a template: the content between marker comments is replaced with the new content, keeping everything else (metadata table, changelog, etc.) intact. With --raw, the input is treated as Confluence storage XML (no conversion). Reads from stdin if no input file is specified. Authentication via --token flag or CONFLUENCE_TOKEN environment variable.`, Args: cobra.RangeArgs(1, 2), RunE: func(cmd *cobra.Command, args []string) error { token := resolveToken() if token == "" { return fmt.Errorf("Confluence token required: use --token flag or set CONFLUENCE_TOKEN env var") } ref, err := api.ParsePageURL(args[0]) if err != nil { return err } // Read input var input []byte if len(args) > 1 { input, err = os.ReadFile(args[1]) } else { input, err = io.ReadAll(os.Stdin) } if err != nil { return fmt.Errorf("reading input: %w", err) } // Convert to Confluence XML if not raw var newXML string if pushRaw { newXML = string(input) } else { newXML, err = converter.MarkdownToConfluence(input) if err != nil { return fmt.Errorf("converting markdown: %w", err) } } client := api.NewClient(ref.BaseURL, token) // Fetch current page for version info (and template if needed) page, err := client.GetPage(ref) if err != nil { return err } fmt.Fprintf(os.Stderr, "Updating page: %s (id=%s, version=%d -> %d)\n", page.Title, page.ID, page.Version.Number, page.Version.Number+1) // If template mode, embed into existing page body body := newXML if pushTemplate { body, err = template.Embed(page.Body.Storage.Value, newXML, pushMarkerStart, pushMarkerEnd) if err != nil { return fmt.Errorf("embedding into template: %w", err) } } if err := client.UpdateContent(page.ID, page, body, pushMessage); err != nil { return err } fmt.Fprintf(os.Stderr, "Page updated successfully\n") return nil }, } func init() { pushCmd.Flags().StringVarP(&pushMessage, "message", "m", "", "Version message for the update") pushCmd.Flags().BoolVar(&pushRaw, "raw", false, "Input is raw Confluence storage XML (skip conversion)") pushCmd.Flags().BoolVar(&pushTemplate, "template", false, "Embed content into existing page body between markers") pushCmd.Flags().StringVar(&pushMarkerStart, "marker-start", template.DefaultMarkerStart, "Start marker comment (with --template)") pushCmd.Flags().StringVar(&pushMarkerEnd, "marker-end", template.DefaultMarkerEnd, "End marker comment (with --template)") rootCmd.AddCommand(pushCmd) }