$token_field))); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $user . ":" . $pass); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $json = curl_exec($ch); curl_close($ch); $res = json_decode($json, true); if(!isset($res['sha1'])) throw new Exception("Could not login to gitea"); return $res['sha1']; } function gitea_api_call($auth_token, $gitea_url, $api_path) { $api_url = "$gitea_url/api/v1/$api_path"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $api_url); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Accept: application/json', "Authorization: token $auth_token" ) ); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $response = curl_exec($ch); $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $header = substr($response, 0, $header_size); $json = substr($response, $header_size); $info = curl_getinfo($ch); curl_close($ch); if($info['http_code'] != 200) return $info['http_code']; return json_decode($json, true); } function gitea_get_tags($auth_token, $gitea_url, $repo) { $res = gitea_api_call($auth_token, $gitea_url, "repos/$repo/tags"); if($res === 404) return array(); else if(is_numeric($res)) throw new Exception("Bad response: $res"); return $res; } function gitea_get_source($auth_token, $gitea_url, $repo, $path) { $res = gitea_api_call($auth_token, $gitea_url, "repos/$repo/contents/$path"); if(is_numeric($res)) throw new Exception("Bad response: $res"); if(!isset($res['content'])) throw new Exception("Could not get file at path '$path'"); return base64_decode($res['content']); } function gitea_get_forks($auth_token, $gitea_url, $repo) { $res = gitea_api_call($auth_token, $gitea_url, "repos/$repo/forks"); if(is_numeric($res)) throw new Exception("Bad response: $res"); return $res; } function gitea_get_commits($auth_token, $gitea_url, $repo) { $res = gitea_api_call($auth_token, $gitea_url, "repos/$repo/commits"); if(is_numeric($res)) throw new Exception("Bad response: $res"); return $res; } function gitea_get_commit($auth_token, $gitea_url, $repo, $sha) { $res = gitea_api_call($auth_token, $gitea_url, "repos/$repo/git/commits/$sha"); if($res === 404) return null; else if(is_numeric($res)) throw new Exception("Bad response: $res"); else return $res; } function github_get_tags($github_repo) { $api_url = "https://api.github.com/repos/$github_repo/tags"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $api_url); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_USERAGENT, "test"); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $response = curl_exec($ch); $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $header = substr($response, 0, $header_size); $json = substr($response, $header_size); $info = curl_getinfo($ch); curl_close($ch); if($info['http_code'] != 200) return $info['http_code']; return json_decode($json, true); } function _is_composer_git_repo(array $repos, $repo) { foreach($repos as $item) { if($item['type'] == 'git' && $item['url'] == $repo) return true; } return false; } function _is_composer_github_package(array $repos, $repo, &$github_repo) { foreach($repos as $item) { if($item['type'] == 'package' && $item['package']['name'] == $repo && preg_match('~https?://github.com/([^/]+)/([^/]+)~', $item['package']['dist']['url'], $matches)) { $github_repo = $matches[1].'/'.$matches[2]; return true; } } return false; } interface IReporter { public function write($msg); public function flush(); } class CliReporter implements IReporter { public function write($msg) { echo $msg; } public function flush() { } } class SlackReporter implements IReporter { private $buffer = ''; public function write($msg) { $this->buffer .= $msg; } public function flush() { slack_post($this->buffer); } } class Reporters implements IReporter { private $all = array(); public function add(IReporter $r) { $this->all[] = $r; } public function write($msg) { foreach($this->all as $r) $r->write($msg); } public function flush() { foreach($this->all as $r) $r->flush(); } } function gitea_check_repo( $auth_token, $gitea_url, $base_repo, array $opts ) { $r = new Reporters(); $r->add(new CliReporter()); if($opts['log_to_slack']) $r->add(new SlackReporter()); $r->write("************************* Chirping about repo '$base_repo' *************************\n"); $commits = gitea_get_commits($auth_token, $gitea_url, $base_repo); if($opts['check_forks']) { $forks = gitea_get_forks($auth_token, $gitea_url, $base_repo); $behind_forks = array(); $r->write("== Checking forks ==\n"); foreach($forks as $fork) { $repo_fork = $fork['full_name']; foreach($commits as $commit) { $status = gitea_get_commit($auth_token, $gitea_url, $repo_fork, $commit['sha']); if($status === null) { $behind_forks[] = $repo_fork; break; } //early exit if commit exists else if(isset($status['sha'])) { break; } } } $r->write("Behind forks: " . implode(", ", $behind_forks) . "\n"); } if($opts['check_composer']) { $r->write("== Checking Composer manifest ==\n"); $composer_json = gitea_get_source($auth_token, $gitea_url, $base_repo, "composer/composer.json"); $composer_arr = json_decode($composer_json, true); foreach($composer_arr['require'] as $repo => $version) { if(strpos($repo, "bit/") !== 0) continue; if(_is_composer_git_repo($composer_arr['repositories'], "$gitea_url/$repo")) { $tags = gitea_get_tags($auth_token, $gitea_url, $repo); if(isset($tags[0])) { $last_tag_info = $tags[0]; if(ltrim($last_tag_info["name"], 'v') != ltrim($version, 'v')) $r->write("Package '$repo': current $version, latest {$last_tag_info["name"]}\n"); } else $r->write("Could not fetch tags for $repo\n"); } else if(_is_composer_github_package($composer_arr['repositories'], $repo, $github_repo)) { $tags = github_get_tags($github_repo); if(isset($tags[0])) { $last_tag_info = $tags[0]; if(ltrim($last_tag_info["name"], 'v') != ltrim($version, 'v')) $r->write("Package '$repo': current $version, latest {$last_tag_info["name"]}\n"); } } } } if($opts['check_upm']) { $r->write("== Checking UPM manifest ==\n"); $upm_json = gitea_get_source($auth_token, $gitea_url, $base_repo, "unity/Packages/manifest.json"); $upm_arr = json_decode($upm_json, true); foreach($upm_arr['dependencies'] as $name => $version) { if(strpos($name, "com.bitgames.") !== 0) continue; $name = str_replace("com.bitgames.ecs", "com.bitgames.leoecs", $name); $name = str_replace("com.bitgames.", "", $name); $name = str_replace(".", "-", $name); $repo = 'bit-upm/' . $name; $tags = gitea_get_tags($auth_token, $gitea_url, $repo); if(isset($tags[0])) { $last_tag_info = $tags[0]; if(ltrim($last_tag_info["name"], 'v') != ltrim($version, 'v')) $r->write("Package '$repo': current $version, latest {$last_tag_info["name"]}\n"); } else $r->write("Could not fetch tags for $repo\n"); } } $r->flush(); } function slack_post($message, $fields = array()) { $ch = curl_init("https://slack.com/api/chat.postMessage"); $fields["token"] = 'xoxb-141599046048-4017237103457-fsUiANhvIcuScMRkrTB7obEU'; $fields["channel"] = "#tech"; $fields["text"] = $message; curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $result = curl_exec($ch); curl_close($ch); return json_decode($result, true); }