Update upstream source from tag 'upstream/0.019'
Update to upstream version '0.019'
with Debian dir 25dcdd40ec1dd507bc30c6e68f636e9bf2dc9003
gregor herrmann
5 years ago
0 | 0 | Revision history for perl module JIRA-REST. -*- text -*- |
1 | ||
2 | 0.019 2018-07-28 18:00:17-03:00 America/Sao_Paulo | |
3 | ||
4 | [Changes] | |
5 | ||
6 | - JIRA::REST now requires at least Perl 5.10. Previously it required Perl | |
7 | 5.8. A new section in the documentation explains our Perl and Jira | |
8 | compatibility Policy. | |
9 | ||
10 | [Fixes] | |
11 | ||
12 | - William Carr fixed the sub_error routine teaching it yet another way Jira | |
13 | can pass error messages back. | |
14 | ||
15 | [Documentation] | |
16 | ||
17 | - Lisa Hare graciously contributed some example scripts which can be found on | |
18 | the 'examples' directory. | |
19 | ||
20 | - All mentions of 'JIRA' were changed to 'Jira', following the change | |
21 | Atlassian made in all of its site and documentation. | |
1 | 22 | |
2 | 23 | 0.018 2017-05-30 09:38:37-03:00 America/Sao_Paulo |
3 | 24 |
0 | This software is copyright (c) 2017 by CPqD <www.cpqd.com.br>. | |
0 | This software is copyright (c) 2018 by CPqD <www.cpqd.com.br>. | |
1 | 1 | |
2 | 2 | This is free software; you can redistribute it and/or modify it under |
3 | 3 | the same terms as the Perl 5 programming language system itself. |
11 | 11 | |
12 | 12 | --- The GNU General Public License, Version 1, February 1989 --- |
13 | 13 | |
14 | This software is Copyright (c) 2017 by CPqD <www.cpqd.com.br>. | |
14 | This software is Copyright (c) 2018 by CPqD <www.cpqd.com.br>. | |
15 | 15 | |
16 | 16 | This is free software, licensed under: |
17 | 17 | |
271 | 271 | |
272 | 272 | --- The Artistic License 1.0 --- |
273 | 273 | |
274 | This software is Copyright (c) 2017 by CPqD <www.cpqd.com.br>. | |
274 | This software is Copyright (c) 2018 by CPqD <www.cpqd.com.br>. | |
275 | 275 | |
276 | 276 | This is free software, licensed under: |
277 | 277 |
0 | # This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.043. | |
0 | # This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.009. | |
1 | 1 | Changes |
2 | 2 | LICENSE |
3 | 3 | MANIFEST |
6 | 6 | Makefile.PL |
7 | 7 | README.pod |
8 | 8 | dist.ini |
9 | examples/create_issue.pl | |
10 | examples/edit_issue.pl | |
11 | examples/lib/JIRACLI.pm | |
12 | examples/search.pl | |
13 | examples/transition.pl | |
9 | 14 | lib/JIRA/REST.pm |
10 | 15 | t/00-load.t |
11 | 16 | t/01-atlassian.t |
0 | 0 | { |
1 | "abstract" : "Thin wrapper around JIRA's REST API", | |
1 | "abstract" : "Thin wrapper around Jira's REST API", | |
2 | 2 | "author" : [ |
3 | 3 | "Gustavo L. de M. Chaves <gnustavo@cpan.org>" |
4 | 4 | ], |
5 | 5 | "dynamic_config" : 0, |
6 | "generated_by" : "Dist::Zilla version 5.043, CPAN::Meta::Converter version 2.150001", | |
6 | "generated_by" : "Dist::Zilla version 6.009, CPAN::Meta::Converter version 2.150010", | |
7 | 7 | "license" : [ |
8 | 8 | "perl_5" |
9 | 9 | ], |
34 | 34 | "requires" : { |
35 | 35 | "Carp" : "0", |
36 | 36 | "Config::Identity" : "0.0019", |
37 | "Encode" : "0", | |
37 | 38 | "HTML::TreeBuilder" : "0", |
38 | 39 | "HTTP::Status" : "0", |
39 | "JSON" : "0", | |
40 | "JSON" : "2.23", | |
40 | 41 | "MIME::Base64" : "0", |
41 | 42 | "Net::Netrc" : "0", |
42 | 43 | "REST::Client" : "0", |
43 | 44 | "URI" : "0", |
44 | 45 | "URI::Escape" : "0", |
45 | "perl" : "5.008_008", | |
46 | "perl" : "5.010", | |
46 | 47 | "strict" : "0", |
47 | 48 | "utf8" : "0", |
48 | 49 | "warnings" : "0" |
64 | 65 | "web" : "https://github.com/gnustavo/jira-rest" |
65 | 66 | } |
66 | 67 | }, |
67 | "version" : "0.018" | |
68 | "version" : "0.019", | |
69 | "x_serialization_backend" : "Cpanel::JSON::XS version 4.02" | |
68 | 70 | } |
69 | 71 |
0 | 0 | --- |
1 | abstract: "Thin wrapper around JIRA's REST API" | |
1 | abstract: "Thin wrapper around Jira's REST API" | |
2 | 2 | author: |
3 | 3 | - 'Gustavo L. de M. Chaves <gnustavo@cpan.org>' |
4 | 4 | build_requires: |
7 | 7 | configure_requires: |
8 | 8 | ExtUtils::MakeMaker: '0' |
9 | 9 | dynamic_config: 0 |
10 | generated_by: 'Dist::Zilla version 5.043, CPAN::Meta::Converter version 2.150001' | |
10 | generated_by: 'Dist::Zilla version 6.009, CPAN::Meta::Converter version 2.150010' | |
11 | 11 | license: perl |
12 | 12 | meta-spec: |
13 | 13 | url: http://module-build.sourceforge.net/META-spec-v1.4.html |
19 | 19 | requires: |
20 | 20 | Carp: '0' |
21 | 21 | Config::Identity: '0.0019' |
22 | Encode: '0' | |
22 | 23 | HTML::TreeBuilder: '0' |
23 | 24 | HTTP::Status: '0' |
24 | JSON: '0' | |
25 | JSON: '2.23' | |
25 | 26 | MIME::Base64: '0' |
26 | 27 | Net::Netrc: '0' |
27 | 28 | REST::Client: '0' |
28 | 29 | URI: '0' |
29 | 30 | URI::Escape: '0' |
30 | perl: 5.008_008 | |
31 | perl: '5.010' | |
31 | 32 | strict: '0' |
32 | 33 | utf8: '0' |
33 | 34 | warnings: '0' |
34 | 35 | resources: |
35 | 36 | homepage: https://metacpan.org/module/JIRA::REST |
36 | 37 | repository: https://github.com/gnustavo/JIRA-REST.git |
37 | version: '0.018' | |
38 | version: '0.019' | |
39 | x_serialization_backend: 'YAML::Tiny version 1.70' |
0 | # This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v5.043. | |
0 | # This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v6.009. | |
1 | 1 | use strict; |
2 | 2 | use warnings; |
3 | 3 | |
4 | use 5.008_008; | |
4 | use 5.010; | |
5 | 5 | |
6 | 6 | use ExtUtils::MakeMaker; |
7 | 7 | |
8 | 8 | my %WriteMakefileArgs = ( |
9 | "ABSTRACT" => "Thin wrapper around JIRA's REST API", | |
9 | "ABSTRACT" => "Thin wrapper around Jira's REST API", | |
10 | 10 | "AUTHOR" => "Gustavo L. de M. Chaves <gnustavo\@cpan.org>", |
11 | 11 | "CONFIGURE_REQUIRES" => { |
12 | 12 | "ExtUtils::MakeMaker" => 0 |
13 | 13 | }, |
14 | 14 | "DISTNAME" => "JIRA-REST", |
15 | 15 | "LICENSE" => "perl", |
16 | "MIN_PERL_VERSION" => "5.008_008", | |
16 | "MIN_PERL_VERSION" => "5.010", | |
17 | 17 | "NAME" => "JIRA::REST", |
18 | 18 | "PREREQ_PM" => { |
19 | 19 | "Carp" => 0, |
20 | 20 | "Config::Identity" => "0.0019", |
21 | "Encode" => 0, | |
21 | 22 | "HTML::TreeBuilder" => 0, |
22 | 23 | "HTTP::Status" => 0, |
23 | "JSON" => 0, | |
24 | "JSON" => "2.23", | |
24 | 25 | "MIME::Base64" => 0, |
25 | 26 | "Net::Netrc" => 0, |
26 | 27 | "REST::Client" => 0, |
34 | 35 | "Test::More" => 0, |
35 | 36 | "lib" => 0 |
36 | 37 | }, |
37 | "VERSION" => "0.018", | |
38 | "VERSION" => "0.019", | |
38 | 39 | "test" => { |
39 | 40 | "TESTS" => "t/*.t" |
40 | 41 | } |
44 | 45 | my %FallbackPrereqs = ( |
45 | 46 | "Carp" => 0, |
46 | 47 | "Config::Identity" => "0.0019", |
48 | "Encode" => 0, | |
47 | 49 | "HTML::TreeBuilder" => 0, |
48 | 50 | "HTTP::Status" => 0, |
49 | "JSON" => 0, | |
51 | "JSON" => "2.23", | |
50 | 52 | "MIME::Base64" => 0, |
51 | 53 | "Net::Netrc" => 0, |
52 | 54 | "REST::Client" => 0, |
0 | 0 | =pod |
1 | 1 | |
2 | JIRA::REST - Thin wrapper around JIRA's REST APIs | |
2 | JIRA::REST - Thin wrapper around Jira's REST APIs | |
3 | 3 | |
4 | L<JIRA|http://www.atlassian.com/software/jira> is a proprietary bug | |
4 | L<Jira|http://www.atlassian.com/software/jira> is a proprietary bug | |
5 | 5 | tracking system from |
6 | 6 | L<Atlassian|http://www.atlassian.com/software/jira/>. |
7 | 7 | |
8 | This module implements a thin wrapper around JIRA's REST APIs: | |
8 | This module implements a thin wrapper around Jira's REST APIs: | |
9 | 9 | |
10 | 10 | =over |
11 | 11 | |
12 | =item * L<JIRA Core REST API|https://docs.atlassian.com/jira/REST/server/> | |
12 | =item * L<Jira Core REST API|https://docs.atlassian.com/jira/REST/server/> | |
13 | 13 | |
14 | This rich API superseded the old L<JIRA SOAP | |
14 | This rich API superseded the old L<Jira SOAP | |
15 | 15 | API|http://docs.atlassian.com/software/jira/docs/api/rpc-jira-plugin/latest/com/atlassian/jira/rpc/soap/JiraSoapService.html> |
16 | which isn't supported anymore as of JIRA version 7. | |
16 | which isn't supported anymore as of Jira version 7. | |
17 | 17 | |
18 | =item * L<JIRA Service Desk REST API|https://docs.atlassian.com/jira-servicedesk/REST/server/> | |
18 | =item * L<Jira Service Desk REST API|https://docs.atlassian.com/jira-servicedesk/REST/server/> | |
19 | 19 | |
20 | This API deals with the objects of the JIRA Service Desk application. | |
20 | This API deals with the objects of the Jira Service Desk application. | |
21 | 21 | |
22 | =item * L<JIRA Software REST API|https://docs.atlassian.com/jira-software/REST/server/> | |
22 | =item * L<Jira Software REST API|https://docs.atlassian.com/jira-software/REST/server/> | |
23 | 23 | |
24 | This API deals with the objects of the JIRA Software application. | |
24 | This API deals with the objects of the Jira Software application. | |
25 | 25 | |
26 | 26 | =back |
27 | 27 | |
28 | Copyright (c) 2013-2016 by CPqD (http://www.cpqd.com.br/) | |
28 | Copyright (c) 2013-2018 by CPqD (http://www.cpqd.com.br/) | |
29 | 29 | |
30 | 30 | This is free software; you can redistribute it and/or modify it under |
31 | 31 | the same terms as the Perl 5 programming language system itself. |
0 | #!/usr/bin/env perl | |
1 | ||
2 | use 5.010; | |
3 | use utf8; | |
4 | use strict; | |
5 | use warnings; | |
6 | use FindBin; | |
7 | use lib "$FindBin::Bin/lib"; | |
8 | use Getopt::Long::Descriptive; | |
9 | use JIRACLI qw/get_credentials/; | |
10 | ||
11 | my ($opt, $usage) = describe_options( | |
12 | '%c %o', | |
13 | ['jiraurl=s', "JIRA server base URL", {default => 'https://jira.cpqd.com.br'}], | |
14 | ['project|p=s', "Project to create issue under", {required => 1}], | |
15 | ['summary|s=s', "Issue summary", {required => 1}], | |
16 | ['description|d=s', "Issue description", {required => 1}], | |
17 | ['help|h', "Print usage message and exit"], | |
18 | {show_defaults => 1}, | |
19 | ); | |
20 | ||
21 | if ($opt->help) { | |
22 | print $usage->text; | |
23 | exit 0; | |
24 | } | |
25 | ||
26 | my $jira = JIRA::REST->new( | |
27 | $opt->jiraurl, | |
28 | get_credentials(), | |
29 | ); | |
30 | ||
31 | my $data = { | |
32 | fields => { | |
33 | project => { | |
34 | key => $opt->project | |
35 | }, | |
36 | summary => $opt->summary, | |
37 | description => $opt->description, | |
38 | issuetype => { | |
39 | name => 'Bug' | |
40 | } | |
41 | } | |
42 | }; | |
43 | ||
44 | my $res = $jira->POST('/issue', undef, $data); | |
45 | ||
46 | print "Issue created ID: $res->{id}\n"; | |
47 | ||
48 | __END__ | |
49 | =encoding utf8 | |
50 | ||
51 | =head1 NAME | |
52 | ||
53 | create_issue.pl - Creates an issue | |
54 | ||
55 | =head1 SYNOPSIS | |
56 | ||
57 | create_issue.pl [-hn] [long options...] | |
58 | --jiraurl STR JIRA server base URL | |
59 | (default value: https://jira.cpqd.com.br) | |
60 | --project STR The project key | |
61 | --summary STR Issue Summary | |
62 | --description Issue Description | |
63 | -h --help Print usage message and exit | |
64 | ||
65 | =head1 DESCRIPTION | |
66 | ||
67 | This script creates an issue | |
68 | ||
69 | =back | |
70 | ||
71 | =head1 ENVIRONMENT | |
72 | ||
73 | See the L<JIRACLI> documentation. | |
74 | ||
75 | =head1 COPYRIGHT | |
76 | ||
77 | Copyright 2016 CPqD. | |
78 | ||
79 | This program is free software; you can redistribute it and/or modify | |
80 | it under the same terms as Perl itself. | |
81 | ||
82 | =head1 AUTHOR | |
83 | ||
84 | Lisa Hare <lharey@gmail.com>⏎ |
0 | #!/usr/bin/env perl | |
1 | ||
2 | use 5.010; | |
3 | use utf8; | |
4 | use strict; | |
5 | use warnings; | |
6 | use FindBin; | |
7 | use lib "$FindBin::Bin/lib"; | |
8 | use Getopt::Long::Descriptive; | |
9 | use JIRACLI qw/get_credentials/; | |
10 | ||
11 | my ($opt, $usage) = describe_options( | |
12 | '%c %o', | |
13 | ['jiraurl=s', "JIRA server base URL", {default => 'https://jira.cpqd.com.br'}], | |
14 | ['issue|i=s', "Key of the issue to progress", {required => 1}], | |
15 | ['assign|a=s@', "Set of KEY[.ATTR]=VALUE assignments to perform", { required => 1 }], | |
16 | ['nonotify', "Supress email notification about the change."], | |
17 | ['help|h', "Print usage message and exit"], | |
18 | {show_defaults => 1}, | |
19 | ); | |
20 | ||
21 | if ($opt->help) { | |
22 | print $usage->text; | |
23 | exit 0; | |
24 | } | |
25 | ||
26 | my $jira = JIRA::REST->new( | |
27 | $opt->jiraurl, | |
28 | get_credentials(), | |
29 | ); | |
30 | ||
31 | my %assignments; | |
32 | foreach my $assign (@{$opt->assign}) { | |
33 | if (my ($key, $value) = ($assign =~ /(.+?)=(.+)/)) { | |
34 | if (my ($kkey, $attr) = ($key =~ /(.+?)\.(.+)/)) { | |
35 | if (!$assignments{$kkey}) { | |
36 | $assignments{$kkey} = {}; | |
37 | } | |
38 | $assignments{$kkey}{$attr} = $value; | |
39 | } else { | |
40 | $assignments{$key} = $value; | |
41 | } | |
42 | } else { | |
43 | die "Invalid assignment specification: $assign"; | |
44 | } | |
45 | } | |
46 | ||
47 | my $data = { fields => \%assignments }; | |
48 | $data->{notifyUsers} = 'false' if $opt->nonotify; | |
49 | ||
50 | $jira->PUT("/issue/@{[$opt->issue]}", undef, $data); | |
51 | ||
52 | __END__ | |
53 | =encoding utf8 | |
54 | ||
55 | =head1 NAME | |
56 | ||
57 | edit_issue.pl - Edit a JIRA issue | |
58 | ||
59 | =head1 SYNOPSIS | |
60 | ||
61 | edit.pl [-h] [long options...] | |
62 | --jiraurl STR JIRA server base URL | |
63 | (default value: https://jira.cpqd.com.br) | |
64 | --issue STR Key of the issue to progress | |
65 | --assign STR... Set of KEY[.ATTR]=VALUE assignments to perform | |
66 | --nonotify Supress email notification about the change. | |
67 | -h --help Print usage message and exit | |
68 | ||
69 | =head1 DESCRIPTION | |
70 | ||
71 | This script edits a JIRA issue, changing its fields. | |
72 | ||
73 | =head1 OPTIONS | |
74 | ||
75 | Common options are specified in the L<JIRACLI> documentation. Specific | |
76 | options are defined below: | |
77 | ||
78 | =over | |
79 | ||
80 | =item * B<--issue STR> | |
81 | ||
82 | Specifies the issue by its key (e.g. HD-1234). | |
83 | ||
84 | =item * B<--assign STR...> | |
85 | ||
86 | This multi-valued option specifies which fields are to be changed. | |
87 | ||
88 | Numeric, date, or string fields can be specified like this: | |
89 | ||
90 | --assign="summary=New summary" | |
91 | --assign="duedate=2017-01-01" | |
92 | ||
93 | Structured fields may need the name of an attribute to be assigned: | |
94 | ||
95 | --assign="assignee.name=gustavo" | |
96 | --assign="assignee.emailAddress=gustavo@cpqd.com.br" | |
97 | ||
98 | =item * B<--nonotify> | |
99 | ||
100 | By default JIRA sends email notifications to all parties involved in an | |
101 | issue when it's changed. This option supresses those notifications. However, | |
102 | admin or project admin permissions are required to disable the notification. | |
103 | ||
104 | =back | |
105 | ||
106 | =head1 ENVIRONMENT | |
107 | ||
108 | See the L<JIRACLI> documentation. | |
109 | ||
110 | =head1 COPYRIGHT | |
111 | ||
112 | Copyright 2016 CPqD. | |
113 | ||
114 | This program is free software; you can redistribute it and/or modify | |
115 | it under the same terms as Perl itself. | |
116 | ||
117 | =head1 AUTHOR | |
118 | ||
119 | Gustavo Chaves <gustavo@cpqd.com.br> | |
120 | Lisa Hare <lharey@gmail.com> |
0 | #!/usr/bin/env perl | |
1 | ||
2 | use 5.010; | |
3 | use utf8; | |
4 | use strict; | |
5 | use warnings; | |
6 | ||
7 | package JIRACLI; | |
8 | ||
9 | use JIRA::REST; | |
10 | ||
11 | use vars qw($VERSION @ISA @EXPORT_OK); | |
12 | ||
13 | require Exporter; | |
14 | ||
15 | @ISA = qw(Exporter); | |
16 | @EXPORT_OK = qw(get_credentials); | |
17 | $VERSION = '0.01'; | |
18 | ||
19 | sub get_credentials { | |
20 | ||
21 | my ($user, $pass) = @ENV{'jirauser', 'jirapass'}; | |
22 | ||
23 | return ($user, $pass) if defined $user && defined $pass; | |
24 | ||
25 | if (! -t STDIN) { | |
26 | die "Cannot prompt user for credentials because STDIN isn't a terminal. Please set environment variables jirauser and jirapass\n"; | |
27 | } | |
28 | ||
29 | require Term::Prompt; | |
30 | Term::Prompt->import(); | |
31 | ||
32 | if (!defined $user) { | |
33 | $user = prompt('x', "Enter Username: ", '', ''); | |
34 | } | |
35 | ||
36 | if (! defined $pass) { | |
37 | $pass = prompt('p', "Enter Password: ", '', ''); | |
38 | print "\n"; | |
39 | } | |
40 | ||
41 | return ($user, $pass); | |
42 | } | |
43 | ||
44 | 1; | |
45 | __END__ | |
46 | =encoding utf8 | |
47 | ||
48 | =head1 NAME | |
49 | ||
50 | JIRACLI - Common utilities for all JIRA CLI examples | |
51 | ||
52 | =head1 SYNOPSIS | |
53 | ||
54 | use lib $FindBin::Bin; | |
55 | use JIRACLI; | |
56 | ||
57 | =head1 DESCRIPTION | |
58 | ||
59 | This module contains a few functions used by most of the JIRA CLI examples | |
60 | ||
61 | =head1 FUNCTIONS | |
62 | ||
63 | =head2 get_credentials | |
64 | ||
65 | my ($user, $pass) = get_credentials(); | |
66 | ||
67 | This function will first check for user and password specified in the | |
68 | environment variables jirauser and jirpass. | |
69 | ||
70 | If no environment variables set will prompt interactively for entry of user and password | |
71 | ||
72 | =over | |
73 | ||
74 | =head1 COPYRIGHT | |
75 | ||
76 | Copyright 2016 CPqD. | |
77 | ||
78 | This program is free software; you can redistribute it and/or modify | |
79 | it under the same terms as Perl itself. | |
80 | ||
81 | =head1 AUTHOR | |
82 | ||
83 | Gustavo Chaves <gustavo@cpqd.com.br> |
0 | #!/usr/bin/env perl | |
1 | ||
2 | # perl -Ilib examples/search.pl --jiraurl https://lharey.atlassian.net --jql "assignee = 'Lisa Hare'" | |
3 | ||
4 | use 5.010; | |
5 | use strict; | |
6 | use warnings; | |
7 | use FindBin; | |
8 | use lib "$FindBin::Bin/lib"; | |
9 | use Getopt::Long::Descriptive; | |
10 | use JIRACLI qw/get_credentials/; | |
11 | ||
12 | ||
13 | my ($opt, $usage) = describe_options( | |
14 | '%c %o', | |
15 | ['jiraurl=s', "JIRA server base URL", {default => 'https://jira.cpqd.com.br'}], | |
16 | ['jql=s', "JQL query expression", {required => 1}], | |
17 | ['help|h', "Print usage message and exit"], | |
18 | {show_defaults => 1}, | |
19 | ); | |
20 | ||
21 | if ($opt->help) { | |
22 | print $usage->text; | |
23 | exit 0; | |
24 | } | |
25 | ||
26 | my $jira = JIRA::REST->new( | |
27 | $opt->jiraurl, | |
28 | get_credentials(), | |
29 | ); | |
30 | ||
31 | $jira->set_search_iterator({ | |
32 | jql => $opt->jql, | |
33 | fields => [qw/summary issuetype status priority assignee reporter/], | |
34 | }); | |
35 | ||
36 | while (my $issue = $jira->next_issue) { | |
37 | my $fields = $issue->{fields}; | |
38 | print "ID: $issue->{id}\n"; | |
39 | print "Summary: $fields->{summary}\n"; | |
40 | print "Type: $fields->{issuetype}{name}\n"; | |
41 | print "Status: $fields->{status}{name}\n"; | |
42 | print "Priority: $fields->{priority}{name}\n"; | |
43 | print "Assignee: $fields->{assignee}{name}\n"; | |
44 | print "Reporter: $fields->{reporter}{name}\n\n"; | |
45 | } | |
46 | ||
47 | __END__ | |
48 | ||
49 | =head1 NAME | |
50 | ||
51 | search.pl - Search JIRA issues by a JQL filter | |
52 | ||
53 | =head1 SYNOPSIS | |
54 | ||
55 | search.pl [-hn] [long options...] | |
56 | --jiraurl STR JIRA server base URL | |
57 | (default value: https://jira.cpqd.com.br) | |
58 | --jql STR JQL query expression | |
59 | -h --help Print usage message and exit | |
60 | ||
61 | =head1 DESCRIPTION | |
62 | ||
63 | This script searches JIRA issues by a JQL filter, printing their keys on | |
64 | STDOUT, one per line, or more information about them, depending on the | |
65 | options given. | |
66 | ||
67 | =head1 OPTIONS | |
68 | ||
69 | =over | |
70 | ||
71 | =item * B<--jql STR> | |
72 | ||
73 | Specifies the L<JQL | |
74 | expression|https://confluence.atlassian.com/jirasoftwareserver072/advanced-searching-829057400.html> | |
75 | used to search for issues. | |
76 | ||
77 | =item * B<--jiraurl STR> | |
78 | ||
79 | The JIRA server base url | |
80 | ||
81 | =back | |
82 | ||
83 | =head1 ENVIRONMENT | |
84 | ||
85 | See the L<JIRACLI> documentation. | |
86 | ||
87 | =head1 COPYRIGHT | |
88 | ||
89 | Copyright 2016 CPqD. | |
90 | ||
91 | This program is free software; you can redistribute it and/or modify | |
92 | it under the same terms as Perl itself. | |
93 | ||
94 | =head1 AUTHOR | |
95 | ||
96 | Gustavo Chaves <gustavo@cpqd.com.br> | |
97 | Lisa Hare <lharey@gmail.com> |
0 | #!/usr/bin/env perl | |
1 | ||
2 | use 5.010; | |
3 | use utf8; | |
4 | use strict; | |
5 | use autodie; | |
6 | use warnings; | |
7 | use FindBin; | |
8 | use lib "$FindBin::Bin/lib"; | |
9 | use Getopt::Long::Descriptive; | |
10 | use JIRACLI qw/get_credentials/; | |
11 | ||
12 | my ($opt, $usage) = describe_options( | |
13 | '%c %o', | |
14 | ['jiraurl=s', "JIRA server base URL", {default => 'https://jira.cpqd.com.br'}], | |
15 | ['issue|i=s', "Key of the issue to progress", {required => 1}], | |
16 | ['transition-id|t=i', "ID of the transition to make", {required => 1}], | |
17 | ['resolution|r=s', "Resolution name to set"], | |
18 | ['comment|c=s', "Comment string to insert during transition"], | |
19 | ['help|h', "Print usage message and exit"], | |
20 | {show_defaults => 1}, | |
21 | ); | |
22 | ||
23 | if ($opt->help) { | |
24 | print $usage->text; | |
25 | exit 0; | |
26 | } | |
27 | ||
28 | my $jira = JIRA::REST->new( | |
29 | $opt->jiraurl, | |
30 | get_credentials(), | |
31 | ); | |
32 | ||
33 | my $data = { | |
34 | transition => { id => $opt->transition_id }, | |
35 | }; | |
36 | ||
37 | $data->{fields}{resolution} = { name => $opt->resolution } if $opt->resolution; | |
38 | $data->{update}{comment} = [{ add => { body => $opt->comment }}] if $opt->comment; | |
39 | ||
40 | $jira->POST("/issue/@{[$opt->issue]}/transitions", undef, $data); | |
41 | ||
42 | ||
43 | __END__ | |
44 | =encoding utf8 | |
45 | ||
46 | =head1 NAME | |
47 | ||
48 | transition.pl - Make a transition in a JIRA issue | |
49 | ||
50 | =head1 SYNOPSIS | |
51 | ||
52 | transition.pl [-hn] [long options...] | |
53 | --jiraurl STR JIRA server base URL | |
54 | (default value: https://jira.cpqd.com.br) | |
55 | --issue STR Key of the issue to progress | |
56 | --transition-id INT ID of the transition to make | |
57 | --resolution STR Resolution name to set | |
58 | --comment STR Comment string to insert during transition | |
59 | -n --dont Do not change anything | |
60 | -h --help Print usage message and exit | |
61 | ||
62 | =head1 DESCRIPTION | |
63 | ||
64 | This script makes a JIRA issue transition through its workflow. | |
65 | ||
66 | =head1 OPTIONS | |
67 | ||
68 | Common options are specified in the L<JIRACLI> documentation. Specific | |
69 | options are defined below: | |
70 | ||
71 | =over | |
72 | ||
73 | =item * B<--issue STR> | |
74 | ||
75 | Specifies the issue by its key (e.g. HD-1234). | |
76 | ||
77 | =item * B<--transition-id INT> | |
78 | ||
79 | Specifies the transition that should be performed by its numeric ID. You can | |
80 | grok it by hovering the mouse over the transition button and looking for the | |
81 | C<action=N> part in its URL. | |
82 | ||
83 | =item * B<--resolution STR> | |
84 | ||
85 | If the transition leads to a terminal state you can specify a Resolution to | |
86 | be set. | |
87 | ||
88 | =item * B<--comment STR> | |
89 | ||
90 | Specifies a comment to be added to the issue during the transition. Note | |
91 | that the comment will not be added if the transition doesn't have a screen | |
92 | associated with it. | |
93 | ||
94 | =back | |
95 | ||
96 | =head1 ENVIRONMENT | |
97 | ||
98 | See the L<JIRACLI> documentation. | |
99 | ||
100 | =head1 COPYRIGHT | |
101 | ||
102 | Copyright 2016 CPqD. | |
103 | ||
104 | This program is free software; you can redistribute it and/or modify | |
105 | it under the same terms as Perl itself. | |
106 | ||
107 | =head1 AUTHOR | |
108 | ||
109 | Gustavo Chaves <gustavo@cpqd.com.br> | |
110 | Lisa Hare <lharey@gmail.com> |
0 | 0 | package JIRA::REST; |
1 | # ABSTRACT: Thin wrapper around JIRA's REST API | |
2 | $JIRA::REST::VERSION = '0.018'; | |
3 | use 5.008_008; | |
1 | # ABSTRACT: Thin wrapper around Jira's REST API | |
2 | $JIRA::REST::VERSION = '0.019'; | |
3 | use 5.010; | |
4 | 4 | use utf8; |
5 | 5 | use strict; |
6 | 6 | use warnings; |
7 | 7 | |
8 | 8 | use Carp; |
9 | 9 | use URI; |
10 | use Encode; | |
10 | 11 | use MIME::Base64; |
11 | 12 | use URI::Escape; |
12 | use JSON; | |
13 | use JSON 2.23; | |
13 | 14 | use REST::Client; |
14 | 15 | |
15 | 16 | sub new { |
65 | 66 | } |
66 | 67 | |
67 | 68 | for ($args{rest_client_config}) { |
68 | $_ = {} unless defined; | |
69 | $_ //= {}; | |
69 | 70 | croak __PACKAGE__ . "::new: 'rest_client_config' argument must be a hash reference.\n" |
70 | 71 | unless defined && ref && ref eq 'HASH'; |
71 | 72 | } |
74 | 75 | # This is deprecated since v0.017 |
75 | 76 | if (my $proxy = delete $args{rest_client_config}{proxy}) { |
76 | 77 | carp __PACKAGE__ . "::new: passing 'proxy' in the 'rest_client_config' hash is deprecated. Please, use the corresponding argument instead.\n"; |
77 | $args{proxy} = $proxy unless defined $args{proxy}; | |
78 | $args{proxy} //= $proxy; | |
78 | 79 | } |
79 | 80 | |
80 | 81 | my $rest = REST::Client->new($args{rest_client_config}); |
85 | 86 | # Follow redirects/authentication by default |
86 | 87 | $rest->setFollow(1); |
87 | 88 | |
88 | # Since JIRA doesn't send an authentication challenge, we force the | |
89 | # Since Jira doesn't send an authentication challenge, we force the | |
89 | 90 | # sending of the authentication header. |
90 | 91 | $rest->addHeader(Authorization => 'Basic ' . encode_base64("$args{username}:$args{password}")) |
91 | 92 | unless $args{anonymous}; |
178 | 179 | } elsif ($type =~ m:application/json:) { |
179 | 180 | my $error = $self->{json}->decode($content); |
180 | 181 | if (ref $error eq 'HASH') { |
181 | # JIRA errors may be laid out in all sorts of ways. You have to | |
182 | # Jira errors may be laid out in all sorts of ways. You have to | |
182 | 183 | # look them up from the scant documentation at |
183 | 184 | # https://docs.atlassian.com/jira/REST/latest/. |
184 | 185 | |
195 | 196 | if (my $errors = $error->{errors}) { |
196 | 197 | $msg .= "- [$_] $errors->{$_}\n" foreach sort keys %$errors; |
197 | 198 | } |
199 | ||
200 | # some give us a single message in 'errorMessage' | |
201 | $msg .= $error->{errorMessage} . qq{\n} if $error->{errorMessage}; | |
198 | 202 | } else { |
199 | 203 | $msg .= $content; |
200 | 204 | } |
274 | 278 | $path = $self->_build_path($path, $query); |
275 | 279 | |
276 | 280 | $headers ||= {}; |
277 | $headers->{'Content-Type'} = 'application/json;charset=UTF-8' | |
278 | unless defined $headers->{'Content-Type'}; | |
281 | $headers->{'Content-Type'} //= 'application/json;charset=UTF-8'; | |
279 | 282 | |
280 | 283 | $self->{rest}->PUT($path, $self->{json}->encode($value), $headers); |
281 | 284 | |
291 | 294 | $path = $self->_build_path($path, $query); |
292 | 295 | |
293 | 296 | $headers ||= {}; |
294 | $headers->{'Content-Type'} = 'application/json;charset=UTF-8' | |
295 | unless defined $headers->{'Content-Type'}; | |
297 | $headers->{'Content-Type'} //= 'application/json;charset=UTF-8'; | |
296 | 298 | |
297 | 299 | $self->{rest}->POST($path, $self->{json}->encode($value), $headers); |
298 | 300 | |
354 | 356 | %{$rest->{_headers}}, |
355 | 357 | 'X-Atlassian-Token' => 'nocheck', |
356 | 358 | 'Content-Type' => 'form-data', |
357 | 'Content' => [ file => [$file, Encode::encode_utf8( $file )] ], | |
359 | 'Content' => [ file => [$file, encode_utf8( $file )] ], | |
358 | 360 | ); |
359 | 361 | |
360 | 362 | $response->is_success |
372 | 374 | |
373 | 375 | =head1 NAME |
374 | 376 | |
375 | JIRA::REST - Thin wrapper around JIRA's REST API | |
377 | JIRA::REST - Thin wrapper around Jira's REST API | |
376 | 378 | |
377 | 379 | =head1 VERSION |
378 | 380 | |
379 | version 0.018 | |
381 | version 0.019 | |
380 | 382 | |
381 | 383 | =head1 SYNOPSIS |
382 | 384 | |
429 | 431 | |
430 | 432 | =head1 DESCRIPTION |
431 | 433 | |
432 | L<JIRA|http://www.atlassian.com/software/jira/> is a proprietary bug | |
434 | L<Jira|http://www.atlassian.com/software/jira/> is a proprietary bug | |
433 | 435 | tracking system from Atlassian. |
434 | 436 | |
435 | This module implements a very thin wrapper around JIRA's REST APIs: | |
437 | This module implements a very thin wrapper around Jira's REST APIs: | |
436 | 438 | |
437 | 439 | =over |
438 | 440 | |
439 | =item * L<JIRA Core REST API|https://docs.atlassian.com/jira/REST/server/> | |
440 | ||
441 | This rich API superseded the old L<JIRA SOAP | |
441 | =item * L<Jira Core REST API|https://docs.atlassian.com/jira/REST/server/> | |
442 | ||
443 | This rich API superseded the old L<Jira SOAP | |
442 | 444 | API|http://docs.atlassian.com/software/jira/docs/api/rpc-jira-plugin/latest/com/atlassian/jira/rpc/soap/JiraSoapService.html> |
443 | which isn't supported anymore as of JIRA version 7. | |
445 | which isn't supported anymore as of Jira version 7. | |
444 | 446 | |
445 | 447 | The endpoints of this API have a path prefix of C</rest/api/VERSION>. |
446 | 448 | |
447 | =item * L<JIRA Service Desk REST API|https://docs.atlassian.com/jira-servicedesk/REST/server/> | |
448 | ||
449 | This API deals with the objects of the JIRA Service Desk application. Its | |
449 | =item * L<Jira Service Desk REST API|https://docs.atlassian.com/jira-servicedesk/REST/server/> | |
450 | ||
451 | This API deals with the objects of the Jira Service Desk application. Its | |
450 | 452 | endpoints have a path prefix of C</rest/servicedeskapi>. |
451 | 453 | |
452 | =item * L<JIRA Software REST API|https://docs.atlassian.com/jira-software/REST/server/> | |
453 | ||
454 | This API deals with the objects of the JIRA Software application. Its | |
454 | =item * L<Jira Software REST API|https://docs.atlassian.com/jira-software/REST/server/> | |
455 | ||
456 | This API deals with the objects of the Jira Software application. Its | |
455 | 457 | endpoints have a path prefix of C</rest/agile/VERSION>. |
456 | 458 | |
457 | 459 | =back |
475 | 477 | |
476 | 478 | =item * B<url> |
477 | 479 | |
478 | A string or a URI object denoting the base URL of the JIRA server. This is a | |
480 | A string or a URI object denoting the base URL of the Jira server. This is a | |
479 | 481 | required argument. |
480 | 482 | |
481 | 483 | The REST methods described below all accept as a first argument the |
503 | 505 | |
504 | 506 | =item * B<password> |
505 | 507 | |
506 | The username and password of a JIRA user to use for authentication. | |
508 | The username and password of a Jira user to use for authentication. | |
507 | 509 | |
508 | 510 | If B<anonymous> is false then, if either B<username> or B<password> isn't |
509 | 511 | defined the module looks them up in either the C<.netrc> file or via |
535 | 537 | |
536 | 538 | Sets the C<SSL_verify_mode> and C<verify_hostname ssl> options on the |
537 | 539 | underlying L<REST::Client>'s user agent to 0, thus disabling them. This |
538 | allows access to JIRA servers that have self-signed certificates that don't | |
540 | allows access to Jira servers that have self-signed certificates that don't | |
539 | 541 | pass L<LWP::UserAgent>'s verification methods. |
540 | 542 | |
541 | 543 | =item * B<anonymous> |
542 | 544 | |
543 | Tells the module that you want to connect to the specified JIRA server with | |
544 | no username or password. This way you can access public JIRA servers | |
545 | Tells the module that you want to connect to the specified Jira server with | |
546 | no username or password. This way you can access public Jira servers | |
545 | 547 | without needing to authenticate. |
546 | 548 | |
547 | 549 | =back |
548 | 550 | |
549 | 551 | =head1 REST METHODS |
550 | 552 | |
551 | JIRA's REST API documentation lists dozens of "resources" which can be | |
553 | Jira's REST API documentation lists dozens of "resources" which can be | |
552 | 554 | operated via the standard HTTP requests: GET, DELETE, PUT, and |
553 | 555 | POST. JIRA::REST objects implement four methods called GET, DELETE, |
554 | PUT, and POST to make it easier to invoke and get results from JIRA's | |
556 | PUT, and POST to make it easier to invoke and get results from Jira's | |
555 | 557 | REST endpoints. |
556 | 558 | |
557 | 559 | All four methods need two arguments: |
565 | 567 | information about an issue you pass |
566 | 568 | C</rest/servicedeskapi/request/$key/sla>. |
567 | 569 | |
568 | If you're using a method form JIRA Core REST API you may omit the prefix | |
570 | If you're using a method form Jira Core REST API you may omit the prefix | |
569 | 571 | C</rest/api/VERSION>. For example, to GET the list of all fields you may |
570 | 572 | pass just C</field>. |
571 | 573 | |
597 | 599 | L<JSON|http://www.json.org/> string using the C<JSON::encode> method |
598 | 600 | and sent with a Content-Type of C<application/json>. |
599 | 601 | |
600 | It's usually easy to infer from the JIRA REST API documentation which | |
602 | It's usually easy to infer from the Jira REST API documentation which | |
601 | 603 | kind of value you should pass to each resource. |
602 | 604 | |
603 | 605 | This argument is required. |
670 | 672 | It must be called before calls to B<next_issue>. |
671 | 673 | |
672 | 674 | PARAMS must conform with the query parameters allowed for the |
673 | C</rest/api/2/search> JIRA REST endpoint. | |
675 | C</rest/api/2/search> Jira REST endpoint. | |
674 | 676 | |
675 | 677 | =head2 B<next_issue> |
676 | 678 | |
690 | 692 | just the C<REST::Client> interface. This utility method offers an easier |
691 | 693 | interface to attach files to issues. |
692 | 694 | |
695 | =head1 PERL AND JIRA COMPATIBILITY POLICY | |
696 | ||
697 | Currently L<JIRA::REST> requires Perl 5.10 and supports Jira 7.0. | |
698 | ||
699 | We try to be compatible with the Perl native packages of the oldest L<Ubuntu | |
700 | LTS|https://www.ubuntu.com/info/release-end-of-life> and | |
701 | L<CentOS|https://wiki.centos.org/About/Product> Linux distributions still | |
702 | getting maintainance updates. | |
703 | ||
704 | +-----------------------+------+-------------+ | |
705 | | Distro | Perl | End of Life | | |
706 | +-----------------------+------+-------------+ | |
707 | | Ubuntu 14.04 (trusty) | 5.18 | 2019-04 | | |
708 | | Ubuntu 16.04 (xenial) | 5.22 | 2021-04 | | |
709 | | Ubuntu 18.04 (bionic) | 5.26 | 2023-04 | | |
710 | | CentOS 6 | 5.10 | 2020-12 | | |
711 | | CentOS 7 | 5.16 | 2024-07 | | |
712 | +-----------------------+------+-------------+ | |
713 | ||
714 | As you can see, we're kept behind mostly by the slow pace of CentOS (actually, | |
715 | RHEL) releases. | |
716 | ||
717 | As for Jira, the policy is very lax. I (the author) only test L<JIRA::REST> on | |
718 | the Jira server installed in the company I work for, which is usually (but not | |
719 | always) at most one year older than the newest released version. I don't have | |
720 | yet an easy way to test it on different versions. | |
721 | ||
693 | 722 | =head1 SEE ALSO |
694 | 723 | |
695 | 724 | =over |
700 | 729 | |
701 | 730 | =item * C<JIRA::Client::REST> |
702 | 731 | |
703 | This is another module implementing JIRA's REST API using | |
732 | This is another module implementing Jira's REST API using | |
704 | 733 | L<SPORE|https://github.com/SPORE/specifications/blob/master/spore_description.pod>. |
705 | 734 | I got a message from the author saying that he doesn't intend to keep |
706 | 735 | it going. |
717 | 746 | |
718 | 747 | =head1 COPYRIGHT AND LICENSE |
719 | 748 | |
720 | This software is copyright (c) 2017 by CPqD <www.cpqd.com.br>. | |
749 | This software is copyright (c) 2018 by CPqD <www.cpqd.com.br>. | |
721 | 750 | |
722 | 751 | This is free software; you can redistribute it and/or modify it under |
723 | 752 | the same terms as the Perl 5 programming language system itself. |
28 | 28 | } |
29 | 29 | |
30 | 30 | for my $info (eval {$jira->GET('/serverInfo')}) { |
31 | ok(defined $info && $info->{serverTitle} eq 'Atlassian JIRA', 'GET /serverInfo'); | |
31 | ok(defined $info && $info->{serverTitle} =~ /Atlassian/, 'GET /serverInfo'); | |
32 | 32 | } |
33 | 33 | |
34 | 34 | $jira->set_search_iterator({ |
1 | 1 | |
2 | 2 | BEGIN { |
3 | 3 | unless ($ENV{AUTHOR_TESTING}) { |
4 | require Test::More; | |
5 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
4 | print qq{1..0 # SKIP these tests are for testing by the author\n}; | |
5 | exit | |
6 | 6 | } |
7 | 7 | } |
8 | 8 |