Five parallel tea-parity additions (~1100 LOC):
- fgj time {list,add,delete,reset} (aliases: times, t)
Tracked time entries. 'list' with no arg uses ListMyTrackedTimes
across all your repos; with an issue number uses ListIssueTrackedTimes.
'add' accepts Go duration strings (30m, 1h30m). 'delete' removes a
single entry by id; 'reset' clears all times on an issue. Confirmation
on delete/reset unless --yes or no TTY.
- fgj branch {protect,unprotect}
Branch protection rules. 'protect' idempotently creates-or-edits via
Get/Create/EditBranchProtection with --require-approvals,
--require-signed-commits, --dismiss-stale-approvals,
--block-on-rejected-reviews, --block-on-outdated-branch,
--push-whitelist, --merge-whitelist, --require-status-checks.
Empty whitelist flags leave existing rule fields untouched.
'unprotect' deletes; 404 is a friendly no-op.
- fgj release asset {list,create,delete} (alias: assets)
Granular attachment management. Resolves the release by tag or
"latest" using the existing helpers in cmd/release.go. 'create'
validates all paths up front then uploads each. 'delete' accepts
numeric ids OR filenames (cross-references the attachment list).
Per-asset confirmation unless --yes.
- fgj milestone issues {add,remove} (alias: i)
Associate/disassociate issues with a milestone. Milestone accepted
as title or numeric id (reuses resolveMilestone from milestone.go).
'remove' passes EditIssueOption{Milestone: &zero} — the Gitea/Forgejo
convention for clearing the association. Continues on per-issue
failure and exits 1 if any failed.
- fgj notification {unread,pin,unpin}
Complement the existing list/read. Factory pattern over
ReadNotification(id, NotifyStatus) with three distinct constants.
All five files are self-contained: each has its own init() attaching
to the existing parent cobra.Command (branchCmd, milestoneCmd,
notificationCmd, releaseCmd) without modifying any other file. Built
by parallel sub-agents; all compile, vet, and test clean.
60 lines
1.6 KiB
Go
60 lines
1.6 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"code.gitea.io/sdk/gitea"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var notificationUnreadCmd = &cobra.Command{
|
|
Use: "unread <id>",
|
|
Short: "Mark a notification as unread",
|
|
Long: "Mark a single notification thread as unread by its ID.",
|
|
Args: cobra.ExactArgs(1),
|
|
RunE: runNotificationState(gitea.NotifyStatusUnread, "unread"),
|
|
}
|
|
|
|
var notificationPinCmd = &cobra.Command{
|
|
Use: "pin <id>",
|
|
Short: "Pin a notification",
|
|
Long: "Mark a single notification thread as pinned by its ID.",
|
|
Args: cobra.ExactArgs(1),
|
|
RunE: runNotificationState(gitea.NotifyStatusPinned, "pinned"),
|
|
}
|
|
|
|
var notificationUnpinCmd = &cobra.Command{
|
|
Use: "unpin <id>",
|
|
Short: "Un-pin a notification",
|
|
Long: "Un-pin a notification thread (marks it as read).",
|
|
Args: cobra.ExactArgs(1),
|
|
RunE: runNotificationState(gitea.NotifyStatusRead, "unpinned"),
|
|
}
|
|
|
|
func init() {
|
|
notificationCmd.AddCommand(notificationUnreadCmd)
|
|
notificationCmd.AddCommand(notificationPinCmd)
|
|
notificationCmd.AddCommand(notificationUnpinCmd)
|
|
}
|
|
|
|
func runNotificationState(status gitea.NotifyStatus, verb string) func(*cobra.Command, []string) error {
|
|
return func(cmd *cobra.Command, args []string) error {
|
|
id, err := parseIssueArg(args[0])
|
|
if err != nil {
|
|
return fmt.Errorf("invalid notification id %q: %w", args[0], err)
|
|
}
|
|
|
|
client, err := loadClient()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, _, err := client.ReadNotification(id, status); err != nil {
|
|
return fmt.Errorf("failed to mark notification %d as %s: %w", id, verb, err)
|
|
}
|
|
|
|
cs := ios.ColorScheme()
|
|
fmt.Fprintf(ios.Out, "%s Marked notification %d as %s\n", cs.SuccessIcon(), id, verb)
|
|
return nil
|
|
}
|
|
}
|