怎样获得 GitHub 的 stars 列表

一直有一个想法:把 GitHub 上加星的仓库做成一个列表或者其他便于浏览查找的形式。今天,我就发现了这种工具。趁着午休,把它用上了,展示仓库:tianheg/stars

该仓库中包含的这个列表是基于一个名为 starred 的 pip 包生成的,再通过 GitHub Action 持续集成,达到每天自动生成列表的目的。该仓库地址:maguowei/starred

接下来记录整个过程:

一、

新建一个名字任意的仓库,新建文件名为 ci.yml 路径为 ~/.github/workflows/ci.yml,并存放以下内容:

 1name: update stars # GitHub Action 的名字
 2on:
 3  workflow_dispatch: # 为了手动部署,查看运行过程
 4  schedule:
 5    - cron: '00 0 * * *' # 定时:此时的时间是 08:00 CST – China Standard Time
 6jobs:
 7  awesome-stars:
 8    name: update awesome-stars
 9    runs-on: ubuntu-latest # 运行在最新的 Ubuntu 环境中,即 Ubuntu 20.04
10    steps:
11    - uses: actions/[email protected]
12    - name: Set up Python
13      uses: actions/[email protected]
14      with:
15        python-version: 3.7 # 安装 3.7 版本的 python
16    - name: Install dependencies # 更新 pip,安装 starred 包
17      run: |
18        python -m pip install --upgrade pip 
19        pip install starred        
20    - name: update repo
21      env:
22        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
23      run: starred --username tianheg --repository stars --sort --token ${GITHUB_TOKEN} --message 'stars update by github actions cron' # 执行生成 stars 列表的操作

手动运行该 GitHub Action,即生成一个属于你自己的 stars 列表,这是我的:

get-github-stars

二、

我们来读读 starred 的代码,地址:maguowei/starred/blob/master/starred/starred.py

  1#!/usr/bin/env python
  2# -*- coding: utf-8 -*-
  3
  4import sys
  5from io import BytesIO
  6from collections import OrderedDict
  7import click
  8from github3 import GitHub
  9from github3.exceptions import NotFoundError
 10from starred import VERSION
 11
 12
 13desc = '''# Awesome Stars [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d730\
 145f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/sindresorhus/awesome)
 15
 16> A curated list of my GitHub stars!  Generated by [starred](https://github.com/maguowei/starred)
 17
 18
 19## Contents
 20'''
 21
 22license_ = '''
 23## License
 24
 25[![CC0](http://mirrors.creativecommons.org/presskit/buttons/88x31/svg/cc-zero.svg)]\
 26(https://creativecommons.org/publicdomain/zero/1.0/)
 27
 28To the extent possible under law, [{username}](https://github.com/{username})\
 29 has waived all copyright and related or neighboring rights to this work.
 30'''
 31
 32html_escape_table = {
 33    ">": ">",
 34    "<": "&lt;",
 35}
 36
 37
 38def html_escape(text):
 39    """Produce entities within text."""
 40    return "".join(html_escape_table.get(c, c) for c in text)
 41
 42@click.command()
 43@click.option('--username', envvar='USER', help='GitHub username')
 44@click.option('--token', envvar='GITHUB_TOKEN', help='GitHub token')
 45@click.option('--sort',  is_flag=True, help='sort by language')
 46@click.option('--repository', default='', help='repository name')
 47@click.option('--message', default='update stars', help='commit message')
 48@click.version_option(version=VERSION, prog_name='starred')
 49def starred(username, token, sort, repository, message):
 50    """GitHub starred
 51
 52    creating your own Awesome List used GitHub stars!
 53
 54    example:
 55        starred --username maguowei --sort > README.md
 56    """
 57    if repository:
 58        if not token:
 59            click.secho('Error: create repository need set --token', fg='red')
 60            return
 61        file = BytesIO()
 62        sys.stdout = file
 63    else:
 64        file = None
 65
 66    gh = GitHub(token=token)
 67    stars = gh.starred_by(username)
 68    click.echo(desc)
 69    repo_dict = {}
 70
 71    for s in stars:
 72        language = s.language or 'Others'
 73        description = html_escape(s.description).replace('\n', '') if s.description else ''
 74        if language not in repo_dict:
 75            repo_dict[language] = []
 76        repo_dict[language].append([s.name, s.html_url, description.strip()])
 77
 78    if sort:
 79        repo_dict = OrderedDict(sorted(repo_dict.items(), key=lambda l: l[0]))
 80
 81    for language in repo_dict.keys():
 82        data = u'  - [{}](#{})'.format(language, '-'.join(language.lower().split()))
 83        click.echo(data)
 84    click.echo('')
 85
 86    for language in repo_dict:
 87        click.echo('## {} \n'.format(language.replace('#', '# #')))
 88        for repo in repo_dict[language]:
 89            data = u'- [{}]({}) - {}'.format(*repo)
 90            click.echo(data)
 91        click.echo('')
 92
 93    click.echo(license_.format(username=username))
 94
 95    if file:
 96        try:
 97            rep = gh.repository(username, repository)
 98            readme = rep.readme()
 99            readme.update(message, file.getvalue())
100        except NotFoundError:
101            rep = gh.create_repository(repository, 'A curated list of my GitHub stars!')
102            rep.create_file('README.md', 'starred initial commit', file.getvalue())
103        click.launch(rep.html_url)
104
105
106if __name__ == '__main__':
107    starred()
  • 4 - 10 行是引用的类库
  • 13 - 30 是生成的 README.md 中的文字叙述
  • 42 - 48 是命令指示

使用的资源