[ 'branch' => [ 'name' => 'branch', 'type' => 'text', 'exampleValue' => 'main', 'required' => false, 'title' => 'Optional, main branch is used by default.', ], ], 'Issues' => [], 'Issue Comments' => [ 'issueId' => [ 'name' => 'Issue ID', 'type' => 'text', 'required' => true, 'exampleValue' => '513', ] ], 'Pull Requests' => [], 'Releases' => [], 'Tags' => [], 'global' => [ 'username' => [ 'name' => 'Username', 'type' => 'text', 'exampleValue' => 'Codeberg', 'title' => 'Username of account that the repository belongs to.', 'required' => true, ], 'repo' => [ 'name' => 'Repository', 'type' => 'text', 'exampleValue' => 'Community', 'required' => true, ] ] ]; const CACHE_TIMEOUT = 1800; const TEST_DETECT_PARAMETERS = [ 'https://codeberg.org/Codeberg/Community/issues/507' => [ 'context' => 'Issue Comments', 'username' => 'Codeberg', 'repo' => 'Community', 'issueId' => '507' ], 'https://codeberg.org/Codeberg/Community/issues' => [ 'context' => 'Issues', 'username' => 'Codeberg', 'repo' => 'Community' ], 'https://codeberg.org/Codeberg/Community/pulls' => [ 'context' => 'Pull Requests', 'username' => 'Codeberg', 'repo' => 'Community' ], 'https://codeberg.org/Codeberg/Community/releases' => [ 'context' => 'Releases', 'username' => 'Codeberg', 'repo' => 'Community' ], 'https://codeberg.org/Codeberg/Community/commits/branch/master' => [ 'context' => 'Commits', 'username' => 'Codeberg', 'repo' => 'Community', 'branch' => 'master' ], 'https://codeberg.org/Codeberg/Community/commits' => [ 'context' => 'Commits', 'username' => 'Codeberg', 'repo' => 'Community' ] ]; private $defaultBranch = 'main'; private $issueTitle = ''; private $urlRegex = '/codeberg\.org\/([\w]+)\/([\w]+)(?:\/commits\/branch\/([\w]+))?/'; private $issuesUrlRegex = '/codeberg\.org\/([\w]+)\/([\w]+)\/issues/'; private $pullsUrlRegex = '/codeberg\.org\/([\w]+)\/([\w]+)\/pulls/'; private $releasesUrlRegex = '/codeberg\.org\/([\w]+)\/([\w]+)\/releases/'; private $issueCommentsUrlRegex = '/codeberg\.org\/([\w]+)\/([\w]+)\/issues\/([0-9]+)/'; public function collectData() { $url = $this->getURI(); $html = getSimpleHTMLDOM($url); $html = defaultLinkTo($html, $url); switch ($this->queriedContext) { case 'Commits': $this->extractCommits($html); break; case 'Issues': $this->extractIssues($html); break; case 'Issue Comments': $this->extractIssueComments($html); break; case 'Pull Requests': $this->extractPulls($html); break; case 'Releases': $this->extractReleases($html); break; case 'Tags': $this->extractTags($html); break; default: throw new \Exception('Invalid context: ' . $this->queriedContext); } } public function getName() { switch ($this->queriedContext) { case 'Commits': if ($this->getBranch() === $this->defaultBranch) { return $this->getRepo() . ' Commits'; } return $this->getRepo() . ' Commits (' . $this->getBranch() . ' branch) - ' . self::NAME; case 'Issues': return $this->getRepo() . ' Issues - ' . self::NAME; case 'Issue Comments': return $this->issueTitle . ' - Issue Comments - ' . self::NAME; case 'Pull Requests': return $this->getRepo() . ' Pull Requests - ' . self::NAME; case 'Releases': return $this->getRepo() . ' Releases - ' . self::NAME; case 'Tags': return $this->getRepo() . ' Tags - ' . self::NAME; default: return parent::getName(); } } public function getURI() { switch ($this->queriedContext) { case 'Commits': return self::URI . $this->getRepo() . '/commits/branch/' . $this->getBranch(); case 'Issues': return self::URI . $this->getRepo() . '/issues/'; case 'Issue Comments': return self::URI . $this->getRepo() . '/issues/' . $this->getInput('issueId'); case 'Pull Requests': return self::URI . $this->getRepo() . '/pulls'; case 'Releases': return self::URI . $this->getRepo() . '/releases'; case 'Tags': return self::URI . $this->getRepo() . '/tags'; default: return parent::getURI(); } } private function getBranch() { if ($this->getInput('branch')) { return $this->getInput('branch'); } return $this->defaultBranch; } private function getRepo() { return $this->getInput('username') . '/' . $this->getInput('repo'); } /** * Extract commits */ private function extractCommits($html) { $table = $html->find('table#commits-table', 0); $tbody = $table->find('tbody.commit-list', 0); foreach ($tbody->find('tr') as $tr) { $item = []; $message = $tr->find('td.message', 0); $item['title'] = $message->find('span.message-wrapper', 0)->plaintext; $item['uri'] = $tr->find('td.sha', 0)->find('a', 0)->href; $item['author'] = $tr->find('td.author', 0)->plaintext; $var = $tr->find('td', 3); $var1 = $var->find('span', 0); if ($var1) { $item['timestamp'] = $var1->title; } if ($message->find('pre.commit-body', 0)) { $message->find('pre.commit-body', 0)->style = ''; $item['content'] = $message->find('pre.commit-body', 0); } else { $item['content'] = '
' . $item['title'] . ''; } $this->items[] = $item; } } /** * Extract issues */ private function extractIssues($html) { $issueList = $html->find('div#issue-list', 0); foreach ($issueList->find('div.flex-item') as $div) { $item = []; $number = trim($div->find('a.index,ml-0.mr-2', 0)->plaintext); $item['title'] = $div->find('a.issue-title', 0)->plaintext . ' (' . $number . ')'; $item['uri'] = $div->find('a.issue-title', 0)->href; $time = $div->find('relative-time.time-since', 0); if ($time) { $item['timestamp'] = $time->datetime; } //$item['author'] = $li->find('div.desc', 0)->find('a', 1)->plaintext; // Fetch issue page $issuePage = getSimpleHTMLDOMCached($item['uri'], 3600); $issuePage = defaultLinkTo($issuePage, self::URI); $item['content'] = $issuePage->find('div.timeline-item.comment.first', 0)->find('div.render-content.markup', 0); foreach ($div->find('a.ui.label') as $label) { $item['categories'][] = $label->plaintext; } $this->items[] = $item; } } /** * Extract issue comments */ private function extractIssueComments($html) { $this->issueTitle = $html->find('span#issue-title', 0)->plaintext . ' (' . $html->find('span.index', 0)->plaintext . ')'; foreach ($html->find('div.timeline-item.comment') as $div) { $item = []; if ($div->class === 'timeline-item comment merge box') { continue; } $item['title'] = $this->ellipsisTitle($div->find('div.render-content.markup', 0)->plaintext); $item['uri'] = $div->find('span.text.grey', 0)->find('a', 1)->href; $item['content'] = $div->find('div.render-content.markup', 0); if ($div->find('div.dropzone-attachments', 0)) { $item['content'] .= $div->find('div.dropzone-attachments', 0); } $item['author'] = $div->find('a.author', 0)->innertext; $timeSince = $div->find('span.time-since', 0); if ($timeSince) { $item['timestamp'] = $timeSince->title; } $this->items[] = $item; } } /** * Extract pulls */ private function extractPulls($html) { $div = $html->find('div#issue-list', 0); $var2 = $div->find('div.flex-item'); foreach ($var2 as $li) { $item = []; $number = trim($li->find('a.index,ml-0.mr-2', 0)->plaintext); $a = $li->find('a.issue-title', 0); $item['title'] = $a->plaintext . ' (' . $number . ')'; $item['uri'] = $a->href; $time = $li->find('relative-time.time-since', 0); if ($time) { $item['timestamp'] = $time->datetime; } // Extracting the author is a bit awkward after they changed their html //$desc = $li->find('div.desc', 0); //$item['author'] = $desc->find('a', 1)->plaintext; // Fetch pull request page $pullRequestPage = getSimpleHTMLDOMCached($item['uri'], 3600); $pullRequestPage = defaultLinkTo($pullRequestPage, self::URI); $var = $pullRequestPage->find('ui.timeline', 0); if ($var) { $var1 = $var->find('div.render-content.markup', 0); $item['content'] = $var1; } foreach ($li->find('a.ui.label') as $label) { $item['categories'][] = $label->plaintext; } $this->items[] = $item; } } /** * Extract releases */ private function extractReleases($html) { $ul = $html->find('ul#release-list', 0); $lis = $ul->find('li.ui.grid'); if ($lis === []) { throw new \Exception('Found zero releases'); } foreach ($lis as $li) { $item = []; $item['title'] = $li->find('h4', 0)->plaintext; $item['uri'] = $li->find('h4', 0)->find('a', 0)->href; $tag = $this->stripSvg($li->find('span.tag', 0)); $commit = $this->stripSvg($li->find('span.commit', 0)); $downloads = $this->extractDownloads($li->find('details.download', 0)); $item['content'] = $li->find('div.markup.desc', 0); $item['content'] .= <<Tag
{$tag}
Commit{$commit}
{$downloads} HTML; $item['timestamp'] = $li->find('span.time', 0)->find('span', 0)->title; $item['author'] = $li->find('span.author', 0)->find('a', 0)->plaintext; $this->items[] = $item; } } private function extractTags($html) { $tags = $html->find('td.tag'); if ($tags === []) { throw new \Exception('Found zero tags'); } foreach ($tags as $tag) { $this->items[] = [ 'title' => $tag->find('a', 0)->plaintext, 'uri' => $tag->find('a', 0)->href, 'content' => $tag->innertext, ]; } } /** * Extract downloads for a releases */ private function extractDownloads($html, $skipFirst = false) { $downloads = ''; foreach ($html->find('a') as $index => $a) { if ($skipFirst === true && $index === 0) { continue; } $downloads .= <<{$a->plaintext}{$downloads}
EOD; } /** * Ellipsis title to first 100 characters */ private function ellipsisTitle($text) { $length = 100; if (strlen($text) > $length) { $text = explode('