package Dist::Zilla::PluginBundle::Author::IOANR 1.201591;

# ABSTRACT: Build dists the way IOANR likes

use v5.24;
use Moose;
use List::Util 1.33 'any';
use Git::Wrapper;

with 'Dist::Zilla::Role::PluginBundle::Easy';

# TODO optionally add OSPreqs
# TODO Test::MinimumVersion - plugin generated test only checks META.yml, which we don't have

# plugins required to make a release, not neccessarily
# ones that *do* DZR::Releaser
has release_plugins => (is => 'ro', lazy_build => 1);

has autogenerated_files => (
    is      => 'ro',
    lazy    => 1,
    default => sub { [qw/README.md Changes LICENSE/] });

has allow_dirty_files => (
    is      => 'ro',
    lazy    => 1,
    default => sub {
        [$_[0]->autogenerated_files->@*, 'dist.ini',];
    },
);

# XXX can I get this from $zilla somehow? Maybe a custom plugin?
has dist_name => (is => 'ro', predicate => 'has_dist_name');
has git_remote => (is => 'ro', default => 'origin');

has _git => (is => 'ro', lazy =>1, default => sub { Git::Wrapper->new('.') });
has major_version => (
    is      => 'ro',
    default => 0,
);

has fake_release => (
    is      => 'ro',
    lazy    => 1,
    default => sub { $ENV{DZIL_FAKE_RELEASE} // 0 },
);

has semantic_version => (
    is      => 'ro',
    default => 0,
);

has assert_os => (
    is      => 'ro',
    default => sub { [] },
);

has disable => (
    is      => 'ro',
    default => sub { [] },
);

has _resources => (
    is         => 'ro',
    isa        => 'HashRef',
    lazy_build => 1,
);

sub BUILDARGS {
    my ($orig, $class, @args) = @_;
    # use the payload as attrs
    return { $class->{payload}->%*, $class->%* };
}

# try to work out metadata resources from the git remote
# totally falls apart if not using git, only works with gitlab and github,
# and relies on the urls being much the same
sub _build__resources {
    my $self      = shift;

    # this will totally fall apart
    my @remote = $self->_git->remote(qw/get-url/, $self->git_remote);
    my $git_url = shift @remote;
    if (!$git_url) {
      die "Failed to find git remote url\n";
    }

    my ($git_host, $git_org, $git_repo) = $git_url =~ m{^.+@?(github|gitlab).com[:/](\w+)/(.+).git$};
    if (!$git_host) {
      die "Unable to find supported git host from $git_url\n";
    }

    # sometimes dist name and repo/project name are the same, sometimes the repo
    # has a p5- prefix
    my $dist_name = $self->has_dist_name ? $self->dist_name : $git_repo;
    my $resources = {
      'bugtracker.web' => sprintf('https://%s.com/%s/%s/issues', $git_host, $git_org, $git_repo),
      'homepage' => sprintf('https://metacpan.org/release/%s', $dist_name),
      'repository.type' => 'git',
      'repository.url' => sprintf('https://%s.com:%s/%s.git', $git_host, $git_org, $git_repo),
      'repository.web' => sprintf('https://%s.com/%s/%s', $git_host, $git_org, $git_repo),
    };

    return $resources;
}

sub _build_release_plugins {
    my $self = shift;

    my @release_plugins = (qw/TestRelease/);

    # do not allow any release to be made without the git plugins
    if ($ENV{DZIL_NO_GIT_LOCAL}) {
        return [@release_plugins, 'FakeRelease'];
    }

    # nothing further should happen without confirmation
    push @release_plugins, 'ConfirmRelease';

    # add plugins which make LOCAL REPO ONLY changes to git
    push @release_plugins,
      ['Git::Commit' => {allow_dirty => $self->allow_dirty_files}],
      [
        'Git::CommitBuild' => {
            branch               => '',
            release_branch       => 'release',
            release_message      => 'Release %v',
            multiple_inheritance => 1,
        }
      ],
      ['Git::Tag' => {signed => 1, branch => 'release'}];

    # add plugins which affect remote git remotes
    unless ($ENV{DZIL_NO_GIT_REMOTE}) {
        push @release_plugins, 'Git::Push';
    }

    # DO NOT allow making a release to CPAN that isn't also pushed to remote git
    # DO allow making remote git changes without a CPAN release as it's easy to undo
    # and is useful for testing plugin settings
    if ($self->fake_release || $ENV{DZIL_NO_GIT_REMOTE}) {
        push @release_plugins, 'FakeRelease';
    } else {
        push @release_plugins, 'UploadToCPAN';
    }

    return \@release_plugins;
}

has build_plugin => (
    is      => 'ro',
    lazy    => 1,
    default => sub {
        if ($_[0]->payload->{custom_builder}) {
            return [ModuleBuild => {mb_class => 'My::Builder'}];
        } else {

            # TODO add an option to handle experimental statis installs
            # https://metacpan.org/pod/Dist::Zilla::Plugin::ModuleBuildTiny#static
            return 'ModuleBuildTiny';
        }
    });

sub mvp_multivalue_args {qw/disable assert_os/}

sub configure {
    my ($self) = @_;

    my $change_opts = {
        exclude_message => '^(dist.ini|v(\d+\.?)+)',
        edit_changelog  => 1,
    };

    if ($self->semantic_version) {
        $change_opts->{tag_regexp} = 'semantic';
    }

    if ($ENV{V}) {
        $self->add_plugins([AutoVersion => {format => q<{{ $ENV{V} }}>}]);
    } else {
        $self->add_plugins([AutoVersion => {major => $self->major_version}]);
    }

    $self->add_plugins([MetaResources => $self->_resources]);

    my @plugins = (
        'AutoPrereqs',
        ['ChangelogFromGit::CPAN::Changes' => $change_opts],
        'ContributorsFile',
        ['Git::Contributors'  => {order_by => 'commits'}],
        ['CopyFilesFromBuild' => {copy     => $self->autogenerated_files}],
        'ExecDir',
        [
            'Git::Check' => {
                allow_dirty     => $self->allow_dirty_files,
                build_warnings  => 1,
                untracked_files => 'warn',
            }
        ],
        [
            'Git::GatherDir' => {
                include_dotfiles => 1,
                exclude_filename => $self->autogenerated_files,
            }
        ],
        'License',
        'Manifest',
        ['MetaData::BuiltWith' => {show_config => 1}],
        'MetaJSON',
        ['PodWeaver'  => {config_plugin => '@Author::IOANR'}],
        ['PkgVersion' => {use_package   => 1}],
        'Prereqs::AuthorDeps',
        'PruneCruft',
        ['ReadmeAnyFromPod' => {type => 'gfm', location => 'build'}],
        'ShareDir',
        'Signature',
        'MojibakeTests',
        'AuthorSignatureTest',
        'Test::CheckDeps',
        'Test::Compile',
        'Test::EOL',
        ['Test::Kwalitee' => {skiptest => [qw/has_readme/]}],
        'Test::NoTabs',
        'Test::Pod::No404s',
        'Test::Portability',
        'Test::ReportPrereqs',
        'Test::UnusedVars',
        'Test::Synopsis',
        'Test::Version',
    );

    # Test::Perl::Critic
    # PodCoverageTests
    # PodSyntaxTests

    push @plugins, $self->release_plugins->@*;
    my @add;
    while (my $p = shift @plugins) {
        next if any { $_ eq $p } $self->disable->@*;
        push @add, $p;
    }

    push @add, $self->build_plugin;

    # these have to come after the builder
    # push @add, 'RunExtraTests';

    if ($self->assert_os->@*) {
        push @add, [AssertOS => { os => $self->assert_os, bundle => 0 }];
    }

    $self->add_plugins(@add);

    return;
}

__PACKAGE__->meta->make_immutable;
1;

__END__

=pod

=encoding UTF-8

=for :stopwords Ioan Rogers cpan testmatrix url bugtracker rt cpants kwalitee diff irc
mailto metadata placeholders metacpan

=head1 NAME

Dist::Zilla::PluginBundle::Author::IOANR - Build dists the way IOANR likes

=head1 VERSION

version 1.201591

=head1 OPTIONS

=head2 C<fake_release>

Doesn't commit or release anything

  fake_release = 1

=head2 C<disable>

Specify plugins to disable. Can be specified multiple times.

  disable = Some::Plugin
  disable = Another::Plugin

=head2 C<assert_os>

Use L<Devel::AssertOS> to control which platforms this dist will build on.
Can be specified multiple times.

  assert_os = Linux

=head2 C<custom_builder>

If C<custom_builder> is set, L<Module::Build> will be used instead of
L<Module::Build::Tiny> with a custom build class set to C<My::Builder>

=head2 C<semantic_version>

If C<semantic_version> is true (the default), git tags will be in the form
C<^v(\d+\.\d+\.\d+)$>. Otherwise they will be C<^v(\d+\.\d+)$>.

=head1 SUPPORT

=head2 Perldoc

You can find documentation for this module with the perldoc command.

  perldoc Dist::Zilla::PluginBundle::Author::IOANR

=head2 Websites

The following websites have more information about this module, and may be of help to you. As always,
in addition to those websites please use your favorite search engine to discover more resources.

=over 4

=item *

MetaCPAN

A modern, open-source CPAN search engine, useful to view POD in HTML format.

L<https://metacpan.org/release/Dist-Zilla-PluginBundle-Author-IOANR>

=back

=head2 Bugs / Feature Requests

Please report any bugs or feature requests through the web interface at L<https://github.com/ioanrogers/Linux-Systemd/issues>.
You will be automatically notified of any progress on the request by the system.

=head2 Source Code

The source code is available for from the following locations:

L<https://github.com/ioanrogers/Linux-Systemd>

  git clone https://github.com:ioanrogers/Linux-Systemd.git

=head1 AUTHOR

Ioan Rogers <ioanr@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2020 by Ioan Rogers.

This is free software, licensed under:

  The Artistic License 2.0 (GPL Compatible)

=cut
