| #!/usr/bin/env perl |
| # |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| use strict; |
| use warnings; |
| |
| use WWW::Curl::Easy; |
| use JSON; |
| use Getopt::Std; |
| |
| my $url = "https://api.github.com"; |
| |
| sub usage() { |
| print "USAGE: changelog.pl -o owner -r repo -m milestone [-a auth] [-v]\n"; |
| print "\t-v verbose\n\n"; |
| print "Example:\n"; |
| print "\tchangelog.pl -o apache -r trafficserver -m 8.0.6 -a auth_token\n"; |
| exit(1); |
| } |
| |
| sub rate_fail |
| { |
| print STDERR "You have exceeded your rate limit. Try using an auth token.\n"; |
| exit 2; |
| } |
| |
| sub milestone_lookup($$$$$) |
| { |
| my($curl, $url, $owner, $repo, $milestone_title) = @_; |
| |
| my $endpoint = "/repos/$owner/$repo/milestones"; |
| my $resp_body; |
| |
| $curl->setopt(CURLOPT_WRITEDATA, \$resp_body); |
| $curl->setopt(CURLOPT_URL, $url . $endpoint); |
| |
| my $retcode = $curl->perform(); |
| if ($retcode == 0 && $curl->getinfo(CURLINFO_HTTP_CODE) == 200) { |
| my $milestones = from_json($resp_body); |
| foreach my $milestone (@{$milestones}) { |
| if ($milestone->{title} eq $milestone_title) { |
| return $milestone->{number}; |
| } |
| } |
| } elsif ($retcode == 0 && $curl->getinfo(CURLINFO_HTTP_CODE) == 403) { |
| rate_fail(); |
| } |
| |
| undef; |
| } |
| |
| sub is_merged($$$$$) |
| { |
| my($curl, $url, $owner, $repo, $issue_id) = @_; |
| |
| my $endpoint = "/repos/$owner/$repo/pulls/$issue_id/merge"; |
| my $resp_body; |
| |
| $curl->setopt(CURLOPT_WRITEDATA, \$resp_body); |
| $curl->setopt(CURLOPT_URL, $url . $endpoint); |
| |
| my $retcode = $curl->perform(); |
| if ($retcode == 0 && $curl->getinfo(CURLINFO_HTTP_CODE) == 204) { |
| return 1; |
| } elsif ($retcode == 0 && $curl->getinfo(CURLINFO_HTTP_CODE) == 403) { |
| rate_fail(); |
| } |
| |
| undef; |
| } |
| |
| sub issue_search($$$$$$) |
| { |
| my($curl, $url, $owner, $repo, $milestone_id, $page) = @_; |
| |
| my $endpoint = "/repos/$owner/$repo/issues"; |
| |
| my $params = "milestone=$milestone_id&state=closed&page=$page"; |
| |
| my $resp_body; |
| |
| $curl->setopt(CURLOPT_WRITEDATA, \$resp_body); |
| $curl->setopt(CURLOPT_URL, $url . $endpoint . '?' . $params); |
| |
| my $retcode = $curl->perform(); |
| if ($retcode == 0 && $curl->getinfo(CURLINFO_HTTP_CODE) == 200) { |
| return from_json($resp_body); |
| } elsif ($retcode == 0 && $curl->getinfo(CURLINFO_HTTP_CODE) == 403) { |
| rate_fail(); |
| } |
| |
| undef; |
| } |
| |
| { |
| # get the command line arguments |
| my %opts; |
| getopts("o:r:m:a:v", \%opts); |
| usage() if (! defined $opts{o} || ! defined $opts{r} || ! defined $opts{m}); |
| my $owner = $opts{o}; |
| my $repo = $opts{r}; |
| my $milestone = $opts{m}; |
| my $auth = $opts{a}; |
| my $verbose = 0; |
| $verbose = 1 if (defined $opts{v}); |
| |
| my $curl = WWW::Curl::Easy->new; |
| $curl->setopt(CURLOPT_VERBOSE, 1) if $verbose; |
| $curl->setopt(CURLOPT_HTTPHEADER, ['Accept: application/vnd.github.v3+json', 'User-Agent: Awesome-Octocat-App']); |
| |
| if (defined($auth)) { |
| $curl->setopt(CURLOPT_USERPWD, $auth); |
| } |
| |
| my $milestone_id = milestone_lookup($curl, $url, $owner, $repo, $milestone); |
| |
| if (!defined($milestone_id)) { |
| print STDERR "Milestone not found: $milestone\n"; |
| exit 1; |
| } |
| |
| my $issues; |
| my $changelog; |
| my $page = 1; |
| |
| print STDERR "Looking for issues from Milestone $milestone\n"; |
| |
| do { |
| print STDERR "Page $page\n"; |
| $issues = issue_search($curl, $url, $owner, $repo, $milestone_id, $page); |
| foreach my $issue (@{$issues}) { |
| if (defined($issue)) { |
| print STDERR "Issue #" . $issue->{number} . " - " . $issue->{title} . " "; |
| |
| if (!exists($issue->{pull_request})) { |
| print STDERR "not a PR.\n"; |
| next; |
| } |
| |
| if (!is_merged($curl, $url, $owner, $repo, $issue->{number})) { |
| print STDERR "not merged.\n"; |
| next; |
| } |
| |
| print STDERR "added.\n"; |
| push @{$changelog}, {number => $issue->{number}, title => $issue->{title}}; |
| } |
| } |
| $page++; |
| } while (scalar @{$issues}); |
| |
| if (defined($changelog)) { |
| print "Changes with Apache Traffic Server $milestone\n"; |
| |
| foreach my $issue (sort {$a->{number} <=> $b->{number}} @{$changelog}) { |
| print " #$issue->{number} - $issue->{title}\n"; |
| } |
| } |
| } |