mirror of https://github.com/tiangolo/fastapi.git
👷♀️ Add script for GitHub Topic Repositories and update External Links (#13135)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
This commit is contained in:
parent
548dd233c3
commit
1b8f823a05
|
|
@ -0,0 +1,40 @@
|
||||||
|
name: Update Topic Repos
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 12 1 * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
UV_SYSTEM_PYTHON: 1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
topic-repos:
|
||||||
|
if: github.repository_owner == 'fastapi'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Dump GitHub context
|
||||||
|
env:
|
||||||
|
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||||
|
run: echo "$GITHUB_CONTEXT"
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.11"
|
||||||
|
- name: Setup uv
|
||||||
|
uses: astral-sh/setup-uv@v5
|
||||||
|
with:
|
||||||
|
version: "0.4.15"
|
||||||
|
enable-cache: true
|
||||||
|
cache-dependency-glob: |
|
||||||
|
requirements**.txt
|
||||||
|
pyproject.toml
|
||||||
|
- name: Install GitHub Actions dependencies
|
||||||
|
run: uv pip install -r requirements-github-actions.txt
|
||||||
|
- name: Update Topic Repos
|
||||||
|
run: python ./scripts/topic_repos.py
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.FASTAPI_PR_TOKEN }}
|
||||||
|
|
@ -28,9 +28,12 @@ If you have an article, project, tool, or anything related to **FastAPI** that i
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
## Projects
|
## GitHub Repositories
|
||||||
|
|
||||||
Latest GitHub projects with the topic `fastapi`:
|
Most starred GitHub repositories with the topic `fastapi`:
|
||||||
|
|
||||||
<div class="github-topic-projects">
|
{% for repo in topic_repos %}
|
||||||
</div>
|
|
||||||
|
<a href={{repo.html_url}} target="_blank">★ {{repo.stars}} - {{repo.name}}</a> by <a href={{repo.owner_html_url}} target="_blank">@{{repo.owner_login}}</a>.
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,3 @@
|
||||||
const div = document.querySelector('.github-topic-projects')
|
|
||||||
|
|
||||||
async function getDataBatch(page) {
|
|
||||||
const response = await fetch(`https://api.github.com/search/repositories?q=topic:fastapi&per_page=100&page=${page}`, { headers: { Accept: 'application/vnd.github.mercy-preview+json' } })
|
|
||||||
const data = await response.json()
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getData() {
|
|
||||||
let page = 1
|
|
||||||
let data = []
|
|
||||||
let dataBatch = await getDataBatch(page)
|
|
||||||
data = data.concat(dataBatch.items)
|
|
||||||
const totalCount = dataBatch.total_count
|
|
||||||
while (data.length < totalCount) {
|
|
||||||
page += 1
|
|
||||||
dataBatch = await getDataBatch(page)
|
|
||||||
data = data.concat(dataBatch.items)
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupTermynal() {
|
function setupTermynal() {
|
||||||
document.querySelectorAll(".use-termynal").forEach(node => {
|
document.querySelectorAll(".use-termynal").forEach(node => {
|
||||||
node.style.display = "block";
|
node.style.display = "block";
|
||||||
|
|
@ -158,20 +136,6 @@ async function showRandomAnnouncement(groupId, timeInterval) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
if (div) {
|
|
||||||
data = await getData()
|
|
||||||
div.innerHTML = '<ul></ul>'
|
|
||||||
const ul = document.querySelector('.github-topic-projects ul')
|
|
||||||
data.forEach(v => {
|
|
||||||
if (v.full_name === 'fastapi/fastapi') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const li = document.createElement('li')
|
|
||||||
li.innerHTML = `<a href="${v.html_url}" target="_blank">★ ${v.stargazers_count} - ${v.full_name}</a> by <a href="${v.owner.html_url}" target="_blank">@${v.owner.login}</a>`
|
|
||||||
ul.append(li)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
setupTermynal();
|
setupTermynal();
|
||||||
showRandomAnnouncement('announce-left', 5000)
|
showRandomAnnouncement('announce-left', 5000)
|
||||||
showRandomAnnouncement('announce-right', 10000)
|
showRandomAnnouncement('announce-right', 10000)
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ plugins:
|
||||||
- members: ../en/data/members.yml
|
- members: ../en/data/members.yml
|
||||||
- sponsors_badge: ../en/data/sponsors_badge.yml
|
- sponsors_badge: ../en/data/sponsors_badge.yml
|
||||||
- sponsors: ../en/data/sponsors.yml
|
- sponsors: ../en/data/sponsors.yml
|
||||||
|
- topic_repos: ../en/data/topic_repos.yml
|
||||||
redirects:
|
redirects:
|
||||||
redirect_maps:
|
redirect_maps:
|
||||||
deployment/deta.md: deployment/cloud.md
|
deployment/deta.md: deployment/cloud.md
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
import logging
|
||||||
|
import secrets
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
from github import Github
|
||||||
|
from pydantic import BaseModel, SecretStr
|
||||||
|
from pydantic_settings import BaseSettings
|
||||||
|
|
||||||
|
|
||||||
|
class Settings(BaseSettings):
|
||||||
|
github_repository: str
|
||||||
|
github_token: SecretStr
|
||||||
|
|
||||||
|
|
||||||
|
class Repo(BaseModel):
|
||||||
|
name: str
|
||||||
|
html_url: str
|
||||||
|
stars: int
|
||||||
|
owner_login: str
|
||||||
|
owner_html_url: str
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
settings = Settings()
|
||||||
|
|
||||||
|
logging.info(f"Using config: {settings.model_dump_json()}")
|
||||||
|
g = Github(settings.github_token.get_secret_value(), per_page=100)
|
||||||
|
r = g.get_repo(settings.github_repository)
|
||||||
|
repos = g.search_repositories(query="topic:fastapi")
|
||||||
|
repos_list = list(repos)
|
||||||
|
final_repos: list[Repo] = []
|
||||||
|
for repo in repos_list[:100]:
|
||||||
|
if repo.full_name == settings.github_repository:
|
||||||
|
continue
|
||||||
|
final_repos.append(
|
||||||
|
Repo(
|
||||||
|
name=repo.name,
|
||||||
|
html_url=repo.html_url,
|
||||||
|
stars=repo.stargazers_count,
|
||||||
|
owner_login=repo.owner.login,
|
||||||
|
owner_html_url=repo.owner.html_url,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
data = [repo.model_dump() for repo in final_repos]
|
||||||
|
|
||||||
|
# Local development
|
||||||
|
# repos_path = Path("../docs/en/data/topic_repos.yml")
|
||||||
|
repos_path = Path("./docs/en/data/topic_repos.yml")
|
||||||
|
repos_old_content = repos_path.read_text(encoding="utf-8")
|
||||||
|
new_repos_content = yaml.dump(data, sort_keys=False, width=200, allow_unicode=True)
|
||||||
|
if repos_old_content == new_repos_content:
|
||||||
|
logging.info("The data hasn't changed. Finishing.")
|
||||||
|
return
|
||||||
|
repos_path.write_text(new_repos_content, encoding="utf-8")
|
||||||
|
logging.info("Setting up GitHub Actions git user")
|
||||||
|
subprocess.run(["git", "config", "user.name", "github-actions"], check=True)
|
||||||
|
subprocess.run(
|
||||||
|
["git", "config", "user.email", "github-actions@github.com"], check=True
|
||||||
|
)
|
||||||
|
branch_name = f"fastapi-topic-repos-{secrets.token_hex(4)}"
|
||||||
|
logging.info(f"Creating a new branch {branch_name}")
|
||||||
|
subprocess.run(["git", "checkout", "-b", branch_name], check=True)
|
||||||
|
logging.info("Adding updated file")
|
||||||
|
subprocess.run(["git", "add", str(repos_path)], check=True)
|
||||||
|
logging.info("Committing updated file")
|
||||||
|
message = "👥 Update FastAPI GitHub topic repositories"
|
||||||
|
subprocess.run(["git", "commit", "-m", message], check=True)
|
||||||
|
logging.info("Pushing branch")
|
||||||
|
subprocess.run(["git", "push", "origin", branch_name], check=True)
|
||||||
|
logging.info("Creating PR")
|
||||||
|
pr = r.create_pull(title=message, body=message, base="master", head=branch_name)
|
||||||
|
logging.info(f"Created PR: {pr.number}")
|
||||||
|
logging.info("Finished")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue