summaryrefslogtreecommitdiffstats
path: root/bin
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2018-11-04 20:09:00 -0500
committerJesse Luehrs <doy@tozt.net>2018-11-04 20:09:00 -0500
commit58bcbcbb64014a4d56f0aac2b103814955e04b1a (patch)
tree3e491f234692d5a8c9c74826fc2f42775f33fc70 /bin
parent3964b602ae658f1f064e30bca9a1b1fb49af75f0 (diff)
downloadconf-58bcbcbb64014a4d56f0aac2b103814955e04b1a.tar.gz
conf-58bcbcbb64014a4d56f0aac2b103814955e04b1a.zip
i am unlikely to ever use this again
Diffstat (limited to 'bin')
-rwxr-xr-xbin/lint-dist713
1 files changed, 0 insertions, 713 deletions
diff --git a/bin/lint-dist b/bin/lint-dist
deleted file mode 100755
index 8516093..0000000
--- a/bin/lint-dist
+++ /dev/null
@@ -1,713 +0,0 @@
-#!/usr/bin/env perl
-use strict;
-use warnings;
-use 5.016;
-
-use Archive::Tar;
-use Getopt::Long;
-use HTTP::Tiny;
-use JSON;
-use Parse::CPAN::Meta;
-use Parse::CPAN::Packages::Fast;
-
-my @checks = (
- [
- sub { 1 },
- sub { !$_[0]->has_file('META.json') },
- "No META.json file found, using META.yml"
- ],
- [
- sub { 1 },
- sub { !!grep { $_[0]->has_file($_) } qw(MYMETA.yml MYMETA.json) },
- "MYMETA found in dist"
- ],
- [
- sub { 1 },
- sub {
- my $main_module = 'lib/' . ($_[0]->name =~ s/-/\//gr) . '.pm';
- $_[0]->read_file($main_module) =~ /search\.cpan\.org/;
- },
- "module docs link to s.c.o"
- ],
- [
- sub { 1 },
- sub {
- my $main_module = 'lib/' . ($_[0]->name =~ s/-/\//gr) . '.pm';
- $_[0]->read_file($main_module) =~ m{rt\.cpan\.org/NoAuth/ReportBug};
- },
- "module docs link to rt.cpan"
- ],
- [
- sub { 1 },
- sub { !$_[0]->has_meta_2 },
- "not using META spec version 2"
- ],
- [
- sub { $_[0]->has_meta_2 },
- sub { !grep { $_ eq 'mit' } @{ $_[0]->meta->{license} } },
- "not using the MIT license"
- ],
- [
- sub { $_[0]->meta && !$_[0]->has_meta_2 },
- sub { $_[0]->meta->{license} ne 'mit' },
- "not using the MIT license"
- ],
- [
- sub { $_[0]->has_meta_2 },
- sub {
- ($_[0]->meta->{resources}{bugtracker}{web} // '') !~ /github\.com/
- },
- "not using github issues"
- ],
- [
- sub { $_[0]->meta && !$_[0]->has_meta_2 },
- sub {
- ($_[0]->meta->{resources}{bugtracker} // '') !~ /github\.com/
- },
- "not using github issues"
- ],
- [
- sub { $_[0]->has_meta_2 },
- sub {
- ($_[0]->meta->{resources}{repository}{url} // '') !~ /github\.com/
- },
- "repository not on github"
- ],
- [
- sub { $_[0]->meta && !$_[0]->has_meta_2 },
- sub {
- ($_[0]->meta->{resources}{repository} // '') !~ /github\.com/
- },
- "repository not on github"
- ],
- [
- sub { $_[0]->has_meta_2 },
- sub {
- my $url = ($_[0]->meta->{resources}{repository}{url} // '');
- my $dist_name = $_[0]->name;
- $url !~ /\/\L$dist_name\.git$/;
- },
- "repository named incorrectly"
- ],
- [
- sub { $_[0]->meta && !$_[0]->has_meta_2 },
- sub {
- my $url = ($_[0]->meta->{resources}{repository} // '');
- my $dist_name = $_[0]->name;
- $url !~ /\/\L$dist_name\.git$/;
- },
- "repository named incorrectly"
- ],
- [
- sub { $_[0]->meta },
- sub { !$_[0]->meta->{resources}{homepage} },
- "no homepage set"
- ],
- [
- sub { $_[0]->meta },
- sub {
- my ($author) = grep { /Jesse Luehrs/ } @{ $_[0]->meta->{author} };
- $author && $author !~ /<doy\@tozt\.net>/
- },
- "using the wrong email address"
- ],
- [
- sub { $_[0]->meta },
- sub { !$_[0]->meta->{x_authority} },
- "no AUTHORITY info set"
- ],
- [
- sub { $_[0]->meta },
- sub { $_[0]->meta->{generated_by} !~ /Dist::Zilla/ },
- "not using Dist::Zilla"
- ],
- [
- sub { $_[0]->meta && $_[0]->meta->{generated_by} =~ /Dist::Zilla/ },
- sub {
- $_[0]->meta->{generated_by} !~
- /Dist::Zilla version .*, CPAN::Meta::Converter version .*/
- },
- "using ancient Dist::Zilla"
- ],
- [
- sub { 1 },
- sub { $_[0]->has_file('weaver.ini') },
- "still using weaver.ini"
- ],
- [
- sub { $_[0]->meta && $_[0]->meta->{x_Dist_Zilla} },
- sub {
- !grep { $_->{class} eq 'Dist::Zilla::Plugin::AutoPrereqs' }
- @{ $_[0]->meta->{x_Dist_Zilla}{plugins} }
- },
- "not using [AutoPrereqs]"
- ],
- [
- sub { $_[0]->meta && $_[0]->meta->{x_Dist_Zilla} },
- sub {
- !grep { $_->{class} eq 'Dist::Zilla::Plugin::ContributorsFromGit' }
- @{ $_[0]->meta->{x_Dist_Zilla}{plugins} }
- },
- "not using [ContributorsFromGit]"
- ],
- [
- sub { $_[0]->has_file('dist.ini') },
- sub {
- return if $_[0]->name eq 'Dist-Zilla-PluginBundle-DOY';
- require Config::INI::Reader;
- my $contents = Config::INI::Reader->read_string(
- $_[0]->read_file('dist.ini')
- );
- !exists $contents->{'@DOY'}
- || !exists $contents->{'@DOY'}{':version'}
- || $contents->{'@DOY'}{':version'} < 0.14;
- },
- "not using the latest version of \@DOY"
- ],
- [
- sub { 1 },
- sub {
- grep { $_->get_content =~ m{\A\#!/usr/bin/env perl} }
- grep { $_->has_content && $_->name !~ /\.t$/ }
- $_[0]->tar->get_files
- },
- "using #!/usr/bin/env perl"
- ],
- [
- sub { 1 },
- sub {
- grep { $_->get_content =~ m{use_ok} }
- grep { $_->has_content && $_->name =~ /\.t$/ }
- $_[0]->tar->get_files
- },
- "uses use_ok"
- ],
- [
- sub { 1 },
- sub {
- my %allowed = map { $_ => 1 } qw(
- 00-compile.t
- );
- grep { /\/\d+.*\.t$/ }
- grep { !$allowed{s/.*\///r} }
- $_[0]->tar->list_files
- },
- "has tests with numbers"
- ],
- [
- sub { 1 },
- sub {
- grep { $_->get_content =~ /\$ENV{RELEASE_TESTING}/ }
- grep { $_->has_content && $_->full_path =~ /\/t\/.*\.t$/ }
- $_[0]->tar->get_files
- },
- "has release tests in t/"
- ],
- [
- sub { 1 },
- sub { !$_[0]->has_file('Changes') },
- "no Changes file"
- ],
- [
- sub { $_[0]->has_file('Changes') },
- sub {
- my $dist = $_[0]->name;
- $_[0]->read_file('Changes') !~ /\ARevision history for $dist$/m
- },
- "changelog has incorrect header"
- ],
- [
- sub { $_[0]->has_file('Changes') },
- sub {
- require CPAN::Changes;
- require version;
-
- my $changes = eval {
- CPAN::Changes->load_string($_[0]->read_file('Changes'))
- };
-
- return "Couldn't parse file" unless $changes;
- return "No releases" unless @{[$changes->releases]};
-
- return "Invalid date format" if grep {
- ($_->date // '') eq ''
- } $changes->releases;
- return "Invalid version format" if grep {
- !version::is_lax($_->version =~ s/-TRIAL$//r)
- } $changes->releases;
- return "No entry for the current version" if !grep {
- $_->version =~ s/-TRIAL$//r eq $_[0]->version
- } $changes->releases;
-
- return;
- },
- sub { "changelog doesn't follow the CPAN::Changes format: $_[1]" }
- ],
- [
- sub { 1 },
- sub {
- my $kwalitee = $_[0]->get_json(
- 'http://cpants.cpanauthors.org/dist/' . $_[0]->name . '.json'
- );
- return ['Most recent dist has not yet been processed.']
- if $kwalitee->{recent}[0]{distv} ne $_[0]->distvname;
-
- # - use_strict and use_warnings don't notice Moose::Exporter, or
- # things that use Moose::Exporter, so they will give a lot of
- # false positives
- # - is_prereq isn't something i can control
- # - metayml_declares_perl_version i just don't care about
- my %ignored = map { $_ => 1 } qw(
- use_strict
- use_warnings
- is_prereq
- metayml_declares_perl_version
- );
- my @res = grep { defined }
- map { $_->{error} }
- grep { !$ignored{$_->{key}} }
- map { @$_ }
- @{ $kwalitee->{kwalitee} };
- return unless @res;
- return \@res;
- },
- sub { map { "Kwalitee: $_" } @{ $_[1] } }
- ],
- [
- sub { 1 },
- sub {
- state $rt_data //= $_[0]->get_json(
- 'https://rt.cpan.org/Public/bugs-per-dist.json'
- );
- return $rt_data->{$_[0]->name}{counts}{active}
-
- },
- sub { "has $_[1] bug(s) on rt.cpan.org" }
- ],
- [
- sub { $_[0]->repository && $_[0]->repository =~ m{/github\.com/} },
- sub { !$_[0]->has_github_data },
- "github repository doesn't exist"
- ],
- [
- sub { $_[0]->has_github_data },
- sub { !$_[0]->github_data->{has_issues} },
- "github issues is not enabled"
- ],
- [
- sub { $_[0]->has_github_data },
- sub { $_[0]->github_data->{open_issues_count} },
- sub { "has $_[1] bug(s) on github issues" }
- ],
- [
- sub { $_[0]->has_github_data },
- sub {
- my $abstract = $_[0]->meta->{abstract} // '';
- my $description = $_[0]->github_data->{description} // '';
- $description ne $abstract;
- },
- sub { "github description doesn't match abstract" }
- ],
- [
- sub { $_[0]->has_github_data },
- sub {
- my $meta_site = $_[0]->meta->{resources}{homepage} // '';
- my $gh_site = $_[0]->github_data->{homepage} // '';
- $meta_site ne $gh_site;
- },
- sub { "github homepage doesn't match meta homepage" }
- ],
- [
- sub { $_[0]->has_github_data },
- sub { !$_[0]->repo_has_file('.gitignore') },
- sub { "repository doesn't contain .gitignore" }
- ],
- [
- sub { $_[0]->has_github_data },
- sub { !$_[0]->repo_has_file('.travis.yml') },
- sub { "repository doesn't contain .travis.yml" }
- ],
- [
- sub { $_[0]->has_github_data && $_[0]->repo_has_file('.travis.yml') },
- sub {
- my $travis = $_[0]->repo_read_file('.travis.yml');
- grep { /cpanm/ && !/build\.log/ } split /\n/, $travis;
- },
- sub { "travis.yml doesn't display build.log on failures" }
- ],
- [
- sub { $_[0]->has_github_data },
- sub {
- my $gh = $_[0]->github_data;
- my $tags = $_[0]->get_json($gh->{tags_url});
- my $commit = $_[0]->get_json(
- $gh->{commits_url} =~ s!{/sha}!/$gh->{default_branch}!r
- );
- !grep { $_->{commit}{sha} eq $commit->{sha} } @$tags
- },
- "repository has unreleased changes"
- ],
- [
- sub { $_[0]->has_github_data && $_[0]->repo_has_file('.travis.yml') },
- sub {
- my $gh = $_[0]->github_data;
- # XXX not sure how to get the current status for a specific branch
- # other than from the status image
- my $url =
- "https://travis-ci.org/$gh->{full_name}.png"
- . "?branch=$gh->{default_branch}";
- my $res = HTTP::Tiny->new->get($url);
- die "couldn't get data for $url ($res->{status}): $res->{content}"
- unless $res->{success};
-
- require Digest::MD5;
- Digest::MD5::md5_hex($res->{content}) ne '64f1b7ce47060cdfca7ac94338e92294';
- },
- sub { "travis isn't passing" }
- ],
-);
-
-package Dist::To::Lint {
- sub new {
- my $class = shift;
- my (%args) = @_;
-
- $args{lint} = [];
-
- if ($args{minicpan}) {
- bless { %args }, "Dist::To::Lint::Minicpan";
- }
- else {
- bless { %args }, "Dist::To::Lint::HTTPTiny";
- }
- }
-
- sub dist { shift->{dist} }
- sub name { shift->dist->dist }
- sub version { shift->dist->version }
- sub distvname { shift->dist->distvname }
- sub lint { @{ shift->{lint} } }
- sub add_lint {
- my $self = shift;
- push @{ $self->{lint} }, @_;
- }
-
- sub tarball_name {
- my $self = shift;
-
- die "tarball_name must be implemented in a subclass";
- }
-
- sub tar {
- my $self = shift;
-
- $self->{tar} //= Archive::Tar->new($self->tarball_name);
- }
-
- sub directory {
- my $self = shift;
- $self->{directory} //= ($self->tar->list_files)[0] =~ s/\/.*//r;
- }
-
- sub has_file {
- my $self = shift;
- $self->tar->contains_file(join('/', $self->directory, $_[0]));
- }
-
- sub read_file {
- my $self = shift;
- $self->tar->get_content(join('/', $self->directory, $_[0]));
- }
-
- sub meta {
- my $self = shift;
- $self->{meta} //= do {
- if ($self->has_file('META.json')) {
- Parse::CPAN::Meta->load_json_string(
- $self->read_file('META.json')
- );
- }
- elsif ($self->has_file('META.yml')) {
- Parse::CPAN::Meta->load_yaml_string(
- $self->read_file('META.yml')
- );
- }
- else {
- undef
- }
- };
- }
-
- sub has_meta_2 {
- my $self = shift;
- $self->meta && ($self->meta->{'meta-spec'}{version} // 0) >= 2
- }
-
- sub repository {
- my $self = shift;
- return unless $self->meta;
- return $self->has_meta_2
- ? $self->meta->{resources}{repository}{url}
- : $self->meta->{resources}{repository};
- }
-
- # XXX doesn't handle files not in the repo root
- sub repo_has_file {
- my $self = shift;
- my ($file) = @_;
-
- my $repo_name =
- $self->repository =~ s{.*://github\.com/(.*?)(?:\.git)?$}{$1}r;
-
- my $gh_data = $self->github_data;
-
- my $tree_data = $self->get_json(
- $gh_data->{trees_url} =~ s!{/sha}!/$gh_data->{default_branch}!r
- );
-
- grep { $_->{path} eq $file } @{ $tree_data->{tree} };
- }
-
- # XXX doesn't handle files not in the repo root
- sub repo_read_file {
- my $self = shift;
- my ($file) = @_;
-
- my $repo_name =
- $self->repository =~ s{.*://github\.com/(.*?)(?:\.git)?$}{$1}r;
-
- my $gh_data = $self->github_data;
-
- my $tree_data = $self->get_json(
- $gh_data->{trees_url} =~ s!{/sha}!/$gh_data->{default_branch}!r
- );
-
- my ($url) =
- map { $_->{url} }
- grep { $_->{path} eq $file }
- @{ $tree_data->{tree} };
- my $data = $self->get_json($url);
- die "unknown encoding"
- unless $data->{encoding} eq 'base64';
-
- require MIME::Base64;
- return MIME::Base64::decode_base64($data->{content});
- }
-
- sub github_data {
- my $self = shift;
-
- return unless $self->repository;
-
- my $repo_name =
- $self->repository =~ s{.*://github\.com/(.*?)(?:\.git)?$}{$1}r;
-
- return $self->get_json("https://api.github.com/repos/$repo_name");
- }
-
- sub has_github_data {
- my $self = shift;
- eval { $self->github_data };
- }
-
- sub report {
- my $self = shift;
-
- say $self->distvname;
- say "=====================";
-
- if ($self->lint) {
- say for $self->lint;
- }
- else {
- say "No issues found";
- }
-
- STDOUT->flush;
- }
-
- sub get_json {
- my $self = shift;
- my ($url) = @_;
-
- my $auth_url = $url;
- if ($url =~ /api\.github\.com/) {
- state $auth //= $self->github_auth;
- $auth_url =~ s{://api\.github\.com}{://$auth\@api.github.com};
- }
-
- $self->{_json}{$url} //= do {
- my $res = HTTP::Tiny->new->get($auth_url);
- die "couldn't get data for $url ($res->{status}): $res->{content}"
- unless $res->{success};
- JSON->new->utf8->decode($res->{content});
- }
- }
-
- sub github_auth {
- my $self = shift;
-
- return '' unless $self->{github_user};
-
- $self->{github_pass} //= do {
- require Term::ReadKey;
-
- open my $read, '<', '/dev/tty'
- or die "couldn't get the terminal for reading: $!";
- open my $write, '>', '/dev/tty'
- or die "couldn't get the terminal for reading: $!";
- $write->print("Github API secret: ");
- $write->flush;
-
- Term::ReadKey::ReadMode(2);
- chomp(my $pass = <$read>);
- Term::ReadKey::ReadMode(0);
-
- $write->print("\n");
-
- $pass;
- };
-
- return join(':',
- map { HTTP::Tiny->_uri_escape($self->{$_}) }
- 'github_user', 'github_pass'
- );
- }
-}
-
-package Dist::To::Lint::Minicpan {
- our @ISA = ('Dist::To::Lint');
-
- sub minicpan { shift->{minicpan} }
-
- sub tarball_name {
- my $self = shift;
- $self->{tarball_name} //=
- $self->minicpan . "/authors/id/" . $self->dist->pathname
- }
-}
-
-package Dist::To::Lint::HTTPTiny {
- our @ISA = ('Dist::To::Lint');
-
- sub tarball_name {
- my $self = shift;
- $self->{tarball_name} //= $self->_fetch_tarball;
- }
-
- sub _fetch_tarball {
- my $self = shift;
-
- my $res = HTTP::Tiny->new->get(
- 'http://cpan.metacpan.org/authors/id/' . $self->dist->pathname
- );
- die "Couldn't get distribution tarball"
- unless $res->{success};
-
- require File::Temp;
- my $fh = File::Temp->new;
- $fh->print($res->{content});
- $fh->flush;
- $fh->seek(0, 0);
- $self->{_tar_fh} = $fh;
-
- return $fh->filename;
- }
-}
-
-my ($all, $minicpan, $github_user);
-my $cpanid = uc($ENV{USER});
-GetOptions(
- 'all' => \$all,
- 'minicpan=s' => \$minicpan,
- 'cpanid' => \$cpanid,
- 'github_user=s' => \$github_user,
-) or die;
-
-my @dists = $all
- ? (get_all_dists_for($cpanid, $minicpan))
- : (get_info_for_dists(\@ARGV, $minicpan));
-
-for my $dist (@dists) {
- lint_dist(@$dist, $minicpan, $github_user);
- say '';
-}
-
-sub get_all_dists_for {
- my ($cpanid, $minicpan) = @_;
-
- return map { [ $_, undef ] }
- sort { fc($a->dist) cmp fc($b->dist) }
- grep { $_->dist ne 'perl' }
- grep { $_->cpanid eq $cpanid }
- _packages($minicpan)->latest_distributions;
-}
-
-sub get_info_for_dists {
- my ($dists, $minicpan) = @_;
-
- my $p = _packages($minicpan);
-
- return map {
- my $name = (-e) ? get_name_for_tarball($_) : $_;
- [
- ($p->latest_distribution($name)
- || die "Couldn't find $_ in the index"),
- ((-e) ? $_ : undef)
- ]
- } @$dists;
-}
-
-sub get_name_for_tarball {
- my ($tarball_name) = @_;
- require CPAN::DistnameInfo;
- my $d = CPAN::DistnameInfo->new($tarball_name);
- return $d->dist;
-}
-
-sub _packages {
- my ($minicpan) = @_;
-
- my ($packages_file, $packages_fh);
-
- if ($minicpan) {
- $packages_file = "$minicpan/modules/02packages.details.txt.gz";
- }
- else {
- my $res = HTTP::Tiny->new->get(
- 'http://cpan.metacpan.org/modules/02packages.details.txt.gz'
- );
- die "Couldn't get package file" unless $res->{success};
-
- require File::Temp;
- $packages_fh = File::Temp->new;
- $packages_file = $packages_fh->filename;
- $packages_fh->print($res->{content});
- $packages_fh->flush;
- }
-
- return Parse::CPAN::Packages::Fast->new($packages_file);
-}
-
-sub lint_dist {
- my ($dist, $tarball_name, $minicpan, $github_user) = @_;
-
- my $to_lint = Dist::To::Lint->new(
- dist => $dist,
- tarball_name => $tarball_name,
- minicpan => $minicpan,
- github_user => $github_user,
- );
-
- for my $check (@checks) {
- next unless $check->[0]->($to_lint);
- if (my $ret = $check->[1]->($to_lint)) {
- my @messages = ref($check->[2])
- ? $check->[2]->($to_lint, $ret)
- : $check->[2];
- $to_lint->add_lint($_) for @messages;
- }
- }
-
- $to_lint->report;
-}