mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Add Changelog generator (#8791)
* feature: Added initial changelog generator * More updates * Update and rename release.php to Release.php * Update Kernel.php
This commit is contained in:
committed by
Tony Murray
parent
e736f5efec
commit
0a983e998e
@@ -0,0 +1,241 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* GitHub.php
|
||||
*
|
||||
* An interface to GitHubs api
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @package LibreNMS
|
||||
* @link http://librenms.org
|
||||
* @copyright 2018 Neil Lathwood
|
||||
* @author Neil Lathwood <gh+n@laf.io>
|
||||
*/
|
||||
|
||||
namespace LibreNMS\Util;
|
||||
|
||||
use Requests;
|
||||
use DateTime;
|
||||
use SebastianBergmann\CodeCoverage\Report\PHP;
|
||||
|
||||
class GitHub
|
||||
{
|
||||
protected $tag;
|
||||
protected $from;
|
||||
protected $token;
|
||||
protected $file;
|
||||
protected $pr;
|
||||
protected $stop = false;
|
||||
protected $pull_requests = [];
|
||||
protected $changelog = [];
|
||||
protected $markdown;
|
||||
protected $labels = ['webui', 'api', 'documentation', 'security', 'feature', 'enhancement', 'device', 'bug', 'alerting'];
|
||||
protected $github = 'https://api.github.com/repos/librenms/librenms';
|
||||
|
||||
public function __construct($tag, $from, $file, $token = null, $pr = null)
|
||||
{
|
||||
$this->tag = $tag;
|
||||
$this->from = $from;
|
||||
$this->file = $file;
|
||||
$this->pr = $pr;
|
||||
if (is_null($token) === false || getenv('GH_TOKEN')) {
|
||||
$this->token = $token ?: getenv('GH_TOKEN');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Return the GitHub Authorization header for the API call
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHeaders()
|
||||
{
|
||||
if (is_null($this->token) === false) {
|
||||
return ['Authorization' => "token {$this->token}"];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the release information for a specific tag
|
||||
*
|
||||
* @param $tag
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRelease($tag)
|
||||
{
|
||||
$release = Requests::get($this->github . "/releases/tags/$tag", self::getHeaders());
|
||||
return json_decode($release->body, true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get a single pull request information
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPullRequest()
|
||||
{
|
||||
$pull_request = Requests::get($this->github . "/pulls/{$this->pr}", self::getHeaders());
|
||||
$this->pr = json_decode($pull_request->body, true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get all closed pull requests up to a certain date
|
||||
*
|
||||
* @param $date
|
||||
* @param int $page
|
||||
* @return bool
|
||||
*/
|
||||
public function getPullRequests($date, $page = 1)
|
||||
{
|
||||
$prs = Requests::get($this->github . "/pulls?state=closed&page=$page", self::getHeaders());
|
||||
$prs = json_decode($prs->body, true);
|
||||
foreach ($prs as $k => $pr) {
|
||||
if ($pr['merged_at']) {
|
||||
$merged = new DateTime($pr['merged_at']);
|
||||
$end_date = new DateTime($date);
|
||||
if (isset($this->pr['merged_at']) && $merged > new DateTime($this->pr['merged_at'])) {
|
||||
// If the date of this PR is newer than the final PR then skip over it
|
||||
continue;
|
||||
} elseif ($merged < $end_date) {
|
||||
// If the date of this PR is older than the last release we're done
|
||||
return true;
|
||||
} else {
|
||||
// If not, assign this PR to the array
|
||||
$this->pull_requests[] = $pr;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->getPullRequests($date, $page+1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Build the data for the change log.
|
||||
*
|
||||
*/
|
||||
public function buildChangeLog()
|
||||
{
|
||||
$output = [];
|
||||
$users = [];
|
||||
foreach ($this->pull_requests as $k => $pr) {
|
||||
if (isset($users[$pr['user']['login']]) === false) {
|
||||
$users[$pr['user']['login']] = 0;
|
||||
}
|
||||
if ($pr['merged_at']) {
|
||||
foreach ($pr['labels'] as $k => $label) {
|
||||
$name = preg_replace('/ :[\S]+:/', '', strtolower($label['name']));
|
||||
if (in_array($name, $this->labels)) {
|
||||
$title = ucfirst(trim(preg_replace('/^[\S]+: /', '', $pr['title'])));
|
||||
$output[$name][] = "$title ([#{$pr['number']}]({$pr['html_url']})) - [{$pr['user']['login']}]({$pr['user']['html_url']})" . PHP_EOL;
|
||||
}
|
||||
}
|
||||
$users[$pr['user']['login']] += 1;
|
||||
}
|
||||
}
|
||||
$this->changelog = ['changelog' => $output, 'users' => $users];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Format the change log into Markdown.
|
||||
*
|
||||
*/
|
||||
public function formatChangeLog()
|
||||
{
|
||||
$tmp_markdown = "##$this->tag" . PHP_EOL;
|
||||
$tmp_markdown .= '*(' . date('Y-m-d') . ')*' . PHP_EOL . PHP_EOL;
|
||||
if (!empty($this->changelog['users'])) {
|
||||
$tmp_markdown .= "A big thank you to the following " . count($this->changelog['users']) . " contributors this last month:" . PHP_EOL;
|
||||
asort($this->changelog['users']);
|
||||
foreach (array_reverse($this->changelog['users']) as $user => $count) {
|
||||
$tmp_markdown .= " - $user ($count)" . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
$tmp_markdown .= PHP_EOL;
|
||||
|
||||
foreach ($this->changelog['changelog'] as $section => $items) {
|
||||
$tmp_markdown .= "#### " . ucfirst($section) . PHP_EOL;
|
||||
$tmp_markdown .= '* ' . implode('* ', $items) . PHP_EOL;
|
||||
}
|
||||
|
||||
$this->markdown = $tmp_markdown;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Update the specified file with the new Change log info.
|
||||
*
|
||||
*/
|
||||
public function writeChangeLog()
|
||||
{
|
||||
if (file_exists($this->file)) {
|
||||
$existing = file_get_contents($this->file);
|
||||
$content = $this->getMarkdown() . PHP_EOL . $existing;
|
||||
if (is_writable($this->file)) {
|
||||
file_put_contents($this->file, $content);
|
||||
}
|
||||
} else {
|
||||
echo "Couldn't write to file {$this->file}" . PHP_EOL;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Return the generated markdown.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMarkdown()
|
||||
{
|
||||
return $this->markdown;
|
||||
}
|
||||
|
||||
public function createRelease()
|
||||
{
|
||||
//FIXME Come back to this
|
||||
return false;
|
||||
$sha = isset($this->pr['merge_commit_sha']) ? $this->pr['merge_commit_sha'] : 'master';
|
||||
$release = Requests::post($this->github . "/releases", self::getHeaders(), [
|
||||
'tag_name' => $this->tag,
|
||||
'target_commitish' => $sha,
|
||||
'body' => $this->getMarkdown(),
|
||||
'draft' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Function to control the creation of creating a change log.
|
||||
*
|
||||
*/
|
||||
public function createChangelog()
|
||||
{
|
||||
$previous_release = $this->getRelease($this->from);
|
||||
if (is_null($this->pr) !== true) {
|
||||
$this->getPullRequest();
|
||||
}
|
||||
$this->getPullRequests($previous_release['published_at']);
|
||||
$this->buildChangeLog();
|
||||
$this->formatChangeLog();
|
||||
$this->writeChangeLog();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use LibreNMS\Util\GitHub;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
class Release extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'release:tag
|
||||
{tag : The new tag / version}
|
||||
{from : The previous tag / version}
|
||||
{--file= : The filename to update}
|
||||
{--pr= : The last PR to include in this release if not master branch}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Create a new LibreNMS release including changelog';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$tag = $this->argument('tag');
|
||||
$from = $this->argument('from');
|
||||
$file = $this->option('file') ?: 'doc/General/Changelog.md';
|
||||
$pr = $this->option('pr');
|
||||
$token = getenv('GH_TOKEN') ?: $this->secret('Enter a GitHub Token?');
|
||||
|
||||
$this->info("Creating release $tag.....");
|
||||
$gh = new GitHub($tag, $from, $file, $token, $pr);
|
||||
$gh->createChangelog();
|
||||
$this->info("Changelog generated for $tag");
|
||||
|
||||
if ($this->confirm('Do you want to view the generated Changelog?')) {
|
||||
echo $gh->getMarkdown();
|
||||
}
|
||||
|
||||
if ($this->confirm("Do you want to create the release $tag on GitHub?")) {
|
||||
//$gh->createRelease();
|
||||
$this->error('Unsupported right now');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ class Kernel extends ConsoleKernel
|
||||
* @var array
|
||||
*/
|
||||
protected $commands = [
|
||||
//
|
||||
Commands\Release::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user