Compare commits

...

18 Commits

Author SHA1 Message Date
Greg Price
3ff2bcf62a shared: Bump version to 0.0.10. 2022-03-30 21:06:37 -07:00
Anders Kaseorg
7de1e7c477 changelog: Remove broken link.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2022-03-30 20:37:31 -07:00
Steve Howell
b7f670f5a0 markdown: Extract set_linkifier_regexes.
This is definitely better than having linkifiers
reach directly into marked.js, but there is
probably further improvement we can do here
to clean up how these regexes get set.

This introduces a circular dependency between
markdown.js and linkifiers.js, but we will
soon break it in the other direction.
2022-03-30 14:31:00 -07:00
Steve Howell
2a240d3e19 markdown: Move handleLinkifier.
All the other handleFoo functions followed this
convention.
2022-03-30 14:31:00 -07:00
Steve Howell
efdf2c8fe3 linkifiers: Avoid parallel data structure.
We can pretty easily work with a map in the
two places that we ever relied on an array.
2022-03-30 14:31:00 -07:00
Steve Howell
71c12e313c markdown: Fix overly loose regex for previews.
Fortunately, the only impact of this bug was that
we would unnecessarily wait for the server to render
the markdown if we got false matches.
2022-03-30 14:31:00 -07:00
Steve Howell
da6d687215 markdown: Extract contains_preview_link.
I also clean up some variable names, comments, and
idioms.
2022-03-30 14:31:00 -07:00
Steve Howell
58799c6ca1 markdown: Extract contains_problematic_linkifier.
Note we now avoid linkifier checks for the case that a message
contains more obvious backend-only syntax such as attachments.

The next commit will eliminate the ugly early-return.
2022-03-30 14:31:00 -07:00
Steve Howell
8d9e6d6b87 markdown: Clean up API for future reuse.
This gets us closer to having an API that can
be used my mobile.

The parse() function becomes a subset of
apply_markdown() that is no longer coupled
to the shape of a webapp object, and it can
be supplied with a new helper_config for each
invocation. Mobile will likely call this directly.

The setup() function becomes a subset of
initialize() that allows you to set up the
parser **before** having to build any kind of
message-specific helpers. Mobile will likely
call this directly.

The webapp continues to call these functions,
which are now thin wrappers:

    * apply_markdown (wrapping parse)
    * initialize (wrapping setup)

Note we still have several other problems to
solve before mobile can use this code, but we
introduce this now so that we can get a head
start on prototyping and unit testing.

Also, this commit does not address the fact
that contains_backend_only_syntax() is still
bound to the webapp config.
2022-03-30 14:31:00 -07:00
Anders Kaseorg
935cb605a5 puppet: Do not ensure Chrony is running.
Commit f6d27562fa (#21564) tried to
ensure Chrony is running, which fails in containers where Chrony
doesn’t have permission to update the host clock.

The Debian package should still attempt to start it, and Puppet should
still restart it when chrony.conf is modified.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
2022-03-30 11:37:54 -07:00
Sahil Batra
ca38b33346 settings: Fix push notifications tooltip being incorrectly shown.
We were showing the push notifications tooltip in user default
settings section even if the push notifications were configured
on the server.

The bug was because the setting value was undefined in the template
used for user default settings section, so this commit fixes the bug
by correctly passing the setting value to relevant template file.

Fixes #21602.
2022-03-30 11:31:29 -07:00
Lauryn Menard
0008a76703 tests: Remove ignored stream_name parameter from test.
Removes unnecessary `stream_name` parameter from
`test_stream_permission_changes_updates_updates_attachments`.
2022-03-30 11:30:31 -07:00
Tim Abbott
d9bf8baca1 tools: Add per-repository commit counts in contributions tool.
This makes the output nice enough to include in the blog post.
2022-03-29 14:13:17 -07:00
Tim Abbott
46b19fe8bd mailmap: Add entries to deduplicate more contributors. 2022-03-29 12:13:21 -07:00
Tim Abbott
c1103e4c7b i18n: Fix missing translation tag in footer. 2022-03-29 10:04:35 -07:00
Tim Abbott
c8dba33408 docs: Fix broken link in changelog. 2022-03-29 09:52:07 -07:00
Tim Abbott
6ea9947991 docs: Run prettier on changelog. 2022-03-29 09:24:06 -07:00
Tim Abbott
12e8f0f5ea version: Update version following 5.0 release. 2022-03-29 08:36:41 -07:00
15 changed files with 319 additions and 84 deletions

View File

@@ -12,6 +12,8 @@
# # shows raw names/emails, filtered by mapped name:
# $ git log --format='%an %ae' --author=$NAME | uniq -c
Adam Benesh <Adam.Benesh@gmail.com> <Adam-Daniel.Benesh@t-systems.com>
Adam Benesh <Adam.Benesh@gmail.com>
Alex Vandiver <alexmv@zulip.com> <alex@chmrr.net>
Alex Vandiver <alexmv@zulip.com> <github@chmrr.net>
Allen Rabinovich <allenrabinovich@yahoo.com> <allenr@humbughq.com>
@@ -20,6 +22,9 @@ Alya Abbott <alya@zulip.com> <2090066+alya@users.noreply.github.com>
Aman Agrawal <amanagr@zulip.com> <f2016561@pilani.bits-pilani.ac.in>
Anders Kaseorg <anders@zulip.com> <anders@zulipchat.com>
Anders Kaseorg <anders@zulip.com> <andersk@mit.edu>
Aryan Shridhar <aryanshridhar7@gmail.com> <53977614+aryanshridhar@users.noreply.github.com>
Aryan Shridhar <aryanshridhar7@gmail.com>
Ashwat Kumar Singh <ashwat.kumarsingh.met20@itbhu.ac.in>
Austin Riba <austin@zulip.com> <austin@m51.io>
BIKI DAS <bikid475@gmail.com>
Brock Whittaker <brock@zulipchat.com> <bjwhitta@asu.edu>
@@ -37,6 +42,7 @@ Jeff Arnold <jbarnold@gmail.com> <jbarnold@humbughq.com>
Jeff Arnold <jbarnold@gmail.com> <jbarnold@zulip.com>
Jessica McKellar <jesstess@mit.edu> <jesstess@humbughq.com>
Jessica McKellar <jesstess@mit.edu> <jesstess@zulip.com>
Julia Bichler <julia.bichler@tum.de> <74348920+juliaBichler01@users.noreply.github.com>
Kevin Mehall <km@kevinmehall.net> <kevin@humbughq.com>
Kevin Mehall <km@kevinmehall.net> <kevin@zulip.com>
Kevin Scott <kevin.scott.98@gmail.com>
@@ -45,11 +51,13 @@ Mateusz Mandera <mateusz.mandera@zulip.com> <mateusz.mandera@protonmail.com>
m-e-l-u-h-a-n <purushottam.tiwari.cd.cse19@itbhu.ac.in>
Palash Raghuwanshi <singhpalash0@gmail.com>
Parth <mittalparth22@gmail.com>
Priyam Seth <sethpriyam1@gmail.com> <b19188@students.iitmandi.ac.in>
Ray Kraesig <rkraesig@zulip.com> <rkraesig@zulipchat.com>
Reid Barton <rwbarton@gmail.com> <rwbarton@humbughq.com>
Rishi Gupta <rishig@zulipchat.com> <rishig+git@mit.edu>
Rishi Gupta <rishig@zulipchat.com> <rishig@kandralabs.com>
Rishi Gupta <rishig@zulipchat.com> <rishig@users.noreply.github.com>
Reid Barton <rwbarton@gmail.com> <rwbarton@humbughq.com>
Rishabh Maheshwari <b20063@students.iitmandi.ac.in>
Sayam Samal <samal.sayam@gmail.com>
Scott Feeney <scott@oceanbase.org> <scott@humbughq.com>
Scott Feeney <scott@oceanbase.org> <scott@zulip.com>
@@ -71,3 +79,5 @@ Sahil Batra <sahil@zulip.com> <sahilbatra839@gmail.com>
Yash RE <33805964+YashRE42@users.noreply.github.com> <YashRE42@github.com>
Yash RE <33805964+YashRE42@users.noreply.github.com>
Yogesh Sirsat <yogeshsirsat56@gmail.com>
Zeeshan Equbal <equbalzeeshan@gmail.com> <54993043+zee-bit@users.noreply.github.com>
Zeeshan Equbal <equbalzeeshan@gmail.com>

View File

@@ -1,9 +1,19 @@
# Version history
This page contains the release history for the Zulip 5.x stable
release series. See the [current Zulip changelog][latest-changelog]
for newer release series, or the [commit log][commit-log] for an
up-to-date list of raw changes.
This page the release history for the Zulip server. See also the
[Zulip release lifecycle](../overview/release-lifecycle.md).
## Zulip 6.x series
### 6.0 -- unreleased
This section is an incomplete draft of the release notes for the next
major release, and is only updated occasionally. See the [commit
log][commit-log] for an up-to-date list of raw changes.
#### Upgrade notes for 6.0
- None yet.
## Zulip 5.x series
@@ -1566,7 +1576,7 @@ Zulip installations; it has minimal changes for existing servers.
disruption by running this migration first, before beginning the
user-facing downtime. However, if you'd like to watch the downtime
phase of the upgrade closely, we recommend
[running them first manually](https://zulip.readthedocs.io/en/1.9.0/production/expensive-migrations.html)
running them first manually
as well as the usual trick of doing an apt upgrade first.
#### Full feature changelog
@@ -1955,7 +1965,7 @@ running a version from before 1.7 should upgrade directly to 1.7.1.
minimizes disruption by running these first, before beginning the
user-facing downtime. However, if you'd like to watch the downtime
phase of the upgrade closely, we recommend
[running them first manually](https://zulip.readthedocs.io/en/1.9.0/production/expensive-migrations.html)
running them first manually
as well as the usual trick of doing an apt upgrade first.
- We've removed support for an uncommon legacy deployment model where
@@ -2580,15 +2590,17 @@ running a version from before 1.7 should upgrade directly to 1.7.1.
This section links to the upgrade notes from past releases, so you can
easily read them all when upgrading across multiple releases.
- [Upgrade notes for 5.0](#upgrade-notes-for-50)
- [Upgrade notes for 4.0](#upgrade-notes-for-40)
- [Upgrade notes for 3.0](#upgrade-notes-for-30)
- [Upgrade notes for 2.1.5](#upgrade-notes-for-215)
- [Upgrade notes for 2.1.0](#upgrade-notes-for-210)
- [Upgrade notes for 2.0.0](#upgrade-notes-for-200)
- [Upgrade notes for 1.9.0](#upgrade-notes-for-190)
- [Upgrade notes for 1.8.0](#upgrade-notes-for-180)
- [Upgrade notes for 1.7.0](#upgrade-notes-for-170)
- [Draft upgrade notes for 6.0](#upgrade-notes-for-60)
* [Upgrade notes for 5.0](#upgrade-notes-for-50)
* [Upgrade notes for 4.0](#upgrade-notes-for-40)
* [Upgrade notes for 3.0](#upgrade-notes-for-30)
* [Upgrade notes for 2.1.5](#upgrade-notes-for-215)
* [Upgrade notes for 2.1.0](#upgrade-notes-for-210)
* [Upgrade notes for 2.0.0](#upgrade-notes-for-200)
* [Upgrade notes for 1.9.0](#upgrade-notes-for-190)
* [Upgrade notes for 1.8.0](#upgrade-notes-for-180)
* [Upgrade notes for 1.7.0](#upgrade-notes-for-170)
[docker-zulip]: https://github.com/zulip/docker-zulip
[commit-log]: https://github.com/zulip/zulip/commits/main

View File

@@ -0,0 +1,149 @@
"use strict";
const {strict: assert} = require("assert");
const {zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test");
const markdown = zrequire("markdown");
const my_id = 101;
const user_map = new Map();
user_map.set(my_id, "Me Myself");
user_map.set(105, "greg");
function get_actual_name_from_user_id(user_id) {
return user_map.get(user_id);
}
function get_user_id_from_name(name) {
for (const [user_id, _name] of user_map.entries()) {
if (name === _name) {
return user_id;
}
}
return undefined;
}
function is_valid_full_name_and_user_id(name, user_id) {
return user_map.has(user_id) && user_map.get(user_id) === name;
}
function my_user_id() {
return my_id;
}
function is_valid_user_id(user_id) {
return user_map.has(user_id);
}
const staff_group = {
id: 201,
name: "Staff",
};
const user_group_map = new Map();
user_group_map.set(staff_group.name, staff_group);
function get_user_group_from_name(name) {
return user_group_map.get(name);
}
function is_member_of_user_group(user_group_id, user_id) {
assert.equal(user_group_id, staff_group.id);
assert.equal(user_id, my_id);
return true;
}
const social = {
stream_id: 301,
name: "social",
};
const sub_map = new Map();
sub_map.set(social.name, social);
function get_stream_by_name(name) {
return sub_map.get(name);
}
function stream_hash(stream_id) {
return `stream-${stream_id}`;
}
function stream_topic_hash(stream_id, topic) {
return `stream-${stream_id}-topic-${topic}`;
}
const helper_config = {
// user stuff
get_actual_name_from_user_id,
get_user_id_from_name,
is_valid_full_name_and_user_id,
is_valid_user_id,
my_user_id,
// user groups
get_user_group_from_name,
is_member_of_user_group,
// stream hashes
get_stream_by_name,
stream_hash,
stream_topic_hash,
// settings
should_translate_emoticons: () => false,
};
function assert_parse(raw_content, expected_content) {
const {content} = markdown.parse({raw_content, helper_config});
assert.equal(content, expected_content);
}
function test(label, f) {
markdown.setup();
run_test(label, f);
}
test("basics", () => {
assert_parse("boring", "<p>boring</p>");
assert_parse("**bold**", "<p><strong>bold</strong></p>");
});
test("user mentions", () => {
assert_parse("@**greg**", '<p><span class="user-mention" data-user-id="105">@greg</span></p>');
assert_parse("@**|105**", '<p><span class="user-mention" data-user-id="105">@greg</span></p>');
assert_parse(
"@**greg|105**",
'<p><span class="user-mention" data-user-id="105">@greg</span></p>',
);
assert_parse(
"@**Me Myself|101**",
'<p><span class="user-mention" data-user-id="101">@Me Myself</span></p>',
);
});
test("user group mentions", () => {
assert_parse(
"@*Staff*",
'<p><span class="user-group-mention" data-user-group-id="201">@Staff</span></p>',
);
});
test("stream links", () => {
assert_parse(
"#**social**",
'<p><a class="stream" data-stream-id="301" href="/stream-301">#social</a></p>',
);
assert_parse(
"#**social>lunch**",
'<p><a class="stream-topic" data-stream-id="301" href="/stream-301-topic-lunch">#social &gt; lunch</a></p>',
);
});

View File

@@ -61,7 +61,7 @@ class zulip::profile::base {
}
}
package { 'ntp': ensure => 'purged', before => Package['chrony'] }
service { 'chrony': ensure => 'running', require => Package['chrony'] }
service { 'chrony': require => Package['chrony'] }
package { $base_packages: ensure => 'installed' }
group { 'zulip':

View File

@@ -161,6 +161,7 @@ export function build_page() {
settings_config.create_web_public_stream_policy_values,
disable_enable_spectator_access_setting: !page_params.server_web_public_streams_enabled,
can_sort_by_email: settings_data.show_email(),
realm_push_notifications_enabled: page_params.realm_push_notifications_enabled,
};
if (options.realm_logo_source !== "D" && options.realm_night_logo_source === "D") {

View File

@@ -1,22 +1,10 @@
import marked from "../third/marked/lib/marked";
import * as blueslip from "./blueslip";
import * as markdown from "./markdown";
const linkifier_map = new Map();
export let linkifier_list = [];
const linkifier_map = new Map(); // regex -> url
function handleLinkifier(pattern, matches) {
let url = linkifier_map.get(pattern);
let current_group = 1;
for (const match of matches) {
const back_ref = "\\" + current_group;
url = url.replace(back_ref, match);
current_group += 1;
}
return url;
export function get_linkifier_map() {
return linkifier_map;
}
function python_to_js_linkifier(pattern, url) {
@@ -78,11 +66,7 @@ function python_to_js_linkifier(pattern, url) {
}
export function update_linkifier_rules(linkifiers) {
// Update the marked parser with our particular set of linkifiers
linkifier_map.clear();
linkifier_list = [];
const marked_rules = [];
for (const linkifier of linkifiers) {
const [regex, final_url] = python_to_js_linkifier(linkifier.pattern, linkifier.url_format);
@@ -92,18 +76,12 @@ export function update_linkifier_rules(linkifiers) {
}
linkifier_map.set(regex, final_url);
linkifier_list.push({
pattern: regex,
url_format: final_url,
});
marked_rules.push(regex);
}
marked.InlineLexer.rules.zulip.linkifiers = marked_rules;
// Update our parser with our particular set of linkifiers.
markdown.set_linkifier_regexes(Array.from(linkifier_map.keys()));
}
export function initialize(linkifiers) {
update_linkifier_rules(linkifiers);
marked.setOptions({linkifierHandler: handleLinkifier});
}

View File

@@ -23,8 +23,9 @@ import * as linkifiers from "./linkifiers";
// for example usage.
let helpers;
// Regexes that match some of our common backend-only Markdown syntax
const backend_only_markdown_re = [
// If we see preview-related syntax in our content, we will need the
// backend to render it.
const preview_regexes = [
// Inline image previews, check for contiguous chars ending in image suffix
// To keep the below regexes simple, split them out for the end-of-message case
@@ -33,9 +34,13 @@ const backend_only_markdown_re = [
// Twitter and youtube links are given previews
/\S*(?:twitter|youtube).com\/\S*/,
/\S*(?:twitter|youtube)\.com\/\S*/,
];
function contains_preview_link(content) {
return preview_regexes.some((re) => re.test(content));
}
export function translate_emoticons_to_names(text) {
// Translates emoticons in a string to their colon syntax.
let translated = text;
@@ -76,25 +81,36 @@ export function translate_emoticons_to_names(text) {
return translated;
}
function contains_problematic_linkifier(content) {
// If a linkifier doesn't start with some specified characters
// then don't render it locally. It is workaround for the fact that
// javascript regex doesn't support lookbehind.
for (const re of linkifiers.get_linkifier_map().keys()) {
const pattern = /[^\s"'(,:<]/.source + re.source + /(?!\w)/.source;
const regex = new RegExp(pattern);
if (regex.test(content)) {
return true;
}
}
return false;
}
export function contains_backend_only_syntax(content) {
// Try to guess whether or not a message contains syntax that only the
// backend Markdown processor can correctly handle.
// If it doesn't, we can immediately render it client-side for local echo.
const markedup = backend_only_markdown_re.find((re) => re.test(content));
// If a linkifier doesn't start with some specified characters
// then don't render it locally. It is workaround for the fact that
// javascript regex doesn't support lookbehind.
const linkifier_list = linkifiers.linkifier_list;
const false_linkifier_match = linkifier_list.find((re) => {
const pattern = /[^\s"'(,:<]/.source + re.pattern.source + /(?!\w)/.source;
const regex = new RegExp(pattern);
return regex.test(content);
});
return markedup !== undefined || false_linkifier_match !== undefined;
return contains_preview_link(content) || contains_problematic_linkifier(content);
}
export function apply_markdown(message) {
export function parse({raw_content, helper_config}) {
// Given the raw markdown content of a message (raw_content)
// we return the HTML content (content) and flags.
// Our caller passes a helper_config object that has several
// helper functions for getting info about users, streams, etc.
helpers = helper_config;
let mentioned = false;
let mentioned_group = false;
let mentioned_wildcard = false;
@@ -249,20 +265,20 @@ export function apply_markdown(message) {
};
// Our Python-Markdown processor appends two \n\n to input
message.content = marked(message.raw_content + "\n\n", options).trim();
const content = marked(raw_content + "\n\n", options).trim();
// Simulate message flags for our locally rendered
// message. Messages the user themselves sent via the browser are
// always marked as read.
message.flags = ["read"];
const flags = ["read"];
if (mentioned || mentioned_group) {
message.flags.push("mentioned");
flags.push("mentioned");
}
if (mentioned_wildcard) {
message.flags.push("wildcard_mentioned");
flags.push("wildcard_mentioned");
}
message.is_me_message = is_status_message(message.raw_content);
return {content, flags};
}
export function add_topic_links(message) {
@@ -272,11 +288,8 @@ export function add_topic_links(message) {
}
const topic = message.topic;
const links = [];
const linkifier_list = linkifiers.linkifier_list;
for (const linkifier of linkifier_list) {
const pattern = linkifier.pattern;
const url = linkifier.url_format;
for (const [pattern, url] of linkifiers.get_linkifier_map().entries()) {
let match;
while ((match = pattern.exec(topic)) !== null) {
let link_url = url;
@@ -360,6 +373,20 @@ function handleEmoji(emoji_name) {
return alt_text;
}
function handleLinkifier(pattern, matches) {
let url = linkifiers.get_linkifier_map().get(pattern);
let current_group = 1;
for (const match of matches) {
const back_ref = "\\" + current_group;
url = url.replace(back_ref, match);
current_group += 1;
}
return url;
}
function handleTimestamp(time) {
let timeobject;
if (Number.isNaN(Number(time))) {
@@ -422,8 +449,15 @@ function handleTex(tex, fullmatch) {
}
}
export function initialize(helper_config) {
helpers = helper_config;
export function set_linkifier_regexes(regexes) {
// This needs to be called any time we modify our linkifier regexes,
// until we find a less clumsy way to handle this.
marked.InlineLexer.rules.zulip.linkifiers = regexes;
}
export function setup() {
// Once we focus on supporting other platforms such as mobile,
// we will export this function.
function disable_markdown_regex(rules, name) {
rules[name] = {
@@ -495,6 +529,7 @@ export function initialize(helper_config) {
smartypants: false,
zulip: true,
emojiHandler: handleEmoji,
linkifierHandler: handleLinkifier,
unicodeEmojiHandler: handleUnicodeEmoji,
streamHandler: handleStream,
streamTopicHandler: handleStreamTopic,
@@ -504,3 +539,28 @@ export function initialize(helper_config) {
preprocessors: [preprocess_code_blocks, preprocess_translate_emoticons],
});
}
// NOTE: Everything below this line is likely to be webapp-specific
// and won't be used by future platforms such as mobile.
// We may eventually move this code to a new file, but we want
// to wait till the dust settles a bit on some other changes first.
let webapp_helpers;
export function initialize(helper_config) {
// This is generally only intended to be called by the webapp. Most
// other platforms should call setup().
webapp_helpers = helper_config;
helpers = helper_config;
setup();
}
export function apply_markdown(message) {
// This is generally only intended to be called by the webapp. Most
// other platforms should call parse().
const raw_content = message.raw_content;
const {content, flags} = parse({raw_content, helper_config: webapp_helpers});
message.content = content;
message.flags = flags;
message.is_me_message = is_status_message(raw_content);
}

View File

@@ -98,6 +98,7 @@ export function build_page() {
user_can_change_avatar: settings_data.user_can_change_avatar(),
user_role_text: people.get_user_type(page_params.user_id),
default_language_name: settings_display.user_default_language_name,
realm_push_notifications_enabled: page_params.realm_push_notifications_enabled,
settings_object: user_settings,
});

View File

@@ -1,6 +1,6 @@
{
"name": "@zulip/shared",
"version": "0.0.9",
"version": "0.0.10",
"license": "Apache-2.0",
"dependencies": {
"katex": "^0.15.3",

View File

@@ -12,7 +12,7 @@
<th colspan="2" width="28%">{{t "Desktop"}}</th>
<th rowspan="2" width="14%" class="{{#if show_push_notifications_tooltip.push_notifications}}control-label-disabled{{/if}}">
{{t "Mobile"}}
{{#if (not page_params.realm_push_notifications_enabled) }}
{{#if (not realm_push_notifications_enabled) }}
<i class="fa fa-question-circle settings-info-icon tippy-zulip-tooltip" data-tippy-content="{{t 'Mobile push notifications are not configured on this server.' }}"></i>
{{/if}}
</th>

View File

@@ -18,6 +18,11 @@ clients should check the `zulip_feature_level` field, present in the
/register`](/api/register-queue) responses, to determine the API
format used by the Zulip server that they are interacting with.
## Changes in Zulip 6.0
Feature levels 123-124 are reserved for future use in 5.x maintenance
releases.
## Changes in Zulip 5.0
**Feature level 122**

View File

@@ -143,7 +143,7 @@
<li><a href="/team/">{{ _("Team") }}</a> &amp; <a href="/history/">{{ _("History") }}</a></li>
<li><a href="https://twitter.com/zulip/">Twitter</a></li>
<li><a href="/jobs/">{{ _("Jobs") }}</a></li>
<li><a href="/attribution">Website attributions</a></li>
<li><a href="/attribution">{{ _("Website attributions") }}</a></li>
<li><a href="https://github.com/sponsors/zulip">{{ _("Sponsor Zulip") }}</a></li>
</ul>
</div>

View File

@@ -7,6 +7,8 @@ import sys
from collections import defaultdict
from typing import Dict, List
bot_commits = 0
def add_log(committer_dict: Dict[str, int], input: List[str]) -> None:
for dataset in input:
@@ -15,6 +17,8 @@ def add_log(committer_dict: Dict[str, int], input: List[str]) -> None:
if committer_name.endswith("[bot]"):
# Exclude dependabot[bot] and other GitHub bots.
global bot_commits
bot_commits += commit_count
continue
committer_dict[committer_name] += commit_count
@@ -131,11 +135,21 @@ print(
f"Commit range {lower_zulip_version}..{upper_zulip_version} corresponds to {lower_time} to {upper_time}"
)
repository_dict: Dict[str, int] = defaultdict(int)
out_dict: Dict[str, int] = defaultdict(int)
subprocess.check_call(["git", "fetch"], cwd=find_path("zulip"))
zulip = retrieve_log("zulip", lower_zulip_version, upper_zulip_version)
print(f"Commit range for zulip/zulip: {lower_zulip_version[0:12]}..{upper_zulip_version[0:12]}")
add_log(out_dict, zulip)
commit_count = len(
subprocess.check_output(
["git", "log", "--pretty=oneline", f"{lower_zulip_version}..{upper_zulip_version}"],
cwd=find_path("zulip"),
text=True,
).splitlines()
)
repo_log = retrieve_log("zulip", lower_zulip_version, upper_zulip_version)
print(
f"{commit_count} commits from zulip/zulip: {lower_zulip_version[0:12]}..{upper_zulip_version[0:12]}"
)
add_log(out_dict, repo_log)
# TODO: We should migrate the last couple repositories to use the
# `main` default branch name and then simplify this.
@@ -163,9 +177,16 @@ for (full_repository, branch) in [
subprocess.check_call(["git", "fetch"], cwd=find_path(repository))
lower_repo_version = find_last_commit_before_time(repository, branch, lower_time)
upper_repo_version = find_last_commit_before_time(repository, branch, upper_time)
commit_count = len(
subprocess.check_output(
["git", "log", "--pretty=oneline", f"{lower_repo_version}..{upper_repo_version}"],
cwd=find_path(repository),
text=True,
).splitlines()
)
repo_log = retrieve_log(repository, lower_repo_version, upper_repo_version)
print(
f"Commit range for {full_repository}: {lower_repo_version[0:12]}..{upper_repo_version[0:12]}"
f"{commit_count} commits from {full_repository}: {lower_repo_version[0:12]}..{upper_repo_version[0:12]}"
)
add_log(out_dict, repo_log)
@@ -177,7 +198,8 @@ for committer_name, commit_count in sorted(
print(str(commit_count) + "\t" + committer_name)
grand_total += commit_count
print(f"Excluded {bot_commits} commits authored by bots.")
print(
f"{grand_total} total commits by {len(out_dict)} contributors between "
f"{lower_zulip_version} and {upper_repo_version}."
f"{lower_zulip_version} and {upper_zulip_version}."
)

View File

@@ -1,6 +1,6 @@
import os
ZULIP_VERSION = "5.0"
ZULIP_VERSION = "6.0-dev+git"
# Add information on number of commits and commit hash to version, if available
zulip_git_version_file = os.path.join(

View File

@@ -978,7 +978,6 @@ class StreamAdminTest(ZulipTestCase):
self.assertTrue(attachment.is_realm_public)
params = {
"stream_name": orjson.dumps("test_stream").decode(),
"is_private": orjson.dumps(True).decode(),
"history_public_to_subscribers": orjson.dumps(True).decode(),
}
@@ -1000,7 +999,6 @@ class StreamAdminTest(ZulipTestCase):
self.assertFalse(validate_attachment_request_for_spectator_access(realm, attachment))
params = {
"stream_name": orjson.dumps("test_stream").decode(),
"is_private": orjson.dumps(False).decode(),
"is_web_public": orjson.dumps(True).decode(),
"history_public_to_subscribers": orjson.dumps(True).decode(),
@@ -1025,7 +1023,6 @@ class StreamAdminTest(ZulipTestCase):
self.assertTrue(attachment.is_realm_public)
params = {
"stream_name": orjson.dumps("test_stream").decode(),
"is_private": orjson.dumps(False).decode(),
"is_web_public": orjson.dumps(False).decode(),
"history_public_to_subscribers": orjson.dumps(True).decode(),