1
0
Fork 0
devscripts/lib/Devscripts/Salsa/Hooks.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

314 lines
12 KiB
Perl

# Common hooks library
package Devscripts::Salsa::Hooks;
use strict;
use Devscripts::Output;
use Moo::Role;
sub add_hooks {
my ($self, $repo_id, $repo) = @_;
if ( $self->config->kgb
or $self->config->disable_kgb
or $self->config->tagpending
or $self->config->disable_tagpending
or $self->config->irker
or $self->config->disable_irker
or $self->config->email
or $self->config->disable_email) {
my $hooks = $self->enabled_hooks($repo_id);
return 1 unless (defined $hooks);
# KGB hook (IRC)
if ($self->config->kgb or $self->config->disable_kgb) {
unless ($self->config->irc_channel->[0]
or $self->config->disable_kgb) {
ds_warn "--kgb needs --irc-channel";
return 1;
}
if ($self->config->irc_channel->[1]) {
ds_warn "KGB accepts only one --irc-channel value,";
}
if ($hooks->{kgb}) {
ds_warn "Deleting old kgb (was $hooks->{kgb}->{url})";
$self->api->delete_project_hook($repo_id, $hooks->{kgb}->{id});
}
if ($self->config->irc_channel->[0]
and not $self->config->disable_kgb) {
# TODO: if useful, add parameters for this options
eval {
$self->api->create_project_hook(
$repo_id,
{
url => $self->config->kgb_server_url
. $self->config->irc_channel->[0],
map { ($_ => 1) } @{ $self->config->kgb_options },
});
ds_verbose "KGB hook added to project $repo_id (channel: "
. $self->config->irc_channel->[0] . ')';
};
if ($@) {
ds_warn "Fail to add KGB hook: $@";
if (!$self->config->no_fail) {
ds_verbose "Use --no-fail to continue";
return 1;
}
}
}
}
# Irker hook (IRC)
if ($self->config->irker or $self->config->disable_irker) {
unless ($self->config->irc_channel->[0]
or $self->config->disable_irker) {
ds_warn "--irker needs --irc-channel";
return 1;
}
if ($hooks->{irker}) {
no warnings;
ds_warn
"Deleting old irker (redirected to $hooks->{irker}->{recipients})";
$self->api->delete_project_service($repo_id, 'irker');
}
if ($self->config->irc_channel->[0]
and not $self->config->disable_irker) {
# TODO: if useful, add parameters for this options
my $ch = join(' ',
map { '#' . $_ } @{ $self->config->irc_channel });
$self->api->edit_project_service(
$repo_id, 'irker',
{
active => 1,
server_host => $self->config->irker_host,
(
$self->config->irker_port
? (server_port => $self->config->irker_port)
: ()
),
default_irc_uri => $self->config->irker_server_url,
recipients => $ch,
colorize_messages => 1,
});
ds_verbose
"Irker hook added to project $repo_id (channel: $ch)";
}
}
# email on push
if ($self->config->email or $self->config->disable_email) {
if ($hooks->{email}) {
no warnings;
ds_warn
"Deleting old email-on-push (redirected to $hooks->{email}->{recipients})";
$self->api->delete_project_service($repo_id, 'emails-on-push');
}
if (@{ $self->config->email_recipient }
and not $self->config->disable_email) {
# TODO: if useful, add parameters for this options
$self->api->edit_project_service(
$repo_id,
'emails-on-push',
{
recipients => join(' ',
map { my $a = $_; $a =~ s/%p/$repo/; $a }
@{ $self->config->email_recipient }),
});
no warnings;
ds_verbose
"Email-on-push hook added to project $repo_id (recipients: "
. join(' ', @{ $self->config->email_recipient }) . ')';
}
}
# Tagpending hook
if ($self->config->tagpending or $self->config->disable_tagpending) {
if ($hooks->{tagpending}) {
ds_warn
"Deleting old tagpending (was $hooks->{tagpending}->{url})";
$self->api->delete_project_hook($repo_id,
$hooks->{tagpending}->{id});
}
my $repo_name = $self->api->project($repo_id)->{name};
unless ($self->config->disable_tagpending) {
eval {
$self->api->create_project_hook(
$repo_id,
{
url => $self->config->tagpending_server_url
. $repo_name,
push_events => 1,
});
ds_verbose "Tagpending hook added to project $repo_id";
};
if ($@) {
ds_warn "Fail to add Tagpending hook: $@";
if (!$self->config->no_fail) {
ds_verbose "Use --no-fail to continue";
return 1;
}
}
}
}
}
return 0;
}
sub enabled_hooks {
my ($self, $repo_id) = @_;
my $hooks;
my $res = {};
if ( $self->config->kgb
or $self->config->disable_kgb
or $self->config->tagpending
or $self->config->disable_tagpending) {
$hooks = eval { $self->api->project_hooks($repo_id) };
if ($@) {
ds_warn "Unable to check hooks for project $repo_id";
return undef;
}
foreach my $h (@{$hooks}) {
$res->{kgb} = {
id => $h->{id},
url => $h->{url},
options => [grep { $h->{$_} and $h->{$_} eq 1 } keys %$h],
}
if $h->{url} =~ /\Q$self->{config}->{kgb_server_url}\E/;
$res->{tagpending} = {
id => $h->{id},
url => $h->{url},
}
if $h->{url} =~ /\Q$self->{config}->{tagpending_server_url}\E/;
}
}
if ( ($self->config->email or $self->config->disable_email)
and $_ = $self->api->project_service($repo_id, 'emails-on-push')
and $_->{active}) {
$res->{email} = $_->{properties};
}
if ( ($self->config->irker or $self->config->disable_irker)
and $_ = $self->api->project_service($repo_id, 'irker')
and $_->{active}) {
$res->{irker} = $_->{properties};
}
return $res;
}
sub _check_config {
my ($config, $key_name, $config_name, $can_be_private, $res_ref) = @_;
if (!$config) { return undef; }
for ($config) {
if ($can_be_private) {
if ($_ eq "private") {
push @$res_ref, $key_name => "private";
} elsif ($_ =~ qr/y(es)?|true|enabled?/) {
push @$res_ref, $key_name => "enabled";
} elsif ($_ =~ qr/no?|false|disabled?/) {
push @$res_ref, $key_name => "disabled";
} else {
print "error with SALSA_$config_name";
}
} else {
if ($_ =~ qr/y(es)?|true|enabled?/) {
push @$res_ref, $key_name => 1;
} elsif ($_ =~ qr/no?|false|disabled?/) {
push @$res_ref, $key_name => 0;
} else {
print "error with SALSA_$config_name";
}
}
}
}
sub desc {
my ($self, $repo) = @_;
my @res = ();
if ($self->config->desc) {
my $str = $self->config->desc_pattern;
$str =~ s/%P/$repo/g;
$repo =~ s#.*/##;
$str =~ s/%p/$repo/g;
push @res, description => $str;
}
if ($self->config->build_timeout) {
push @res, build_timeout => $self->config->build_timeout;
}
if ($self->config->ci_config_path) {
push @res, ci_config_path => $self->config->ci_config_path;
}
# Parameter: config value, key name, config name, has private
_check_config($self->config->analytics,
"analytics_access_level", "ENABLE_ANALYTICS", 1, \@res);
_check_config($self->config->auto_devops,
"auto_devops_enabled", "ENABLE_AUTO_DEVOPS", 0, \@res);
_check_config(
$self->config->container,
"container_registry_access_level",
"ENABLE_CONTAINER", 1, \@res
);
_check_config($self->config->environments,
"environments_access_level", "ENABLE_ENVIRONMENTS", 1, \@res);
_check_config($self->config->feature_flags,
"feature_flags_access_level", "ENABLE_FEATURE_FLAGS", 1, \@res);
_check_config($self->config->forks, "forking_access_level",
"ENABLE_FORKS", 1, \@res);
_check_config($self->config->infrastructure,
"infrastructure_access_level", "ENABLE_INFRASTRUCTURE", 1, \@res);
_check_config($self->config->issues, "issues_access_level",
"ENABLE_ISSUES", 1, \@res);
# Renamed terminology, kept for legacy: jobs == builds_access_level (ENABLE_JOBS -> ENABLE_BUILD)
_check_config($self->config->jobs, "builds_access_level", "ENABLE_JOBS",
1, \@res);
_check_config($self->config->lfs, "lfs_enabled", "ENABLE_LFS", 0, \@res);
_check_config($self->config->mr, "merge_requests_access_level",
"ENABLE_MR", 1, \@res);
_check_config($self->config->monitor,
"monitor_access_level", "ENABLE_MONITOR", 1, \@res);
_check_config($self->config->packages,
"packages_enabled", "ENABLE_PACKAGES", 0, \@res);
_check_config($self->config->pages, "pages_access_level", "ENABLE_PAGES",
1, \@res);
_check_config($self->config->releases,
"releases_access_level", "ENABLE_RELEASES", 1, \@res);
_check_config(
$self->config->disable_remove_branch,
"remove_source_branch_after_merge",
"REMOVE_SOURCE_BRANCH", 0, \@res
);
_check_config($self->config->repo, "repository_access_level",
"ENABLE_REPO", 1, \@res);
_check_config($self->config->request_access,
"request_access_enabled", "REQUEST_ACCESS", 0, \@res);
_check_config($self->config->requirements,
"requirements_access_level", "ENABLE_REQUIREMENTS", 1, \@res);
_check_config(
$self->config->security_compliance,
"security_and_compliance_access_level",
"ENABLE_SECURITY_COMPLIANCE", 1, \@res
);
_check_config($self->config->service_desk,
"service_desk_enabled", "ENABLE_SERVICE_DESK", 0, \@res);
_check_config($self->config->snippets,
"snippets_access_level", "ENABLE_SNIPPETS", 1, \@res);
_check_config($self->config->wiki, "wiki_access_level", "ENABLE_WIKI", 1,
\@res);
return @res;
}
sub desc_multipart {
my ($self, $repo) = @_;
my @res = ();
if ($self->config->avatar_path) {
my $str = $self->config->avatar_path;
$str =~ s/%p/$repo/g;
unless (-r $str) {
ds_warn "Unable to find: $str";
unless ($self->config->no_fail) {
ds_verbose "Use --no-fail to continue";
exit 1;
}
} else {
# avatar_path (salsa) -> avatar (GitLab API)
push @res, avatar => $str;
}
}
return @res;
}
1;