1
0
Fork 0
devscripts/lib/Devscripts/Salsa/merge_request.pm
Daniel Baumann b543f2e88d
Adding upstream version 2.25.15.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-21 11:04:07 +02:00

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;