+++ /dev/null
-# psycopg3 backers
-
-`psycopg3` is brought to you thanks to the help of our generous backers.
-
-Thank you very much for supporting the project!
-
-
-## Github Sponsors
-
-<a href="https://github.com/gporcari"><img src="https://avatars2.githubusercontent.com/u/601732?v=4" title="Giovanni Porcari" width="100" height="100" style="border-radius: 50%"></a>
-<a href="https://github.com/svennek"><img src="https://avatars3.githubusercontent.com/u/37837?v=4" title="Svenne Krap" width="100" height="100" style="border-radius: 50%"></a>
-<a href="https://github.com/pontikos"><img src="https://avatars3.githubusercontent.com/u/3852020?v=4" title="Nikolas Pontikos" width="100" height="100" style="border-radius: 50%"></a>
-<a href="https://github.com/jdatcmd"><img src="https://avatars0.githubusercontent.com/u/330373?v=4" title="Joshua D. Drake" width="100" height="100" style="border-radius: 50%"></a>
-
-<a href="https://github.com/taifu"><img src="https://avatars1.githubusercontent.com/u/115712?v=4" title="Marco Beri" width="60" height="60" style="border-radius: 50%"></a>
-<a href="https://github.com/la-mar"><img src="https://avatars0.githubusercontent.com/u/16618300?v=4" title="Brock Friedrich" width="60" height="60" style="border-radius: 50%"></a>
-<a href="https://github.com/xarg"><img src="https://avatars2.githubusercontent.com/u/94721?v=4" title="Alex Plugaru" width="60" height="60" style="border-radius: 50%"></a>
-<a href="https://github.com/rafmagns-skepa-dreag"><img src="https://avatars0.githubusercontent.com/u/7447491?v=4" title="Richard H" width="60" height="60" style="border-radius: 50%"></a>
-<a href="https://github.com/rustprooflabs"><img src="https://avatars0.githubusercontent.com/u/3085224?v=4" title="Ryan Lambert" width="60" height="60" style="border-radius: 50%"></a>
-<a href="https://github.com/asqui"><img src="https://avatars3.githubusercontent.com/u/174182?v=4" title="Daniel Fortunov" width="60" height="60" style="border-radius: 50%"></a>
-<a href="https://github.com/iqbalabd"><img src="https://avatars2.githubusercontent.com/u/14254614?v=4" title="Iqbal Abdullah" width="60" height="60" style="border-radius: 50%"></a>
-<a href="https://github.com/c-rindi"><img src="https://avatars2.githubusercontent.com/u/7826876?v=4" title="C~+" width="60" height="60" style="border-radius: 50%"></a>
-<a href="https://github.com/Intevation"><img src="https://avatars2.githubusercontent.com/u/2050405?v=4" title="Intevation" width="60" height="60" style="border-radius: 50%"></a>
--- /dev/null
+---
+# You can find our sponsors at https://www.psycopg.org/sponsors/ Thank you!
+
+- username: gporcari
+ tier: top
+ avatar: https://avatars2.githubusercontent.com/u/601732?v=4
+ name: Giovanni Porcari
+
+- username: svennek
+ tier: top
+ avatar: https://avatars3.githubusercontent.com/u/37837?v=4
+ name: Svenne Krap
+
+- username: pontikos
+ tier: top
+ avatar: https://avatars3.githubusercontent.com/u/3852020?v=4
+ name: Nikolas Pontikos
+
+- username: jdatcmd
+ tier: top
+ avatar: https://avatars0.githubusercontent.com/u/330373?v=4
+ name: Joshua D. Drake
+
+
+- username: taifu
+ avatar: https://avatars1.githubusercontent.com/u/115712?v=4
+ name: Marco Beri
+
+- username: la-mar
+ avatar: https://avatars0.githubusercontent.com/u/16618300?v=4
+ name: Brock Friedrich
+
+- username: xarg
+ avatar: https://avatars2.githubusercontent.com/u/94721?v=4
+ name: Alex Plugaru
+
+- username: rafmagns-skepa-dreag
+ avatar: https://avatars0.githubusercontent.com/u/7447491?v=4
+ name: Richard H
+
+- username: rustprooflabs
+ avatar: https://avatars0.githubusercontent.com/u/3085224?v=4
+ name: Ryan Lambert
+
+- username: asqui
+ avatar: https://avatars3.githubusercontent.com/u/174182?v=4
+ name: Daniel Fortunov
+
+- username: iqbalabd
+ avatar: https://avatars2.githubusercontent.com/u/14254614?v=4
+ name: Iqbal Abdullah
+
+- username: c-rindi
+ avatar: https://avatars2.githubusercontent.com/u/7826876?v=4
+ name: C~+
+
+- username: Intevation
+ by: bernhardreiter
+ avatar: https://avatars2.githubusercontent.com/u/2050405?v=4
+ name: Intevation
+++ /dev/null
-#!/usr/bin/env python3
-r"""Add a github user to the backers file
-
-Print the tag to represent an user.
-
-Hint: to reprocess the list of users you can use:
-
- grep 'github.com.*"100"' BACKERS.md \
- | sed 's|\(.*github.com/\)\([^"]\+\)\(.*\)|\2|' \
- | xargs ./tools/add_backer.py --big
-
- grep 'github.com.*"60"' BACKERS.md \
- | sed 's|\(.*github.com/\)\([^"]\+\)\(.*\)|\2|' \
- | xargs ./tools/add_backer.py
-"""
-
-import sys
-import html
-import logging
-import requests
-
-logger = logging.getLogger()
-logging.basicConfig(
- level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s"
-)
-
-
-def main():
- opt = parse_cmdline()
- tags = []
- for username in opt.username:
- logger.info("fetching %s", username)
- resp = requests.get(
- f"https://api.github.com/users/{username}",
- headers={"Accept": "application/vnd.github.v3+json"},
- )
- size = 100 if opt.big else 60
- resp.raise_for_status()
- data = resp.json()
- tags.append(
- f"""<a href="{data['html_url']}">"""
- f"""<img src="{data['avatar_url']}" """
- f"""title="{html.escape(data['name'])}" """
- f"""width="{size}" height="{size}" """
- f"""style="border-radius: 50%"></a>"""
- )
- for tag in tags:
- print(tag)
-
-
-def parse_cmdline():
- from argparse import ArgumentParser
-
- parser = ArgumentParser(description=__doc__)
- parser.add_argument("username", nargs="*", help="github user to add")
- parser.add_argument("--big", action="store_true", help="make them larger")
-
- opt = parser.parse_args()
-
- return opt
-
-
-if __name__ == "__main__":
- sys.exit(main())
--- /dev/null
+#!/usr/bin/env python3
+r"""Add or edit github users in the backers file
+"""
+
+import sys
+import logging
+import requests
+from pathlib import Path
+from ruamel.yaml import YAML
+
+logger = logging.getLogger()
+logging.basicConfig(
+ level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s"
+)
+
+
+def fetch_user(username):
+ logger.info("fetching %s", username)
+ resp = requests.get(
+ f"https://api.github.com/users/{username}",
+ headers={"Accept": "application/vnd.github.v3+json"},
+ )
+ resp.raise_for_status()
+ return resp.json()
+
+
+def get_user_data(data):
+ """
+ Get the data to save from the request data
+ """
+ return {
+ "username": data["login"],
+ "avatar": data["avatar_url"],
+ "name": data["name"],
+ }
+
+
+def add_entry(opt, filedata, username):
+ userdata = get_user_data(fetch_user(username))
+ if opt.top:
+ userdata["tier"] = "top"
+
+ filedata.append(userdata)
+
+
+def update_entry(opt, filedata, entry):
+ # entry is an username or an user entry daat
+ if isinstance(entry, str):
+ username = entry
+ entry = [e for e in filedata if e["username"] == username]
+ if not entry:
+ raise Exception(f"{username} not found")
+ entry = entry[0]
+ else:
+ username = entry["username"]
+
+ userdata = get_user_data(fetch_user(username))
+ entry.update(userdata)
+
+
+def main():
+ opt = parse_cmdline()
+ logger.info("reading %s", opt.file)
+ yaml = YAML(typ="rt")
+ filedata = yaml.load(opt.file)
+
+ for username in opt.add or ():
+ add_entry(opt, filedata, username)
+
+ for username in opt.update or ():
+ update_entry(opt, filedata, username)
+
+ if opt.update_all:
+ for entry in filedata:
+ update_entry(opt, filedata, entry)
+
+ # yamllint happy
+ yaml.explicit_start = True
+ logger.info("writing %s", opt.file)
+ yaml.dump(filedata, opt.file)
+
+
+def parse_cmdline():
+ from argparse import ArgumentParser
+
+ parser = ArgumentParser(description=__doc__)
+ parser.add_argument(
+ "--file",
+ help="the file to update [default: %(default)s]",
+ default=Path(__file__).parent.parent / "BACKERS.yaml",
+ type=Path,
+ )
+ parser.add_argument(
+ "--add",
+ metavar="USERNAME",
+ nargs="+",
+ help="add USERNAME to the backers",
+ )
+
+ parser.add_argument(
+ "--top",
+ action="store_true",
+ help="add to the top tier",
+ )
+
+ parser.add_argument(
+ "--update",
+ metavar="USERNAME",
+ nargs="+",
+ help="update USERNAME data",
+ )
+
+ parser.add_argument(
+ "--update-all",
+ action="store_true",
+ help="update all the existing backers data",
+ )
+
+ opt = parser.parse_args()
+
+ return opt
+
+
+if __name__ == "__main__":
+ sys.exit(main())