Initial push
This commit is contained in:
commit
d6212dbe91
3 changed files with 223 additions and 0 deletions
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 Mattia Verga
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
40
README.md
Normal file
40
README.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# find-inactive-packagers
|
||||
|
||||
A script for detecting inactive user in the Fedora packager group.
|
||||
|
||||
The script will search for any activity in the last year in:
|
||||
|
||||
- src.fedoraproject.org
|
||||
- datagrepper (this includes src.fedoraproject.org but it's slower)
|
||||
- Fedora mailing lists
|
||||
|
||||
It will output the `inactive_packagers.csv` file with a list of all users in the packager
|
||||
group and their email which are found to be inactive. This can be used to contact
|
||||
the inactive users, asking them to show some activity in pagure, datagrepper or mailing lists.
|
||||
|
||||
If `inactive_packagers.csv` is already present in the directory, it will be used as to be the
|
||||
result of the previous run, so the script will also output the `still_inactive.csv` file.
|
||||
This other file will list all usernames which were contacted after the previous run,
|
||||
but still don't show any activity. Therefore we should consider these users to have
|
||||
abandoned Fedora.
|
||||
|
||||
Use the `--privacy` flag to not print emails in the log.
|
||||
|
||||
You need fasjson_client to be installed and an active kerberos ticket
|
||||
to login to fasjson.fedoraproject.org.
|
||||
|
||||
## Example usage
|
||||
|
||||
```
|
||||
$ pipenv shell
|
||||
...
|
||||
$ pip install fasjson-client
|
||||
...
|
||||
$ kinit <USER>@FEDORAPROJECT.ORG
|
||||
...
|
||||
$ python find-inactive-packagers.py [--privacy]
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
find-inactive-packagers is licensed under MIT.
|
||||
162
find_inactive_packagers.py
Normal file
162
find_inactive_packagers.py
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
# -*- coding:utf-8 -*-
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2022 Mattia Verga <mattia.verga@protonmail.com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
#
|
||||
|
||||
"""Detect inactive user in the packager group.
|
||||
|
||||
The script will search for any activity in the last year in:
|
||||
|
||||
- src.fedoraproject.org
|
||||
- datagrepper (this includes src.fedoraproject.org but it's slower)
|
||||
- Fedora mailing lists
|
||||
|
||||
It will output the 'inactive_packagers.csv' file with a list of all users in the packager
|
||||
group and their email which are found to be inactive. This can be used to contact
|
||||
the inactive users, asking them to show some activity in pagure, datagrepper or mailing lists.
|
||||
|
||||
If 'inactive_packagers.csv' is already present in the directory, it will be used as to be the
|
||||
result of the previous run, so the script will also output the 'still_inactive.csv' file.
|
||||
This other file will list all usernames which were contacted after the previous run,
|
||||
but still don't show any activity. Therefore we should consider these users to have
|
||||
abandoned Fedora.
|
||||
|
||||
Use the '--privacy' flag to not print emails in the log.
|
||||
|
||||
You need fasjson_client to be installed and an active kerberos ticket
|
||||
to login to fasjson.fedoraproject.org.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import requests
|
||||
import sys
|
||||
from copy import copy
|
||||
from datetime import datetime, timezone
|
||||
from os.path import exists as file_exists
|
||||
|
||||
from fasjson_client import Client
|
||||
|
||||
logging.basicConfig(level=logging.INFO,
|
||||
format='%(message)s',
|
||||
handlers=[
|
||||
logging.FileHandler(f'find_inactive_packagers_{datetime.now(timezone.utc).strftime("%Y_%m_%d")}.log', 'w+'),
|
||||
logging.StreamHandler(sys.stdout)
|
||||
])
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--privacy", action='store_true', help='Hide users email in log.')
|
||||
args = parser.parse_args()
|
||||
|
||||
prev_results = {}
|
||||
if file_exists('inactive_packagers.csv'):
|
||||
with open('inactive_packagers.csv', 'r') as fin:
|
||||
for line in fin:
|
||||
user, email = line.split(',')
|
||||
prev_results[user] = email.strip()
|
||||
print(prev_results)
|
||||
|
||||
# OLD method
|
||||
# r = requests.get('https://src.fedoraproject.org/api/0/group/packager').json()
|
||||
# packagers = r.get('members', [])
|
||||
|
||||
client = Client('https://fasjson.fedoraproject.org/')
|
||||
packagers = client.list_group_members(groupname='packager').result
|
||||
logging.info(f'### Found {len(packagers)} users in the packager group. ###')
|
||||
|
||||
inactive_packagers = []
|
||||
|
||||
# Check for activity in Pagure
|
||||
# may take a while...
|
||||
logging.info(f'Checking users activity in src.fedoraproject.org...')
|
||||
for i, p in enumerate(packagers):
|
||||
user = p.get('username')
|
||||
try:
|
||||
r = requests.get(f'https://src.fedoraproject.org/api/0/user/{user}/activity/stats').json()
|
||||
if not r:
|
||||
logging.info(f'No packaging activity detected for user {user}.')
|
||||
inactive_packagers.append(user)
|
||||
except Exception:
|
||||
# May happen when the user never interacted with pagure
|
||||
logging.warning(f'Error while retrieving data for user {user} (possibly not existent).')
|
||||
inactive_packagers.append(user)
|
||||
if i % 100 == 0:
|
||||
logging.info(f'Done {i}.')
|
||||
|
||||
logging.info(f'### Found {len(inactive_packagers)} users with no activity in pagure over the last year. ###')
|
||||
|
||||
# Check for activity Fedora wide by datagrepper
|
||||
# May take more than a while...
|
||||
logging.info(f'Checking users activity in datagrepper...')
|
||||
for i, p in enumerate(copy(inactive_packagers)):
|
||||
try:
|
||||
r = requests.get(f'https://apps.fedoraproject.org/datagrepper/raw/?user={p}&order=desc&delta=31536000&rows_per_page=10').json()
|
||||
if r.get('total', 0) != 0:
|
||||
logging.info(f'User {p} is still active in Fedora.')
|
||||
inactive_packagers.remove(p)
|
||||
except Exception:
|
||||
# May happen if there are a lot of entries in datagrepper
|
||||
logging.error(f'Error while retrieving data for user {p}.')
|
||||
if i % 100 == 0:
|
||||
logging.info(f'Done {i}.')
|
||||
|
||||
logging.info(f'### Found {len(inactive_packagers)} users which also show no activity in datagrepper over the last year. ###')
|
||||
|
||||
# Finally, check for any activity in mailing lists
|
||||
logging.info(f'Checking users activity in mailing lists...')
|
||||
packager_email_map = {}
|
||||
for i, p in enumerate(inactive_packagers):
|
||||
try:
|
||||
packager = client.get_user(username=p).result
|
||||
email = packager['emails'][0]
|
||||
r = requests.get(f'https://lists.fedoraproject.org/archives/api/sender/{email}/emails/?ordering=-date').json()
|
||||
if r.get('count', 0) != 0:
|
||||
last_email_date = datetime.fromisoformat(r.get('results')[0]['date'].replace('Z', '+00:00'))
|
||||
time_delta = datetime.now(timezone.utc) - last_email_date
|
||||
if time_delta.days > 365:
|
||||
packager_email_map[p] = email
|
||||
else:
|
||||
logging.info(f'Found recent email from user {p}: {last_email_date}.')
|
||||
else:
|
||||
packager_email_map[p] = email
|
||||
except Exception:
|
||||
logging.error(f'Error while retrieving last mailing lists activity for user {p}.')
|
||||
packager_email_map[p] = email
|
||||
if i % 100 == 0:
|
||||
logging.info(f'Done {i}.')
|
||||
|
||||
logging.info(f'### Found {len(packager_email_map)} users which show also no activity in mailing lists over the last year. ###')
|
||||
if packager_email_map:
|
||||
logging.info(f'Final results are:')
|
||||
with open('inactive_packagers.csv', 'w') as fout:
|
||||
for user, email in packager_email_map.items():
|
||||
logging.info(f'{user} - {email if not args.privacy else "***"}')
|
||||
fout.write(f'{user},{email}\n')
|
||||
|
||||
if prev_results:
|
||||
still_inactive = set(prev_results.keys()).intersection(packager_email_map.keys())
|
||||
logging.info(f'### These {len(still_inactive)} users didn\'t react to previous inquiry: ###')
|
||||
with open('still_inactive.csv', 'w') as finactive:
|
||||
for user in still_inactive:
|
||||
logging.info(f'{user}')
|
||||
finactive.write(f'{user}\n')
|
||||
Loading…
Add table
Add a link
Reference in a new issue