package Dist::Zilla::Plugin::GitLab::Create 1.0002; use Modern::Perl; use JSON::MaybeXS; use Moose; use Try::Tiny; use Git::Wrapper; use File::Basename; extends 'Dist::Zilla::Plugin::GitLab'; with 'Dist::Zilla::Role::AfterMint'; with 'Dist::Zilla::Role::TextTemplate'; has issues => ( is => 'ro', isa => 'Bool', default => 1, ); has merge_requests => ( is => 'ro', isa => 'Bool', default => 1, ); has namespace => ( is => 'ro', isa => 'Maybe[Str]', ); has packages => ( is => 'ro', isa => 'Bool', default => 1, ); has prompt => ( is => 'ro', isa => 'Bool', default => 0, ); has public => ( is => 'ro', isa => 'Bool', default => 1, ); has remote => ( is => 'ro', isa => 'Str', default => 'origin', ); has repo => ( is => 'ro', isa => 'Maybe[Str]', ); has snippets => ( is => 'ro', isa => 'Bool', default => 1, ); has wiki => ( is => 'ro', isa => 'Bool', default => 1, ); sub after_mint { my $self = shift; my ($opts) = @_; return if $self->prompt and not $self->_confirm; my $root = $opts->{mint_root}; my $repo_name = $self->zilla->name; if ( $opts->{repo} ) { $repo_name = $opts->{repo}; } elsif ( $self->repo ) { $repo_name = $self->fill_in_string( $self->repo, { dist => \( $self->zilla ) }, ); } $self->log( [ 'Creating new GitLab repository \'%s\'', $repo_name ] ); my $http = HTTP::Tiny->new; my ( $params, $headers, $content ); $headers = $self->_auth_headers; if ( $self->namespace ) { my $namespaces_url = $self->api . '/namespaces'; my $namespaces = $http->request( 'GET', $namespaces_url, { headers => $headers } ); my $spaces = $self->_check_response($namespaces); foreach my $space (@$spaces) { next if $self->namespace ne $space->path; $params->{namespace_id} = $space->id; } } $params->{name} = $repo_name; $params->{visibility} = $self->public ? 'public' : 'private'; $params->{description} = $opts->{description} ? $opts->{description} : undef; $params->{issues_enabled} = $self->issues; $self->log( [ 'Issues are %s', $params->{issues_enabled} ? 'enabled' : 'disabled' ] ); $params->{wiki_enabled} = $self->wiki; $self->log( [ 'Wiki is %s', $params->{wiki_enabled} ? 'enabled' : 'disabled' ] ); $params->{packages_enabled} = $self->packages; $self->log( [ 'Packages are %s', $params->{packages_enabled} ? 'enabled' : 'disabled' ] ); $params->{snippets_enabled} = $self->snippets; $self->log( [ 'Snippets are %s', $params->{snippets_enabled} ? 'enabled' : 'disabled' ] ); $params->{merge_requests_enabled} = $self->merge_requests; $self->log( [ 'Merge requests are %s', $params->{merge_requests_enabled} ? 'enabled' : 'disabled' ] ); my $url = $self->api . '/projects'; $content = encode_json($params); $headers->{'content-type'} = 'application/json'; $self->log_debug("Sending POST $url"); my $response = $http->request( 'POST', $url, { content => $content, headers => $headers, } ); my $repo = $self->_check_response($response); return if not $repo; my $git_dir = "$root/.git"; my $rem_ref = $git_dir . '/refs/remotes/' . $self->remote; if ( ( -d $git_dir ) && ( not -d $rem_ref ) ) { my $git = Git::Wrapper->new($root); $self->log( [ 'Setting GitLab remote \'%s\'', $self->remote ] ); $git->remote( 'add', $self->remote, $repo->{ssh_url_to_repo} ); my ($branch) = try { $git->rev_parse( { abbrev_ref => 1, symbolic_full_name => 1 }, 'HEAD' ) }; if ($branch) { try { $git->config("branch.$branch.merge"); $git->config("branch.$branch.remote"); } catch { $self->log( [ 'Setting up remote tracking for branch \'%s\'', $branch ] ); $git->config( "branch.$branch.merge", "refs/heads/$branch" ); $git->config( "branch.$branch.remote", $self->remote ); }; } } } sub _confirm { my ($self) = @_; my $dist = $self->zilla->name; my $prompt = "Shall I create a GitLab repository for $dist?"; return $self->zilla->chrome->prompt_yn( $prompt, { default => 1 } ); } __PACKAGE__->meta->make_immutable; 1; =pod =encoding UTF-8 =head1 NAME Dist::Zilla::Plugin::GitLab::Create - Create a new GitLab repo on dzil new =head1 VERSION version 1.0002 =head1 SYNOPSIS Configure git with your GitLab credentials: $ git config --global gitlab.user LoginName $ git config --global gitlab.token AccessToken Alternatively you can install L and write your credentials in the (optionally GPG-encrypted) C<~/.gitlab> file as follows: login LoginName token AccessToken Set up an access token on GitLab, in your profile under "Personal Access Tokens." You must grant the token the C scope! then, in your F: # default config [GitLab::Create] # to override publicness [GitLab::Create] public = 0 # use a template for the repository name [GitLab::Create] repo = {{ lc $dist->name }} See L for more options. =head1 DESCRIPTION This Dist::Zilla plugin creates a new git repository on GitLab.com when a new distribution is created with C. It will also add a new git remote pointing to the newly created GitLab repository's private URL. See L for more info. =head1 ATTRIBUTES =over =item C Enable issues for the new repository if this option is set to true (default). =item C Enable merge requests for the new repository if this option is set to true (default). =item C Specifies the project namespace path in which to create the repository (by default the repository is created in the user's account). =item C Enable packages for the new repository if this option is set to true (default). =item C Prompt for confirmation before creating a GitLab repository if this option is set to true (default is false). =item C Create a public repository if this option is set to true (default), otherwise create a private repository. =item C Specifies the git remote name to be added (default 'origin'). This will point to the newly created GitLab repository's private URL. See L for more info. =item C Specifies the name of the GitLab repository to be created (by default the name of the dist is used). This can be a template, so something like the following will work: repo = {{ lc $dist->name }} =item C Enable snippets for the new repository if this option is set to true (default). =item C Enable the wiki for the new repository if this option is set to true (default). =back =head1 ADDING REMOTE By default C adds a new git remote pointing to the newly created GitLab repository's private URL B a git repository has already been initialized, and if the remote doesn't already exist in that repository. To take full advantage of this feature you should use, along with C, the L plugin, leaving blank its C option, as follows: [Git::Init] ; here goes your Git::Init config, remember ; to not set the 'remote' option [GitLab::Create] You may set your preferred remote name, by setting the C option of the C plugin, as follows: [Git::Init] [GitLab::Create] remote = myremote Remember to put C<[Git::Init]> B C<[GitLab::Create]>. After the new remote is added, the current branch will track it, unless remote tracking for the branch was already set. This may allow one to use the L plugin without the need to do a C between the C and C. Note though that this will work only when the C Git configuration option is set to either C or C (which will be the default in Git 2.0). If you are using an older Git or don't want to change your config, you may want to have a look at L. =head1 AUTHOR D Ruth Holloway =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2022 by D Ruth Holloway. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ # ABSTRACT: Create a new GitLab repo on dzil new