summaryrefslogtreecommitdiffstats
path: root/lib/Devscripts/Salsa/Config.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Devscripts/Salsa/Config.pm')
-rwxr-xr-xlib/Devscripts/Salsa/Config.pm460
1 files changed, 460 insertions, 0 deletions
diff --git a/lib/Devscripts/Salsa/Config.pm b/lib/Devscripts/Salsa/Config.pm
new file mode 100755
index 0000000..8c9ccbd
--- /dev/null
+++ b/lib/Devscripts/Salsa/Config.pm
@@ -0,0 +1,460 @@
+# Salsa configuration (inherits from Devscripts::Config)
+package Devscripts::Salsa::Config;
+
+use strict;
+use Devscripts::Output;
+use Moo;
+
+extends 'Devscripts::Config';
+
+# Declare accessors for each option
+foreach (qw(
+ all api_url cache_file command desc desc_pattern dest_branch rename_head
+ disable_irker disable_kgb disable_tagpending irc_channel irker wiki
+ snippets pages releases auto_devops request_acc issues mr repo forks
+ lfs packages jobs container analytics requirements irker_server_url
+ irker_host irker_port kgb kgb_server_url kgb_options mr_allow_squash
+ mr_desc mr_dst_branch mr_dst_project mr_remove_source_branch mr_src_branch
+ mr_src_project mr_title no_fail path private_token skip source_branch
+ group group_id user user_id tagpending tagpending_server_url email
+ email_recipient disable_email ci_config_path archived build_timeout
+ enable_remove_branch disable_remove_branch all_archived git_server_url
+ schedule_desc schedule_ref schedule_cron schedule_tz
+ schedule_enable schedule_disable schedule_run schedule_delete
+ avatar_path request_access
+ )
+) {
+ has $_ => (is => 'rw');
+}
+
+my $cacheDir;
+
+our @kgbOpt = qw(push_events issues_events confidential_issues_events
+ confidential_comments_events merge_requests_events tag_push_events
+ note_events job_events pipeline_events wiki_page_events
+ confidential_note_events enable_ssl_verification);
+
+BEGIN {
+ $cacheDir = $ENV{XDG_CACHE_HOME} || $ENV{HOME} . '/.cache';
+}
+
+# Options
+use constant keys => [
+
+ # General options
+ [
+ 'C|chdir=s', undef,
+ sub { return (chdir($_[1]) ? 1 : (0, "$_[1] doesn't exist")) }
+ ],
+ [
+ 'cache-file',
+ 'SALSA_CACHE_FILE',
+ sub {
+ $_[0]->cache_file($_[1] ? $_[1] : undef);
+ },
+ "$cacheDir/salsa.json"
+ ],
+ [
+ 'no-cache',
+ 'SALSA_NO_CACHE',
+ sub {
+ $_[0]->cache_file(undef)
+ if ($_[1] !~ /^(?:no|0+)$/i);
+ return 1;
+ }
+ ],
+ ['debug', undef, sub { $verbose = 2 }],
+ ['info|i', 'SALSA_INFO', sub { info(-1, 'SALSA_INFO', @_) }],
+ [
+ 'path=s',
+ 'SALSA_REPO_PATH',
+ sub {
+ $_ = $_[1];
+ s#/*(.*)/*#$1#;
+ $_[0]->path($_);
+ return /^[\w\d\-]+$/ ? 1 : (0, "Bad path $_");
+ }
+ ],
+ ['group=s', 'SALSA_GROUP', qr/^[\/\-\w]+$/],
+ ['group-id=s', 'SALSA_GROUP_ID', qr/^\d+$/],
+ ['token', 'SALSA_TOKEN', sub { $_[0]->private_token($_[1]) }],
+ [
+ 'token-file',
+ 'SALSA_TOKEN_FILE',
+ sub {
+ my ($self, $v) = @_;
+ return (0, "Unable to open token file") unless (-r $v);
+ open F, $v;
+ my $s = join '', <F>;
+ close F;
+ if ($s
+ =~ m/^[^#]*(?:SALSA_(?:PRIVATE_)?TOKEN)\s*=\s*(["'])?([-\w]+)\1?$/m
+ ) {
+ $self->private_token($2);
+ return 1;
+ } else {
+ return (0, "No token found in file $v");
+ }
+ }
+ ],
+ ['user=s', 'SALSA_USER', qr/^[\-\w]+$/],
+ ['user-id=s', 'SALSA_USER_ID', qr/^\d+$/],
+ ['verbose', 'SALSA_VERBOSE', sub { $verbose = 1 }],
+ ['yes!', 'SALSA_YES', sub { info(1, "SALSA_YES", @_) },],
+
+ # Update/create repo options
+ ['all'],
+ ['all-archived'],
+ ['skip=s', 'SALSA_SKIP', undef, sub { [] }],
+ [
+ 'skip-file=s',
+ 'SALSA_SKIP_FILE',
+ sub {
+ return 1 unless $_[1];
+ return (0, "Unable to read $_[1]") unless (-r $_[1]);
+ open my $fh, $_[1];
+ push @{ $_[0]->skip }, (map { chomp $_; ($_ ? $_ : ()) } <$fh>);
+ return 1;
+ }
+ ],
+ ['no-skip', undef, sub { $_[0]->skip([]); $_[0]->skip_file(undef); }],
+ ['build-timeout=s', 'SALSA_BUILD_TIMEOUT', qr/^\d+$/, '3600'],
+ ['ci-config-path=s', 'SALSA_CI_CONFIG_PATH', qr/\./],
+ ['desc!', 'SALSA_DESC', 'bool'],
+ ['desc-pattern=s', 'SALSA_DESC_PATTERN', qr/\w/, 'Debian package %p'],
+ [
+ 'enable-remove-source-branch!',
+ undef,
+ sub {
+ !$_[1]
+ or $_[0]
+ ->enable('yes', 'enable_remove_branch', 'disable_remove_branch');
+ }
+ ],
+ [
+ 'disable-remove-source-branch!',
+ undef,
+ sub {
+ !$_[1]
+ or $_[0]
+ ->enable('no', 'enable_remove_branch', 'disable_remove_branch');
+ }
+ ],
+ [
+ undef,
+ 'SALSA_REMOVE_SOURCE_BRANCH',
+ sub {
+ $_[0]
+ ->enable($_[1], 'enable_remove_branch', 'disable_remove_branch');
+ }
+ ],
+ [
+ 'issues=s', 'SALSA_ENABLE_ISSUES',
+ qr/y(es)?|true|enabled?|private|no?|false|disabled?/
+ ],
+ [
+ 'repo=s', 'SALSA_ENABLE_REPO',
+ qr/y(es)?|true|enabled?|private|no?|false|disabled?/
+ ],
+ [
+ 'mr=s', 'SALSA_ENABLE_MR',
+ qr/y(es)?|true|enabled?|private|no?|false|disabled?/
+ ],
+ [
+ 'forks=s', 'SALSA_ENABLE_FORKS',
+ qr/y(es)?|true|enabled?|private|no?|false|disabled?/
+ ],
+ [
+ 'lfs=s', 'SALSA_ENABLE_LFS',
+ qr/y(es)?|true|enabled?|no?|false|disabled?/
+ ],
+ [
+ 'packages=s',
+ 'SALSA_ENABLE_PACKAGES',
+ qr/y(es)?|true|enabled?|no?|false|disabled?/
+ ],
+ [
+ 'jobs=s', 'SALSA_ENABLE_JOBS',
+ qr/y(es)?|true|enabled?|private|no?|false|disabled?/
+ ],
+ [
+ 'container=s', 'SALSA_ENABLE_CONTAINER',
+ qr/y(es)?|true|enabled?|private|no?|false|disabled?/
+ ],
+ [
+ 'analytics=s', 'SALSA_ENABLE_ANALYTICS',
+ qr/y(es)?|true|enabled?|private|no?|false|disabled?/
+ ],
+ [
+ 'requirements=s',
+ 'SALSA_ENABLE_REQUIREMENTS',
+ qr/y(es)?|true|enabled?|private|no?|false|disabled?/
+ ],
+ [
+ 'wiki=s', 'SALSA_ENABLE_WIKI',
+ qr/y(es)?|true|enabled?|private|no?|false|disabled?/
+ ],
+ [
+ 'snippets=s', 'SALSA_ENABLE_SNIPPETS',
+ qr/y(es)?|true|enabled?|private|no?|false|disabled?/
+ ],
+ [
+ 'pages=s', 'SALSA_ENABLE_PAGES',
+ qr/y(es)?|true|enabled?|private|no?|false|disabled?/
+ ],
+ [
+ 'releases=s', 'SALSA_ENABLE_RELEASES',
+ qr/y(es)?|true|enabled?|private|no?|false|disabled?/
+ ],
+ [
+ 'auto-devops=s',
+ 'SALSA_ENABLE_AUTO_DEVOPS',
+ qr/y(es)?|true|enabled?|no?|false|disabled?/
+ ],
+ [
+ 'request-acc=s',
+ 'SALSA_ENABLE_REQUEST_ACC',
+ qr/y(es)?|true|enabled?|no?|false|disabled?/
+ ],
+ [
+ 'email!', undef,
+ sub { !$_[1] or $_[0]->enable('yes', 'email', 'disable_email'); }
+ ],
+ [
+ 'disable-email!', undef,
+ sub { !$_[1] or $_[0]->enable('no', 'email', 'disable_email'); }
+ ],
+ [
+ undef, 'SALSA_EMAIL',
+ sub { $_[0]->enable($_[1], 'email', 'disable_email'); }
+ ],
+ ['email-recipient=s', 'SALSA_EMAIL_RECIPIENTS', undef, sub { [] },],
+ ['irc-channel|irc=s', 'SALSA_IRC_CHANNEL', undef, sub { [] }],
+ [
+ 'irker!', undef,
+ sub { !$_[1] or $_[0]->enable('yes', 'irker', 'disable_irker'); }
+ ],
+ [
+ 'disable-irker!', undef,
+ sub { !$_[1] or $_[0]->enable('no', 'irker', 'disable_irker'); }
+ ],
+ [
+ undef, 'SALSA_IRKER',
+ sub { $_[0]->enable($_[1], 'irker', 'disable_irker'); }
+ ],
+ ['irker-host=s', 'SALSA_IRKER_HOST', undef, 'ruprecht.snow-crash.org'],
+ ['irker-port=s', 'SALSA_IRKER_PORT', qr/^\d*$/],
+ [
+ 'kgb!', undef,
+ sub { !$_[1] or $_[0]->enable('yes', 'kgb', 'disable_kgb'); }
+ ],
+ [
+ 'disable-kgb!', undef,
+ sub { !$_[1] or $_[0]->enable('no', 'kgb', 'disable_kgb'); }
+ ],
+ [undef, 'SALSA_KGB', sub { $_[0]->enable($_[1], 'kgb', 'disable_kgb'); }],
+ [
+ 'kgb-options=s',
+ 'SALSA_KGB_OPTIONS',
+ qr/\w/,
+ 'push_events,issues_events,merge_requests_events,tag_push_events,'
+ . 'note_events,pipeline_events,wiki_page_events,'
+ . 'enable_ssl_verification'
+ ],
+
+ ['no-fail', 'SALSA_NO_FAIL', 'bool'],
+ ['rename-head!', 'SALSA_RENAME_HEAD', 'bool'],
+ ['avatar-path=s', 'SALSA_AVATAR_PATH', undef],
+ ['source-branch=s', 'SALSA_SOURCE_BRANCH', undef, 'master'],
+ ['dest-branch=s', 'SALSA_DEST_BRANCH', undef, 'debian/master'],
+ [
+ 'tagpending!',
+ undef,
+ sub {
+ !$_[1]
+ or $_[0]->enable('yes', 'tagpending', 'disable_tagpending');
+ }
+ ],
+ [
+ 'disable-tagpending!',
+ undef,
+ sub {
+ !$_[1] or $_[0]->enable('no', 'tagpending', 'disable_tagpending');
+ }
+ ],
+ [
+ undef, 'SALSA_TAGPENDING',
+ sub { $_[0]->enable($_[1], 'tagpending', 'disable_tagpending'); }
+ ],
+
+ # Pipeline schedules options
+ ['schedule-desc=s', 'SALSA_SCHEDULE_DESC', qr/\w/],
+ ['schedule-ref=s', 'SALSA_SCHEDULE_REF'],
+ ['schedule-cron=s', 'SALSA_SCHEDULE_CRON'],
+ ['schedule-tz=s', 'SALSA_SCHEDULE_TZ'],
+ ['schedule-enable!', 'SALSA_SCHEDULE_ENABLE', 'bool'],
+ ['schedule-disable!', 'SALSA_SCHEDULE_DISABLE', 'bool'],
+ ['schedule-run!', 'SALSA_SCHEDULE_RUN', 'bool'],
+ ['schedule-delete!', 'SALSA_SCHEDULE_DELETE', 'bool'],
+
+ # Merge requests options
+ ['mr-allow-squash!', 'SALSA_MR_ALLOW_SQUASH', 'bool', 1],
+ ['mr-desc=s'],
+ ['mr-dst-branch=s', undef, undef, 'master'],
+ ['mr-dst-project=s'],
+ ['mr-remove-source-branch!', 'SALSA_MR_REMOVE_SOURCE_BRANCH', 'bool', 0],
+ ['mr-src-branch=s'],
+ ['mr-src-project=s'],
+ ['mr-title=s'],
+
+ # Options to manage other Gitlab instances
+ [
+ 'api-url=s', 'SALSA_API_URL',
+ qr#^https?://#, 'https://salsa.debian.org/api/v4'
+ ],
+ [
+ 'git-server-url=s', 'SALSA_GIT_SERVER_URL',
+ qr/^\S+\@\S+/, 'git@salsa.debian.org:'
+ ],
+ [
+ 'irker-server-url=s', 'SALSA_IRKER_SERVER_URL',
+ qr'^ircs?://', 'ircs://irc.oftc.net:6697/'
+ ],
+ [
+ 'kgb-server-url=s', 'SALSA_KGB_SERVER_URL',
+ qr'^https?://', 'http://kgb.debian.net:9418/webhook/?channel='
+ ],
+ [
+ 'tagpending-server-url=s',
+ 'SALSA_TAGPENDING_SERVER_URL',
+ qr'^https?://',
+ 'https://webhook.salsa.debian.org/tagpending/'
+ ],
+
+ [
+ 'request-access=s',
+ 'SALSA_REQUEST_ACCESS',
+ qr/y(es)?|true|enabled?|1|no?|false|disabled?|0/
+ ],
+
+ # List/search options
+ ['archived!', 'SALSA_ARCHIVED', 'bool', 0],
+];
+
+# Consistency rules
+use constant rules => [
+ # Reject unless token exists
+ sub {
+ return (1,
+"SALSA_TOKEN not set in configuration files. Some commands may fail"
+ ) unless ($_[0]->private_token);
+ },
+ # Get command
+ sub {
+ return (0, "No command given, aborting") unless (@ARGV);
+ $_[0]->command(shift @ARGV);
+ return (0, "Malformed command: " . $_[0]->command)
+ unless ($_[0]->command =~ /^[a-z_]+$/);
+ return 1;
+ },
+ sub {
+ if ( ($_[0]->group or $_[0]->group_id)
+ and ($_[0]->user_id or $_[0]->user)) {
+ ds_warn(
+ "Both --user-id and --group-id are set, ignore --group-id");
+ $_[0]->group(undef);
+ $_[0]->group_id(undef);
+ }
+ return 1;
+ },
+ sub {
+ if ($_[0]->group and $_[0]->group_id) {
+ ds_warn("Both --group-id and --group are set, ignore --group");
+ $_[0]->group(undef);
+ }
+ return 1;
+ },
+ sub {
+ if ($_[0]->user and $_[0]->user_id) {
+ ds_warn("Both --user-id and --user are set, ignore --user");
+ $_[0]->user(undef);
+ }
+ return 1;
+ },
+ sub {
+ if ($_[0]->email and not @{ $_[0]->email_recipient }) {
+ return (0, '--email-recipient needed with --email');
+ }
+ return 1;
+ },
+ sub {
+ if (@{ $_[0]->irc_channel }) {
+ foreach (@{ $_[0]->irc_channel }) {
+ if (/^#/) {
+ return (1,
+"# found in --irc-channel, assuming double hash is wanted"
+ );
+ }
+ }
+ if ($_[0]->irc_channel->[1] and $_[0]->kgb) {
+ return (0, "Only one IRC channel is accepted with --kgb");
+ }
+ }
+ return 1;
+ },
+ sub {
+ $_[0]->kgb_options([sort split ',\s*', $_[0]->kgb_options]);
+ my @err;
+ foreach my $o (@{ $_[0]->kgb_options }) {
+ unless (grep { $_ eq $o } @kgbOpt) {
+ push @err, $o;
+ }
+ }
+ return (0, 'Unknown KGB options: ' . join(', ', @err))
+ if @err;
+ return 1;
+ },
+];
+
+sub usage {
+ print <<END;
+usage: salsa <command> <parameters> <options>
+
+Most used commands:
+ - checkout, co: clone repo in current dir
+ - fork : fork a project
+ - mr : create a merge request
+ - push_repo : push local git repo to upstream repository
+ - whoami : gives information on the token owner
+
+See salsa(1) manpage for more.
+END
+}
+
+sub info {
+ my ($num, $key, undef, $nv) = @_;
+ $nv = (
+ $nv =~ /^yes|1$/ ? $num
+ : $nv =~ /^no|0$/i ? 0
+ : return (0, "Bad $key value"));
+ $ds_yes = $nv;
+}
+
+sub enable {
+ my ($self, $v, $en, $dis) = @_;
+ $v = lc($v);
+ if ($v eq 'ignore') {
+ $self->{$en} = $self->{$dis} = 0;
+ } elsif ($v eq 'yes') {
+ $self->{$en} = 1;
+ $self->{$dis} = 0;
+ } elsif ($v eq 'no') {
+ $self->{$en} = 0;
+ $self->{$dis} = 1;
+ } else {
+ return (0, "Bad value for SALSA_" . uc($en));
+ }
+ return 1;
+}
+
+1;