From 2c68a721bf05d6a907dd6f11c2807db34c0da036 Mon Sep 17 00:00:00 2001 From: Aurelian Shuttleworth Date: Sun, 25 Jan 2026 16:54:43 +0100 Subject: [PATCH] feat: add standard automation flags (--yes, --force) --- docs/automation.md | 10 ++++++++++ gcalcli/argparsers.py | 33 ++++++++++++++++++++++++++++++--- gcalcli/gcal.py | 11 +++++++++-- 3 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 docs/automation.md diff --git a/docs/automation.md b/docs/automation.md new file mode 100644 index 00000000..9bf1a672 --- /dev/null +++ b/docs/automation.md @@ -0,0 +1,10 @@ +# Automation Guide + +`gcalcli` provides features specifically designed for automation scripts and agents. + +## Non-Interactive Mode support (CI/CD) + +Use automation flags to prevent the tool from pausing for user input: + +- `--yes`, `--force`, `--no-prompt`: Automatically answer "yes" to confirmation prompts (like delete). +- `--noprompt` (specific to `add`): Skips prompting for missing fields during event creation. diff --git a/gcalcli/argparsers.py b/gcalcli/argparsers.py index 023a338e..478f28a9 100644 --- a/gcalcli/argparsers.py +++ b/gcalcli/argparsers.py @@ -354,6 +354,30 @@ def get_search_parser(): return search_parser +def get_automation_parser(): + # Flags for skipping confirmation prompts + automation_parser = argparse.ArgumentParser(add_help=False) + automation_parser.add_argument( + '--yes', '-y', + action='store_true', + dest='noconfirm', + help='Answer "yes" to all prompts (e.g. delete confirmation)' + ) + automation_parser.add_argument( + '--force', '-f', + action='store_true', + dest='noconfirm', + help='Alias for --yes' + ) + automation_parser.add_argument( + '--no-prompt', + action='store_true', + dest='noconfirm', + help='Alias for --yes' + ) + return automation_parser + + def handle_unparsed(unparsed, namespace): # Attempt a reparse against the program options. # Provides some robustness for misplaced global options @@ -450,6 +474,9 @@ def get_argument_parser(): # tacks on search text search_parser = get_search_parser() + + # automation flags + automation_parser = get_automation_parser() sub = parser.add_subparsers( help='Invoking a subcommand with --help prints subcommand usage.', @@ -496,13 +523,13 @@ def get_argument_parser(): delete = sub.add_parser( 'delete', - parents=[calendars_parser, output_parser, search_parser], + parents=[calendars_parser, output_parser, search_parser, automation_parser], help='delete events from the calendar', description='Case insensitive search for items to delete ' 'interactively.', ) delete.add_argument( - '--iamaexpert', action='store_true', help='Probably not' + '--iamaexpert', action='store_true', help='Legacy alias for --yes' ) sub.add_parser( @@ -656,7 +683,7 @@ def get_argument_parser(): _import = sub.add_parser( 'import', - parents=[calendar_parser, remind_parser], + parents=[calendar_parser, remind_parser, automation_parser], help='import an ics/vcal file to a calendar', description='Import from an ics/vcal file; a single --calendar ' 'must be specified. Reads from stdin when no file argument is ' diff --git a/gcalcli/gcal.py b/gcalcli/gcal.py index c8fb52f0..aa63820e 100644 --- a/gcalcli/gcal.py +++ b/gcalcli/gcal.py @@ -997,11 +997,18 @@ def _delete_event(self, event): cal_id = event['gcalcli_cal']['id'] event_id = event['id'] - if self.expert: + if self.expert or self.options.get('noconfirm'): self.delete(cal_id, event_id) self.printer.msg('Deleted!\n', 'red') return + # Print "Safe Prompt" summary + time_str = event['s'].strftime('%Y-%m-%d %H:%M') + if is_all_day(event): + time_str = event['s'].strftime('%Y-%m-%d') + + self.printer.msg(f'> Found Event: "{_valid_title(event).strip()}" ({time_str})\n', 'yellow') + self.printer.msg('Delete? [N]o [y]es [q]uit: ', 'magenta') val = input() @@ -1643,7 +1650,7 @@ def ImportICS(self, verbose=False, dump=False, reminders=None, self._add_reminders(event.body, reminders) - if not verbose: + if not verbose or self.options.get('noconfirm'): # Don't prompt, just assume user wants to import. pass else: