Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

git-push target for Makefile (via ExtUtils::MakeMaker)

by bliako (Monsignor)
on May 21, 2019 at 13:22 UTC ( [id://11100309]=perlmeditation: print w/replies, xml ) Need Help??

I was trying to automate more (=keep as far away as possible) the process of pushing to github through a Makefile and I came up with the following simplistic approach. It basically creates a make target called git-push via MY::postamble provided by ExtUtils::MakeMaker. I got the postamble idea from pryrt's answer to Benchmarks target in Makefile

perl Makefile.PL make all make git-push

At first it creates a .gitignore file which whitelists the files/dirs to push, then calls git init, git add ., git commit ... and finally git push ... (I hope it's correct, it works for me).

As it is, it works for me but I am sure there are lots and lots of improvements and safeguards. Also, it does not proceed unless the target repository already exists remotely - there is no git-cmdline-only way to create a repository as I understand.

Possible major improvement would be to use Git::Repository instead of make shelling out git commands. But this is the idea I wanted to share.

Deviations from the normal Makefile.PL are designated by ADD this:

use 5.006; use strict; use warnings; use ExtUtils::MakeMaker; use File::Spec; WriteMakefile( #INSTALL_BASE => $ENV{'HOME'}.'/usr', NAME => '<My::Module::Name>', AUTHOR => q{<MY-NAME> <MY-EMAIL>}, VERSION_FROM => 'My/Module/Name/file.pm', ABSTRACT_FROM => 'My/Module/Name/file.pm', LICENSE => 'artistic_2', PL_FILES => {}, MIN_PERL_VERSION => '5.006', CONFIGURE_REQUIRES => { 'ExtUtils::MakeMaker' => '0', }, BUILD_REQUIRES => { 'Test::More' => '0', 'LWP::UserAgent' => '6.35', 'HTTP::Request::Common' => '6.15', }, PREREQ_PM => { 'File::Spec' => '3.75', }, dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', }, clean => { FILES => 'My::Module::Name-*' }, # ADD this: postamble => { SRCDIR => '.', # repo must already exist, you must explicitly create it using git +hub web interface # or use some API perhaps? GIT_DESTINATION => 'git@github.com:<GIT-USERNAME>/<GIT-REPO-NAME>. +git', # list of files to add or wildcards, space separated, quote for sh +ell GIT_ADD => '.', # the above with the whitelist gitignore below will add what I nee +d GITIGNORE => <<'EOC', # WARNING: will overwrite any existing .giti +gnore (in dist dir) # whitelist mode: # first, ignore everything /* # then add what we like !lib !bin !*/t !*/xt !Makefile.PL !Changes !MANIFEST !README EOC } ); # ADD this: # this is based on https://www.perlmonks.org/?node_id=1216932 (especia +lly pryrt's answer) sub MY::postamble { my (undef,%h) = @_; #require Data::Dumper; #print STDERR Data::Dumper->Dump([\%h], [qw(mm_args{postamble})]); my $indir = $h{'SRCDIR'}; $indir = '.' unless defined $indir; if( defined $h{'GITIGNORE'} ){ # we have a string of .gitignore content, replace any existing .gi +tignore my $gitignorefile = File::Spec->catdir($indir, '.gitignore'); my $GH; if( ! open $GH, '>:encoding(utf-8)', $gitignorefile ){ print STDER +R "$0 : failed to open '$gitignorefile' file for writing.\n"; exit(1) + } print $GH $h{'GITIGNORE'}; close $GH } # if # append to Makefile, newlines and tabs are important! my $ret = "git-push ::\n"; $ret .= "\t".'@git ls-remote '.$h{GIT_DESTINATION}.' &> /dev/null +|| (echo "make : you need to create the repository '.$h{GIT_DESTINATI +ON}.' first ..."; exit 1)'."\n"; $ret .= "\tgit init\n"; $ret .= "\tgit add ".(exists($h{'GIT_ADD'})?$h{'GIT_ADD'}:'.')."\n +"; $ret .= "\tgit commit -am 'first commit'\n"; $ret .= "\t".'git push -f "'.$h{GIT_DESTINATION}.'" --all'."\n"; return $ret; }

bw, bliako

Replies are listed 'Best First'.
Re: git-push target for Makefile (via ExtUtils::MakeMaker)
by Haarg (Priest) on May 27, 2019 at 13:19 UTC

    It isn't obvious what advantage you see from putting this in a Makefile.PL, rather than just having a standalone shell script that initializes your local git repository. The target you are creating only seems to be useful once, when creating the repo. After that, you would be cloning the repository, or running normal git operations on your repo.

    Normally, make targets would be used for things you run repeatedly as a dist author, or for things you would expect a user of your module to run.

      The advantage, for me, is not to have to look for the git commands and their switches to update my local files into the remote (or init if it is the first time). I just do make git-push and all my local changes are pushed onto the remote, ready for end users to use it. First time or Nth time, this can be run repeatedly, every time I need to update the remote with my local changes.

      It's bad enough to have to remember every time how to make available to git my public key, I just refuse to learn git nomenclature. It is very likely that the git commands I am using are not entirely fit - I was under the impression that git push will forward all local changes to remote. If you need something else, then just create another target. The main idea is still the same.

      The obvious disadvantage of my method is that Makefile.PL now contains a target (git-push) which the end user should never need.

        I frequently find myself trying to replicate what bliako posts. I was able to get the expected result with the github values hard-coded into the script and taking the repo name off of STDIN. I then wanted to shuffle those values out of the source and load them using Config:Tiny, and take the new repo name off of STDIN. Right now I'm failing. Source:

        #!/usr/bin/perl use 5.011; use warnings; # original by bliako on 27/05/2019 PM node_id=11100309 ## embellishments don't work yet use Net::GitHub; use Data::Dumper; use Config::Tiny; my $ini_path = qw( /home/bob/Documents/html_template_data/3.values.ini + ); say "ini path is $ini_path"; my $sub_hash = "my_github"; my $Config = Config::Tiny->new; $Config = Config::Tiny->read( $ini_path, 'utf8' ); say Dumper $Config; # -> is optional between brackets my $github_login = $Config->{$sub_hash}{'email'}; my $github_username = $Config->{$sub_hash}{'username'}; my $github_password = $Config->{$sub_hash}{'password'}; say "login is $github_login"; say "password is $github_password"; print "$0 : enter value for reponame: "; my $github_reponame = <STDIN>; chomp($github_reponame); my $git = Net::GitHub->new( login => $github_username, pass => $github_password ); say "username is $github_username"; my $reposinfo = $git->repos->list($github_username); print Dumper($reposinfo); my %reposlist = map { lc $_->{'full_name'} =~ s|^${github_username}/||r => $_ } @$re +posinfo; print "Repos: " . join( ",", keys %reposlist ) . "\n"; if ( !defined $reposlist{ lc $github_reponame } ) { print "$0 : creating new repository '$github_reponame' ...\n"; my $ret = undef; eval { $ret = $git->repos->create( { name => $github_reponame, description => "change this to suit", } ); }; if ($@) { print STDERR "$0 : failed to create repository '$github_reponame' +: $@\n"; exit(1); } } __END__

        Output:

        $ ./2.github.pl ini path is /home/bob/Documents/html_template_data/3.values.ini $VAR1 = bless( { ... 'my_github' => { 'password' => 'redacted', 'email' => 'tblazer66@gmail.com', 'user' => 'TBlazer66' }, ... }, 'Config::Tiny' ); login is tblazer66@gmail.com password is redacted ./2.github.pl : enter value for reponame: 2.newrepo Undef did not pass type constraint "Str" (in $args->{"login"}) at /usr +/local/share/perl/5.26.1/Net/GitHub.pm line 10 "Str" is a subtype of "Value" "Value" is a subtype of "Defined" Undef did not pass type constraint "Defined" (in $args->{"login"}) "Defined" is defined as: (defined($_))

        It seems like the problem is that I'm not getting values passed. I looked at line 10 of Github.pm is in the subroutine that wraps the arguments and sends them further:

        $ cd /usr/local/share/perl/5.26.1/Net $ cat GitHub.pm package Net::GitHub; use Net::GitHub::V3; our $VERSION = '0.95'; our $AUTHORITY = 'cpan:FAYLAND'; sub new { my $class = shift; Net::GitHub::V3->new(@_); } 1; __END__

        Question 1 is what gives with the values being undefined?

        The obvious disadvantage of my method is that Makefile.PL now contains a target (git-push) which the end user should never need.

        I spent a lot of time looking at ExtUtils::MakeMaker, and I'm wondering what the word "target" denotes. I had used it for the OS of the plaform you're developing for.

        Thanks for your post, and thanks for your comments,

Re: git-push target for Makefile (via ExtUtils::MakeMaker)
by bliako (Monsignor) on May 27, 2019 at 16:02 UTC

    Here is an example scriptto programmatically create a remote repository if it does not exist in specified user's assets. It uses Net::GitHub.

    use strict; use warnings; # by bliako on 27/05/2019 # creates a new git repository if it does not exist # requires git username, login and password which is # read from command line. use Net::GitHub; use Data::Dumper; my $github_reponame = 'new-repo'; my $github_login = '<like-an-email>'; my $github_username = '...'; print "$0 : enter password for '$github_login': "; my $github_password = <STDIN>; chomp($github_password); my $git = Net::GitHub->new( login => $github_username, pass => $github_password ); my $reposinfo = $git->repos->list($github_username); print Dumper($reposinfo); my %reposlist = map { lc $_->{'full_name'} =~ s|^${github_username}/|| +r => $_ } @$reposinfo; print "Repos: ".join(",", keys %reposlist)."\n"; if( ! defined $reposlist{lc $github_reponame} ){ print "$0 : creating new repository '$github_reponame' ...\n"; my $ret = undef; eval { $ret = $git->repos->create({ name => $github_reponame, description => "change me", }) }; if( $@ ){ print STDERR "$0 : failed to create repository '$github_ +reponame' : $@\n"; exit(1) } }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://11100309]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (5)
As of 2024-04-24 18:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found