View | Details | Raw Unified | Return to bug 6473
Collapse All | Expand All

(-)a/lib/GitBz/Commands/Attach.pm (-12 / +130 lines)
Lines 16-25 package GitBz::Commands::Attach; Link Here
16
# along with git-bz; if not, see <https://www.gnu.org/licenses>.
16
# along with git-bz; if not, see <https://www.gnu.org/licenses>.
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
20
use utf8;
21
19
use Getopt::Long qw(GetOptionsFromArray);
22
use Getopt::Long qw(GetOptionsFromArray);
20
use Try::Tiny    qw(catch try);
23
use Try::Tiny    qw(catch try);
24
use File::Temp;
21
use GitBz::Git;
25
use GitBz::Git;
22
use GitBz::Exception;
26
use GitBz::Exception;
27
use GitBz::StatusWorkflow;
23
28
24
sub new {
29
sub new {
25
    my ( $class, $commands ) = @_;
30
    my ( $class, $commands ) = @_;
Lines 29-45 sub new { Link Here
29
sub execute {
34
sub execute {
30
    my ( $self, @args ) = @_;
35
    my ( $self, @args ) = @_;
31
36
32
    my %opts = (
37
    my %opts;
33
        'add-url' => undef,
34
    );
35
38
36
    GetOptionsFromArray(
39
    GetOptionsFromArray(
37
        \@args,
40
        \@args,
38
        'edit|e'       => \$opts{edit},
41
        'edit|e' => \$opts{edit},
39
        'mail|m'       => \$opts{mail},
40
        'add-url|u'    => \$opts{'add-url'},
41
        'no-add-url|n' => sub { $opts{'add-url'} = 0 },
42
        'bugzilla|b=s' => \$opts{bugzilla},
43
    ) or GitBz::Exception->throw("Invalid options");
42
    ) or GitBz::Exception->throw("Invalid options");
44
43
45
    return try {
44
    return try {
Lines 91-111 sub attach_patches { Link Here
91
    my ( $self, $bug_ref, $commits, $opts ) = @_;
90
    my ( $self, $bug_ref, $commits, $opts ) = @_;
92
91
93
    my $client = $self->{commands}->{client};
92
    my $client = $self->{commands}->{client};
94
93
    my $bug = $client->get_bug($bug_ref);
94
    
95
    my $is_first = 1;
95
    for my $commit (@$commits) {
96
    for my $commit (@$commits) {
96
        my $patch    = GitBz::Git->format_patch( $commit->{id} . '^..' . $commit->{id} );
97
        my $patch    = GitBz::Git->format_patch( $commit->{id} . '^..' . $commit->{id} );
97
        my $filename = sprintf( "%s.patch", substr( $commit->{id}, 0, 7 ) );
98
        my $filename = sprintf( "%s.patch", substr( $commit->{id}, 0, 7 ) );
99
        my $description = $commit->{subject};
100
        my $body = GitBz::Git->run( 'log', '--format=%b', '-1', $commit->{id} );
101
        my $comment = $body || "Patch from commit " . substr( $commit->{id}, 0, 7 );
102
        my @obsoletes;
103
        
104
        if ( $opts->{edit} && $is_first ) {
105
            ( $description, $comment, my $obsoletes_ref ) = $self->edit_attachment_comment( $bug, $commit );
106
            @obsoletes = @$obsoletes_ref if $obsoletes_ref;
107
        }
98
108
99
        $client->add_attachment(
109
        $client->add_attachment(
100
            $bug_ref,
110
            $bug_ref,
101
            $patch,
111
            $patch,
102
            $filename,
112
            $filename,
103
            $commit->{subject},
113
            $description,
104
            comment => "Patch from commit " . substr( $commit->{id}, 0, 7 )
114
            comment => $comment,
115
            obsoletes => \@obsoletes
105
        );
116
        );
106
117
107
        print "Attached: $commit->{subject}\n";
118
        print "Attached: $description\n";
119
        $is_first = 0;
120
    }
121
}
122
123
sub edit_attachment_comment {
124
    my ( $self, $bug, $commit ) = @_;
125
126
    my $template = "";
127
    $template .= "# Attachment to Bug $bug->{id} - $bug->{summary}\n\n";
128
    $template .= $commit->{subject} . "\n\n";
129
    
130
    # Add commit body as initial comment
131
    my $body = GitBz::Git->run( 'log', '--format=%b', '-1', $commit->{id} );
132
    $template .= $body . "\n\n" if $body;
133
    
134
    # Show existing patches for obsoleting
135
    if ( $bug->{attachments} && @{ $bug->{attachments} } ) {
136
        for my $patch ( @{ $bug->{attachments} } ) {
137
            next unless $patch->{is_patch};
138
            my $obsoleted = ( $commit->{subject} eq $patch->{summary} ) ? "" : "#";
139
            $template .= "${obsoleted}Obsoletes: $patch->{id} - $patch->{summary}\n";
140
        }
141
        $template .= "\n";
142
    }
143
    
144
    # Add status options
145
    my $client = $self->{commands}->{client};
146
    my $workflow = GitBz::StatusWorkflow->new($client);
147
    $template .= "# Current status: $bug->{status}\n";
148
    my $status_values = $workflow->get_next_status_values($bug->{status});
149
    for my $status (@$status_values) {
150
        $template .= "# Status: $status\n";
151
    }
152
    $template .= "\n";
153
    
154
    # Add patch complexity options
155
    my $complexity = $bug->{cf_patch_complexity} || "";
156
    $template .= "# Current patch-complexity: $complexity\n";
157
    my $complexity_values = $client->get_field_values('cf_patch_complexity');
158
    if ($complexity_values) {
159
        for my $comp (@$complexity_values) {
160
            $template .= "# Patch-complexity: $comp\n";
161
        }
162
    }
163
    $template .= "\n";
164
    
165
    # Add depends options
166
    my $depends = $bug->{depends_on} || [];
167
    my $depends_str = ref($depends) eq 'ARRAY' ? join(' ', @$depends) : $depends;
168
    $template .= "# Current depends: $depends_str\n";
169
    $template .= "# Depends: bug xxxx\n";
170
    $template .= "# Depends: bug yyyy\n";
171
    $template .= "\n";
172
    
173
    $template .= "# Please edit the description (first line) and comment (other lines).\n";
174
    $template .= "# Lines starting with '#' will be ignored. Delete everything to abort.\n";
175
    $template .= "# To obsolete existing patches, uncomment the appropriate lines.\n";
176
    
177
    my $edited = $self->edit_template($template);
178
    return $self->parse_edited_content($edited);
179
}
180
181
sub edit_template {
182
    my ( $self, $template ) = @_;
183
184
    my $temp = File::Temp->new( SUFFIX => '.txt' );
185
    binmode $temp, ':utf8';
186
    print $temp $template;
187
    close $temp;
188
189
    my $editor = $ENV{EDITOR} || $ENV{GIT_EDITOR} || 'vi';
190
    system( $editor, $temp->filename );
191
192
    open my $fh, '<:utf8', $temp->filename or die "Cannot read temp file: $!";
193
    my $content = do { local $/; <$fh> };
194
    close $fh;
195
196
    return $content;
197
}
198
199
sub parse_edited_content {
200
    my ( $self, $content ) = @_;
201
    
202
    my @lines = split /\n/, $content;
203
    my @non_comment_lines = grep { !/^#/ && /\S/ } @lines;  # Also filter empty lines
204
    
205
    my $description = shift @non_comment_lines || "";
206
    $description =~ s/^\s+|\s+$//g;
207
    
208
209
    
210
    my @obsoletes;
211
    my @comment_lines;
212
    
213
    for my $line (@non_comment_lines) {
214
        if ( $line =~ /^\s*Obsoletes\s*:\s*(\d+)/ ) {
215
            push @obsoletes, $1;
216
        } else {
217
            push @comment_lines, $line;
218
        }
108
    }
219
    }
220
    
221
    my $comment = join( "\n", @comment_lines );
222
    $comment =~ s/^\s+|\s+$//g;
223
    
224
    GitBz::Exception->throw("Empty description, aborting\n") unless $description;
225
    
226
    return ( $description, $comment, \@obsoletes );
109
}
227
}
110
228
111
1;
229
1;
(-)a/lib/GitBz/Commands/Edit.pm (-43 / +145 lines)
Lines 16-26 package GitBz::Commands::Edit; Link Here
16
# along with git-bz; if not, see <https://www.gnu.org/licenses>.
16
# along with git-bz; if not, see <https://www.gnu.org/licenses>.
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
20
use utf8;
21
19
use Getopt::Long qw(GetOptionsFromArray);
22
use Getopt::Long qw(GetOptionsFromArray);
20
use Try::Tiny    qw(catch try);
23
use Try::Tiny    qw(catch try);
21
use File::Temp;
24
use File::Temp;
22
use GitBz::Git;
25
use GitBz::Git;
23
use GitBz::Exception;
26
use GitBz::Exception;
27
use GitBz::StatusWorkflow;
24
28
25
sub new {
29
sub new {
26
    my ( $class, $commands ) = @_;
30
    my ( $class, $commands ) = @_;
Lines 50-66 sub execute { Link Here
50
        if ( $arg =~ /^\d+$/ ) {
54
        if ( $arg =~ /^\d+$/ ) {
51
55
52
            # Bug reference
56
            # Bug reference
53
            $self->edit_bug( $arg, \%opts );
57
            my $changed = $self->edit_bug( $arg, \%opts );
58
            print "No changes made\n" unless $changed;
54
        } else {
59
        } else {
55
60
56
            # Commit or revision range
61
            # Commit or revision range
57
            my @commits = GitBz::Git->get_commits($arg);
62
            my @commits = GitBz::Git->get_commits($arg);
58
            GitBz::Exception->throw("No commits found") unless @commits;
63
            GitBz::Exception->throw("No commits found") unless @commits;
59
64
60
            $self->edit_commits( \@commits, \%opts );
65
            my $changed = $self->edit_commits( \@commits, \%opts );
66
            print "No changes made\n" unless $changed;
61
        }
67
        }
62
68
63
        print "Edit completed successfully\n";
69
        # Success message is handled in individual methods
64
    } catch {
70
    } catch {
65
        GitBz::Exception->throw("Edit failed: $_");
71
        GitBz::Exception->throw("Edit failed: $_");
66
    };
72
    };
Lines 76-82 sub edit_bug { Link Here
76
    my $template = $self->create_bug_template( $bug, $opts );
82
    my $template = $self->create_bug_template( $bug, $opts );
77
    my $edited   = $self->edit_template($template);
83
    my $edited   = $self->edit_template($template);
78
84
79
    $self->update_bug( $client, $bug_ref, $edited, $opts );
85
    return $self->update_bug( $client, $bug_ref, $edited, $opts );
80
}
86
}
81
87
82
sub edit_commits {
88
sub edit_commits {
Lines 94-103 sub edit_commits { Link Here
94
    GitBz::Exception->throw("No bug references found in commits") unless %bugs;
100
    GitBz::Exception->throw("No bug references found in commits") unless %bugs;
95
101
96
    # Edit each bug
102
    # Edit each bug
103
    my $any_changed = 0;
97
    for my $bug_ref ( keys %bugs ) {
104
    for my $bug_ref ( keys %bugs ) {
98
        print "Editing bug $bug_ref...\n";
105
        print "Editing bug $bug_ref...\n";
99
        $self->edit_bug_with_commits( $bug_ref, $bugs{$bug_ref}, $opts );
106
        my $changed = $self->edit_bug_with_commits( $bug_ref, $bugs{$bug_ref}, $opts );
107
        $any_changed ||= $changed;
100
    }
108
    }
109
    
110
    return $any_changed;
101
}
111
}
102
112
103
sub edit_bug_with_commits {
113
sub edit_bug_with_commits {
Lines 110-136 sub edit_bug_with_commits { Link Here
110
    my $template = $self->create_bug_template_with_commits( $bug, $commits, $opts );
120
    my $template = $self->create_bug_template_with_commits( $bug, $commits, $opts );
111
    my $edited   = $self->edit_template($template);
121
    my $edited   = $self->edit_template($template);
112
122
113
    $self->update_bug( $client, $bug_ref, $edited, $opts );
123
    return $self->update_bug( $client, $bug_ref, $edited, $opts );
114
}
124
}
115
125
116
sub create_bug_template {
126
sub create_bug_template {
117
    my ( $self, $bug, $opts ) = @_;
127
    my ( $self, $bug, $opts ) = @_;
128
    my $client = $self->{commands}->{client};
118
129
119
    my $template = "";
130
    my $template = "";
120
131
    $template .= "# Bug $bug->{id} - $bug->{summary}\n\n";
121
    if ( $opts->{fix} ) {
132
    
122
        $template .= "# Closing bug as FIXED\n";
133
    # Show existing patches for obsoleting
123
        $template .= "Status: RESOLVED\n";
134
    my $attachments = $client->get_attachments($bug->{id});
124
        $template .= "Resolution: FIXED\n\n";
135
    if ( $attachments && @$attachments ) {
136
        for my $patch ( @$attachments ) {
137
            next unless $patch->{is_patch} && !$patch->{is_obsolete};
138
            $template .= "#Obsoletes: $patch->{id} - $patch->{summary}\n";
139
        }
140
        $template .= "\n";
125
    }
141
    }
126
142
    
127
    $template .= "# Bug $bug->{id}: $bug->{summary}\n";
143
    # Add status options
128
    $template .= "# Product: $bug->{product}\n";
144
    my $workflow = GitBz::StatusWorkflow->new($client);
129
    $template .= "# Component: $bug->{component}\n";
145
    $template .= "# Current status: $bug->{status}\n";
130
    $template .= "# Status: $bug->{status}\n\n";
146
    my $status_values = $workflow->get_next_status_values($bug->{status});
131
147
    for my $status (@$status_values) {
132
    $template .= "Comment:\n";
148
        $template .= "# Status: $status\n";
133
    $template .= "# Enter your comment above. Lines starting with # are ignored.\n";
149
    }
150
    $template .= "\n";
151
    
152
    # Add patch complexity options
153
    my $complexity = $bug->{cf_patch_complexity} || "";
154
    $template .= "# Current patch-complexity: $complexity\n";
155
    my $complexity_values = $client->get_field_values('cf_patch_complexity');
156
    if ($complexity_values) {
157
        for my $comp (@$complexity_values) {
158
            $template .= "# Patch-complexity: $comp\n";
159
        }
160
    }
161
    $template .= "\n";
162
    
163
    # Add depends options
164
    my $depends = $bug->{depends_on} || [];
165
    my $depends_str = ref($depends) eq 'ARRAY' ? join(' ', @$depends) : $depends;
166
    $template .= "# Current depends: $depends_str\n";
167
    $template .= "# Depends: bug xxxx\n";
168
    $template .= "# Depends: bug yyyy\n";
169
    $template .= "\n";
170
    
171
    $template .= "# Enter comment below. Lines starting with '#' will be ignored.\n";
172
    $template .= "# To obsolete patches, uncomment the appropriate Obsoletes lines.\n";
134
173
135
    return $template;
174
    return $template;
136
}
175
}
Lines 159-209 sub edit_template { Link Here
159
    my ( $self, $template ) = @_;
198
    my ( $self, $template ) = @_;
160
199
161
    my $temp = File::Temp->new( SUFFIX => '.txt' );
200
    my $temp = File::Temp->new( SUFFIX => '.txt' );
201
    binmode $temp, ':utf8';
162
    print $temp $template;
202
    print $temp $template;
163
    close $temp;
203
    close $temp;
164
204
165
    my $editor = $ENV{EDITOR} || 'vi';
205
    my $editor = $ENV{EDITOR} || $ENV{GIT_EDITOR} || 'vi';
166
    system( $editor, $temp->filename );
206
    system( $editor, $temp->filename );
167
207
168
    open my $fh, '<', $temp->filename or die "Cannot read temp file: $!";
208
    open my $fh, '<:utf8', $temp->filename or die "Cannot read temp file: $!";
169
    my $content = do { local $/; <$fh> };
209
    my $content = do { local $/; <$fh> };
170
    close $fh;
210
    close $fh;
171
211
172
    # Remove comment lines
212
    return $content;
173
    my @lines = grep { !/^#/ } split /\n/, $content;
174
    return join( "\n", @lines );
175
}
213
}
176
214
177
sub update_bug {
215
sub update_bug {
178
    my ( $self, $client, $bug_ref, $edited, $opts ) = @_;
216
    my ( $self, $client, $bug_ref, $edited, $opts ) = @_;
179
217
218
    my @lines = split /\n/, $edited;
219
    my @non_comment_lines = grep { !/^#/ && /\S/ } @lines;
220
    
221
    # Early return if no non-comment lines - no API calls needed
222
    return 0 unless @non_comment_lines;
223
    
224
    my @obsoletes;
225
    my @comment_lines;
180
    my %update_params;
226
    my %update_params;
181
227
    
182
    # Parse edited content
228
    for my $line (@non_comment_lines) {
183
    my @lines      = split /\n/, $edited;
229
        if ( $line =~ /^\s*Status\s*:\s*(.+)/ ) {
184
    my $comment    = '';
185
    my $in_comment = 0;
186
187
    for my $line (@lines) {
188
        if ( $line =~ /^Status:\s*(.+)/ ) {
189
            $update_params{status} = $1;
230
            $update_params{status} = $1;
190
        } elsif ( $line =~ /^Resolution:\s*(.+)/ ) {
231
        } elsif ( $line =~ /^\s*Resolution\s*:\s*(.+)/ ) {
191
            $update_params{resolution} = $1;
232
            $update_params{resolution} = $1;
192
        } elsif ( $line =~ /^Comment:/ ) {
233
        } elsif ( $line =~ /^\s*Patch-complexity\s*:\s*(.+)/ ) {
193
            $in_comment = 1;
234
            $update_params{cf_patch_complexity} = $1;
194
        } elsif ( $in_comment && $line =~ /\S/ ) {
235
        } elsif ( $line =~ /^\s*Depends\s*:\s*([Bb][Uu][Gg])?\s*(\d+)/ ) {
195
            $comment .= $line . "\n";
236
            push @{ $update_params{depends_on} }, $2;
237
        } elsif ( $line =~ /^\s*Obsoletes\s*:\s*(\d+)/ ) {
238
            push @obsoletes, $1;
239
        } else {
240
            push @comment_lines, $line;
196
        }
241
        }
197
    }
242
    }
198
243
    
244
    my $comment = join( "\n", @comment_lines );
245
    $comment =~ s/^\s+|\s+$//g;
246
    
247
    # Early return if no changes
248
    return 0 unless %update_params || $comment || @obsoletes;
249
    
250
    # Only fetch bug data if we have changes to process
251
    my $bug = $client->get_bug($bug_ref);
252
    my $changed = 0;
253
    
254
    # Check if there are actual changes before making API call
255
    my %actual_changes;
256
    if ($update_params{status} && $update_params{status} ne $bug->{status}) {
257
        $actual_changes{status} = $update_params{status};
258
    }
259
    if ($update_params{resolution} && $update_params{resolution} ne ($bug->{resolution} || '')) {
260
        $actual_changes{resolution} = $update_params{resolution};
261
    }
262
    if ($update_params{cf_patch_complexity} && $update_params{cf_patch_complexity} ne ($bug->{cf_patch_complexity} || '')) {
263
        $actual_changes{cf_patch_complexity} = $update_params{cf_patch_complexity};
264
    }
265
    if ($update_params{depends_on}) {
266
        $actual_changes{depends_on} = $update_params{depends_on};
267
    }
199
    if ($comment) {
268
    if ($comment) {
200
        $update_params{comment} = { body => $comment };
269
        $actual_changes{comment} = { body => $comment };
201
    }
270
    }
202
271
    
203
    if (%update_params) {
272
    if (%actual_changes) {
204
        $client->update_bug( $bug_ref, %update_params );
273
        print "Updating bug $bug_ref\n";
205
        print "Updated bug $bug_ref\n";
274
        
275
        # Show field changes
276
        if ($actual_changes{status}) {
277
            print "Status changed: $bug->{status} → $actual_changes{status}\n";
278
        }
279
        if ($actual_changes{resolution}) {
280
            my $old = $bug->{resolution} || 'none';
281
            print "Resolution changed: $old → $actual_changes{resolution}\n";
282
        }
283
        if ($actual_changes{cf_patch_complexity}) {
284
            my $old = $bug->{cf_patch_complexity} || 'none';
285
            print "Patch-complexity changed: $old → $actual_changes{cf_patch_complexity}\n";
286
        }
287
        if ($actual_changes{comment}) {
288
            print "Added comment\n";
289
        }
290
        
291
        $client->update_bug( $bug_ref, %actual_changes );
292
        $changed = 1;
293
    }
294
    
295
    # Handle obsoleting attachments
296
    if (@obsoletes) {
297
        my $attachments = $client->get_attachments($bug_ref);
298
        my %attach_lookup = map { $_->{id} => $_->{summary} } @$attachments;
299
        
300
        for my $attach_id (@obsoletes) {
301
            $client->obsolete_attachment($attach_id);
302
            my $summary = $attach_lookup{$attach_id} || "Unknown";
303
            print "Obsoleted attachment $attach_id - $summary\n";
304
            $changed = 1;
305
        }
206
    }
306
    }
307
    
308
    return $changed;
207
}
309
}
208
310
209
sub extract_bug_ref {
311
sub extract_bug_ref {
(-)a/lib/GitBz/Git.pm (-3 / +9 lines)
Lines 63-74 sub format_patch { Link Here
63
sub get_commits {
63
sub get_commits {
64
    my ( $class, $range ) = @_;
64
    my ( $class, $range ) = @_;
65
65
66
    # Try as single commit first
66
    # Try as single commit first - exactly like original git-bz
67
    my $rev = try { $class->run( 'rev-parse', $range, '--verify' ) } catch { undef };
67
    my $rev = try { 
68
        $class->run( 'rev-parse', $range, '--verify' );
69
    } catch { 
70
        undef 
71
    };
68
72
69
    if ($rev) {
73
    if ($rev) {
70
        return $class->rev_list( $rev, '--max-count=1' );
74
        # Single commit - return just that one commit
75
        return $class->rev_list( '--max-count=1', $rev );
71
    } else {
76
    } else {
77
        # Not a single commit, treat as range
72
        return $class->rev_list($range);
78
        return $class->rev_list($range);
73
    }
79
    }
74
}
80
}
(-)a/lib/GitBz/RestClient.pm (-4 / +73 lines)
Lines 16-21 package GitBz::RestClient; Link Here
16
# along with git-bz; if not, see <https://www.gnu.org/licenses>.
16
# along with git-bz; if not, see <https://www.gnu.org/licenses>.
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
use LWP::UserAgent;
20
use LWP::UserAgent;
20
use JSON;
21
use JSON;
21
use MIME::Base64;
22
use MIME::Base64;
Lines 39-44 sub new { Link Here
39
        ua       => $ua,
40
        ua       => $ua,
40
        base_url => $base_url,
41
        base_url => $base_url,
41
        token    => undef,
42
        token    => undef,
43
        username => $args{username},
44
        password => $args{password},
42
        %args
45
        %args
43
    }, $class;
46
    }, $class;
44
}
47
}
Lines 46-56 sub new { Link Here
46
sub login {
49
sub login {
47
    my ( $self, $username, $password ) = @_;
50
    my ( $self, $username, $password ) = @_;
48
51
52
    $self->{username} = $username if $username;
53
    $self->{password} = $password if $password;
54
49
    my $response = $self->{ua}->get(
55
    my $response = $self->{ua}->get(
50
        sprintf(
56
        sprintf(
51
            "%s/login?login=%s&password=%s",
57
            "%s/login?login=%s&password=%s",
52
            $self->{base_url}, $username,
58
            $self->{base_url}, $self->{username},
53
            $password
59
            $self->{password}
54
        )
60
        )
55
    );
61
    );
56
62
Lines 63-68 sub login { Link Here
63
    GitBz::Exception::Bugzilla->throw( "Login failed: " . $response->status_line );
69
    GitBz::Exception::Bugzilla->throw( "Login failed: " . $response->status_line );
64
}
70
}
65
71
72
sub get_token {
73
    my ($self) = @_;
74
    
75
    return $self->{token} if $self->{token};
76
    
77
    if ($self->{username} && $self->{password}) {
78
        $self->login();
79
        return $self->{token};
80
    }
81
    
82
    return undef;
83
}
84
66
sub get_bug {
85
sub get_bug {
67
    my ( $self, $bug_id ) = @_;
86
    my ( $self, $bug_id ) = @_;
68
87
Lines 106-112 sub add_attachment { Link Here
106
    };
125
    };
107
126
108
    $payload->{comment} = $opts{comment} if $opts{comment};
127
    $payload->{comment} = $opts{comment} if $opts{comment};
109
    $payload->{token}   = $self->{token} if $self->{token};
128
    my $token = $self->get_token();
129
    $payload->{token} = $token if $token;
110
130
111
    my $response = $self->{ua}->post(
131
    my $response = $self->{ua}->post(
112
        $url,
132
        $url,
Lines 131-137 sub update_bug { Link Here
131
        %params
151
        %params
132
    };
152
    };
133
153
134
    $payload->{token} = $self->{token} if $self->{token};
154
    my $token = $self->get_token();
155
    $payload->{token} = $token if $token;
135
156
136
    my $response = $self->{ua}->put(
157
    my $response = $self->{ua}->put(
137
        $url,
158
        $url,
Lines 146-149 sub update_bug { Link Here
146
    return decode_json( $response->content );
167
    return decode_json( $response->content );
147
}
168
}
148
169
170
sub get_field_values {
171
    my ( $self, $field_name ) = @_;
172
173
    my $url = sprintf( "%s/field/bug", $self->{base_url} );
174
    my $response = $self->{ua}->get($url);
175
176
    if ( !$response->is_success ) {
177
        return [];
178
    }
179
180
    my $data = decode_json( $response->content );
181
    
182
    # Find the field in the fields array
183
    for my $field ( @{ $data->{fields} || [] } ) {
184
        if ( $field->{name} eq $field_name && $field->{values} ) {
185
            return [ map { $_->{name} } @{ $field->{values} } ];
186
        }
187
    }
188
    
189
    return [];
190
}
191
192
sub obsolete_attachment {
193
    my ( $self, $attachment_id ) = @_;
194
195
    my $url = sprintf( "%s/bug/attachment/%s", $self->{base_url}, $attachment_id );
196
197
    my $payload = {
198
        ids => [$attachment_id],
199
        is_obsolete => JSON::true,
200
    };
201
202
    my $token = $self->get_token();
203
    $payload->{token} = $token if $token;
204
205
    my $response = $self->{ua}->put(
206
        $url,
207
        Content_Type => 'application/json',
208
        Content      => encode_json($payload)
209
    );
210
211
    if ( !$response->is_success ) {
212
        GitBz::Exception::Bugzilla->throw( "Failed to obsolete attachment: " . $response->status_line );
213
    }
214
215
    return decode_json( $response->content );
216
}
217
149
1;
218
1;
(-)a/lib/GitBz/StatusWorkflow.pm (-1 / +50 lines)
Line 0 Link Here
0
- 
1
package GitBz::StatusWorkflow;
2
3
# This file is part of git-bz.
4
#
5
# git-bz is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# git-bz is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with git-bz; if not, see <https://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
sub new {
21
    my ( $class, $client ) = @_;
22
    bless { client => $client }, $class;
23
}
24
25
sub get_next_status_values {
26
    my ( $self, $current_status ) = @_;
27
    
28
    # Koha Bugzilla workflow transitions
29
    my %transitions = (
30
        'NEW'           => ['ASSIGNED', 'Needs Signoff', 'RESOLVED'],
31
        'ASSIGNED'      => ['Needs Signoff', 'RESOLVED'],
32
        'Needs Signoff' => ['Signed Off', 'Failed QA', 'RESOLVED'],
33
        'Signed Off'    => ['Passed QA', 'Failed QA', 'RESOLVED'],
34
        'Failed QA'     => ['Needs Signoff', 'RESOLVED'],
35
        'Passed QA'     => ['Pushed to Master', 'Pushed to Stable', 'RESOLVED'],
36
        'Pushed to Master' => ['RESOLVED'],
37
        'Pushed to Stable' => ['RESOLVED'],
38
        'RESOLVED'      => ['REOPENED'],
39
        'REOPENED'      => ['ASSIGNED', 'Needs Signoff', 'RESOLVED'],
40
    );
41
    
42
    return $transitions{$current_status} || [];
43
}
44
45
sub get_all_status_values {
46
    my ( $self ) = @_;
47
    return $self->{client}->get_field_values('bug_status');
48
}
49
50
1;

Return to bug 6473