Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
E
ensembl
Manage
Activity
Members
Labels
Plan
Issues
0
Issue boards
Milestones
Iterations
Wiki
Requirements
Jira
Code
Merge requests
1
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package Registry
Container Registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
ensembl-gh-mirror
ensembl
Commits
c505bfaf
Commit
c505bfaf
authored
8 years ago
by
Alessandro Vullo
Browse files
Options
Downloads
Patches
Plain Diff
[
ENSCORESW-2129
]. Script to programmatically create release tasks and sub-tasks in JIRA at EBI.
parent
70773b12
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
misc-scripts/jira/create_release_tasks.pl
+569
-0
569 additions, 0 deletions
misc-scripts/jira/create_release_tasks.pl
with
569 additions
and
0 deletions
misc-scripts/jira/create_release_tasks.pl
0 → 100755
+
569
−
0
View file @
c505bfaf
#!/usr/bin/env perl
use
strict
;
use
warnings
;
use
diagnostics
;
use
autodie
;
use
feature
qw(say)
;
use
FindBin
;
use
Getopt::
Long
;
use
Config::
Tiny
;
use
JSON
;
use
HTTP::
Request
;
use
LWP::
UserAgent
;
use
Term::
ReadKey
;
use
Bio::EnsEMBL::Utils::
Logger
;
use
Bio::EnsEMBL::
ApiVersion
;
main
();
sub
main
{
# -----------------
# initialize logger
# -----------------
my
$logger
=
Bio::EnsEMBL::Utils::
Logger
->
new
();
# $logger->init_log();
# ----------------------------
# read command line parameters
# ----------------------------
my
(
$relco
,
$release
,
$password
,
$help
,
$tickets_tsv
,
$config
);
GetOptions
(
'
relco=s
'
=>
\
$relco
,
'
release=i
'
=>
\
$release
,
'
password=s
'
=>
\
$password
,
'
p=s
'
=>
\
$password
,
'
tickets=s
'
=>
\
$tickets_tsv
,
'
config=s
'
=>
\
$config
,
'
c=s
'
=>
\
$config
,
'
help
'
=>
\
$help
,
'
h
'
=>
\
$help
,
);
# ------------
# display help
# ------------
if
(
$help
)
{
usage
();
}
# ---------------------------------
# deal with command line parameters
# ---------------------------------
(
$relco
,
$release
,
$password
,
$tickets_tsv
,
$config
)
=
set_parameters
(
$relco
,
$release
,
$password
,
$tickets_tsv
,
$config
,
$logger
);
# ---------------------------
# read config file parameters
# ---------------------------
my
$parameters
=
Config::
Tiny
->
read
(
$config
);
# check_dates($parameters);
# integrate command line parameters to parameters object
$parameters
->
{
relco
}
=
$relco
;
$parameters
->
{
password
}
=
$password
;
$parameters
->
{
release
}
=
$release
;
# ------------------
# parse tickets file
# ------------------
my
$tickets
=
parse_tickets_file
(
$parameters
,
$tickets_tsv
,
$logger
);
# --------------------------------
# get existing tickets for current
# release from the JIRA server
# --------------------------------
my
$existing_tickets_response
=
post_request
(
'
rest/api/latest/search
',
{
"
jql
"
=>
"
fixVersion =
"
.
$parameters
->
{
release
}
},
$parameters
,
$logger
);
my
$existing_tickets
=
decode_json
(
$existing_tickets_response
->
content
()
);
#use Data::Dumper; print Dumper $existing_tickets; exit;
# --------------------
# check for duplicates
# --------------------
my
%tickets_to_skip
;
for
my
$ticket
(
@
{
$tickets
}
)
{
my
$duplicate
=
check_for_duplicate
(
$ticket
,
$existing_tickets
);
if
(
$duplicate
)
{
$tickets_to_skip
{
$ticket
->
{
summary
}
}
=
$duplicate
;
}
}
# --------------------
# validate JIRA fields
# --------------------
# for my $ticket ( @{$tickets} ) {
# $logger->info( 'Validating' . ' "' . $ticket->{summary} . '" ... ' );
# validate_fields( $ticket, $parameters, $logger );
# $logger->info("Done\n");
# }
# -----------------------
# create new JIRA tickets
# -----------------------
for
my
$ticket
(
@
{
$tickets
}
)
{
$logger
->
info
(
'
Creating
'
.
'
"
'
.
$ticket
->
{
summary
}
.
'
" ...
'
);
# if the ticket to be submitted is a subtask then fetch the parent key and
# replace the parent summary with the parent key
if
(
$ticket
->
{'
issuetype
'}
->
{'
name
'}
eq
'
Sub-task
'
)
{
my
$parent_key
=
get_parent_key
(
$ticket
->
{'
parent
'},
$parameters
,
$logger
);
$ticket
->
{'
parent
'}
=
{
'
key
'
=>
$parent_key
};
}
if
(
$tickets_to_skip
{
$ticket
->
{
summary
}
}
)
{
$logger
->
info
(
'
Skipped: This seems to be a duplicate of https://www.ebi.ac.uk/panda/jira/browse/
'
.
$tickets_to_skip
{
$ticket
->
{
summary
}
}
.
"
\n
"
);
}
else
{
my
$ticket_key
=
create_ticket
(
$ticket
,
$parameters
,
$logger
);
$logger
->
info
(
"
Done
\t
"
.
$ticket_key
.
"
\n
"
);
}
}
}
=head2 set_parameters
Arg[1] : String $relco - a Regulation team member name or JIRA username
Arg[2] : Integer $release - the EnsEMBL release version
Arg[3] : String $password - user's JIRA password
Arg[4] : String $tickets_tsv - path to the tsv file that holds the input
Arg[5] : String $config - path to the config file holding handover dates
Arg[6] : Bio::EnsEMBL::Utils::Logger $logger - object used for logging
Description : Makes sure that the parameters provided through the command line
are valid and assigns default values to the ones which where not
supplied
Return type : Listref
Exceptions : none
=cut
sub
set_parameters
{
my
(
$relco
,
$release
,
$password
,
$tickets_tsv
,
$config
,
$logger
)
=
@_
;
$relco
=
$ENV
{'
USER
'}
unless
$relco
;
validate_user_name
(
$relco
,
$logger
);
$release
=
Bio::EnsEMBL::
ApiVersion
->
software_version
()
if
!
$release
;
$tickets_tsv
=
$
FindBin::
Bin
.
'
/jira_recurrent_tickets.tsv
'
if
!
$tickets_tsv
;
if
(
!-
e
$tickets_tsv
)
{
$logger
->
error
(
'
Tickets file
'
.
$tickets_tsv
.
'
not found! Please specify one using the -tickets option!
',
0
,
0
);
}
$config
=
$
FindBin::
Bin
.
'
/jira.conf
'
if
!
$config
;
if
(
!-
e
$config
)
{
$logger
->
error
(
'
Config file
'
.
$config
.
'
not found! Please specify one using the -config option!
',
0
,
0
);
}
printf
(
"
\t
relco: %s
\n\t
release: %i
\n\t
tickets: %s
\n\t
config: %s
\n
",
$relco
,
$release
,
$tickets_tsv
,
$config
);
print
"
Are the above parameters correct? (y,N) :
";
my
$response
=
readline
();
chomp
$response
;
if
(
$response
ne
'
y
'
)
{
$logger
->
error
(
'
Aborted by user. Please rerun with correct parameters.
',
0
,
0
);
}
if
(
!
$password
)
{
print
'
Please type your JIRA password:
';
ReadMode
('
noecho
');
# make password invisible on terminal
$password
=
ReadLine
(
0
);
chomp
$password
;
ReadMode
(
0
);
# restore typing visibility on terminal
print
"
\n
";
}
return
(
$relco
,
$release
,
$password
,
$tickets_tsv
,
$config
);
}
=head2 validate_user_name
Arg[1] : String $user - a Core team member JIRA username
Arg[2] : Bio::EnsEMBL::Utils::Logger $logger - object used for logging
Example : validate_user_name($user, $logger)
Description : Checks if the provided user name is valid
Return type : none
Exceptions : none
=cut
sub
validate_user_name
{
my
(
$user
,
$logger
)
=
@_
;
my
%valid_user_names
=
(
'
mr6
'
=>
1
,
'
avullo
'
=>
1
,
'
ktaylor
'
=>
1
,
'
lairdm
'
=>
1
,
'
prem
'
=>
1
,
'
killm9m1
'
=>
1
);
return
if
exists
$valid_user_names
{
$user
};
my
$valid_names
=
join
(
"
\n
",
sort
keys
%valid_user_names
);
$logger
->
error
("
User name
$user
not valid! Here is a list of valid names:
\n
"
.
$valid_names
,
0
,
0
);
}
=head2 parse_tickets_file
Arg[1] : Hashref $parameters - parameters from command line and config
Arg[2] : String $tickets_tsv - path to the tsv file that holds the input
Arg[3] : Bio::EnsEMBL::Utils::Logger $logger - object used for logging
Example : my $tickets = parse_tickets_file( $parameters, $tickets_tsv, $logger );
Description : Reads the tsv input file, replaces placeholder tags and returns
a listref of tickets to be submitted
Return type : Listref
Exceptions : none
=cut
sub
parse_tickets_file
{
my
(
$parameters
,
$tickets_tsv
,
$logger
)
=
@_
;
my
@tickets
;
# create main ticket for the given release, will have tickets read from the file
# as sub-tasks except Xrefs, which will have its own main ticket since it contains
# the individual species xrefs as sub-tasks and we cannot create sub-sub-tasks
my
$project
=
'
ENSCORESW
';
my
$priority
=
'
Major
';
push
@tickets
,
{
'
project
'
=>
{
'
key
'
=>
$project
},
'
issuetype
'
=>
{
'
name
'
=>
'
Task
'
},
'
summary
'
=>
sprintf
("
Release %d
",
$parameters
->
{
release
}),
# 'reporter' => { 'name' => $reporter },
'
assignee
'
=>
{
'
name
'
=>
$parameters
->
{
relco
}
},
'
priority
'
=>
{
'
name
'
=>
$priority
},
'
fixVersions
'
=>
[
{
'
name
'
=>
sprintf
("
%d
",
$parameters
->
{
release
})
}
],
'
duedate
'
=>
$parameters
->
{
dates
}{
release
},
# 'components' => \@components,
'
description
'
=>
sprintf
"
Core activities for release %s
",
$parameters
->
{
release
},
};
open
my
$tsv
,
'
<
',
$tickets_tsv
;
my
$header
=
readline
$tsv
;
chomp
$header
;
while
(
readline
$tsv
)
{
my
$line
=
$_
;
chomp
$line
;
$line
=
replace_placeholders
(
$line
,
$parameters
);
my
(
$summary
,
$reporter
,
$assignee
,
$due_date
,
$component_string
,
$description
,
$species_list
)
=
split
/\t/
,
$line
;
# print "Summary: $summary\nReporter: $reporter\nAssignee: $assignee\nPriority: $priority\nDue date: $due_date\nComponents: $component_string\nDescription: $description\n\n";
if
(
$reporter
)
{
validate_user_name
(
$reporter
,
$logger
);
}
else
{
$reporter
=
$parameters
->
{
relco
};
}
if
(
$assignee
)
{
validate_user_name
(
$assignee
,
$logger
);
}
else
{
$assignee
=
$parameters
->
{
relco
};
}
my
@components
;
map
{
push
@components
,
{
'
name
'
=>
$_
}
}
split
/,/
,
$component_string
;
my
%ticket
;
# Xrefs is a task with its own sub-tasks, one for each species
if
(
$summary
=~
/xrefs/i
)
{
$species_list
or
$logger
->
error
("
Empty list of xref species
",
0
,
0
);
my
@species
=
split
/,/
,
$species_list
;
# this is the main Xref issue
push
@tickets
,
{
'
project
'
=>
{
'
key
'
=>
$project
},
'
issuetype
'
=>
{
'
name
'
=>
'
Task
'
},
'
summary
'
=>
$summary
,
# 'reporter' => { 'name' => $reporter },
'
assignee
'
=>
{
'
name
'
=>
$assignee
},
'
priority
'
=>
{
'
name
'
=>
$priority
},
'
fixVersions
'
=>
[
{
'
name
'
=>
sprintf
("
%d
",
$parameters
->
{
release
})
}
],
'
duedate
'
=>
$due_date
,
'
components
'
=>
\
@components
,
'
description
'
=>
$description
.
"
\n
Run xrefs for the following species:
\n\n
"
.
join
("
\n
",
@species
)
};
# now proceed with its sub-tasks, one for every species
foreach
my
$species
(
@species
)
{
push
@tickets
,
{
'
project
'
=>
{
'
key
'
=>
$project
},
'
issuetype
'
=>
{
'
name
'
=>
'
Sub-task
'
},
'
summary
'
=>
sprintf
("
Xrefs, %s %d
",
$species
,
$parameters
->
{
release
}),
'
parent
'
=>
$summary
,
# 'reporter' => { 'name' => $reporter },
'
assignee
'
=>
{
'
name
'
=>
$assignee
},
'
priority
'
=>
{
'
name
'
=>
$priority
},
'
fixVersions
'
=>
[
{
'
name
'
=>
sprintf
("
%d
",
$parameters
->
{
release
})
}
],
'
duedate
'
=>
$due_date
,
'
components
'
=>
\
@components
};
}
}
else
{
# create an issue as a sub-task of the main release one
%ticket
=
(
'
project
'
=>
{
'
key
'
=>
$project
},
'
issuetype
'
=>
{
'
name
'
=>
'
Sub-task
'
},
'
summary
'
=>
$summary
,
# the parent summary is replaced by the parent key
# just before the ticket submission
'
parent
'
=>
sprintf
("
Release %d
",
$parameters
->
{
release
}),
# 'reporter' => { 'name' => $reporter },
'
assignee
'
=>
{
'
name
'
=>
$assignee
},
'
priority
'
=>
{
'
name
'
=>
$priority
},
'
fixVersions
'
=>
[
{
'
name
'
=>
sprintf
("
%d
",
$parameters
->
{
release
})
}
],
'
duedate
'
=>
$due_date
,
'
components
'
=>
\
@components
,
'
description
'
=>
$description
,
);
# delete empty fields from ticket
for
my
$key
(
keys
%ticket
)
{
if
(
!
$ticket
{
$key
}
)
{
delete
$ticket
{
$key
};
}
}
push
@tickets
,
\
%ticket
;
}
}
# use Data::Dumper; print Dumper \@tickets; <STDIN>;
return
\
@tickets
;
}
=head2 replace_placeholders
Arg[1] : String $line - One line from the tsv input file
Arg[2] : Hashref $parameters - parameters from command line and config
Example : $line = replace_placeholders( $line, $parameters );
Description : Replaces the placeholder tags with valid values and returns a
a new string
Return type : String
Exceptions : none
=cut
sub
replace_placeholders
{
my
(
$line
,
$parameters
)
=
@_
;
$line
=~
s/<RelCo>/$parameters->{relco}/g
;
$line
=~
s/<version>/$parameters->{release}/g
;
$line
=~
s/<declaration_of_intentions>/$parameters->{dates}->{declaration_of_intentions}/g
;
$line
=~
s/<core_handover_xrefs>/$parameters->{dates}->{core_handover_xrefs}/g
;
$line
=~
s/<compara_final_handover>/$parameters->{dates}->{compara_final_handover}/g
;
$line
=~
s/<code_branching>/$parameters->{dates}->{code_branching}/g
;
$line
=~
s/<release>/$parameters->{dates}->{release}/g
;
return
$line
;
}
=head2 get_parent_key
Arg[1] : String $summary - Summary of the parent ticket
Arg[2] : Hashref $parameters - parameters from command line and config
Arg[3] : Bio::EnsEMBL::Utils::Logger $logger - object used for logging
Example : my $parent_key
= get_parent_key( $ticket->{'parent'}, $parameters, $logger );
Description : Gets the ticket key of the parent task
Return type : String
Exceptions : none
=cut
sub
get_parent_key
{
my
(
$summary
,
$parameters
,
$logger
)
=
@_
;
# jql=summary ~ "Update declarations" AND fixVersion %3D release-88
my
$content
=
{
"
jql
"
=>
'
fixVersion =
'
.
$parameters
->
{
release
}
.
'
and summary ~ "
'
.
$summary
.
'
"
'
};
my
$response
=
post_request
(
'
rest/api/latest/search
',
$content
,
$parameters
,
$logger
);
my
$parent
=
decode_json
(
$response
->
content
()
)
->
{'
issues
'}
->
[
0
];
return
$parent
->
{'
key
'};
}
=head2 create_ticket
Arg[1] : Hashref $line - Holds the ticket data
Arg[2] : Hashref $parameters - parameters from command line and config
Arg[3] : Bio::EnsEMBL::Utils::Logger $logger - object used for logging
Example : my $ticket_key = create_ticket( $ticket, $parameters, $logger );
Description : Submits a post request to the JIRA server that creates a new
ticket. Returns the key of the created ticket
Return type : String
Exceptions : none
=cut
sub
create_ticket
{
my
(
$ticket
,
$parameters
,
$logger
)
=
@_
;
my
$endpoint
=
'
rest/api/latest/issue
';
my
$content
=
{
'
fields
'
=>
$ticket
};
my
$response
=
post_request
(
$endpoint
,
$content
,
$parameters
,
$logger
);
return
decode_json
(
$response
->
content
()
)
->
{'
key
'};
}
=head2 post_request
Arg[1] : String $endpoint - the request's endpoint
Arg[2] : Hashref $content - the request's content
Arg[3] : Hashref $parameters - parameters used for authorization
Arg[4] : Bio::EnsEMBL::Utils::Logger $logger - object used for logging
Example : my $response = post_request( $endpoint, $content, $parameters, $logger )
Description : Sends a POST request to the JIRA server
Return type : HTTP::Response object
Exceptions : none
=cut
sub
post_request
{
my
(
$endpoint
,
$content
,
$parameters
,
$logger
)
=
@_
;
my
$host
=
'
https://www.ebi.ac.uk/panda/jira/
';
my
$url
=
$host
.
$endpoint
;
my
$json_content
=
encode_json
(
$content
);
my
$request
=
HTTP::
Request
->
new
(
'
POST
',
$url
);
$request
->
authorization_basic
(
$parameters
->
{
relco
},
$parameters
->
{
password
}
);
$request
->
header
(
'
Content-Type
'
=>
'
application/json
'
);
$request
->
content
(
$json_content
);
my
$agent
=
LWP::
UserAgent
->
new
();
my
$response
=
$agent
->
request
(
$request
);
if
(
$response
->
code
()
==
401
)
{
$logger
->
error
(
'
Your JIRA password is not correct. Please try again
',
0
,
0
);
}
if
(
$response
->
code
()
==
403
)
{
$logger
->
error
(
'
Your do not have permission to submit JIRA tickets programmatically
',
0
,
0
);
}
if
(
!
$response
->
is_success
()
)
{
my
$error_message
=
$response
->
as_string
();
$logger
->
error
(
$error_message
,
0
,
0
);
}
return
$response
;
}
=head2 check_for_duplicate
Arg[1] : Hashref $ticket - holds the data for the ticket which is about
to be submitted
Arg[2] : Hashref $existing_tickets - holds the data for all tickets that
already exist on the JIRA server for the current EnsEMBL release
Example : my $duplicate = check_for_duplicate($ticket, $existing_tickets);
Description : Checks whether the ticket which is about to be submitted exists
already on the JIRA server and returns the relevant key if this
is true
Return type : String
Exceptions : none
=cut
sub
check_for_duplicate
{
my
(
$ticket
,
$existing_tickets
)
=
@_
;
my
$duplicate
;
for
my
$existing_ticket
(
@
{
$existing_tickets
->
{
issues
}
}
)
{
if
(
$ticket
->
{
summary
}
eq
$existing_ticket
->
{
fields
}
->
{
summary
}
)
{
$duplicate
=
$existing_ticket
->
{
key
};
last
;
}
}
return
$duplicate
;
}
sub
usage
{
print
<<EOF;
=head1
create_JIRA_tickets.pl -relco <string> -password <string> -release <integer> -tickets <file> -config <file>
-relco JIRA username. Optional, will be inferred from current system user if not supplied.
-password | -p JIRA password. Will need to be typed in standard input if not supplied.
-release EnsEMBL Release. Optional, will be inferred from EnsEMBL API if not supplied.
-tickets File that holds the input data for creating the JIRA tickets in tab separated format.
If not supplied, the script is looking for the default one 'jira_recurrent_tickets.tsv'
in the same directory as the executable.
-config Configuration parameters file, currently holds the handover deadlines, may be expanded
in the future. If not supplied, the script is looking for the default one 'jira.conf'
in the same directory as the executable.
-help | -h Prints this help text.
Reads the -tickets input file and creates JIRA tickets
EOF
exit
0
;
}
#TODO check date timeline
This diff is collapsed.
Click to expand it.
Preview
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment