App-karr

 view release on metacpan or  search on metacpan

lib/App/karr/Role/BoardDiscovery.pm  view on Meta::CPAN


1;

__END__

=pod

=encoding UTF-8

=head1 NAME

App::karr::Role::BoardDiscovery - Role providing minimal board discovery and config access

=head1 VERSION

version 0.600

=head1 DESCRIPTION

This role provides the minimal interface for discovering the board's Git
repository and BoardStore. It provides:

=over 4

=item * C<dir> -- CLI option overriding the directory discovery starts from

=item * C<git_root> -- path to the Git repository (walks up from C<dir> or CWD)

=item * C<store> -- L<App::karr::BoardStore> instance backed by the Git repo

=item * C<git> -- shortcut to C<< $self->store->git >> (lazy)

=item * C<config> -- shortcut to C<< $self->store->effective_config >> (lazy)

=item * C<role> -- activity log identity role, C<user> (default) or C<agent>;
read from C<KARR_ROLE> when not overridden

=back

Commands that need the sync lifecycle should also compose
L<App::karr::Role::SyncLifecycle>.

=head2 require_board

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

Refuses to go on when this repository has no initialized board. Every command
that writes to C<refs/karr/*> calls it, because without the check a C<karr
create> typed in the wrong directory silently seeded a partial board in an
unrelated repository -- and that partial board then locked C<karr init> out of
it permanently (#62).

It distinguishes the two ways of not having a board, because they call for
different things from the reader (#133):

=over 4

=item * nothing under C<refs/karr/> -- "No karr board found:", followed by
C<karr init> on its own line (L<App::karr::Error/command_hint>), the same
message C<backup>, C<destroy>, C<materialize> and C<repair> raise off
L<App::karr::BoardStore/has_board_refs> for the same state;

=item * refs present, C<refs/karr/config> missing -- a half-board: the message
names it as one, says how many task refs are at stake, and says that C<karr
init> completes it without discarding them.

=back

Call it B<after> C<sync_before>, never before: on a fresh clone the board only
exists on the remote until the pull has run, and checking first would report a
board that is merely not fetched yet as missing. The four commands that read or
clean up raw refs (C<backup>, C<destroy>, C<materialize>, C<repair>) ask
L<App::karr::BoardStore/has_board_refs> instead, so they can still deal with a
half-board left behind by an older karr.

The read-only commands do not sync, so they cannot use this method; they ask
L</require_local_board>, which puts C<karr sync> in front of C<karr init> for
exactly the fresh clone this one may assume has already been pulled.

=head2 require_local_board

    $self->require_local_board;   # no sync_before: reads stay offline
    $self->require_local_board( hint => "...one more sentence.\n" );

The read side of L</require_board>, for the commands that render the board
without pulling first (C<board>, C<list>, C<show>, C<log>, C<context>, and
C<config show>/C<config get>). It answers one question those commands never
asked: was anything actually read here? Without it they rendered the code
defaults over an empty task list, so a repository holding no board printed
exactly what a board holding no tasks prints -- and since C<git clone> does not
fetch C<refs/karr/*>, that is the normal state of every fresh clone, where the
user's tickets are all on the remote (#135, and #136 for the config half).

The two states L</require_board> distinguishes need different answers on the
read path:

=over 4

=item * nothing under C<refs/karr/> -- fetch it, if there is anything to fetch;
otherwise refuse. Where the repository has a remote and that remote advertises
C<refs/karr/*>, the board is not missing, it is merely unfetched, and karr can
see that from where it stands, so it pulls once and answers the question that
was asked (#173). One line on STDERR says it did; C<KARR_NO_AUTO_FETCH=1>
switches it off for good, in an environment where karr may not touch the
network. The refusal stays for the case where it is the truth -- no remote, or
a remote with no board -- and where there is a remote it still leads with
C<karr sync> rather than C<karr init>, which is the one command that would
answer an unfetched board by starting a second, empty one.

=item * refs present, C<refs/karr/config> missing -- a half-board: go on, and
say so on STDERR. Refusing would hide tasks that are demonstrably there, which
is the mistake #133 was about; but the board name, statuses and defaults being
rendered are karr's own, not the board's, and nothing else on the page says so.
STDERR keeps C<--json> parsable.

=back

Reads deliberately do not sync (a network round trip in front of every C<karr
show> is not worth it, and a stale read is recoverable where a stale write is
not), so unlike L</require_board> this may be called first thing in C<execute>
-- after option validation, so that a usage error still exits 2.

The optional C<hint> argument appends one caller-supplied sentence to the
refusal, for a command that can offer something beyond C<karr sync> /
C<karr init>. L<App::karr::Cmd::Config> is the one caller: what it used to
print here -- karr's built-in defaults -- is a real answer to a different
question, so its refusal points at C<karr config show --defaults>, where the
same values are true by construction (#136). The half-board note takes no
hint: it already says the values shown are karr's own.

=head1 SUPPORT



( run in 0.835 second using v1.01-cache-2.11-cpan-4ef0a570458 )