App-karr

 view release on metacpan or  search on metacpan

lib/App/karr/Cmd/Edit.pm  view on Meta::CPAN

  doc => 'New assignee',
);

option add_tag => (
  is => 'ro',
  format => 's',
  doc => 'Add tags (comma-separated)',
);

option remove_tag => (
  is => 'ro',
  format => 's',
  doc => 'Remove tags (comma-separated)',
);

option add_depends_on => (
  is => 'ro',
  format => 's',
  doc => 'Add dependency ids (comma-separated)',
);

option remove_depends_on => (
  is => 'ro',
  format => 's',
  doc => 'Remove dependency ids (comma-separated)',
);

option due => (
  is => 'ro',
  format => 's',
  doc => 'New due date',
);

option body => (
  is => 'ro',
  format => 's',
  doc => 'New body text',
);

option append_body => (
  is => 'ro',
  format => 's',
  short => 'a',
  doc => 'Append text to body',
);

option claim => (
  is => 'ro',
  format => 's',
  doc => 'Claim task for an agent',
);

option release => (
  is => 'ro',
  doc => 'Release claim',
);

option block => (
  is => 'ro',
  format => 's',
  doc => 'Mark as blocked with reason',
);

option unblock => (
  is => 'ro',
  doc => 'Clear blocked state',
);

sub execute {
  my ($self, $args_ref, $chain_ref) = @_;

  $self->check_positional_args($args_ref, 1);

  $self->sync_before;
  $self->require_board;

  my @pos = $self->positional_args($args_ref);
  my $id_str = $pos[0] or die "Usage: karr edit ID[,ID,...] [FLAGS]\n";
  # See the note in Cmd::Move: a comma with no ids around it is truthy here and
  # splits to nothing, so the command used to exit 0 having done nothing.
  my @ids = $self->parse_ids($id_str);
  die "Usage: karr edit ID[,ID,...] [FLAGS]\n" unless @ids;

  # Once, before any task is touched: these are plain option values, so a bad
  # one must not update the first half of a batch (ticket #54). --status is not
  # here because it goes through apply_status_change, which is the one place a
  # status change happens and therefore the one place its name is checked.
  #
  # --claim and --release are mutually exclusive: --claim sets a claim --release
  # is about to discard, so the require_claim guard in apply_status_change would
  # be satisfied by a claim the same command is clearing and let the task land
  # in a require_claim column with no claim on it (ticket #150). kanban-md
  # rejects the pair at the flag layer too (cmd/edit.go:128-130); we match.
  $self->usage_error('cannot use --claim and --release together')
      if (defined $self->claim && length $self->claim) && $self->release;

  my $config = App::karr::Config->from_merged( $self->store->effective_config );
  $config->validate_priority( $self->priority ) if defined $self->priority;
  App::karr::Config->validate_due( $self->due ) if defined $self->due;

  # Same rule for the dependency flags (ticket #124): a malformed or unknown
  # id is wrong for every id in the batch at once. Only ids being *added* must
  # exist -- removing an id the board no longer has is how a dependency on a
  # deleted task is cleaned up. length, not truth (ticket #78).
  my $add_depends;
  if ( defined $self->add_depends_on && length $self->add_depends_on ) {
    $add_depends = $self->parse_dependency_ids( '--add-depends-on', $self->add_depends_on );
    $self->assert_dependencies_exist($add_depends);
  }
  my $remove_depends;
  if ( defined $self->remove_depends_on && length $self->remove_depends_on ) {
    $remove_depends = $self->parse_dependency_ids( '--remove-depends-on', $self->remove_depends_on );
  }

  # Every id is attempted, whatever the ones before it did: a missing id used to
  # die from inside this loop and take the rest of the batch with it (ticket
  # #61). The option-value checks above stay outside it, because they condemn
  # the whole invocation rather than one id.
  my ($results, $failed) = $self->run_batch(\@ids, sub {
    my ($id) = @_;

    # A self-reference is the one dependency error that is per-id rather than
    # per-invocation: `edit 4,5 --add-depends-on 5` is valid for 4 and wrong
    # for 5, so it fails this id and lets the batch carry on (ticket #61).
    # kanban-md rejects it at the same moment (ValidateDependencyIDs). The
    # numeric guard keeps a non-numeric batch id headed for its own "Task X

lib/App/karr/Cmd/Edit.pm  view on Meta::CPAN

        $task->depends_on([grep { !$remove{$_} } @{$task->depends_on}]);
      }

      if (defined $self->claim && length $self->claim) {
        $task->claimed_by($self->claim);
        $task->claimed_at(gmtime->datetime . 'Z');
      }

      if (defined $self->block && length $self->block) {
        $task->block($self->block);
      }

      if ($self->unblock) {
        $task->unblock;
      }
    });

    printf "Updated task %d: %s\n", $task->id, $task->title unless $self->json;
    # --status goes through apply_status_change, so an edit that takes a card
    # up gets the same dependency warning `karr move` does, for free and by
    # construction -- the #55 point again (ticket #123). An edit that changes
    # anything else records nothing, so this adds no key.
    return { id => $task->id, title => $task->title,
             $self->dependency_report( $task->id ) };
  });

  $self->sync_after;

  $self->print_json_results(@$results);

  $self->report_batch_failure($failed, scalar @ids);
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

App::karr::Cmd::Edit - Modify an existing task

=head1 VERSION

version 0.500

=head1 SYNOPSIS

    karr edit 5 --title "Updated title"
    karr edit 5 --add-tag urgent --remove-tag stale
    karr edit 5 --add-depends-on 2,3 --remove-depends-on 4
    karr edit 5 -a "Waiting for review"
    karr edit 5 --claim agent-fox --block "waiting on API"

=head1 DESCRIPTION

Updates one or more existing tasks in place. Use it to adjust metadata, append
notes, manage tags, claim or release ownership, and mark tasks as blocked or
unblocked without changing the task id.

=head1 COMMON OPERATIONS

=over 4

=item * Metadata updates

C<--title>, C<--status>, C<--priority>, C<--assignee>, and C<--due> replace
existing values. C<--status> is the same status change L<App::karr::Cmd::Move>
performs and obeys the same rules, C<require_claim> included.

=item * Claim ownership

Editing a task claimed by another agent is refused unless that claim has
expired. C<--claim> with the current claimant's name proceeds, and C<--release>
is exempt, since breaking a stale claim is what it is for.

=item * Body updates

C<--body> replaces the entire body; C<-a>/C<--append-body> appends a new line
to the existing body text.

=item * Claims and blocking

C<--claim> refreshes claim ownership and timestamp, C<--release> clears the
claim, C<--block> records a blocking reason, and C<--unblock> removes it.

=item * Tag management

C<--add-tag> and C<--remove-tag> accept comma-separated lists.

=item * Dependency management

C<--add-depends-on> and C<--remove-depends-on> accept comma-separated task
ids and follow the tag rule: add appends without duplicating, remove is a
no-op for ids the card does not carry. Ids being added must exist on this
board and must not name the task itself; an unknown or non-numeric id rejects
the whole invocation as a usage error before anything is written, while a
self-reference fails only the id it is wrong for and lets the rest of the
batch proceed. Removing an id the board no longer has stays legal -- it is
how a dependency on a deleted task is cleaned up.

=back

=head1 SEE ALSO

L<karr>, L<App::karr>, L<App::karr::Cmd::Show>, L<App::karr::Cmd::Move>,
L<App::karr::Cmd::Handoff>, L<App::karr::Cmd::List>

=head1 SUPPORT

=head2 Issues

Please report bugs and feature requests on GitHub at
L<https://github.com/Getty/karr/issues>.

=head2 IRC

Join C<#langertha> on C<irc.perl.org> or message Getty directly.



( run in 0.894 second using v1.01-cache-2.11-cpan-788537b7465 )