diff options
Diffstat (limited to 'lib/Devscripts/Salsa/Hooks.pm')
-rw-r--r-- | lib/Devscripts/Salsa/Hooks.pm | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/lib/Devscripts/Salsa/Hooks.pm b/lib/Devscripts/Salsa/Hooks.pm new file mode 100644 index 0000000..1aa2a35 --- /dev/null +++ b/lib/Devscripts/Salsa/Hooks.pm @@ -0,0 +1,314 @@ +# 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; |