Bug 1388150: Convert release notes to use git repo and JSON

Will allow us to simplify bedrock by not installing RNA.

Remove:

* django-mozilla-rna
* django-restframework
* django-synctool

Do markdown conversion on load of release: Helps with cache and perf.

Add tests for new release models
This commit is contained in:
Paul McLanahan 2017-08-17 14:55:47 -04:00
Родитель 60d99689d4
Коммит f9d55e9fc4
34 изменённых файлов: 977 добавлений и 180 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -33,6 +33,7 @@ test-results.xml
tests/unit/coverage
bedrock/externalfiles/files_cache
mofo_security_advisories
release_notes
product_details_json
supervisord.log
.idea

Просмотреть файл

@ -14,6 +14,6 @@
</div>
<div class="description">
<h2>{{ _('Version {version}, first offered to Firefox Developer Edition channel users on {date}')|f(channel=release.channel, date=release.release_date|l10n_format_date, version=release.version) }}</h2>
<p>{{ release.text|markdown|safe }}</p>
<p>{{ release.text|safe }}</p>
</div>
{% endblock %}

Просмотреть файл

@ -121,7 +121,7 @@
</div>
<div class="description">
<h2>{{ _('Version {version}, first offered to {channel} channel users on {date}')|f(channel=release.channel, date=release.release_date|l10n_format_date, version=release.version) }}</h2>
<p>{{ release.text|markdown|safe }}</p>
<p>{{ release.text|safe }}</p>
</div>
{% endblock %}
</div>
@ -133,8 +133,8 @@
<section class="notes-section">
<div class="features" id="new-features">
<div class="container">
{% if new_features %}
{% for note in new_features if note.tag == "New" %}
{% if release.notes %}
{% for note in release.notes if note.tag == "New" %}
{% if loop.first %}
<div class="section-wrapper" id="{{ note.tag|lower() }}">
<h4>{{ note.tag }}</h4>
@ -147,7 +147,7 @@
{% endif %}
{% endfor %}
{% for note in new_features if note.tag == "Fixed" %}
{% for note in release.notes if note.tag == "Fixed" %}
{% if loop.first %}
<div class="section-wrapper" id="{{ note.tag|lower() }}">
<h4>{{ note.tag }}</h4>
@ -160,7 +160,7 @@
{% endif %}
{% endfor %}
{% for note in new_features if note.tag == "Changed" %}
{% for note in release.notes if note.tag == "Changed" %}
{% if loop.first %}
<div class="section-wrapper" id="{{ note.tag|lower() }}">
<h4>{{ note.tag }}</h4>
@ -173,7 +173,7 @@
{% endif %}
{% endfor %}
{% for note in new_features if note.tag == "Developer" %}
{% for note in release.notes if note.tag == "Developer" %}
{% if loop.first %}
<div class="section-wrapper" id="{{ note.tag|lower() }}">
<h4>{{ note.tag }}</h4>
@ -182,12 +182,12 @@
{{ note_entry(note) }}
{% if loop.last %}
</ul>
<a class="mdn-icon more" rel="external" href="https://developer.mozilla.org/docs/Mozilla/Firefox/Releases/{{ release.major_version() }}">{{ _('Developer Information') }}</a>
<a class="mdn-icon more" rel="external" href="https://developer.mozilla.org/docs/Mozilla/Firefox/Releases/{{ release.major_version }}">{{ _('Developer Information') }}</a>
</div>
{% endif %}
{% endfor %}
{% for note in new_features if note.tag == "HTML5" %}
{% for note in release.notes if note.tag == "HTML5" %}
{% if loop.first %}
<div class="section-wrapper" id="{{ note.tag|lower() }}">
<h4>{{ note.tag }}</h4>
@ -200,7 +200,7 @@
{% endif %}
{% endfor %}
{% for note in new_features if note.tag == "Resolved" %}
{% for note in release.notes if note.tag == "Resolved" %}
{% if loop.first %}
<div class="section-wrapper" id="{{ note.tag|lower() }}">
<h4>{{ note.tag }}</h4>
@ -213,7 +213,7 @@
{% endif %}
{% endfor %}
{% for note in new_features if not note.tag %}
{% for note in release.notes if not note.tag %}
{% if loop.first %}
<div class="section-wrapper" id="{{ note.tag|lower() }}">
<h4>{{ note.tag }}</h4>
@ -225,10 +225,8 @@
</div>
{% endif %}
{% endfor %}
{% endif %}
{% if known_issues %}
{% for note in known_issues %}
{% for note in release.notes if note.tag == "Known" %}
{% if loop.first %}
<div class="section-wrapper" id="known">
<h4>{{ _('unresolved') }}</h4>
@ -314,7 +312,7 @@
<div class="col">
<h2>{{ _('Other Resources') }}</h2>
{% block extra_resources %}{% endblock %}
<a rel="external" href="https://developer.mozilla.org/docs/Mozilla/Firefox/Releases/{{ release.major_version() }}">{{ _('Developer Information') }}</a>
<a rel="external" href="https://developer.mozilla.org/docs/Mozilla/Firefox/Releases/{{ release.major_version }}">{{ _('Developer Information') }}</a>
<a rel="external" href="{{ release.get_bug_search_url() }}">{{ _('Complete list of changes for this release') }}</a>
<a rel="external" href="https://blog.mozilla.org/press/kits/">{{ _('Press Kit') }}</a>
<a rel="external" href="https://blog.mozilla.org/press/">{{ _('Mozilla and Firefox News') }}</a>
@ -335,7 +333,7 @@
{% macro note_entry(note) %}
<li id="note-{{ note.id }}">
{{ note.note|markdown|safe }}
{{ note.note|safe }}
{% if release.channel == 'Nightly' and note.bug -%}
<span class="bug-id"><a href="https://bugzilla.mozilla.org/show_bug.cgi?id={{ note.bug }}">{{ _('Bug %d')|format(note.bug) }}</a></span>
{%- endif %}

Просмотреть файл

@ -23,7 +23,7 @@
<div id="main-content">
<article class="main-column">
{{ release.system_requirements|markdown|safe }}
{{ release.system_requirements|safe }}
</article>
</div>
{% block sidebar %}{% endblock %}

Просмотреть файл

@ -12,11 +12,11 @@ from jinja2 import Markup
from mock import patch
from nose.tools import eq_, ok_
from pyquery import PyQuery as pq
from rna.models import Release
from bedrock.base.templatetags.helpers import static
from bedrock.mozorg.templatetags import misc
from bedrock.mozorg.tests import TestCase
from bedrock.releasenotes.models import Release
TEST_FILES_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)),
@ -505,8 +505,8 @@ class TestReleaseNotesURL(TestCase):
"""
Should return the results of reverse with the correct args
"""
release = Release(
channel='Aurora', version='42.0a2', product='Firefox for Android')
release = Release(dict(
channel='Aurora', version='42.0a2', product='Firefox for Android'))
eq_(misc.releasenotes_url(release), mock_reverse.return_value)
mock_reverse.assert_called_with(
'firefox.android.releasenotes', args=('42.0a2', 'aurora'))
@ -516,7 +516,7 @@ class TestReleaseNotesURL(TestCase):
"""
Should return the results of reverse with the correct args
"""
release = Release(version='42.0', product='Firefox')
release = Release(dict(version='42.0', product='Firefox'))
eq_(misc.releasenotes_url(release), mock_reverse.return_value)
mock_reverse.assert_called_with(
'firefox.desktop.releasenotes', args=('42.0', 'release'))

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -0,0 +1,19 @@
from __future__ import print_function
from django.conf import settings
from django.core.management.base import BaseCommand
from bedrock.utils.git import GitRepo
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument('-q', '--quiet', action='store_true', dest='quiet', default=False,
help='If no error occurs, swallow all output.'),
def handle(self, *args, **options):
repo = GitRepo(settings.RELEASE_NOTES_PATH, settings.RELEASE_NOTES_REPO,
branch_name=settings.RELEASE_NOTES_BRANCH)
repo.update()
if not options['quiet']:
print('Release Notes Successfully Updated')

Просмотреть файл

@ -0,0 +1,229 @@
import codecs
import json
import os
from glob import glob
from operator import attrgetter
from django.conf import settings
from django.core.cache import caches
from django.http import Http404
from django.utils.dateparse import parse_date, parse_datetime
from django.utils.text import slugify
import markdown
from product_details.version_compare import Version
from raven.contrib.django.raven_compat.models import client as sentry_client
cache = caches['release-notes']
markdowner = markdown.Markdown(extensions=[
'tables', 'codehilite', 'fenced_code', 'toc', 'nl2br'
])
def release_notes_path():
return os.path.join(settings.RELEASE_NOTES_PATH, 'releases')
def process_markdown(value):
return markdowner.reset().convert(value)
def process_notes(notes):
notes = [Note(d) for d in notes]
return [n for n in notes if n.is_public]
def process_is_public(is_public):
if settings.DEV:
return True
return is_public
FIELD_PROCESSORS = {
'release_date': parse_date,
'created': parse_datetime,
'modified': parse_datetime,
'notes': process_notes,
'is_public': process_is_public,
'note': process_markdown,
'text': process_markdown,
'system_requirements': process_markdown,
}
class ReleaseNotFound(Exception):
pass
class RNModel(object):
def __init__(self, data):
for key, value in data.items():
if not hasattr(self, key):
continue
if key in FIELD_PROCESSORS:
value = FIELD_PROCESSORS[key](value)
setattr(self, key, value)
class Note(RNModel):
id = None
bug = None
note = ''
tag = None
is_public = True
fixed_in_release = None
sort_num = None
created = None
modified = None
class Release(RNModel):
CHANNELS = ['release', 'esr', 'beta', 'aurora', 'nightly']
product = None
channel = None
version = None
slug = None
title = None
release_date = None
text = ''
is_public = True
bug_list = None
bug_search_url = None
system_requirements = None
created = None
modified = None
notes = None
_version_obj = None
@property
def major_version(self):
return str(self.version_obj.major)
@property
def version_obj(self):
if self._version_obj is None:
self._version_obj = Version(self.version)
return self._version_obj
def get_bug_search_url(self):
if self.bug_search_url:
return self.bug_search_url
if self.product == 'Thunderbird':
return (
'https://bugzilla.mozilla.org/buglist.cgi?'
'classification=Client%20Software&query_format=advanced&'
'bug_status=RESOLVED&bug_status=VERIFIED&bug_status=CLOSED&'
'target_milestone=Thunderbird%20{version}.0&product=Thunderbird'
'&resolution=FIXED'
).format(version=self.major_version)
return (
'https://bugzilla.mozilla.org/buglist.cgi?'
'j_top=OR&f1=target_milestone&o3=equals&v3=Firefox%20{version}&'
'o1=equals&resolution=FIXED&o2=anyexact&query_format=advanced&'
'f3=target_milestone&f2=cf_status_firefox{version}&'
'bug_status=RESOLVED&bug_status=VERIFIED&bug_status=CLOSED&'
'v1=mozilla{version}&v2=fixed%2Cverified&limit=0'
).format(version=self.major_version)
def equivalent_release_for_product(self, product):
"""
Returns the release for a specified product with the same
channel and major version with the highest minor version,
or None if no such releases exist
"""
major_version_file_id = get_file_id(product, self.channel, self.major_version + '.*')
releases = glob(os.path.join(release_notes_path(), major_version_file_id + '.json'))
if releases:
releases = [get_release_from_file(fn) for fn in releases]
releases = [r for r in releases if r.is_public]
return sorted(releases, reverse=True, key=attrgetter('version_obj'))[0]
return None
def equivalent_android_release(self):
if self.product == 'Firefox':
return self.equivalent_release_for_product('Firefox for Android')
def equivalent_desktop_release(self):
if self.product == 'Firefox for Android':
return self.equivalent_release_for_product('Firefox')
def get_release(product, version, channel=None):
channels = [channel] if channel else Release.CHANNELS
if product.lower() == 'firefox extended support release':
product = 'firefox'
channels = ['esr']
for channel in channels:
file_name = get_release_file_name(product, channel, version)
if not file_name:
continue
release = get_release_from_file(file_name)
if release is not None:
return release
raise ReleaseNotFound()
def get_release_from_file(file_name):
release = cache.get(file_name)
if not release:
release = get_release_from_file_system(file_name)
if release:
cache.set(file_name, release, 300) # 5 min
return release
def get_release_from_file_system(file_name):
try:
with codecs.open(file_name, 'r', encoding='utf-8') as rel_fh:
return Release(json.load(rel_fh))
except Exception:
sentry_client.captureException()
return None
def get_release_file_name(product, channel, version):
file_id = get_file_id(product, channel, version)
file_name = os.path.join(release_notes_path(), '{}.json'.format(file_id))
if os.path.exists(file_name):
return file_name
return None
def get_file_id(product, channel, version):
product = slugify(product)
channel = channel.lower()
if product == 'firefox-extended-support-release':
product = 'firefox'
channel = 'esr'
return '-'.join([product, version, channel])
def get_release_or_404(version, product):
try:
release = get_release(product, version)
except ReleaseNotFound:
raise Http404
if not release.is_public:
raise Http404
return release
def get_releases_or_404(product, channel):
file_prefix = get_file_id(product, channel, '*')
releases = glob(os.path.join(release_notes_path(), file_prefix + '.*'))
if releases:
return [get_release_from_file(r) for r in releases]
raise Http404

Просмотреть файл

@ -0,0 +1,27 @@
{
"bug_list": "",
"bug_search_url": "https://bugzilla.mozilla.org/buglist.cgi?f1=cf_status_firefox_esr24&o1=anywordssubstr&o2=equals&query_format=advanced&f2=cf_tracking_firefox_esr24&v1=fixed%20verified&v2=29%2B",
"channel": "ESR",
"created": "2014-04-24T21:49:38+00:00",
"is_public": true,
"modified": "2014-06-10T08:59:37+00:00",
"notes": [
{
"bug": null,
"created": "2013-11-25T00:24:50+00:00",
"id": 107,
"is_public": true,
"modified": "2015-05-12T16:59:10+00:00",
"note": "Security fixes can be found <a href=\"https://www.mozilla.org/security/known-vulnerabilities/firefoxESR.html\">here</a>",
"sort_num": 0,
"tag": "Fixed"
}
],
"product": "Firefox Extended Support Release",
"release_date": "2014-04-29",
"slug": "firefox-24.5.0-esr",
"system_requirements": " ",
"text": " ",
"title": "Firefox Extended Support Release 24.5.0 ESR",
"version": "24.5.0"
}

Просмотреть файл

@ -0,0 +1,47 @@
{
"bug_list": "",
"bug_search_url": "",
"channel": "ESR",
"created": "2016-03-08T15:21:24.120000+00:00",
"is_public": true,
"modified": "2016-08-22T09:09:17.746000+00:00",
"notes": [
{
"bug": null,
"created": "2016-03-08T15:23:04.674000+00:00",
"id": 786524,
"is_public": true,
"modified": "2017-03-01T14:21:10.798000+00:00",
"note": "[Complete 45.0 release notes][1]\r\n\r\n\r\n [1]: /en-US/firefox/45.0/releasenotes/",
"sort_num": 0,
"tag": "New"
},
{
"bug": 1232029,
"created": "2016-03-08T15:24:17.674000+00:00",
"id": 786525,
"is_public": true,
"modified": "2017-03-01T14:30:28.655000+00:00",
"note": "[Service workers disabled][1]\r\n\r\n\r\n [1]: https://www.fxsitecompat.com/en-CA/docs/2016/service-workers-have-been-disabled-in-firefox-45-esr/",
"sort_num": 0,
"tag": "Changed"
},
{
"bug": 1241501,
"created": "2016-03-08T15:25:36.574000+00:00",
"id": 786526,
"is_public": true,
"modified": "2017-03-01T14:30:36.099000+00:00",
"note": "Firefox Hello disabled\r\n",
"sort_num": 0,
"tag": "Changed"
}
],
"product": "Firefox Extended Support Release",
"release_date": "2016-03-08",
"slug": "firefox-45.0esr-esr",
"system_requirements": "## Windows\r\n\r\n### Operating Systems (32-bit and 64-bit)\r\n - Windows XP SP2\r\n - Windows Server 2003 SP1\r\n - Windows Vista\r\n - Windows 7\r\n - Windows 8\r\n - Windows 10\r\n\r\n*Please note that 64-bit builds of Firefox are only supported on Windows 7 and higher.*\r\n\r\n*To install [Firefox on a Windows XP system][1], because of Windows restrictions, the user will have to download Firefox 43.0.1 and then update to the current release.*\r\n\r\n### Recommended Hardware\r\n- Pentium 4 or newer processor that supports SSE2\r\n- 512MB of RAM\r\n- 200MB of hard drive space\r\n\r\n---\r\n\r\n## Mac\r\n\r\n### Operating Systems\r\n- Mac OS X 10.6\r\n- Mac OS X 10.7\r\n- Mac OS X 10.8\r\n- Mac OS X 10.9\r\n- Mac OS X 10.10\r\n- Mac OS X 10.11\r\n\r\n### Recommended Hardware\r\n- Macintosh computer with an Intel x86 processor\r\n- 512 MB of RAM\r\n- 200 MB hard drive space\r\n\r\n---\r\n\r\n## GNU/Linux\r\n\r\n### Software Requirements\r\n\r\n*Please note that GNU/Linux distributors may provide packages for your distribution which have different requirements.*\r\n\r\n- Firefox will not run at all without the following libraries or packages:\r\n - GTK+ 3.4 or higher\r\n - GLib 2.22 or higher\r\n - Pango 1.14 or higher\r\n - X.Org 1.0 or higher (1.7 or higher is recommended)\r\n - libstdc++ 4.3 or higher\r\n- For optimal functionality, we recommend the following libraries or packages:\r\n - NetworkManager 0.7 or higher\r\n - DBus 1.0 or higher\r\n - HAL 0.5.8 or higher\r\n - GNOME 2.16 or higher\r\n\r\n [1]: https://support.mozilla.org/kb/get-latest-version-firefox-windows-xp-vista",
"text": "",
"title": "Firefox Extended Support Release 45.0esr ESR",
"version": "45.0esr"
}

Просмотреть файл

@ -0,0 +1,205 @@
{
"bug_list": "1335905",
"bug_search_url": "",
"channel": "Nightly",
"created": "2017-03-21T13:19:13.668000+00:00",
"is_public": true,
"modified": "2017-05-30T18:51:00.765000+00:00",
"notes": [
{
"bug": 1218482,
"created": "2017-06-06T13:07:52.986000+00:00",
"id": 787117,
"is_public": true,
"modified": "2017-08-08T06:49:53.641000+00:00",
"note": "Launched Windows support for [WebVR][1], bringing immersive experiences to the web. See examples and try working demos at [Mozilla VR][2].\r\n\r\n\r\n [1]: https://developer.mozilla.org/en-US/docs/Web/API/WebVR_API\r\n [2]: https://mozvr.com/",
"sort_num": 10000,
"tag": "New"
},
{
"bug": 1365998,
"created": "2017-06-02T13:07:35.562000+00:00",
"id": 787108,
"is_public": true,
"modified": "2017-08-08T13:08:09.659000+00:00",
"note": "Simplified installation process with a streamlined Windows stub installer\r\n\r\n - Firefox for Windows 64-bit is now installed by default on 64-bit systems with at least 2GB of RAM\r\n - [Full installers][1] with advanced installation options are still available \r\n\r\n[1]: https://www.mozilla.org/firefox/all/",
"sort_num": 999,
"tag": "New"
},
{
"bug": 1355331,
"created": "2017-04-24T07:57:30.608000+00:00",
"id": 787058,
"is_public": true,
"modified": "2017-08-08T06:51:01.191000+00:00",
"note": "Updated [Sidebar for bookmarks, history, and synced tabs][1] so it can appear at the right edge of the window as well as the left\r\n\r\n[1]: https://support.mozilla.org/kb/firefox-sidebar-access-bookmarks-history-social\r\n",
"sort_num": 900,
"tag": "New"
},
{
"bug": 1362526,
"created": "2017-06-05T21:40:21.983000+00:00",
"id": 787115,
"is_public": true,
"modified": "2017-08-08T19:02:36.800000+00:00",
"note": "Pages can be simplified before printing from within Print Preview",
"sort_num": 400,
"tag": "New"
},
{
"bug": 429824,
"created": "2017-06-05T21:31:14.641000+00:00",
"id": 787114,
"is_public": true,
"modified": "2017-08-08T06:51:49.291000+00:00",
"note": "Updated Firefox for OSX and macOS to allow users to assign [custom keyboard shortcuts][1] to Firefox menu items via System Preferences \r\n\r\n\r\n [1]: https://support.mozilla.org/en-US/kb/keyboard-shortcuts-perform-firefox-tasks-quickly",
"sort_num": 300,
"tag": "New"
},
{
"bug": 1355082,
"created": "2017-04-19T16:11:03.099000+00:00",
"id": 787056,
"is_public": true,
"modified": "2017-06-05T14:46:22.654000+00:00",
"note": "All locales are now available for Nightly",
"sort_num": 3,
"tag": "New"
},
{
"bug": 1345090,
"created": "2017-05-17T14:47:50.171000+00:00",
"id": 787091,
"is_public": true,
"modified": "2017-08-01T13:51:16.107000+00:00",
"note": "Browsing sessions with a high number of tabs are now restored in an instant",
"sort_num": 2,
"tag": "New"
},
{
"bug": 1346488,
"created": "2017-05-24T13:14:31.757000+00:00",
"id": 787105,
"is_public": true,
"modified": "2017-06-05T14:44:47.117000+00:00",
"note": "The Photon project aiming at refreshing the user interface started being implemented in Nightly. These changes are only visible on the nightly channel and will not land in the beta and release channels before at least version 57.",
"sort_num": 1,
"tag": "New"
},
{
"bug": 1364070,
"created": "2017-05-29T14:18:06.077000+00:00",
"id": 787106,
"is_public": true,
"modified": "2017-08-08T06:25:05.078000+00:00",
"note": "[Fine-tune your browser performance][1] from the Preferences/Options page.\r\n\r\n[1]: https://support.mozilla.org/kb/performance-settings",
"sort_num": 0,
"tag": "New"
},
{
"bug": 1356243,
"created": "2017-05-30T18:50:40.058000+00:00",
"id": 787107,
"is_public": true,
"modified": "2017-08-01T13:51:16.107000+00:00",
"note": "Make [screenshots][1] of webpages, and save them locally or upload them to the cloud. This feature will undergo A/B testing and will not be visible for some users.\r\n\r\n[1]: https://screenshots.firefox.com/",
"sort_num": 0,
"tag": "New"
},
{
"bug": 1344928,
"created": "2017-06-06T13:49:34.896000+00:00",
"id": 787119,
"is_public": true,
"modified": "2017-08-01T15:08:42.498000+00:00",
"note": " Search suggestions are now enabled by default for users who haven't explicitly opted-out",
"sort_num": 0,
"tag": "New"
},
{
"bug": 893505,
"created": "2017-04-18T16:40:23.196000+00:00",
"fixed_in_release": {
"channel": "Nightly",
"is_public": true,
"product": "Firefox",
"slug": "firefox-55.0a1-nightly",
"title": "Firefox 55.0a1 Nightly",
"version": "55.0a1"
},
"id": 787048,
"is_public": true,
"modified": "2017-08-01T13:51:16.107000+00:00",
"note": "Modernized application update UI to be less intrusive and more aligned with the rest of the browser. Only users who have not restarted their browser 8 days after downloading an update or users who opted out of automatic updates will see this change.",
"sort_num": 0,
"tag": "Changed"
},
{
"bug": 548311,
"created": "2017-04-19T13:12:28.496000+00:00",
"id": 787051,
"is_public": true,
"modified": "2017-06-06T15:04:57.628000+00:00",
"note": "The default font for Japanese text is now Meiryo",
"sort_num": 0,
"tag": "Changed"
},
{
"bug": 977177,
"created": "2017-04-19T13:16:55.825000+00:00",
"id": 787052,
"is_public": true,
"modified": "2017-08-08T06:40:10.406000+00:00",
"note": "Firefox does not support downgrades, even though this may have worked in past versions. Users who install Firefox 55+ and later downgrade to an earlier version may experience issues with Firefox. \r\n",
"sort_num": 0,
"tag": "Changed"
},
{
"bug": 1341897,
"created": "2017-04-19T16:07:16.327000+00:00",
"id": 787055,
"is_public": true,
"modified": "2017-06-05T14:47:28.870000+00:00",
"note": "Firefox uses Mozilla Location Service for geolocation",
"sort_num": 0,
"tag": "Changed"
},
{
"bug": 1335907,
"created": "2017-04-19T16:17:08.859000+00:00",
"id": 787057,
"is_public": true,
"modified": "2017-06-05T14:44:14.166000+00:00",
"note": "about:preferences has been cleaned up and reorganized to make it easier for you to find what you need",
"sort_num": 0,
"tag": "Changed"
},
{
"bug": 1317856,
"created": "2017-06-06T13:26:48.862000+00:00",
"id": 787118,
"is_public": true,
"modified": "2017-08-08T06:39:42.278000+00:00",
"note": "Made the Adobe Flash plugin click-to-activate by default and allowed only on http:// and https:// URL schemes. (This change will not be visible to all users immediately. For more information see the [Firefox plugin roadmap][1])\r\n\r\n\r\n[1]:https://developer.mozilla.org/docs/Plugins/Roadmap\r\n\r\n",
"sort_num": 0,
"tag": "Changed"
},
{
"bug": 1072859,
"created": "2017-04-19T13:19:25.800000+00:00",
"id": 787053,
"is_public": true,
"modified": "2017-08-08T06:48:39.244000+00:00",
"note": "Sites that don\u2019t use SSL can no longer access Geolocation APIs to determine a user\u2019s physical location\r\n",
"sort_num": 0,
"tag": "Developer"
}
],
"product": "Firefox",
"release_date": "2017-03-06",
"slug": "firefox-55.0a1-nightly",
"system_requirements": "## Windows\r\n\r\n### Operating Systems (32-bit and 64-bit)\r\n - Windows 7\r\n - Windows 8\r\n - Windows 10\r\n\r\n### Recommended Hardware\r\n- Pentium 4 or newer processor that supports SSE2\r\n- 512MB of RAM\r\n- 200MB of hard drive space\r\n\r\n---\r\n\r\n## Mac\r\n\r\n### Operating Systems\r\n- Mac OS X 10.9\r\n- Mac OS X 10.10\r\n- Mac OS X 10.11\r\n- Mac OS X 10.12\r\n\r\n### Recommended Hardware\r\n- Macintosh computer with an Intel x86 processor\r\n- 512 MB of RAM\r\n- 200 MB hard drive space\r\n\r\n---\r\n\r\n## GNU/Linux\r\n\r\n### Software Requirements\r\n\r\n*Please note that GNU/Linux distributors may provide packages for your distribution which have different requirements.*\r\n\r\n- Firefox will not run at all without the following libraries or packages:\r\n - GTK+ 3.4 or higher\r\n - GLib 2.22 or higher\r\n - Pango 1.14 or higher\r\n - X.Org 1.0 or higher (1.7 or higher is recommended)\r\n - libstdc++ 4.6.1 or higher\r\n- For optimal functionality, we recommend the following libraries or packages:\r\n - NetworkManager 0.7 or higher\r\n - DBus 1.0 or higher\r\n - GNOME 2.16 or higher\r\n - PulseAudio\r\n\r\n [1]: https://support.mozilla.org/kb/get-latest-version-firefox-windows-xp-vista",
"text": "Firefox Nightly gets a new version every day and as a consequence, the release notes for the Nightly channel are updated continuously to reflect features that have reached sufficient maturity to benefit from community feedback and bug reports. \r\n\r\nFeatures listed here may or may not make a final release of Firefox.",
"title": "Firefox 55.0a1 Nightly",
"version": "55.0a1"
}

Просмотреть файл

@ -0,0 +1,6 @@
{
"product": "Firefox",
"channel": "Release",
"version": "56.0",
"is_public": true
}

Просмотреть файл

@ -0,0 +1,37 @@
{
"bug_list": "",
"bug_search_url": "",
"channel": "Nightly",
"created": "2017-06-12T13:42:25.322000+00:00",
"is_public": true,
"modified": "2017-08-17T08:24:32.975000+00:00",
"notes": [
{
"bug": 1353954,
"created": "2017-06-15T09:07:15.524000+00:00",
"id": 787156,
"is_public": true,
"modified": "2017-06-15T09:11:36.233000+00:00",
"note": "Search within the Options/Preferences panel to find relevant options across categories\r\n",
"sort_num": 0,
"tag": "New"
},
{
"bug": 1372309,
"created": "2017-06-16T15:35:13.038000+00:00",
"id": 787157,
"is_public": true,
"modified": "2017-06-16T15:58:42.656000+00:00",
"note": "<!-- Nightly only -->\r\nThe application menu was [restructured][1] as part of the Photon redesign for Firefox 57. Nightly users are encouraged to [flle bugs][2] for any regression they may find.\r\n\r\n\r\n[1]: https://dolske.wordpress.com/2017/06/15/photon-engineering-newsletter-6/ \r\n[2]: https://bugzilla.mozilla.org/enter_bug.cgi?product=Firefox&component=Toolbars%20and%20Customization",
"sort_num": 0,
"tag": "Changed"
}
],
"product": "Firefox",
"release_date": "2017-06-12",
"slug": "firefox-56.0a1-nightly",
"system_requirements": "## Windows\r\n\r\n### Operating Systems (32-bit and 64-bit)\r\n - Windows 7\r\n - Windows 8\r\n - Windows 10\r\n\r\n### Recommended Hardware\r\n- Pentium 4 or newer processor that supports SSE2\r\n- 512MB of RAM\r\n- 200MB of hard drive space\r\n\r\n---\r\n\r\n## Mac\r\n\r\n### Operating Systems\r\n- Mac OS X 10.9\r\n- Mac OS X 10.10\r\n- Mac OS X 10.11\r\n- Mac OS X 10.12\r\n\r\n### Recommended Hardware\r\n- Macintosh computer with an Intel x86 processor\r\n- 512 MB of RAM\r\n- 200 MB hard drive space\r\n\r\n---\r\n\r\n## GNU/Linux\r\n\r\n### Software Requirements\r\n\r\n*Please note that GNU/Linux distributors may provide packages for your distribution which have different requirements.*\r\n\r\n- Firefox will not run at all without the following libraries or packages:\r\n - GTK+ 3.4 or higher\r\n - GLib 2.22 or higher\r\n - Pango 1.14 or higher\r\n - X.Org 1.0 or higher (1.7 or higher is recommended)\r\n - libstdc++ 4.6.1 or higher\r\n- For optimal functionality, we recommend the following libraries or packages:\r\n - NetworkManager 0.7 or higher\r\n - DBus 1.0 or higher\r\n - GNOME 2.16 or higher\r\n - PulseAudio\r\n\r\n [1]: https://support.mozilla.org/kb/get-latest-version-firefox-windows-xp-vista",
"text": "Firefox Nightly gets a new version every day and as a consequence, the release notes for the Nightly channel are updated continuously to reflect features that have reached sufficient maturity to benefit from community feedback and bug reports. Features listed here may or may not make a final release of Firefox.",
"title": "Firefox 56.0a1 Nightly",
"version": "56.0a1"
}

Просмотреть файл

@ -0,0 +1,77 @@
{
"bug_list": "",
"bug_search_url": "",
"channel": "Nightly",
"created": "2017-08-02T14:20:49.003000+00:00",
"is_public": true,
"modified": "2017-09-13T08:55:02.648000+00:00",
"notes": [
{
"bug": 1387254,
"created": "2017-08-07T08:00:48.092000+00:00",
"id": 787203,
"is_public": true,
"modified": "2017-08-07T08:00:48.092000+00:00",
"note": "Firefox Nightly has a new logo",
"sort_num": 0,
"tag": "New"
},
{
"bug": 1373650,
"created": "2017-08-17T08:23:04.304000+00:00",
"id": 787237,
"is_public": true,
"modified": "2017-09-11T07:02:27.350000+00:00",
"note": "Added an option to the Page Action menu to report a website issue in Firefox Nightly and Firefox Dev Edition",
"sort_num": 0,
"tag": "New"
},
{
"bug": 1349227,
"created": "2017-08-31T07:52:29.636000+00:00",
"id": 787243,
"is_public": false,
"modified": "2017-08-31T07:55:06.229000+00:00",
"note": "Firefox Nightly now gets updated twice a day so as to help our communities in EMEA and Asia regions to catch regressions and report them during the Americas night.",
"sort_num": 0,
"tag": "New"
},
{
"bug": 1388902,
"created": "2017-09-04T11:13:42.634000+00:00",
"id": 787244,
"is_public": false,
"modified": "2017-09-04T11:13:42.634000+00:00",
"note": " The \"Share\" button was removed. If you relied on this feature, you can install the [Share Backported][1] extension instead.\r\n\r\n[1]: https://addons.mozilla.org/firefox/addon/share-backported/",
"sort_num": 0,
"tag": "Changed"
},
{
"bug": 1346488,
"created": "2017-09-07T13:00:41.753000+00:00",
"id": 787245,
"is_public": true,
"modified": "2017-09-07T13:00:41.753000+00:00",
"note": "Firefox is getting a major Visual Redesign ([Photon project][1]) activated on the Nightly channel and which will ship with Firefox 57 on the release channel.\r\n\r\n[1]: https://wiki.mozilla.org/Firefox/Photon/Updates",
"sort_num": 0,
"tag": "Changed"
},
{
"bug": 1385463,
"created": "2017-09-07T13:21:44.911000+00:00",
"id": 787246,
"is_public": true,
"modified": "2017-09-07T13:21:44.911000+00:00",
"note": "The browser's \"autoscrolling\" feature now uses asynchronous scrolling, similar to other input methods like mousewheel, providing a smoother scrolling experience.",
"sort_num": 0,
"tag": "Fixed"
}
],
"product": "Firefox",
"release_date": "2017-08-02",
"slug": "firefox-57.0a1-nightly",
"system_requirements": "## Windows\r\n\r\n### Operating Systems (32-bit and 64-bit)\r\n - Windows 7\r\n - Windows 8\r\n - Windows 10\r\n\r\n### Recommended Hardware\r\n- Pentium 4 or newer processor that supports SSE2\r\n- 512MB of RAM / 2GB of RAM for the 64-bit version\r\n- 200MB of hard drive space\r\n\r\n---\r\n\r\n## Mac\r\n\r\n### Operating Systems\r\n- macOS 10.9\r\n- macOS 10.10\r\n- macOS 10.11\r\n- macOS 10.12\r\n- macOS 10.13\r\n\r\n### Recommended Hardware\r\n- Macintosh computer with an Intel x86 processor\r\n- 512 MB of RAM\r\n- 200 MB hard drive space\r\n\r\n---\r\n\r\n## GNU/Linux\r\n\r\n### Software Requirements\r\n\r\n*Please note that GNU/Linux distributors may provide packages for your distribution which have different requirements.*\r\n\r\n- Firefox will not run at all without the following libraries or packages:\r\n - GTK+ 3.4 or higher\r\n - GLib 2.22 or higher\r\n - Pango 1.14 or higher\r\n - X.Org 1.0 or higher (1.7 or higher is recommended)\r\n - libstdc++ 4.6.1 or higher\r\n- For optimal functionality, we recommend the following libraries or packages:\r\n - NetworkManager 0.7 or higher\r\n - DBus 1.0 or higher\r\n - GNOME 2.16 or higher\r\n - PulseAudio\r\n\r\n [1]: https://support.mozilla.org/kb/get-latest-version-firefox-windows-xp-vista",
"text": "Firefox Nightly gets a new version every day and as a consequence, the release notes for the Nightly channel are updated continuously to reflect features that have reached sufficient maturity to benefit from community feedback and bug reports. Features listed here may or may not make a final release of Firefox.\r\n\r\nIn addition to these release notes, you can follow ongoing development on our [@FirefoxNightly][1] Twitter account as well as read our [Nightly Blog][2].\r\n\r\n[1]: https://twitter.com/FirefoxNightly\r\n[2]: https://blog.nightly.mozilla.org",
"title": "Firefox 57.0a1 Nightly",
"version": "57.0a1"
}

Просмотреть файл

@ -0,0 +1,7 @@
{
"product": "Firefox for Android",
"channel": "Release",
"version": "56.0",
"release_date": "2017-08-02",
"is_public": true
}

Просмотреть файл

@ -0,0 +1,7 @@
{
"product": "Firefox for Android",
"channel": "Release",
"version": "56.0.1",
"release_date": "2017-08-03",
"is_public": true
}

Просмотреть файл

@ -0,0 +1,7 @@
{
"product": "Firefox for Android",
"channel": "Release",
"version": "56.0.2",
"release_date": "2017-08-04",
"is_public": true
}

Просмотреть файл

@ -0,0 +1,7 @@
{
"product": "Firefox for Android",
"channel": "Release",
"version": "56.0.3",
"release_date": "2017-08-05",
"is_public": false
}

Просмотреть файл

@ -1,7 +1,6 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from dateutil.parser import parse as date_parse
from django.core.cache import caches
from django.http import Http404
@ -13,21 +12,26 @@ from mock import patch, Mock
from nose.tools import eq_, ok_
from pathlib2 import Path
from pyquery import PyQuery as pq
from rna.models import Release, Note
from bedrock.firefox.firefox_details import FirefoxDesktop
from bedrock.mozorg.tests import TestCase
from bedrock.releasenotes import views
from bedrock.releasenotes.models import Release, ReleaseNotFound
from bedrock.thunderbird.details import ThunderbirdDesktop
DATA_PATH = str(Path(__file__).parent / 'data')
TESTS_PATH = Path(__file__).parent
DATA_PATH = str(TESTS_PATH.joinpath('data'))
firefox_desktop = FirefoxDesktop(json_dir=DATA_PATH)
thunderbird_desktop = ThunderbirdDesktop(json_dir=DATA_PATH)
RELEASES_PATH = str(TESTS_PATH)
class TestRNAViews(TestCase):
@override_settings(RELEASE_NOTES_PATH=RELEASES_PATH)
class TestReleaseViews(TestCase):
def setUp(self):
caches['release-notes'].clear()
self.activate('en-US')
self.factory = RequestFactory()
self.request = self.factory.get('/')
@ -46,30 +50,24 @@ class TestRNAViews(TestCase):
"""
return self.mock_render.call_args[0][2]
@patch('bedrock.releasenotes.views.get_object_or_404')
@patch('bedrock.releasenotes.views.Q')
def test_get_release_or_404(self, Q, get_object_or_404):
@patch('bedrock.releasenotes.models.get_release')
def test_get_release_or_404(self, get_release):
eq_(views.get_release_or_404('version', 'product'),
get_object_or_404.return_value)
get_object_or_404.assert_called_with(
Release, Q.return_value, version='version')
Q.assert_called_once_with(product='product')
get_release.return_value)
get_release.assert_called_with('product', 'version')
get_release.side_effect = ReleaseNotFound
with self.assertRaises(Http404):
views.get_release_or_404('version', 'product')
@patch('bedrock.releasenotes.views.get_object_or_404')
@patch('bedrock.releasenotes.views.Q')
def test_get_release_or_404_esr(self, Q, get_object_or_404):
eq_(views.get_release_or_404('24.5.0', 'Firefox'),
get_object_or_404.return_value)
Q.assert_any_call(product='Firefox')
Q.assert_any_call(product='Firefox Extended Support Release')
def test_get_release_or_404_esr(self):
rel = views.get_release_or_404('24.5.0', 'Firefox')
eq_(rel.version, '24.5.0')
eq_(rel.channel, 'ESR')
@patch('bedrock.releasenotes.views.get_object_or_404')
@patch('bedrock.releasenotes.views.Q')
def test_get_release_or_404_endswith_esr(self, Q, get_object_or_404):
eq_(views.get_release_or_404('45.0esr', 'Firefox'),
get_object_or_404.return_value)
Q.assert_any_call(product='Firefox')
Q.assert_any_call(product='Firefox Extended Support Release')
def test_get_release_or_404_endswith_esr(self):
rel = views.get_release_or_404('45.0esr', 'Firefox')
eq_(rel.version, '45.0esr')
eq_(rel.channel, 'ESR')
@override_settings(DEV=False)
@patch('bedrock.releasenotes.views.release_notes_template')
@ -83,17 +81,14 @@ class TestRNAViews(TestCase):
template to l10n_utils.render.
"""
mock_release = get_release_or_404.return_value
mock_release.major_version.return_value = '34'
mock_release.notes.return_value = ([Release(id=1), Release(id=2)],
[Release(id=3), Release(id=4)])
mock_release.major_version = '34'
mock_release.notes.return_value = ([Release({}), Release({})],
[Release({}), Release({})])
views.release_notes(self.request, '27.0')
get_release_or_404.assert_called_with('27.0', 'Firefox')
mock_release.notes.assert_called_with(public_only=True)
eq_(self.last_ctx['version'], '27.0')
eq_(self.last_ctx['release'], mock_release)
eq_(self.last_ctx['new_features'], [Release(id=1), Release(id=2)])
eq_(self.last_ctx['known_issues'], [Release(id=3), Release(id=4)])
eq_(self.mock_render.call_args[0][1],
mock_release_notes_template.return_value)
mock_equiv_rel_url.assert_called_with(mock_release)
@ -171,12 +166,12 @@ class TestRNAViews(TestCase):
'firefox/releases/release-notes.html')
@override_settings(DEV=False)
@patch('bedrock.releasenotes.views.get_object_or_404')
def test_non_public_release(self, get_object_or_404):
@patch('bedrock.releasenotes.models.get_release')
def test_non_public_release(self, get_release):
"""
Should raise 404 if not release.is_public and not settings.DEV
"""
get_object_or_404.return_value = Release(is_public=False)
get_release.return_value = Release({'is_public': False})
with self.assertRaises(Http404):
views.get_release_or_404('42', 'Firefox')
@ -254,47 +249,22 @@ class TestRNAViews(TestCase):
eq_(views.check_url('Firefox', '42.0'),
'/en-US/firefox/42.0/system-requirements/')
@patch('bedrock.releasenotes.views.get_list_or_404')
def test_nightly_feed(self, get_list_or_404):
@override_settings(DEV=False)
def test_nightly_feed(self):
"""Nightly Notes feed should be served with public changes"""
release_1 = Mock()
release_1.version = '55.0a1'
release_1.is_public = True
release_1.release_date = date_parse('2017-03-06T00:00:00')
release_1.notes.return_value = ([
Note(id=1, tag='New', note='New 1', is_public=True,
modified=date_parse('2017-04-20T13:27:28')),
Note(id=2, tag='New', note='New 2', is_public=True,
modified=date_parse('2017-04-20T13:28:32')),
Note(id=11, tag='Changed', note='Change 1', is_public=True,
modified=date_parse('2017-04-20T13:27:50')),
Note(id=12, tag='Changed', note='Change 2', is_public=True,
modified=date_parse('2017-04-20T13:28:03')),
Note(id=13, tag='Changed', note='Change 3', is_public=False,
modified=date_parse('2017-04-20T13:28:16')),
], [
Note(id=21, tag='', note='Known issue 1', is_public=True,
modified=date_parse('2017-04-20T13:30:12')),
])
release_2 = Mock()
release_2.version = '56.0a1'
release_2.is_public = True
release_2.release_date = date_parse('2017-05-08T00:00:00')
release_2.notes.return_value = ([
Note(id=31, tag='New', note='New 1', is_public=True,
modified=date_parse('2017-05-08T13:27:28')),
], [])
get_list_or_404.return_value = [release_1, release_2]
views.nightly_feed(self.request)
eq_(len(self.last_ctx['notes']), 24)
eq_(self.last_ctx['notes'][0].id, 787237)
eq_(self.last_ctx['notes'][1].id, 787246)
eq_(self.last_ctx['notes'][2].id, 787245)
eq_(self.last_ctx['notes'][3].id, 787115)
eq_(self.last_ctx['notes'][4].id, 787108)
eq_(len(self.last_ctx['notes']), 5)
eq_(self.last_ctx['notes'][0].id, 31)
eq_(self.last_ctx['notes'][1].id, 2)
eq_(self.last_ctx['notes'][2].id, 12)
eq_(self.last_ctx['notes'][3].id, 11)
eq_(self.last_ctx['notes'][4].id, 1)
@override_settings(DEV=True)
def test_nightly_feed_dev_mode(self):
"""Nightly Notes feed should be served with all changes in DEV"""
views.nightly_feed(self.request)
eq_(len(self.last_ctx['notes']), 26)
class TestReleaseNotesIndex(TestCase):

Просмотреть файл

@ -0,0 +1,188 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import os
from django.conf import settings
from django.core.cache import caches
from django.test.utils import override_settings
from mock import call, patch
from pathlib2 import Path
from bedrock.mozorg.tests import TestCase
from bedrock.releasenotes import models
RELEASES_PATH = str(Path(__file__).parent)
release_cache = caches['release-notes']
@override_settings(RELEASE_NOTES_PATH=RELEASES_PATH)
class TestReleaseModel(TestCase):
def setUp(self):
release_cache.clear()
def test_release_major_version(self):
rel = models.get_release('firefox', '57.0a1')
assert rel.major_version == '57'
def test_get_bug_search_url(self):
rel = models.get_release('firefox', '57.0a1')
assert '=Firefox%2057&' in rel.get_bug_search_url()
rel.product = 'Thunderbird'
assert '=Thunderbird%2057.0&' in rel.get_bug_search_url()
rel.bug_search_url = 'custom url'
assert 'custom url' == rel.get_bug_search_url()
def test_equivalent_release_for_product(self):
"""Based on the test files the equivalent release for 56 should be 56.0.2."""
rel = models.get_release('firefox', '56.0', 'release')
android = rel.equivalent_release_for_product('Firefox for Android')
assert android.version == '56.0.2'
assert android.product == 'Firefox for Android'
def test_equivalent_release_for_product_none_match(self):
rel = models.get_release('firefox', '45.0esr', 'esr')
android = rel.equivalent_release_for_product('Firefox for Android')
assert android is None
def test_field_processors(self):
rel = models.get_release('firefox', '57.0a1')
# datetime conversion
assert rel.created.year == 2017
# datetime conversion
assert rel.modified.year == 2017
# date conversion
assert rel.release_date.year == 2017
# markdown
assert rel.system_requirements.startswith('<h2 id="windows">Windows</h2>')
# version
assert rel.version_obj.major == 57
# notes
note = rel.notes[0]
# datetime conversion
assert note.created.year == 2017
# datetime conversion
assert note.modified.year == 2017
# markdown
assert note.note.startswith('<p>Firefox Nightly')
assert note.id == 787203
@override_settings(DEV=False)
def test_is_public_field_processor(self):
"""Should return the real value when DEV is false."""
rel = models.get_release('firefox for android', '56.0.3')
assert not rel.is_public
rel = models.get_release('firefox', '57.0a1')
assert len(rel.notes) == 4
@override_settings(DEV=True)
def test_is_public_field_processor_dev_true(self):
"""Should always be true when DEV is true."""
rel = models.get_release('firefox for android', '56.0.3')
assert rel.is_public
rel = models.get_release('firefox', '57.0a1')
assert len(rel.notes) == 6
@patch.object(models, 'get_release_file_name')
@patch.object(models, 'get_release_from_file')
class TestGetRelease(TestCase):
def test_get_release(self, grff_mock, grfn_mock):
grfn_mock.return_value = 'dude'
grff_mock.return_value = 'dude is released'
ret = models.get_release('Firefox', '57.0')
grfn_mock.assert_called_with('Firefox', models.Release.CHANNELS[0], '57.0')
grff_mock.assert_called_with('dude')
assert ret == 'dude is released'
def test_get_release_esr(self, grff_mock, grfn_mock):
grfn_mock.return_value = 'dude'
grff_mock.return_value = 'dude is released'
ret = models.get_release('Firefox Extended Support Release', '51.0')
grfn_mock.assert_called_with('firefox', 'esr', '51.0')
grff_mock.assert_called_with('dude')
assert ret == 'dude is released'
def test_get_release_none_match(self, grff_mock, grfn_mock):
"""Make sure the proper exception is raised if no file matches the query"""
grfn_mock.return_value = None
with self.assertRaises(models.ReleaseNotFound):
models.get_release('Firefox', '57.0')
expected_calls = [call('Firefox', ch, '57.0') for ch in models.Release.CHANNELS]
grfn_mock.assert_has_calls(expected_calls)
def test_get_release_none_load(self, grff_mock, grfn_mock):
"""Make sure the proper exception is raised if no file successfully loads"""
grfn_mock.return_value = 'dude'
grff_mock.return_value = None
with self.assertRaises(models.ReleaseNotFound):
models.get_release('Firefox', '57.0')
expected_calls = [call('Firefox', ch, '57.0') for ch in models.Release.CHANNELS]
grfn_mock.assert_has_calls(expected_calls)
@patch.object(models, 'cache')
@patch.object(models, 'get_release_from_file_system')
class TestGetReleaseFromFile(TestCase):
def test_get_release_from_file(self, grffs_mock, cache_mock):
cache_mock.get.return_value = 'dude'
assert models.get_release_from_file('walter') == 'dude'
cache_mock.get.assert_called_with('walter')
grffs_mock.assert_not_called()
def test_get_release_from_file_no_cache(self, grffs_mock, cache_mock):
cache_mock.get.return_value = None
grffs_mock.return_value = 'donnie'
assert models.get_release_from_file('walter') == 'donnie'
cache_mock.get.assert_called_with('walter')
grffs_mock.assert_called_with('walter')
cache_mock.set.assert_called_with('walter', 'donnie', 300)
@override_settings(RELEASE_NOTES_PATH=RELEASES_PATH)
class TestGetReleaseFromFileSystem(TestCase):
def test_get_release_from_file_system(self):
filename = models.get_release_file_name('firefox', 'nightly', '57.0a1')
rel = models.get_release_from_file_system(filename)
assert rel.product == 'Firefox'
assert rel.channel == 'Nightly'
assert rel.version == '57.0a1'
@patch.object(models, 'codecs')
def test_get_release_from_file_system_exception(self, codecs_mock):
codecs_mock.open.side_effect = IOError()
assert models.get_release_from_file_system('does-not-exist') is None
@patch('os.path.exists')
@patch.object(models, 'get_file_id')
class TestGetReleaseFileName(TestCase):
def test_get_release_file_name(self, gfi_mock, exists_mock):
gfi_mock.return_value = 'dude'
exists_mock.return_value = True
file_name = os.path.join(settings.RELEASE_NOTES_PATH, 'releases', 'dude.json')
assert models.get_release_file_name('firefox', 'nightly', '57.0a1') == file_name
gfi_mock.assert_called_with('firefox', 'nightly', '57.0a1')
exists_mock.assert_called_with(file_name)
def test_get_release_file_name_no_exists(self, gfi_mock, exists_mock):
gfi_mock.return_value = 'dude'
exists_mock.return_value = False
file_name = os.path.join(settings.RELEASE_NOTES_PATH, 'releases', 'dude.json')
assert models.get_release_file_name('firefox', 'nightly', '57.0a1') is None
gfi_mock.assert_called_with('firefox', 'nightly', '57.0a1')
exists_mock.assert_called_with(file_name)
class TestGetFileID(TestCase):
def test_get_file_id(self):
assert models.get_file_id('Firefox', 'Nightly', '57.0a1') == 'firefox-57.0a1-nightly'
assert models.get_file_id('Firefox', 'Release', '57.0') == 'firefox-57.0-release'
assert models.get_file_id('Firefox Extended Support Release', 'ESR', '52.0') == 'firefox-52.0-esr'
assert models.get_file_id('Firefox for Android', 'Beta', '57.0b2') == 'firefox-for-android-57.0b2-beta'

Просмотреть файл

@ -4,21 +4,17 @@
import re
from django.conf import settings
from django.db.models import Q
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import get_object_or_404, get_list_or_404
from bedrock.base.urlresolvers import reverse
from lib import l10n_utils
from rna.models import Release
from product_details import product_details
from bedrock.base.urlresolvers import reverse
from bedrock.firefox.firefox_details import firefox_desktop, firefox_android, firefox_ios
from bedrock.thunderbird.details import thunderbird_desktop
from bedrock.mozorg.decorators import cache_control_expires
from bedrock.mozorg.templatetags.misc import releasenotes_url
from bedrock.firefox.templatetags.helpers import android_builds, ios_builds
from bedrock.thunderbird.details import thunderbird_desktop
from bedrock.mozorg.templatetags.misc import releasenotes_url
from bedrock.releasenotes.models import get_release_or_404, get_releases_or_404
SUPPORT_URLS = {
'Firefox for Android': 'https://support.mozilla.org/products/mobile',
@ -29,8 +25,7 @@ SUPPORT_URLS = {
def release_notes_template(channel, product, version=None):
prefix = dict((c, c.lower()) for c in Release.CHANNELS)
channel = channel or 'release'
if product == 'Firefox' and channel == 'Aurora' and version >= 35:
return 'firefox/releases/dev-browser-notes.html'
@ -39,7 +34,7 @@ def release_notes_template(channel, product, version=None):
dir = 'thunderbird'
return ('{dir}/releases/{channel}-notes.html'
.format(dir=dir, channel=prefix.get(channel, 'release')))
.format(dir=dir, channel=channel.lower()))
def equivalent_release_url(release):
@ -49,19 +44,6 @@ def equivalent_release_url(release):
return releasenotes_url(equivalent_release)
def get_release_or_404(version, product):
if product == 'Firefox' and (version.endswith('esr') or
len(version.split('.')) == 3):
product_query = Q(product='Firefox') | Q(
product='Firefox Extended Support Release')
else:
product_query = Q(product=product)
release = get_object_or_404(Release, product_query, version=version)
if not release.is_public and not settings.DEV:
raise Http404
return release
def get_download_url(release):
if release.product == 'Thunderbird':
if release.channel == 'Beta':
@ -113,22 +95,18 @@ def release_notes(request, version, product='Firefox'):
release = get_release_or_404(version + 'beta', product)
return HttpResponseRedirect(releasenotes_url(release))
new_features, known_issues = release.notes(public_only=not settings.DEV)
return l10n_utils.render(
request, release_notes_template(release.channel, product,
int(release.major_version())), {
int(release.major_version)), {
'version': version,
'download_url': get_download_url(release),
'support_url': SUPPORT_URLS.get(product, 'https://support.mozilla.org/'),
'check_url': check_url(product, version),
'release': release,
'equivalent_release_url': equivalent_release_url(release),
'new_features': new_features,
'known_issues': known_issues})
})
@cache_control_expires(1)
def system_requirements(request, version, product='Firefox'):
release = get_release_or_404(version, product)
dir = 'firefox'
@ -239,9 +217,8 @@ def releases_index(request, product):
def nightly_feed(request):
"""Serve an Atom feed with the latest changes in Firefox Nightly"""
notes = []
query = Q(product='Firefox', channel='Nightly')
releases = sorted(get_list_or_404(Release, query),
notes = {}
releases = sorted(get_releases_or_404('firefox', 'nightly'),
key=lambda x: x.release_date, reverse=True)[0:5]
for release in releases:
@ -249,14 +226,17 @@ def nightly_feed(request):
link = reverse('firefox.desktop.releasenotes',
args=(release.version, 'release'))
for note in release.notes()[0]:
for note in release.notes:
if note.id in notes:
continue
if note.is_public and note.tag:
note.link = link + '#note-' + str(note.id)
note.version = release.version
notes.append(note)
notes[note.id] = note
# Sort by date in descending order
notes = sorted(notes, key=lambda x: x.modified, reverse=True)
notes = sorted(notes.values(), key=lambda x: x.modified, reverse=True)
return l10n_utils.render(request, 'firefox/releases/nightly-feed.xml',
{'notes': notes},

Просмотреть файл

@ -47,6 +47,16 @@ CACHES['product-details'] = {
}
}
# cache for release notes
CACHES['release-notes'] = {
'BACKEND': 'bedrock.base.cache.SimpleDictCache',
'LOCATION': 'release-notes',
'OPTIONS': {
'MAX_ENTRIES': 300, # currently 564 json files but most are rarely accessed
'CULL_FREQUENCY': 4, # 1/4 entries deleted if max reached
}
}
# cache for externalfiles
CACHES['externalfiles'] = {
'BACKEND': 'bedrock.base.cache.SimpleDictCache',

Просмотреть файл

@ -243,7 +243,6 @@ SUPPORTED_NONLOCALES = [
'contribute.json',
'credits',
'gameon',
'rna',
'robots.txt',
'telemetry',
'webmaker',
@ -280,7 +279,6 @@ NOINDEX_URLS = [
r'^tabzilla/',
r'/system-requirements/$',
r'.*/(firstrun|thanks)/$',
r'^rna/',
r'^healthz/$',
r'^country-code\.json$',
# exclude redirects
@ -445,7 +443,6 @@ INSTALLED_APPS = (
'django_jinja_markdown',
'django_statsd',
'pagedown',
'rest_framework',
'pipeline',
'localflavor',
'django_jinja',
@ -483,7 +480,6 @@ INSTALLED_APPS = (
'django_extensions',
'lib.l10n_utils',
'captcha',
'rna',
)
# Must match the list at CloudFlare if the
@ -1183,8 +1179,9 @@ SEND_TO_DEVICE_LOCALES = ['de', 'en-GB', 'en-US', 'en-ZA',
DEV_GEO_COUNTRY_CODE = config('DEV_GEO_COUNTRY_CODE', default='US')
SEND_TO_DEVICE_COUNTRIES = config('SEND_TO_DEVICE_COUNTRIES', default='US', cast=Csv())
RNA_SYNC_URL = config('RNA_SYNC_URL',
default='https://nucleus.mozilla.org/rna/sync/')
RELEASE_NOTES_PATH = config('RELEASE_NOTES_PATH', default=path('release_notes'))
RELEASE_NOTES_REPO = config('RELEASE_NOTES_REPO', default='https://github.com/mozilla/release-notes.git')
RELEASE_NOTES_BRANCH = config('RELEASE_NOTES_BRANCH', default='master')
MOFO_SECURITY_ADVISORIES_PATH = config('MOFO_SECURITY_ADVISORIES_PATH',
default=path('mofo_security_advisories'))
@ -1226,25 +1223,6 @@ LOGGING = {
PASSWORD_HASHERS = ['django.contrib.auth.hashers.PBKDF2PasswordHasher']
REST_FRAMEWORK = {
# Use hyperlinked styles by default.
# Only used if the `serializer_class` attribute is not set on a view.
'DEFAULT_MODEL_SERIALIZER_CLASS':
'rna.serializers.HyperlinkedModelSerializerWithPkField',
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_FILTER_BACKENDS': ('rna.filters.TimestampedFilterBackend',)
}
TABLEAU_DB_URL = config('TABLEAU_DB_URL', default=None)
ADMINS = MANAGERS = config('ADMINS', cast=json.loads,

Просмотреть файл

@ -45,35 +45,38 @@
{% else %}
If interested, please see the <a href="{{ release.get_bug_search_url() }}">complete list of changes</a> in this release.
{% endif %}
{{ release.text|markdown|safe }}
{{ release.text|safe }}
</p>
</header>
{% endblock %}
<div class="main-column">
{% if new_features %}
{% for note in release.notes if note.tag != 'Known' %}
{% if loop.first %}
<section class="notes-section" id="new-features">
<h3>{{ _('Whats New') }}</h3>
<ul class="section-items tagged">
{% for note in new_features %}
{% endif %}
<li {% if not note.tag %}class="untagged"{% endif %} id="note-{{ note.id }}">
{% if note.tag %}
<b class="tag tag-{{ note.tag.lower() }}">{{ note.tag }}</b>
{% endif %}
{{ note.note|markdown|safe }}
{{ note.note|safe }}
</li>
{% endfor %}
{% if loop.last %}
</ul>
</section>
{% endif %}
{% if known_issues %}
{% endfor %}
{% for note in release.notes if note.tag == 'Known' %}
{% if loop.first %}
<section class="notes-section" id="known-issues">
<h3>{{ _('Known Issues') }}</h3>
<ul class="section-items tagged">
{% for note in known_issues %}
{% endif %}
<li id="note-{{ note.id }}">
<b class="tag tag-unresolved">{{ _('unresolved') }}</b>
{{ note.note|markdown|safe }}
{{ note.note|safe }}
{% if note.fixed_in_release %}
<p class="note">
<a href="{{ releasenotes_url(note.fixed_in_release) }}">
@ -82,10 +85,11 @@
</p>
{% endif %}
</li>
{% endfor %}
{% if loop.last %}
</ul>
</section>
{% endif %}
{% endfor %}
</div>
{% block notes_sidebar %}

Просмотреть файл

@ -23,7 +23,7 @@
<div id="main-content">
<article class="main-column">
{{ release.system_requirements|markdown|safe }}
{{ release.system_requirements|safe }}
</article>
</div>
{% block sidebar %}{% endblock %}

Просмотреть файл

@ -12,7 +12,6 @@ handler500 = 'bedrock.base.views.server_error_view'
urlpatterns = (
url(r'^rna/', include('rna.urls')),
# Main pages
url(r'^lightbeam/', include('bedrock.lightbeam.urls')),
url(r'^foundation/', include('bedrock.foundation.urls')),

Просмотреть файл

@ -85,11 +85,6 @@ def schedule_database_jobs():
def update_security_advisories():
call_command('update_security_advisories')
@scheduled_job('interval', minutes=5)
def rnasync():
# running in a subprocess as rnasync was not designed for long-running process
call_command('rnasync')
@scheduled_job('interval', hours=6)
def update_tweets():
call_command('cron update_tweets')
@ -109,6 +104,10 @@ def schedul_l10n_jobs():
def update_locales():
call_command('l10n_update')
@scheduled_job('interval', minutes=5)
def update_release_notes():
call_command('update_release_notes --quiet')
if __name__ == '__main__':
args = sys.argv[1:]

Просмотреть файл

@ -6,13 +6,13 @@ if [ ! -e ./manage.py ]; then
cd $script_parent_dir
fi
./manage.py migrate --noinput --database bedrock
./manage.py rnasync
./manage.py cron update_ical_feeds
./manage.py update_product_details_files --database bedrock
./manage.py update_wordpress --database bedrock
./manage.py update_externalfiles
./manage.py update_security_advisories
./manage.py l10n_update
./manage.py update_release_notes
./manage.py update_sitemaps
#requires twitter api credentials not distributed publicly
./manage.py cron update_tweets

Просмотреть файл

@ -88,6 +88,7 @@ if $PROD_MODE && ! imageExists "l10n"; then
ENVFILE="master";
fi
dockerRun $ENVFILE code "python manage.py l10n_update"
dockerRun $ENVFILE code "python manage.py update_release_notes"
dockerRun $ENVFILE code "python manage.py update_sitemaps"
docker/bin/docker_build.sh "l10n"
fi

Просмотреть файл

@ -8,7 +8,6 @@
deis login $DEIS_CONTROLLER --username=$DEIS_USERNAME --password=$DEIS_PASSWORD
deis run -a $DEIS_APPLICATION -- '\
./manage.py rnasync; \
./manage.py cron update_ical_feeds; \
./manage.py update_product_details_files --database bedrock; \
./manage.py update_externalfiles; \

Просмотреть файл

@ -1,6 +1,7 @@
FROM mozorg/bedrock_code:${GIT_COMMIT}
COPY ./locale ./locale
COPY ./release_notes ./release_notes
COPY ./root_files/sitemap.xml ./root_files/
COPY ./root_files/default-urls.json ./root_files/
COPY ./bedrock.db ./

Просмотреть файл

@ -1,11 +1,13 @@
FROM mozorg/bedrock_code:${GIT_COMMIT}
COPY ./locale ./locale
COPY ./release_notes ./release_notes
COPY ./root_files/sitemap.xml ./root_files/
COPY ./root_files/default-urls.json ./root_files/
# Change User
USER root
RUN chown webdev.webdev -R locale
RUN chown webdev.webdev -R release_notes
RUN chown webdev.webdev -R root_files
USER webdev

Просмотреть файл

@ -50,9 +50,6 @@ whitenoise==3.3.0 \
django-localflavor==1.1 \
--hash=sha256:3b5503b512248af661cf91e4f402327619ffc3bc5b3b0ea774a969ed3bf84594 \
--hash=sha256:afd6627cd0fd396824e44a5e4f7bfe9c8d7a45d9bf09b4db2c0683d92681ba93
djangorestframework==3.3.2 \
--hash=sha256:5634b1ff56581bf0fe4075e86227fc9693c1ca031c7213c9ae942c445c24817b \
--hash=sha256:4962418a57804f8323282728a4f9b9496e78caec1adda352170697752eff01bf
django-filter==0.11.0 \
--hash=sha256:7d17547b65216cc5c6fbc04aee55088ccd5917c0775304d96f7017c26c789cd7 \
--hash=sha256:00cc47935afbbd83260fdd283b0aa790e658d2a71922049f6e467dca8a124537
@ -100,11 +97,6 @@ puente==0.4.1 \
babel==2.3.4 \
--hash=sha256:3318ed2960240d61cbc6558858ee00c10eed77a6508c4d1ed8e6f7f48399c975 \
--hash=sha256:c535c4403802f6eb38173cd4863e419e2274921a01a8aad8a5b497c131c62875
https://github.com/pmclanahan/django-synctool/archive/5f7cf9bad741e60bd9df32aa90e71425d98e437c.tar.gz#egg=django-synctool==1.1.1 \
--hash=sha256:2dd290c5339769e3c40d644b5248236bec7c558eaccb922badd7c39c5fd5e095
django-mozilla-rna==2.0.2 \
--hash=sha256:da0e199ef08b3ed7200232b2724cee82812d70edfcea63202c48408e3241eb4f \
--hash=sha256:c75c905a0cfe744af143d7e7007ed5376ed0f27bf0db00b790dd9421eae027a0
django-jinja==2.1.3 \
--hash=sha256:64446ae1de3593136042147cb16ba9a3aa4449370d9c26c1ec9b7553b2d1c809
django-jinja-markdown==1.0 \