snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
This commit is contained in:
157
manage.py
Executable file
157
manage.py
Executable file
@@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env python3
|
||||
import configparser
|
||||
import os
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.append(BASE_DIR)
|
||||
from scripts.lib.setup_path import setup_path
|
||||
|
||||
setup_path()
|
||||
|
||||
from django.core.management import ManagementUtility, get_commands
|
||||
from django.core.management.color import color_style
|
||||
from typing_extensions import override
|
||||
|
||||
from scripts.lib.zulip_tools import assert_not_running_as_root
|
||||
|
||||
|
||||
def get_filtered_commands() -> dict[str, str]:
|
||||
"""Because Zulip uses management commands in production, `manage.py
|
||||
help` is a form of documentation for users. Here we exclude from
|
||||
that documentation built-in commands that are not constructive for
|
||||
end users or even Zulip developers to run.
|
||||
|
||||
Ideally, we'd do further customization to display management
|
||||
commands with more organization in the help text, and also hide
|
||||
development-focused management commands in production.
|
||||
"""
|
||||
all_commands = get_commands()
|
||||
documented_commands = dict()
|
||||
documented_apps = [
|
||||
# "auth" removed because its commands are not applicable to Zulip.
|
||||
# "contenttypes" removed because we don't use that subsystem, and
|
||||
# even if we did.
|
||||
"django.core",
|
||||
"analytics",
|
||||
# "otp_static" removed because it's a 2FA internals detail.
|
||||
# "sessions" removed because it's just a cron job with a misleading
|
||||
# name, since all it does is delete expired sessions.
|
||||
# "social_django" removed for similar reasons to sessions.
|
||||
# "staticfiles" removed because its commands are only usefully run when
|
||||
# wrapped by Zulip tooling.
|
||||
# "two_factor" removed because it's a 2FA internals detail.
|
||||
"zerver",
|
||||
"zilencer",
|
||||
]
|
||||
documented_command_subsets = {
|
||||
"django.core": {
|
||||
"changepassword",
|
||||
"dbshell",
|
||||
"makemigrations",
|
||||
"migrate",
|
||||
"shell",
|
||||
"showmigrations",
|
||||
},
|
||||
}
|
||||
for command, app in all_commands.items():
|
||||
if app not in documented_apps:
|
||||
continue
|
||||
if app in documented_command_subsets and command not in documented_command_subsets[app]:
|
||||
continue
|
||||
|
||||
documented_commands[command] = app
|
||||
return documented_commands
|
||||
|
||||
|
||||
class FilteredManagementUtility(ManagementUtility):
|
||||
"""Replaces the main_help_text function of ManagementUtility with one
|
||||
that calls our get_filtered_commands(), rather than the default
|
||||
get_commands() function.
|
||||
|
||||
All other changes are just code style differences to pass the Zulip linter.
|
||||
"""
|
||||
|
||||
@override
|
||||
def main_help_text(self, commands_only: bool = False) -> str:
|
||||
"""Return the script's main help text, as a string."""
|
||||
if commands_only:
|
||||
usage = sorted(get_filtered_commands())
|
||||
else:
|
||||
usage = [
|
||||
"",
|
||||
f"Type '{self.prog_name} help <subcommand>' for help on a specific subcommand.",
|
||||
"",
|
||||
"Available subcommands:",
|
||||
]
|
||||
commands_dict = defaultdict(list)
|
||||
for name, app in get_filtered_commands().items():
|
||||
if app == "django.core":
|
||||
app = "django"
|
||||
else:
|
||||
app = app.rpartition(".")[-1]
|
||||
commands_dict[app].append(name)
|
||||
style = color_style()
|
||||
for app in sorted(commands_dict):
|
||||
usage.append("")
|
||||
usage.append(style.NOTICE(f"[{app}]"))
|
||||
usage.extend(f" {name}" for name in sorted(commands_dict[app]))
|
||||
# Output an extra note if settings are not properly configured
|
||||
if self.settings_exception is not None:
|
||||
usage.append(
|
||||
style.NOTICE(
|
||||
"Note that only Django core commands are listed "
|
||||
f"as settings are not properly configured (error: {self.settings_exception})."
|
||||
)
|
||||
)
|
||||
|
||||
return "\n".join(usage)
|
||||
|
||||
|
||||
def execute_from_command_line(argv: list[str] | None = None) -> None:
|
||||
"""Run a FilteredManagementUtility."""
|
||||
utility = FilteredManagementUtility(argv)
|
||||
utility.execute()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1 and sys.argv[1] == "email_server":
|
||||
# This needs to be able to run as root to read certificates
|
||||
# for STARTTLS, and bind to port 25.
|
||||
pass
|
||||
else:
|
||||
assert_not_running_as_root()
|
||||
|
||||
config_file = configparser.RawConfigParser()
|
||||
config_file.read("/etc/zulip/zulip.conf")
|
||||
PRODUCTION = config_file.has_option("machine", "deploy_type")
|
||||
HAS_SECRETS = os.access("/etc/zulip/zulip-secrets.conf", os.R_OK)
|
||||
|
||||
if PRODUCTION and not HAS_SECRETS:
|
||||
# The best way to detect running manage.py as another user in
|
||||
# production before importing anything that would require that
|
||||
# access is to check for access to /etc/zulip/zulip.conf (in
|
||||
# which case it's a production server, not a dev environment)
|
||||
# and lack of access for /etc/zulip/zulip-secrets.conf (which
|
||||
# should be only readable by root and zulip)
|
||||
print(
|
||||
"Error accessing Zulip secrets; manage.py in production must be run as the zulip user."
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "zproject.settings")
|
||||
from django.conf import settings
|
||||
from django.core.management.base import CommandError
|
||||
|
||||
from scripts.lib.zulip_tools import log_management_command
|
||||
|
||||
log_management_command(sys.argv, settings.MANAGEMENT_LOG_PATH)
|
||||
|
||||
if "--no-traceback" not in sys.argv and len(sys.argv) > 1:
|
||||
sys.argv.append("--traceback")
|
||||
try:
|
||||
execute_from_command_line(sys.argv)
|
||||
except CommandError as e:
|
||||
print(e, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user