aozq / GitHubIssuesSortedByVotesPage

GNU General Public License v3.0
1 stars 0 forks source link

Code for caniuse issue list #1

Open Fyrd opened 4 years ago

Fyrd commented 4 years ago

Wasn't sure how best to share this, guess an issue is as good a way as any. Feel free to close whenever :)

Here's the bulk of the code using the GraphQL API for GitHub, see https://developer.github.com/v4/ for details on that. It's in PHP, should be easy enough to rewrite in the language of your choice. Basically I have a cron job that runs this every hour, then other code reads the JSON file to generate the HTML list.

I'm certainly not an expert on GraphQL btw, only learned enough to get this to work. :) But aside from that let me know if you have any other questions!

<?php

class GithubVoting {
    var $outputFile = 'votes.json';

    public function __construct() 
        $this->token = '(token here)'
    }

    private function makeQueryRequest($query) {
        $ch = curl_init();

        $url = 'https://api.github.com/graphql';
        $ua = 'API request by (name here)';
        $headers = [
            "Authorization: bearer " . $this->token
        ];
        $payload = '{"query": ' . json_encode($query) . '}';

        $opt = [
            CURLOPT_URL => $url,
            CURLOPT_POST => true,
            CURLOPT_USERAGENT => $ua,
            CURLOPT_POSTFIELDS => $payload,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_RETURNTRANSFER => true
        ];
        curl_setopt_array($ch, $opt);

        $output = curl_exec($ch);

        curl_close($ch);
        return json_decode($output);
    }

    public function makeTopList() {

        $issues = $this->getIssues();

        $outputIssues = array();
        foreach($issues as $issue) {
            $oIssue = [
                'title' => $issue->node->title,
                'number' => $issue->node->number,
                'votes' => $issue->node->reactions->totalCount + 1 // include self
            ];
            $outputIssues[] = $oIssue;
            // echo htmlentities($oIssue['title']) . '/' . $oIssue['number'] . ": " . $oIssue['votes'] . "<br>";
        }

        function voteSort($a, $b) {
            return $a['votes'] < $b['votes'];
        }

        usort($outputIssues, 'voteSort');
        $json = json_encode($outputIssues);
        file_put_contents(__DIR__ . $this->outputFile, $json);
    }

    // Get chunk of up to 100 issues (max for each request)
    private function fetchIssueChunk($cursor=null) {
        $cursorStr = $cursor ? "after:\"$cursor\"" : "";

        $query = "query {
            repository(owner: \"fyrd\", name: \"caniuse\") {
              issues(states: OPEN, first: 100 $cursorStr, filterBy: {labels: \"Support data suggestion\"}, orderBy: {field: CREATED_AT, direction: ASC}) {
                edges {
                  node {
                    number
                    title
                    reactions(content: THUMBS_UP) {
                      totalCount
                    }
                  }
                }
                pageInfo {
                    endCursor
                    hasNextPage
                }
              }
            }
          }
          ";

        $output = $this->makeQueryRequest($query);
        $issues = $output->data->repository->issues;
        $issueArr = $issues->edges;
        $cursor = $issues->pageInfo->endCursor;
        $hasNextPage = $issues->pageInfo->hasNextPage;

        return [
            "issues" => $issueArr,
            "cursor" => $cursor,
            "hasNextPage" => $hasNextPage
        ];
    }

    // Gets ALL the issues
    private function getIssues() {
        $needMore = true;
        $cursor = null;
        $issues = [];
        $requestCount = 0; // Prevent infinite loop

        while ($needMore && $requestCount < 50) {
            try {
                $issueChunk = $this->fetchIssueChunk($cursor);
                $cursor = $issueChunk['cursor'];
                $issues = array_merge($issues, $issueChunk['issues']);
                $needMore = $issueChunk['hasNextPage'];
                $requestCount++;
                sleep(1);
            } catch (Exception $e) {
                die($e);
                break;
            }
        }

        return $issues;
    }
}

?>
aozq commented 4 years ago

Thanks so much Alexis.. wanted to wait for a possible response, so I didn't go reinventing the wheel, and the work you did.. thank you so much!

On Fri, Jun 19, 2020, 7:49 PM Alexis Deveria notifications@github.com wrote:

Wasn't sure how best to share this, guess an issue is as good a way as any. Feel free to close whenever :)

Here's the bulk of the code using the GraphQL API for GitHub, see https://developer.github.com/v4/ for details on that. It's in PHP, should be easy enough to rewrite in the language of your choice. Basically I have a cron job that runs this every hour, then other code reads the JSON file to generate the HTML list.

I'm certainly not an expert on GraphQL btw, only learned enough to get this to work. :) But aside from that let me know if you have any other questions!

<?php

class GithubVoting { var $outputFile = 'votes.json';

public function __construct() $this->token = '(token here)' }

private function makeQueryRequest($query) { $ch = curl_init();

  $url = 'https://api.github.com/graphql';
  $ua = 'API request by (name here)';
  $headers = [
      "Authorization: bearer " . $this->token
  ];
  $payload = '{"query": ' . json_encode($query) . '}';

  $opt = [
      CURLOPT_URL => $url,
      CURLOPT_POST => true,
      CURLOPT_USERAGENT => $ua,
      CURLOPT_POSTFIELDS => $payload,
      CURLOPT_HTTPHEADER => $headers,
      CURLOPT_RETURNTRANSFER => true
  ];
  curl_setopt_array($ch, $opt);

  $output = curl_exec($ch);

  curl_close($ch);
  return json_decode($output);

}

public function makeTopList() {

  $issues = $this->getIssues();

  $outputIssues = array();
  foreach($issues as $issue) {
      $oIssue = [
          'title' => $issue->node->title,
          'number' => $issue->node->number,
          'votes' => $issue->node->reactions->totalCount + 1 // include self
      ];
      $outputIssues[] = $oIssue;
      // echo htmlentities($oIssue['title']) . '/' . $oIssue['number'] . ": " . $oIssue['votes'] . "<br>";
  }

  function voteSort($a, $b) {
      return $a['votes'] < $b['votes'];
  }

  usort($outputIssues, 'voteSort');
  $json = json_encode($outputIssues);
  file_put_contents(__DIR__ . $this->outputFile, $json);

}

// Get chunk of up to 100 issues (max for each request) private function fetchIssueChunk($cursor=null) { $cursorStr = $cursor ? "after:\"$cursor\"" : "";

  $query = "query {
      repository(owner: \"fyrd\", name: \"caniuse\") {
        issues(states: OPEN, first: 100 $cursorStr, filterBy: {labels: \"Support data suggestion\"}, orderBy: {field: CREATED_AT, direction: ASC}) {
          edges {
            node {
              number
              title
              reactions(content: THUMBS_UP) {
                totalCount
              }
            }
          }
          pageInfo {
              endCursor
              hasNextPage
          }
        }
      }
    }
    ";

  $output = $this->makeQueryRequest($query);
  $issues = $output->data->repository->issues;
  $issueArr = $issues->edges;
  $cursor = $issues->pageInfo->endCursor;
  $hasNextPage = $issues->pageInfo->hasNextPage;

  return [
      "issues" => $issueArr,
      "cursor" => $cursor,
      "hasNextPage" => $hasNextPage
  ];

}

// Gets ALL the issues private function getIssues() { $needMore = true; $cursor = null; $issues = []; $requestCount = 0; // Prevent infinite loop

  while ($needMore && $requestCount < 50) {
      try {
          $issueChunk = $this->fetchIssueChunk($cursor);
          $cursor = $issueChunk['cursor'];
          $issues = array_merge($issues, $issueChunk['issues']);
          $needMore = $issueChunk['hasNextPage'];
          $requestCount++;
          sleep(1);
      } catch (Exception $e) {
          die($e);
          break;
      }
  }

  return $issues;

} }

?>

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/aozq/GitHubIssuesSortedByVotesPage/issues/1, or unsubscribe https://github.com/notifications/unsubscribe-auth/AP7MBDXP7MFTOZKGYZ5FWMLRXQPSBANCNFSM4ODFZMYQ .

chrisjsewell commented 4 years ago

Hey guys, found this issue whilst googling for how to achieve a similar goal. It may be of interest, that I've taken the code above, converted it to JavaScript and added some extra stuff: https://jsfiddle.net/chrisjsewell/xjw5623y/ Cheers, Chris

Edit: I've now implemented this page: https://executablebooks.org/en/latest/feature-vote.html