1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
# Creates a merge request from current directory (or using parameters)
package Devscripts::Salsa::merge_request;
use strict;
use Devscripts::Output;
use Dpkg::IPC;
use Moo::Role;
with 'Devscripts::Salsa::search_project';
sub merge_request {
my ($self, $dst_project, $dst_branch) = @_;
my $src_branch = $self->config->mr_src_branch;
my $src_project = $self->config->mr_src_project;
$dst_project ||= $self->config->mr_dst_project;
$dst_branch ||= $self->config->mr_dst_branch;
my $title = $self->config->mr_title;
my $desc = $self->config->mr_desc;
if ($src_branch) {
unless ($src_project and $dst_project) {
ds_warn "--mr-src-project and --mr-src-project "
. "are required when --mr-src-branch is set";
return 1;
}
unless ($src_project =~ m#/#) {
$src_project = $self->project2path($src_project);
}
} else { # Use current repository to find elements
ds_verbose "using current branch as source";
my $out;
unless ($src_project) {
# 1. Verify that repo is ready
spawn(
exec => [qw(git status -s -b -uno)],
wait_child => 1,
to_string => \$out
);
chomp $out;
# Case "rebased"
if ($out =~ /\[/) {
ds_warn "Current branch isn't pushed, aborting:\n";
return 1;
}
# Case else: nothing after src...dst
unless ($out =~ /\s(\S+)\.\.\.(\S+)/s) {
ds_warn
"Current branch as no origin or isn't pushed, aborting";
return 1;
}
# 2. Set source branch to current branch
$src_branch ||= $1;
ds_verbose "Found current branch: $src_branch";
}
unless ($src_project and $dst_project) {
# Check remote links
spawn(
exec => [qw(git remote --verbose show)],
wait_child => 1,
to_string => \$out,
);
my $origin = $self->config->api_url;
$origin =~ s#api/v4$##;
# 3. Set source project using "origin" target
unless ($src_project) {
if ($out
=~ /origin\s+(?:\Q$self->{config}->{git_server_url}\E|\Q$origin\E)(\S*)/m
) {
$src_project = $1;
$src_project =~ s/\.git$//;
} else {
ds_warn
"Unable to find project origin, set it using --mr-src-project";
return 1;
}
}
# 4. Steps to find destination project:
# - command-line
# - GitLab API (search for "forked_from_project"
# - "upstream" in git remote
# - use source project as destination project
# 4.1. Stop if dest project has been given in command line
unless ($dst_project) {
my $project = $self->api->project($src_project);
# 4.2. Search original project from GitLab API
if ($project->{forked_from_project}) {
$dst_project
= $project->{forked_from_project}->{path_with_namespace};
}
if ($dst_project) {
ds_verbose "Project was forked from $dst_project";
# 4.3. Search for an "upstream" target in `git remote`
} elsif ($out
=~ /upstream\s+(?:\Q$self->{config}->{git_server_url}\E|\Q$origin\E)(\S*)/m
) {
$dst_project = $1;
$dst_project =~ s/\.git$//;
ds_verbose 'Use "upstream" target as dst project';
# 4.4. Use source project as destination
} else {
ds_warn
"No upstream target found, using current project as target";
$dst_project = $src_project;
}
ds_verbose "Use $dst_project as dest project";
}
}
# 5. Search for MR title and desc
unless ($title) {
ds_warn "Title not set, using last commit";
spawn(
exec => ['git', 'show', '--format=format:%s###%b'],
wait_child => 1,
to_string => \$out,
);
$out =~ s/\ndiff.*$//s;
my ($t, $d) = split /###/, $out;
chomp $d;
$title = $t;
ds_verbose "Title set to $title";
$desc ||= $d;
# Replace all bug links by markdown links
if ($desc) {
$desc =~ s@#(\d{6,})\b@[#$1](https://bugs.debian.org/$1)@mg;
ds_verbose "Desc set to $desc";
}
}
}
if ($dst_project eq 'same') {
$dst_project = $src_project;
}
my $src = $self->api->project($src_project);
unless ($title) {
ds_warn "Title is required";
return 1;
}
unless ($src and $src->{id}) {
ds_warn "Target project not found $src_project";
return 1;
}
my $dst;
if ($dst_project) {
$dst = $self->api->project($dst_project);
unless ($dst and $dst->{id}) {
ds_warn "Target project not found";
return 1;
}
}
return 1
if (
ds_prompt(
"You're going to push an MR to $dst_project:$dst_branch. Continue (Y/n)"
) =~ refuse
);
my $res = $self->api->create_merge_request(
$src->{id},
{
source_branch => $src_branch,
target_branch => $dst_branch,
title => $title,
remove_source_branch => $self->config->mr_remove_source_branch,
squash => $self->config->mr_allow_squash,
($dst ? (target_project_id => $dst->{id}) : ()),
($desc ? (description => $desc) : ()),
});
ds_warn "MR '$title' posted:";
ds_warn $res->{web_url};
return 0;
}
1;
|