174 lines
6.1 KiB
Perl
174 lines
6.1 KiB
Perl
# 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'; # search_projects
|
|
|
|
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 project 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 has 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;
|