ci: merge main to release(#7613)

ci: merge main to release
This commit is contained in:
Robert Sparks 2024-06-28 15:04:26 -05:00 committed by GitHub
commit 2033d607ec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 165 additions and 94 deletions

View file

@ -430,6 +430,7 @@ jobs:
with: with:
workflow: deploy.yml workflow: deploy.yml
repo: ietf-tools/infra-k8s repo: ietf-tools/infra-k8s
ref: main
token: ${{ secrets.GH_INFRA_K8S_TOKEN }} token: ${{ secrets.GH_INFRA_K8S_TOKEN }}
inputs: '{ "environment":"${{ secrets.GHA_K8S_CLUSTER }}", "app":"datatracker", "appVersion":"${{ env.PKG_VERSION }}", "remoteRef":"${{ github.sha }}" }' inputs: '{ "environment":"${{ secrets.GHA_K8S_CLUSTER }}", "app":"datatracker", "appVersion":"${{ env.PKG_VERSION }}", "remoteRef":"${{ github.sha }}" }'
wait-for-completion: true wait-for-completion: true
@ -455,6 +456,7 @@ jobs:
with: with:
workflow: deploy.yml workflow: deploy.yml
repo: ietf-tools/infra-k8s repo: ietf-tools/infra-k8s
ref: main
token: ${{ secrets.GH_INFRA_K8S_TOKEN }} token: ${{ secrets.GH_INFRA_K8S_TOKEN }}
inputs: '{ "environment":"${{ secrets.GHA_K8S_CLUSTER }}", "app":"datatracker", "appVersion":"${{ env.PKG_VERSION }}", "remoteRef":"${{ github.sha }}" }' inputs: '{ "environment":"${{ secrets.GHA_K8S_CLUSTER }}", "app":"datatracker", "appVersion":"${{ env.PKG_VERSION }}", "remoteRef":"${{ github.sha }}" }'
wait-for-completion: true wait-for-completion: true

View file

@ -11,7 +11,7 @@
"nanoid": "5.0.7", "nanoid": "5.0.7",
"nanoid-dictionary": "5.0.0-beta.1", "nanoid-dictionary": "5.0.0-beta.1",
"slugify": "1.6.6", "slugify": "1.6.6",
"tar": "^7.1.0", "tar": "^7.4.0",
"yargs": "^17.7.2" "yargs": "^17.7.2"
}, },
"engines": { "engines": {
@ -496,9 +496,9 @@
} }
}, },
"node_modules/minipass": { "node_modules/minipass": {
"version": "7.1.0", "version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"engines": { "engines": {
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.17"
} }
@ -788,13 +788,13 @@
} }
}, },
"node_modules/tar": { "node_modules/tar": {
"version": "7.1.0", "version": "7.4.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-7.1.0.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.0.tgz",
"integrity": "sha512-ENhg4W6BmjYxl8GTaE7/h99f0aXiSWv4kikRZ9n2/JRxypZniE84ILZqimAhxxX7Zb8Px6pFdheW3EeHfhnXQQ==", "integrity": "sha512-XQs0S8fuAkQWuqhDeCdMlJXDX80D7EOVLDPVFkna9yQfzS+PHKgfxcei0jf6/+QAWcjqrnC8uM3fSAnrQl+XYg==",
"dependencies": { "dependencies": {
"@isaacs/fs-minipass": "^4.0.0", "@isaacs/fs-minipass": "^4.0.0",
"chownr": "^3.0.0", "chownr": "^3.0.0",
"minipass": "^7.1.0", "minipass": "^7.1.2",
"minizlib": "^3.0.1", "minizlib": "^3.0.1",
"mkdirp": "^3.0.1", "mkdirp": "^3.0.1",
"yallist": "^5.0.0" "yallist": "^5.0.0"
@ -1311,9 +1311,9 @@
} }
}, },
"minipass": { "minipass": {
"version": "7.1.0", "version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==" "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="
}, },
"minizlib": { "minizlib": {
"version": "3.0.1", "version": "3.0.1",
@ -1503,13 +1503,13 @@
} }
}, },
"tar": { "tar": {
"version": "7.1.0", "version": "7.4.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-7.1.0.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.0.tgz",
"integrity": "sha512-ENhg4W6BmjYxl8GTaE7/h99f0aXiSWv4kikRZ9n2/JRxypZniE84ILZqimAhxxX7Zb8Px6pFdheW3EeHfhnXQQ==", "integrity": "sha512-XQs0S8fuAkQWuqhDeCdMlJXDX80D7EOVLDPVFkna9yQfzS+PHKgfxcei0jf6/+QAWcjqrnC8uM3fSAnrQl+XYg==",
"requires": { "requires": {
"@isaacs/fs-minipass": "^4.0.0", "@isaacs/fs-minipass": "^4.0.0",
"chownr": "^3.0.0", "chownr": "^3.0.0",
"minipass": "^7.1.0", "minipass": "^7.1.2",
"minizlib": "^3.0.1", "minizlib": "^3.0.1",
"mkdirp": "^3.0.1", "mkdirp": "^3.0.1",
"yallist": "^5.0.0" "yallist": "^5.0.0"

View file

@ -7,7 +7,7 @@
"nanoid": "5.0.7", "nanoid": "5.0.7",
"nanoid-dictionary": "5.0.0-beta.1", "nanoid-dictionary": "5.0.0-beta.1",
"slugify": "1.6.6", "slugify": "1.6.6",
"tar": "^7.1.0", "tar": "^7.4.0",
"yargs": "^17.7.2" "yargs": "^17.7.2"
}, },
"engines": { "engines": {

View file

@ -17,7 +17,7 @@
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"luxon": "^3.4.4", "luxon": "^3.4.4",
"pretty-bytes": "^6.1.1", "pretty-bytes": "^6.1.1",
"tar": "^7.1.0", "tar": "^7.4.0",
"yargs": "^17.7.2" "yargs": "^17.7.2"
}, },
"engines": { "engines": {
@ -1101,9 +1101,9 @@
} }
}, },
"node_modules/minipass": { "node_modules/minipass": {
"version": "7.1.0", "version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"engines": { "engines": {
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.17"
} }
@ -1493,13 +1493,13 @@
} }
}, },
"node_modules/tar": { "node_modules/tar": {
"version": "7.1.0", "version": "7.4.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-7.1.0.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.0.tgz",
"integrity": "sha512-ENhg4W6BmjYxl8GTaE7/h99f0aXiSWv4kikRZ9n2/JRxypZniE84ILZqimAhxxX7Zb8Px6pFdheW3EeHfhnXQQ==", "integrity": "sha512-XQs0S8fuAkQWuqhDeCdMlJXDX80D7EOVLDPVFkna9yQfzS+PHKgfxcei0jf6/+QAWcjqrnC8uM3fSAnrQl+XYg==",
"dependencies": { "dependencies": {
"@isaacs/fs-minipass": "^4.0.0", "@isaacs/fs-minipass": "^4.0.0",
"chownr": "^3.0.0", "chownr": "^3.0.0",
"minipass": "^7.1.0", "minipass": "^7.1.2",
"minizlib": "^3.0.1", "minizlib": "^3.0.1",
"mkdirp": "^3.0.1", "mkdirp": "^3.0.1",
"yallist": "^5.0.0" "yallist": "^5.0.0"
@ -2433,9 +2433,9 @@
} }
}, },
"minipass": { "minipass": {
"version": "7.1.0", "version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==" "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="
}, },
"minizlib": { "minizlib": {
"version": "3.0.1", "version": "3.0.1",
@ -2691,13 +2691,13 @@
} }
}, },
"tar": { "tar": {
"version": "7.1.0", "version": "7.4.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-7.1.0.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.0.tgz",
"integrity": "sha512-ENhg4W6BmjYxl8GTaE7/h99f0aXiSWv4kikRZ9n2/JRxypZniE84ILZqimAhxxX7Zb8Px6pFdheW3EeHfhnXQQ==", "integrity": "sha512-XQs0S8fuAkQWuqhDeCdMlJXDX80D7EOVLDPVFkna9yQfzS+PHKgfxcei0jf6/+QAWcjqrnC8uM3fSAnrQl+XYg==",
"requires": { "requires": {
"@isaacs/fs-minipass": "^4.0.0", "@isaacs/fs-minipass": "^4.0.0",
"chownr": "^3.0.0", "chownr": "^3.0.0",
"minipass": "^7.1.0", "minipass": "^7.1.2",
"minizlib": "^3.0.1", "minizlib": "^3.0.1",
"mkdirp": "^3.0.1", "mkdirp": "^3.0.1",
"yallist": "^5.0.0" "yallist": "^5.0.0"

View file

@ -13,7 +13,7 @@
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"luxon": "^3.4.4", "luxon": "^3.4.4",
"pretty-bytes": "^6.1.1", "pretty-bytes": "^6.1.1",
"tar": "^7.1.0", "tar": "^7.4.0",
"yargs": "^17.7.2" "yargs": "^17.7.2"
}, },
"engines": { "engines": {

View file

@ -19,6 +19,7 @@ from zoneinfo import ZoneInfo
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.db.models import OuterRef
from django.forms import ValidationError from django.forms import ValidationError
from django.http import Http404 from django.http import Http404
from django.template.loader import render_to_string from django.template.loader import render_to_string
@ -39,7 +40,7 @@ from ietf.doc.models import TelechatDocEvent, DocumentActionHolder, EditedAuthor
from ietf.name.models import DocReminderTypeName, DocRelationshipName from ietf.name.models import DocReminderTypeName, DocRelationshipName
from ietf.group.models import Role, Group, GroupFeatures from ietf.group.models import Role, Group, GroupFeatures
from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream, is_individual_draft_author, is_bofreq_editor from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream, is_individual_draft_author, is_bofreq_editor
from ietf.person.models import Person from ietf.person.models import Email, Person
from ietf.review.models import ReviewWish from ietf.review.models import ReviewWish
from ietf.utils import draft, log from ietf.utils import draft, log
from ietf.utils.mail import parseaddr, send_mail from ietf.utils.mail import parseaddr, send_mail
@ -1301,9 +1302,13 @@ class DraftAliasGenerator:
def get_draft_authors_emails(self, doc): def get_draft_authors_emails(self, doc):
"""Get list of authors for the given draft.""" """Get list of authors for the given draft."""
author_emails = set() author_emails = set()
for author in doc.documentauthor_set.all(): for email in Email.objects.filter(documentauthor__document=doc):
if author.email and author.email.email_address(): if email.active:
author_emails.add(author.email.email_address()) author_emails.add(email.address)
elif email.person:
person_email = email.person.email_address()
if person_email:
author_emails.add(person_email)
return author_emails return author_emails
def get_draft_notify_emails(self, doc): def get_draft_notify_emails(self, doc):
@ -1336,59 +1341,82 @@ class DraftAliasGenerator:
notify_emails.add(email) notify_emails.add(email)
return notify_emails return notify_emails
def _yield_aliases_for_draft(self, doc)-> Iterator[tuple[str, list[str]]]:
alias = doc.name
all = set()
# no suffix and .authors are the same list
emails = self.get_draft_authors_emails(doc)
all.update(emails)
if emails:
yield alias, list(emails)
yield alias + ".authors", list(emails)
# .chairs = group chairs
emails = self.get_draft_chair_emails(doc)
if emails:
all.update(emails)
yield alias + ".chairs", list(emails)
# .ad = sponsoring AD / WG AD (WG document)
emails = self.get_draft_ad_emails(doc)
if emails:
all.update(emails)
yield alias + ".ad", list(emails)
# .notify = notify email list from the Document
emails = self.get_draft_notify_emails(doc)
if emails:
all.update(emails)
yield alias + ".notify", list(emails)
# .shepherd = shepherd email from the Document
emails = self.get_draft_shepherd_email(doc)
if emails:
all.update(emails)
yield alias + ".shepherd", list(emails)
# .all = everything from above
if all:
yield alias + ".all", list(all)
def __iter__(self) -> Iterator[tuple[str, list[str]]]: def __iter__(self) -> Iterator[tuple[str, list[str]]]:
# Internet-Drafts with active status or expired within self.days # Internet-Drafts with active status or expired within self.days
show_since = timezone.now() - datetime.timedelta(days=self.days) show_since = timezone.now() - datetime.timedelta(days=self.days)
drafts = self.draft_queryset drafts = self.draft_queryset
active_drafts = drafts.filter(states__slug='active')
inactive_recent_drafts = drafts.exclude(states__slug='active').filter(expires__gte=show_since)
interesting_drafts = active_drafts | inactive_recent_drafts
for this_draft in interesting_drafts.distinct().iterator(): # Look up the draft-active state properly. Doing this with
# states__type_id, states__slug directly in the `filter()`
# works, but it does not work as expected in `exclude()`.
active_state = State.objects.get(type_id="draft", slug="active")
active_drafts = drafts.filter(states=active_state)
for this_draft in active_drafts:
for alias, addresses in self._yield_aliases_for_draft(this_draft):
yield alias, addresses
# Annotate with the draft state slug so we can check for drafts that
# have become RFCs
inactive_recent_drafts = (
drafts.exclude(states=active_state)
.filter(expires__gte=show_since)
.annotate(
# Why _default_manager instead of objects? See:
# https://docs.djangoproject.com/en/4.2/topics/db/managers/#django.db.models.Model._default_manager
draft_state_slug=Document.states.through._default_manager.filter(
document__pk=OuterRef("pk"),
state__type_id="draft"
).values("state__slug"),
)
)
for this_draft in inactive_recent_drafts:
# Omit drafts that became RFCs, unless they were published in the last DEFAULT_YEARS # Omit drafts that became RFCs, unless they were published in the last DEFAULT_YEARS
if this_draft.get_state_slug() == "rfc": if this_draft.draft_state_slug == "rfc":
rfc = this_draft.became_rfc() rfc = this_draft.became_rfc()
log.assertion("rfc is not None") log.assertion("rfc is not None")
if rfc.latest_event(type='published_rfc').time < show_since: if rfc.latest_event(type='published_rfc').time < show_since:
continue continue
for alias, addresses in self._yield_aliases_for_draft(this_draft):
alias = this_draft.name yield alias, addresses
all = set()
# no suffix and .authors are the same list
emails = self.get_draft_authors_emails(this_draft)
all.update(emails)
if emails:
yield alias, list(emails)
yield alias + ".authors", list(emails)
# .chairs = group chairs
emails = self.get_draft_chair_emails(this_draft)
if emails:
all.update(emails)
yield alias + ".chairs", list(emails)
# .ad = sponsoring AD / WG AD (WG document)
emails = self.get_draft_ad_emails(this_draft)
if emails:
all.update(emails)
yield alias + ".ad", list(emails)
# .notify = notify email list from the Document
emails = self.get_draft_notify_emails(this_draft)
if emails:
all.update(emails)
yield alias + ".notify", list(emails)
# .shepherd = shepherd email from the Document
emails = self.get_draft_shepherd_email(this_draft)
if emails:
all.update(emails)
yield alias + ".shepherd", list(emails)
# .all = everything from above
if all:
yield alias + ".all", list(all)
def get_doc_email_aliases(name: Optional[str] = None): def get_doc_email_aliases(name: Optional[str] = None):

View file

@ -1,15 +1,9 @@
--- django_cprofile_middleware/middleware.py.old 2018-04-04 06:32:29.282187502 -0700 --- django_cprofile_middleware/middleware.py.old 2024-06-27 21:03:56.975128007 +0000
+++ django_cprofile_middleware/middleware.py 2018-04-06 10:11:18.936855634 -0700 +++ django_cprofile_middleware/middleware.py 2024-06-27 23:45:59.421683008 +0000
@@ -1,4 +1,5 @@ @@ -19,6 +19,16 @@
import pstats from django_cprofile_middleware.utils import MiddlewareMixin
+import re
try:
import cProfile as profile
@@ -14,6 +15,15 @@
from django.utils.deprecation import MiddlewareMixin
+class Stats(pstats.Stats): +class Stats(pstats.Stats):
+ def filter_stats(self, regex): + def filter_stats(self, regex):
+ oldstats = self.stats + oldstats = self.stats
@ -18,17 +12,64 @@
+ for func, (cc, nc, tt, ct, callers) in oldstats.iteritems(): + for func, (cc, nc, tt, ct, callers) in oldstats.iteritems():
+ if filter.search(pstats.func_std_string(func)): + if filter.search(pstats.func_std_string(func)):
+ newstats[func] = (cc, nc, tt, ct, callers) + newstats[func] = (cc, nc, tt, ct, callers)
+
+ +
class ProfilerMiddleware(MiddlewareMixin): class ProfilerMiddleware(MiddlewareMixin):
""" """
Simple profile middleware to profile django views. To run it, add ?prof to Simple profile middleware to profile django views. To run it, add ?prof to
@@ -62,8 +72,13 @@ @@ -38,9 +48,11 @@
?download => Download profile file suitable for visualization. For example
in snakeviz or RunSnakeRun
- This is adapted from an example found here:
- http://www.slideshare.net/zeeg/django-con-high-performance-django-presentation.
+ Patched with https://github.com/omarish/django-cprofile-middleware/pull/23
+ for operation with Django 4.2.5+
"""
+ PROFILER_REQUEST_ATTR_NAME = '_django_cprofile_middleware_profiler'
+
def can(self, request):
requires_staff = getattr(
settings, "DJANGO_CPROFILE_MIDDLEWARE_REQUIRE_STAFF", True)
@@ -52,10 +64,11 @@
def process_view(self, request, callback, callback_args, callback_kwargs):
if self.can(request):
- self.profiler = profile.Profile()
+ profiler = profile.Profile()
+ setattr(request, self.PROFILER_REQUEST_ATTR_NAME, profiler)
args = (request,) + callback_args
try:
- return self.profiler.runcall(
+ return profiler.runcall(
callback, *args, **callback_kwargs)
except Exception:
# we want the process_exception middleware to fire
@@ -63,12 +76,13 @@
return
def process_response(self, request, response):
- if self.can(request):
- self.profiler.create_stats()
+ if hasattr(request, self.PROFILER_REQUEST_ATTR_NAME):
+ profiler = getattr(request, self.PROFILER_REQUEST_ATTR_NAME)
+ profiler.create_stats()
if 'download' in request.GET:
import marshal
- output = marshal.dumps(self.profiler.stats)
+ output = marshal.dumps(profiler.stats)
response = HttpResponse(
output, content_type='application/octet-stream')
response['Content-Disposition'] = 'attachment;' \
@@ -76,9 +90,14 @@
response['Content-Length'] = len(output) response['Content-Length'] = len(output)
else: else:
io = StringIO() io = StringIO()
- stats = pstats.Stats(self.profiler, stream=io) - stats = pstats.Stats(self.profiler, stream=io)
+ stats = Stats(profiler, stream=io)
- stats.strip_dirs().sort_stats(request.GET.get('sort', 'time')) - stats.strip_dirs().sort_stats(request.GET.get('sort', 'time'))
+ stats = Stats(self.profiler, stream=io)
+ if request.GET.get('stripdirs', False): + if request.GET.get('stripdirs', False):
+ stats = stats.strip_dirs() + stats = stats.strip_dirs()
+ filter = request.GET.get('filter', None) + filter = request.GET.get('filter', None)
@ -36,5 +77,5 @@
+ stats.filter_stats(filter) + stats.filter_stats(filter)
+ stats.sort_stats(request.GET.get('psort') or 'time') + stats.sort_stats(request.GET.get('psort') or 'time')
stats.print_stats(int(request.GET.get('count', 100))) stats.print_stats(int(request.GET.get('count', 100)))
response = HttpResponse('<pre>%s</pre>' % io.getvalue()) response = HttpResponse('<pre>%s</pre>' % io.getvalue())
return response