App-karr

 view release on metacpan or  search on metacpan

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

# ABSTRACT: Atomically find and claim the next available task

package App::karr::Cmd::Pick;
our $VERSION = '0.601';
use Moo;
use MooX::Cmd;
use MooX::Options (
  usage_string => 'USAGE: karr pick --claim NAME [--move STATUS] [--status LIST] [--tags LIST] [--compact]',
);
use App::karr::Role::BoardAccess;
use App::karr::Role::Output;
use App::karr::Role::CompactOutput;
use App::karr::Role::DependencyCheck;
use App::karr::Role::PickRules;
use App::karr::Role::ClaimDefault;
use App::karr::Task;
use App::karr::Config;
use App::karr::Lock;
use App::karr::Error ();
use Time::Piece;

with 'App::karr::Role::BoardAccess', 'App::karr::Role::Output',
     'App::karr::Role::CompactOutput', 'App::karr::Role::ClaimTimeout',
     'App::karr::Role::DependencyCheck', 'App::karr::Role::PickRules',
     'App::karr::Role::ClaimDefault';


option claim => (
  is => 'ro',
  format => 's',
  doc => 'Agent name to claim the task for (defaults to KARR_CLAIM)',
);

option status => (
  is => 'ro',
  format => 's',
  doc => 'Source status(es) to pick from (comma-separated)',
);

option move => (
  is => 'ro',
  format => 's',
  doc => 'Move picked task to this status',
);

option tags => (
  is => 'ro',
  format => 's',
  doc => 'Only pick tasks matching at least one tag',
);

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

  # --claim was `required => 1` before ADR 0005; KARR_CLAIM now fills it when the
  # flag is omitted. pick has to claim under some name, so when neither supplies
  # one this is a usage error (exit 2, as the old required was) naming both ways.
  # Before sync_before, so an invalid invocation fails without a network round
  # trip, the way an option-parse error always did.
  my $claim = $self->resolved_claim;
  $self->usage_error(
      App::karr::Error::mandatory_claim_message( 'pick', 'pick', '--claim', 'NAME' ) )
    unless defined $claim && length $claim;

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

  my $ec = $self->store->effective_config;
  my $timeout = $self->_parse_timeout($ec->{claim_timeout} // '1h');

  # Before any lock is taken: --move is a plain option value, and a bad one used
  # to be discovered only after a task had already been locked and claimed, so
  # the pick parked it in a status that is not a column (ticket #54). Pick does
  # not go through apply_status_change -- it has its own compare-and-swap loop --
  # so the check is here.
  App::karr::Config->from_merged($ec)->validate_status($self->move)
    if defined $self->move;

  # --status is a comma-separated list of source statuses, and every element is
  # a status the board must know -- a typo used to be answered with "No available
  # tasks to pick." and exit 0, which reads as "no work" when the truth is "no
  # such status" (ticket #271). The filter form accepts `archived` the way
  # `list --status` does (App::karr::Config/validate_status_filter).



( run in 4.373 seconds using v1.01-cache-2.11-cpan-85d3896f969 )