From 89b581c6fa663d8a9db728d98e7f56c83c991444 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Tue, 11 Feb 2020 14:34:08 -0700 Subject: rework script into API::GitForge generic interface Signed-off-by: Sean Whitton --- lib/API/GitForge/Role/GitForge.pm | 160 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 lib/API/GitForge/Role/GitForge.pm (limited to 'lib/API/GitForge/Role/GitForge.pm') diff --git a/lib/API/GitForge/Role/GitForge.pm b/lib/API/GitForge/Role/GitForge.pm new file mode 100644 index 0000000..46877ba --- /dev/null +++ b/lib/API/GitForge/Role/GitForge.pm @@ -0,0 +1,160 @@ +package API::GitForge::Role::GitForge; +# ABSTRACT: role implementing generic git forge operations +# +# Copyright (C) 2017, 2020 Sean Whitton +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or (at +# your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +=head1 DESCRIPTION + +Operations which one might wish to perform against any git forge. See +L. + +In this documentation, C should be replaced with the +domain at which your GitForge is hosted, e.g. C. + +=cut + +use 5.028; +use strict; +use warnings; + +use Role::Tiny; + +use Carp; +use File::Temp qw(tempdir); +use Git::Wrapper; +use File::Spec::Functions qw(catfile); + +=method new(domain => $domain, access_token => $token) + +Instantiate an object representing the GitForge at C<$domain>. The +C argument is optional; if present, it should be an API +key for the forge. + +=cut + +sub new { + my ($class, %opts) = @_; + croak "need domain!" unless exists $opts{domain}; + + my %attrs = (_domain => $opts{domain}); + $attrs{_access_token} = $opts{access_token} if exists $opts{access_token}; + my $self = bless \%attrs => $class; + + $self->_make_api; + + return $self; +} + +=method ensure_repo($repo) + +Create a new repo at C. + +=cut + +sub ensure_repo { shift->_create_repo(@_) } + +=method clean_repo($repo) + +Create a new repo at C and turn off +optional forge features. + +=cut + +sub clean_repo { + my ($self, $repo) = @_; + $self->_ensure_repo($repo); + $self->_clean_config_repo($repo); +} + +=method ensure_fork($upstream) + +Ensure that the current user has a fork of the repo at +C, and return URI to that fork suitable +for adding as a git remote. + +=cut + +sub ensure_fork { shift->_ensure_fork(@_) } + +=method clean_fork($upstream) + +Ensure that the current user has a fork of the repo at +C, config that fork to make it obvious +it's only there for submitting change proposals, and return URI to +fork suitable for adding as a git remote. + +=cut + +sub clean_fork { + my $self = shift; + my $fork_uri = $self->_ensure_fork(@_); + + my $temp = tempdir CLEANUP => 1; + my $git = Git::Wrapper->new($temp); + $git->init; + $git->remote(qw(add fork), $fork_uri); + my @fork_branches + = map { m#refs/heads/#; $' } $git->ls_remote(qw(--heads fork)); + return $fork_uri if grep /\Agitforge\z/, @fork_branches; + + open my $fh, ">", catfile $temp, "README.md"; + say $fh "This repository exists only in order to submit pull request(s)."; + close $fh; + $git->add("README.md"); + $git->commit({ message => "Temporary fork for pull request(s)" }); + $git->RUN("push", $fork_uri, "master:gitforge"); + $self->_clean_config_fork(@_); + + # assume that if we had to create the gitforge branch, we just + # created the fork, so can go ahead and nuke all branches there. + # may fail if some branches are protected; that's okay. + eval { $git->push($fork_uri, "--delete", @fork_branches) }; + + return $fork_uri; +} + +=method nuke_fork($upstream) + +Delete the user's fork of the repo at +C. + +=cut + +sub nuke_fork { shift->_nuke_fork(@_) } + +=method clean_config_repo($repo) + +Turn off optional forge features for repo at +C. + +=cut + +sub clean_config_repo { shift->_clean_config_repo(@_) } + +=method clean_config_fork($upstream) + +Configure user's fork of repo at C to +make it obvious that it's only there for submitting change proposals. + +=cut + +sub clean_config_fork { shift->_clean_config_fork(@_) } + +requires + qw<_make_api _ensure_repo _clean_config_repo _clean_config_fork + _ensure_fork _nuke_fork>; + +1; -- cgit v1.2.3