Merged in a management command which provides glue code for creation and maintenance of Trac issue tracker and wiki installations per group. New groups of type wg, rg, and area will autmatically receive a Trac instance.

- Legacy-Id: 12182
This commit is contained in:
Henrik Levkowetz 2016-10-19 18:08:05 +00:00
commit ba5c17ecfd
15 changed files with 778 additions and 8 deletions

7
env/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
/bin
/share
/selenium
/etc
/local
/lib
/include

3
env/pip.conf vendored Normal file
View file

@ -0,0 +1,3 @@
[install]
ignore-installed = true

View file

@ -1,5 +1,6 @@
import os import os
import time import time
from textwrap import dedent
from django.conf import settings from django.conf import settings
from django.core import checks from django.core import checks
@ -209,3 +210,32 @@ def check_cache(app_configs, **kwargs):
errors.append(cache_error("Cache didn't accept session cookie age", "E0016")) errors.append(cache_error("Cache didn't accept session cookie age", "E0016"))
return errors return errors
@checks.register('cache')
def check_svn_import(app_configs, **kwargs):
errors = []
if settings.SERVER_MODE == 'production':
try:
import svn # pyflakes:ignore
except ImportError as e:
errors.append(checks.Critical(
"Could not import the python svn module:\n %s\n" % e,
hint = dedent("""
You are running in production mode, and the subversion bindings for python
are necessary in order to run the Trac wiki glue scripts.
However, the subversion bindings seem to be unavailable. The subversion
bindings are not available for install using pip, but must be supplied by
the system package manager. In order to be available within a python
virtualenv, the virtualenv must have been created with the
--system-site-packages flag, so that the packages installed by the system
package manager are visible.
Please install 'python-subversion' (Debian), 'subversion-python' (RedHat,
CentOS, Fedora), 'subversion-python27bindings' (BSD); and set up a
virtualenv using the --system-site-packages flag. Further tips are
available at https://trac.edgewall.org/wiki/TracSubversion.
""").replace('\n', '\n ').rstrip(),
id = "datatracker.E0014",
))
return errors

View file

@ -382,7 +382,7 @@ TEST_URL_COVERAGE_EXCLUDE = [
r"^\^admin/", r"^\^admin/",
] ]
# Tese are filename globs # These are filename globs. They are fed directly to the coverage code checker.
TEST_CODE_COVERAGE_EXCLUDE = [ TEST_CODE_COVERAGE_EXCLUDE = [
"*/tests*", "*/tests*",
"*/admin.py", "*/admin.py",
@ -660,14 +660,43 @@ USER_PREFERENCE_DEFAULTS = {
"left_menu" : "on", "left_menu" : "on",
} }
TRAC_ADMIN_CMD = "/usr/bin/trac-admin" TRAC_MASTER_DIR = "/a/www/trac-setup/"
TRAC_WIKI_DIR_ROOT = "/a/www/www6s/trac/" TRAC_WIKI_DIR_PATTERN = "/a/www/www6s/trac/%s"
TRAC_WIKI_DIR_PATTERN = os.path.join(TRAC_WIKI_DIR_ROOT, "%s")
TRAC_WIKI_URL_PATTERN = "https://trac.ietf.org/trac/%s/wiki" TRAC_WIKI_URL_PATTERN = "https://trac.ietf.org/trac/%s/wiki"
TRAC_ISSUE_URL_PATTERN = "https://trac.ietf.org/trac/%s/report/1" TRAC_ISSUE_URL_PATTERN = "https://trac.ietf.org/trac/%s/report/1"
TRAC_SVN_DIR_PATTERN = "/a/svn/group/%s" TRAC_SVN_DIR_PATTERN = "/a/svn/group/%s"
TRAC_SVN_URL_PATTERN = "https://svn.ietf.org/svn/group/%s/" TRAC_SVN_URL_PATTERN = "https://svn.ietf.org/svn/group/%s/"
TRAC_ENV_OPTIONS = [
('project', 'name', "{name} Wiki"),
('trac', 'database', 'sqlite:db/trac.db' ),
('trac', 'repository_type', 'svn'),
('trac', 'repository_dir', "{svn_dir}"),
('inherit', 'file', "/a/www/trac-setup/conf/trac.ini"),
]
TRAC_WIKI_PAGES_TEMPLATES = [
"utils/wiki/IetfSpecificFeatures",
"utils/wiki/InterMapTxt",
"utils/wiki/SvnTracHooks",
"utils/wiki/ThisTracInstallation",
"utils/wiki/TrainingMaterials",
"utils/wiki/WikiStart",
]
TRAC_ISSUE_SEVERITY_ADD = [
"-",
"Candidate WG Document",
"Active WG Document",
"Waiting for Expert Review",
"In WG Last Call",
"Waiting for Shepherd Writeup",
"Submitted WG Document",
"Dead WG Document",
]
SVN_ADMIN_COMMAND = "/usr/bin/svnadmin"
# Email addresses people attempt to set for their account will be checked # Email addresses people attempt to set for their account will be checked
# against the following list of regex expressions with re.search(pat, addr): # against the following list of regex expressions with re.search(pat, addr):
EXLUDED_PERSONAL_EMAIL_REGEX_PATTERNS = ["@ietf.org$"] EXLUDED_PERSONAL_EMAIL_REGEX_PATTERNS = ["@ietf.org$"]

View file

@ -0,0 +1,94 @@
= IETF-Specific Information =
== Editing the Wiki and Issues ==
In order to create and edit wiki pages and issues, you need to log in. Click on the
small 'Login' link above the main horizontal menubar. You log in with the same
username (your email address) and password as for all other ''tools.ietf.org'' password
protected accesses. If you don't have a login/passwd or need to reset your passwd, go
to http://tools.ietf.org/newpasswd .
The login and password is also used for commits to the SVN repository. See more about
the repository further down.
== IETF-Specific Features ==
This Trac installation has a few IETF-specific features which are not generally found
in Trac:
* Occurences of RFC numbers or draft names in Wiki text will generate links to the
RFC or draft in question. Unless you want to point to an RFC or draft in a
specific location which is different from the automatically generated link, you
don't need to explicitly add links for RFCs and drafts. Examples: RFC 2026,
draft-ietf-poised95-std-proc-3
* Each issue in the issue tracker can be indicated to concern a 'component'. This is
a standard Trac feature; however, the list of available components is automatically
updated to include all the active working group drafts. This makes it easier to
associate issues with drafts for the WG participants, without the Chairs needing to
go in as admin users and add a new component each time there's a new WG draft.
* The 'Severity' field of an issue has a special significance if the issue type is
set to 'state' or 'task'. In that case, the Severity will be shown as an
annotation to the draft state on the regular WG status page on tools.ietf.org.
This can be useful for WG chairs to indicate more exactly the state of a WG draft,
which will otherwise simply be indicated as 'Active' on the status page, until it
is sent to the IESG for processing.
* If issues are registered against a draft ,indicated by setting the issue's
'component' field to the appropriate (abbreviated) draft name, the status page
will show a progress bar, indicating the total number of issues for that draft, as
well as the proportion which have been closed, and the number of still open issues.
* Everywhere you can use wiki markup (on the wiki pages, roadmap descriptions,
etc.) you may embed a macro which shows a ticket statistics graph. Full
information about the macro is available at [http://trac-hacks.org/wiki/TicketStatsMacro].
Briefly, the macro syntax is:
{{{
[[TicketStats( height=250,daterange=12m,res_days=30)]]
}}}
which gives this result: [[TicketStats( height=250,daterange=12m,res_days=30)]]
Issue tracker changes which are reflected in the WG status pages ('Severity'
annotations and issue progress bars) may take up to 1 hour to propagate from the
server which hosts the Trac instance (trac.tools.ietf.org) to the other tools servers.
== Integration with tools.ietf.org ==
For all working groups which have an instance of Trac installed, the URL to Trac for
that WG has the form '''''!http://tools.ietf.org/wg/<wg>/trac'''''.
There's also a link to the Trac issue tracker and a link to the Trac
wiki in the horizontal menu on the WG status page
'''''!http://tools.ietf.org/wg/<wg>'''''
once Trac has been installed.
== SVN Repository ==
For each WG with a Trac instance there is also a SVN repository, with an URL of the
form '''''!https://svn.tools.ietf.org/svn/wg/<wg>'''''. Anybody can check out from
the repository, but you need to use the tools server login and password in order to
commit to the repository.
To check out a repository with a command-line svn client, see this example for the ''hybi'' WG:
{{{
work/ $ svn co --username=henrik@levkowetz.com https://svn.tools.ietf.org/svn/wg/hybi/
work/ $ cd hybi/
hybi/ $
}}}
SVN also lets you check out parts of the repository tree, but for more info on
that, please see the documentation on http://subversion.apache.org/.
To add a document to the repository, place the document in your SVN working folder,
tell SVN it should be added, and when ready, commit it to the repository:
{{{
hybi/ $ svn add draft-foo-bar-baz.txt
hybi/ $ #...
hybi/ $ svn commit draft-foo-bar-baz.txt -m "Commit message ..."
hybi/ $
}}}
The IETF Trac instances use a variation of the Trac SVN hook script which is provided
with Trac. This script updates Track Issue Tickets based on keywords in the SVN
commit messages; the keywords and their use is described in SvnTracHooks.

View file

@ -0,0 +1,72 @@
= InterMapTxt =
== This is the place for defining InterWiki prefixes ==
This page was modelled after the MeatBall:InterMapTxt page.
In addition, an optional comment is allowed after the mapping.
This page is interpreted in a special way by Trac, in order to support
!InterWiki links in a flexible and dynamic way.
The code block after the first line separator in this page
will be interpreted as a list of !InterWiki specifications:
{{{
prefix <space> URL [<space> # comment]
}}}
By using `$1`, `$2`, etc. within the URL, it is possible to create
InterWiki links which support multiple arguments, e.g. Trac:ticket:40.
The URL itself can be optionally followed by a comment,
which will subsequently be used for decorating the links
using that prefix.
New !InterWiki links can be created by adding to that list, in real time.
Note however that ''deletions'' are also taken into account immediately,
so it may be better to use comments for disabling prefixes.
Also note that !InterWiki prefixes are case insensitive.
== List of Active Prefixes ==
[[InterWiki]]
----
== Prefix Definitions ==
{{{
PEP http://www.python.org/peps/pep-$1.html # Python Enhancement Proposal
Trac-ML http://thread.gmane.org/gmane.comp.version-control.subversion.trac.general/ # Message $1 in Trac Mailing List
trac-dev http://thread.gmane.org/gmane.comp.version-control.subversion.trac.devel/ # Message $1 in Trac Development Mailing List
Mercurial http://www.selenic.com/mercurial/wiki/index.cgi/ # the wiki for the Mercurial distributed SCM
RFC http://tools.ietf.org/html/rfc$1.html # IETF's RFC $1
DataTracker https://datatracker.ietf.org/doc/
dt https://datatracker.ietf.org/doc/
#
# A arbitrary pick of InterWiki prefixes...
#
Acronym http://www.acronymfinder.com/af-query.asp?String=exact&Acronym=
C2find http://c2.com/cgi/wiki?FindPage&value=
Cache http://www.google.com/search?q=cache:
CPAN http://search.cpan.org/perldoc?
DebianBug http://bugs.debian.org/
DebianPackage http://packages.debian.org/
Dictionary http://www.dict.org/bin/Dict?Database=*&Form=Dict1&Strategy=*&Query=
Google http://www.google.com/search?q=
GoogleGroups http://groups.google.com/group/$1/msg/$2 # Message $2 in $1 Google Group
JargonFile http://downlode.org/perl/jargon-redirect.cgi?term=
MeatBall http://www.usemod.com/cgi-bin/mb.pl?
MetaWiki http://sunir.org/apps/meta.pl?
MetaWikiPedia http://meta.wikipedia.org/wiki/
MoinMoin http://moinmoin.wikiwikiweb.de/
WhoIs http://www.whois.sc/
Why http://clublet.com/c/c/why?
c2Wiki http://c2.com/cgi/wiki?
WikiPedia http://en.wikipedia.org/wiki/
}}}

View file

@ -0,0 +1,77 @@
= SVN Trac Hooks =
If the Trac Hooks for SVN has been installed for the svn repository
coupled to this Trac instance, the Key Phrases documented below may
be used in SVN commit messages to cause automatic updates and annotations
of Trac issues.
== The trac-post-commit-hook ==
This script looks at the commit message associated with an SVN commit,
and based on the presence of a number of key phrases will add annotations
to tickets and also possibly change ticket status, for instance closing
it.
=== Key Phrases ===
The key phrases available are:
{{{
Fix <ticket_spec>
Fixes <ticket_spec>
Fix for <ticket_spec>
Close <ticket_spec>
Closes <ticket_spec>
Addresses <ticket_spec>
References <ticket_spec>
Relates to <ticket_spec>
Related to <ticket_spec>
See <ticket_spec>
}}}
=== Ticket specification ===
The specification of the ticket to act on may specify one or more
tickets, using any of the following forms:
{{{
<ticket>
<ticket>, <ticket>{, <ticket>}
<ticket>, <ticket> and <ticket>
}}}
and variations thereof.
=== Ticket identification ===
The individual ticket specification
can take any of the following forms:
{{{
#<number>
ticket <number>
ticket:<number>
issue <number>
issue:<number>
bug <number>
bug:<number>
}}}
=== Examples ===
{{{
Clarify header normalization vs matching request headers (see #147)
Resolve #27: fix definition of idempotent
Note change for issue 157 (related to #157)
Define http and https URI schemes: addresses #58, #128, #159
Define http and https URI schemes: addresses #58, #128, #159;
fixes #157: removed reference to RFC1900 use of IP addresses in URI.
Resolve #140: rephrase note so that it becomes clear that the described ...
}}}
=== Script ===
The default script installed as trac-post-commit-hook is:
http://tools.ietf.org/tools/wg-pages/svn-hook-files/trac-post-commit-hook

View file

@ -0,0 +1,94 @@
{{{
#!rst
Trac Installation on tools.ietf.org
===================================
Background
----------
The Track installation used on the tools.ietf.org site is different from the
installation examples provided with Trac and on http://trac.edgewall.com. The
reason is mainly that the multi-project examples all assume that Trac
constitutes the whole of the deployed environment, rather than being part of a
greater set. This means that the examples assume that accessing the
individual projects through URLs of the form "/$some_path/trac/$projname"
makes sense, while in our case, we would like the URLs to look like
"/$some_path/$projname/trac". In the multi-project configuration, this would
make Trac always believe that the project name is 'trac' - the last path
component.
Explored Alternatives
---------------------
Make Apache set ``TRAC_ENV`` dynamically
........................................
Tell Apache to dynamically set Trac's environment variable ``TRAC_ENV`` to the
particular value for the accessed project:
``/etc/apache2/sites-available/tools.ietf.org``:
::
ScriptAliasMatch "^/wg/[^/]+/trac(/.*)?" /usr/share/trac/cgi-bin/trac.cgi$1
<LocationMatch "^/wg/([^/]+)/trac">
SetEnv TRAC_ENV "/www/tools.ietf.org/tools/trac/wg/$1"
</LocationMatch>
This doesn't work because Apache doesn't support $n replacements based on
earlier LocationMatch matches.
Use .htaccess with default ScriptAlias
......................................
Maybe we could use individual .htaccess files in each WG directory to set the
``TRAC_ENV`` variable to the required value?
``/etc/apache2/sites-available/tools.ietf.org``:
::
ScriptAliasMatch "^/wg/[^/]+/trac(/.*)?" /usr/share/trac/cgi-bin/trac.cgi$1
``/www/tools.ietf.org/wg/examplewg/.htaccess``:
::
SetEnv TRAC_ENV "/www/tools.ietf.org/wg/examplewg/trac"
This doesn't work because this .htaccess isn't read when ScriptAlias points to
another directory.
Use .htaccess with a local CGI script
.....................................
Suppose we let ScriptAlias point to a script which is placed so that the
.htaccess file actually gets read?
``/etc/apache2/sites-available/tools.ietf.org``:
::
ScriptAliasMatch "^/wg/([^/]+)/trac(/.*)?" /www/tools.ietf.org/wg/$1/trac/index.cgi$2
``/www/tools.ietf.org/wg/examplewg/.htaccess``:
::
SetEnv TRAC_ENV "/www/tools.ietf.org/wg/examplewg/trac"
This *does* work, but it is not easily adapted to a Fast-CGI solution. It is
the set-up which is currently in use, but an alternative which will permit
fast-cgi usage would be preferred - the current solution is anything but
snappy...
}}}

View file

@ -0,0 +1,10 @@
= Training Materials =
WG Traingin Materials go here.
If you want to embed video, you can use the ![[Movie(<url>,width=<width>,height=<height>)]]
macro to embed moves from [http://youtube.com/ YouTube]. Suggested width and height parameters: width=640,height=385.
Example which doesn't point to an actual video:
[[Movie(http://www.youtube.com/watch?v=g_exampleid,width=640px,height=385px)]]

View file

@ -0,0 +1,29 @@
= Welcome to this IETF WG Trac installation =
Trac is a '''minimalistic''' approach to '''web-based''' project management,
suitable for software and documentation projects and similar. Its goal is to
simplify effective tracking and handling of project issues, enhancements and
overall progress.
As all Wiki pages, this page is editable, this means that you can modify the
contents of this page simply by using your web-browser. Simply click on the
"Edit this page" link at the bottom of the page. WikiFormatting will give you
a detailed description of available Wiki formatting commands.
There is nothing in this page which isn't also covered in one of the other
wiki pages, so the first adjustment you make of this Trac installation could
be to edit the content of this page, replacing this initial text with content
appropriate to your Working Group.
There are some aspects of this Trac installation which are specific to the
IETF environment. Those are described in IetfSpecificFeatures.
== Starting Points ==
* TracGuide -- Built-in Documentation
* [http://trac.edgewall.org/ The Trac project] -- Trac Open Source Project
* [http://trac.edgewall.org/wiki/TracFaq Trac FAQ] -- Frequently Asked Questions
* TracSupport -- Trac Support
For a complete list of local wiki pages, see TitleIndex.

View file

@ -0,0 +1,280 @@
# Copyright 2016 IETF Trust
import os
import copy
import syslog
import pkg_resources
from optparse import make_option
#from optparse import make_option
from trac.core import TracError
from trac.env import Environment
from trac.perm import PermissionSystem
from trac.ticket.model import Component, Milestone, Severity
from trac.util.text import unicode_unquote
from trac.wiki.model import WikiPage
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from django.template.loader import render_to_string
import debug # pyflakes:ignore
from ietf.group.models import Group, GroupURL
from ietf.utils.pipe import pipe
logtag = __name__.split('.')[-1]
logname = "user.log"
syslog.openlog(logname, syslog.LOG_PID, syslog.LOG_USER)
class Command(BaseCommand):
help = "Create group wikis for WGs, RGs and Areas which don't have one."
option_list = BaseCommand.option_list + (
make_option('--wiki-dir-pattern', dest='wiki_dir_pattern', help='File containing email (default: stdin)'),
)
def note(self, msg):
if self.verbosity > 1:
self.stdout.write(msg)
def log(self, msg):
syslog.syslog(msg)
self.stderr.write(msg)
# --- svn ---
def do_cmd(self, cmd, *args):
quoted_args = [ '"%s"'%a if ' ' in a else a for a in args ]
self.note("Running %s %s ..." % (os.path.basename(cmd), " ".join(quoted_args)))
command = [ cmd, ] + list(args)
code, out, err = pipe(command)
msg = None
if code != 0:
msg = "Error %s: %s when executing '%s'" % (code, err, " ".join(command))
self.log(msg)
return msg, out
def svn_admin_cmd(self, *args):
return self.do_cmd(settings.SVN_ADMIN_COMMAND, *args)
def create_svn(self, svn):
self.note(" Creating svn repository: %s" % svn)
if not os.path.exists(os.path.dirname(svn)):
msg = "Intended to create '%s', but parent directory is missing" % svn
self.log(msg)
return msg
err, out= self.svn_admin_cmd("create", svn )
return err
# --- trac ---
def remove_demo_components(self, group, env):
for component in Component.select(env):
if component.name.startswith('component'):
component.delete()
def remove_demo_milestones(self, group, env):
for milestone in Milestone.select(env):
if milestone.name.startswith('milestone'):
milestone.delete()
def symlink_to_master_assets(self, group, env):
master_dir = settings.TRAC_MASTER_DIR
master_htdocs = os.path.join(master_dir, "htdocs")
group_htdocs = os.path.join(group.trac_dir, "htdocs")
self.note(" Symlinking %s to %s" % (master_htdocs, group_htdocs))
os.removedirs(group_htdocs)
os.symlink(master_htdocs, group_htdocs)
def add_wg_draft_states(self, group, env):
for state in settings.TRAC_ISSUE_SEVERITY_ADD:
self.note(" Adding severity %s" % state)
severity = Severity(env)
severity.name = state
severity.insert()
def add_wiki_page(self, env, name, text):
page = WikiPage(env, name)
if page.time:
self.note(" ** Page %s already exists, not adding it." % name)
return
page.text = text
page.save(author="(System)", comment="Initial page import")
def add_default_wiki_pages(self, group, env):
dir = pkg_resources.resource_filename('trac.wiki', 'default-pages')
#WikiAdmin(env).load_pages(dir)
with env.db_transaction:
for name in os.listdir(dir):
filename = os.path.join(dir, name)
name = unicode_unquote(name.encode('utf-8'))
if os.path.isfile(filename):
self.note(" Adding page %s" % name)
with open(filename) as file:
text = file.read().decode('utf-8')
self.add_wiki_page(env, name, text)
def add_custom_wiki_pages(self, group, env):
for templ in settings.TRAC_WIKI_PAGES_TEMPLATES:
_, name = os.path.split(templ)
text = render_to_string(templ, {"group": group})
self.note(" Adding page %s" % name)
self.add_wiki_page(env, name, text)
def sync_default_repository(self, group, env):
repository = env.get_repository('')
if repository:
self.note(" Indexing default repository")
repository.sync()
def create_trac(self, group):
if not os.path.exists(os.path.dirname(group.trac_dir)):
msg = "Intended to create '%s', but parent directory is missing" % group.trac_dir
self.log(msg)
return None
options = copy.deepcopy(settings.TRAC_ENV_OPTIONS)
# Interpolate group field names to values in the option settings:
for i in range(len(options)):
sect, key, val = options[i]
val = val.format(**group.__dict__)
options[i] = sect, key, val
# Try to creat ethe environment, remove unwanted defaults, and add
# custom pages and settings.
try:
env = Environment(group.trac_dir, create=True, options=options)
self.remove_demo_components(group, env)
self.remove_demo_milestones(group, env)
self.maybe_add_group_url(group, 'Wiki', settings.TRAC_WIKI_URL_PATTERN % group.acronym)
self.maybe_add_group_url(group, 'Issue tracker', settings.TRAC_ISSUE_URL_PATTERN % group.acronym)
# Use custom assets (if any) from the master setup
self.symlink_to_master_assets(group, env)
if group.type_id == 'wg':
self.add_wg_draft_states(group, env)
self.add_custom_wiki_pages(group, env)
self.add_default_wiki_pages(group, env)
self.sync_default_repository(group, env)
# Components (i.e., drafts) will be handled during components
# update later
# Permissions will be handled during permission update later.
return env
except TracError as e:
self.log("While creating trac instance for %s: %s" % (group, e))
raise
return None
def update_trac_permissions(self, group, env):
mgr = PermissionSystem(env)
permission_list = mgr.get_all_permissions()
permission_list = [ (u,a) for (u,a) in permission_list if not u in ['anonymous', 'authenticated']]
permissions = {}
for user, action in permission_list:
if not user in permissions:
permissions[user] = []
permissions[user].append(action)
roles = group.role_set.filter(name_id__in=['chair', 'secr', 'ad'])
users = []
for role in roles:
user = role.email.address.lower()
users.append(user)
if not user in permissions:
try:
mgr.grant_permission(user, 'TRAC_ADMIN')
self.note(" Granting admin permission for %s" % user)
except TracError as e:
self.log("While adding admin permission for %s: %s" (user, e))
for user in permissions:
if not user in users:
if 'TRAC_ADMIN' in permissions[user]:
try:
self.note(" Revoking admin permission for %s" % user)
mgr.revoke_permission(user, 'TRAC_ADMIN')
except TracError as e:
self.log("While revoking admin permission for %s: %s" (user, e))
def update_trac_components(self, group, env):
components = Component.select(env)
comp_names = [ c.name for c in components ]
group_docs = group.document_set.filter(states__slug='active', type_id='draft').distinct()
group_comp = []
for doc in group_docs:
if not doc.name.startswith('draft-'):
self.log("While adding components: unexpectd %s group doc name: %s" % (group.acronym, doc.name))
continue
name = doc.name[len('draft-'):]
if name.startswith('ietf-'):
name = name[len('ietf-'):]
elif name.startswith('irtf-'):
name = name[len('ietf-'):]
if name.startswith(group.acronym+'-'):
name = name[len(group.acronym+'-'):]
group_comp.append(name)
if not name in comp_names and not doc.name in comp_names:
self.note(" Group draft: %s" % doc.name)
self.note(" Adding component %s" % name)
comp = Component(env)
comp.name = name
comp.owner = "%s@ietf.org" % doc.name
comp.insert()
def maybe_add_group_url(self, group, name, url):
urls = [ u for u in group.groupurl_set.all() if name.lower() in u.name.lower() ]
if not urls:
self.note(" adding %s %s URL ..." % (group.acronym, name.lower()))
group.groupurl_set.add(GroupURL(group=group, name=name, url=url))
def add_custom_pages(self, group, env):
for template_name in settings.TRAC_WIKI_PAGES_TEMPLATES:
pass
def add_custom_group_states(self, group, env):
for state_name in settings.TRAC_ISSUE_SEVERITY_ADD:
pass
# --------------------------------------------------------------------
def handle(self, *filenames, **options):
self.verbosity = options['verbosity']
self.errors = 0
self.wiki_dir_pattern = options.get('wiki_dir_pattern', settings.TRAC_WIKI_DIR_PATTERN)
if isinstance(self.verbosity, (type(""), type(u""))) and self.verbosity.isdigit():
self.verbosity = int(self.verbosity)
if not os.path.exists(os.path.dirname(self.wiki_dir_pattern)):
raise CommandError('The Wiki base direcory specified for the wiki directories (%s) does not exist.' % os.path.dirname(self.wiki_dir_pattern))
groups = Group.objects.filter(
type__slug__in=['wg','rg','area'],
state__slug='active'
).order_by('acronym')
for group in groups:
try:
self.note("Processing group %s" % group.acronym)
group.trac_dir = self.wiki_dir_pattern % group.acronym
group.svn_dir = settings.TRAC_SVN_DIR_PATTERN % group.acronym
if not os.path.exists(group.svn_dir):
err = self.create_svn(group.svn_dir)
self.errors += 1 if err else 0
if not os.path.exists(group.trac_dir):
trac_env = self.create_trac(group)
self.errors += 1 if not trac_env else 0
else:
trac_env = Environment(group.trac_dir)
if not trac_env:
continue
self.update_trac_permissions(group, trac_env)
self.update_trac_components(group, trac_env)
except Exception as e:
self.errors += 1
self.log("While processing %s: %s" % (group.acronym, e))
raise
if self.errors:
raise CommandError("There were %s failures in WG Trac creation, see syslog %s for details." % (self.errors, logname))

View file

@ -24,7 +24,7 @@ def pipe(cmd, str=None):
err = pipe.childerr.read() err = pipe.childerr.read()
break break
if len(out) >= MAX: if len(out) >= MAX:
err = "Output exceeds %s bytes and has been truncated" err = "Output exceeds %s bytes and has been truncated" % MAX
break break
return (code, out, err) return (code, out, err)

View file

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os.path import os.path
import types import types
#import json import shutil
#from pathlib import Path from StringIO import StringIO
from pipe import pipe
from textwrap import dedent from textwrap import dedent
from email.mime.text import MIMEText from email.mime.text import MIMEText
@ -10,6 +11,7 @@ from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart from email.mime.multipart import MIMEMultipart
from django.conf import settings from django.conf import settings
from django.core.management import call_command
from django.template import Context from django.template import Context
from django.template.defaulttags import URLNode from django.template.defaulttags import URLNode
from django.templatetags.static import StaticNode from django.templatetags.static import StaticNode
@ -21,7 +23,9 @@ import debug # pyflakes:ignore
import ietf.urls import ietf.urls
from ietf.utils.management.commands import pyflakes from ietf.utils.management.commands import pyflakes
from ietf.utils.mail import send_mail_text, send_mail_mime, outbox from ietf.utils.mail import send_mail_text, send_mail_mime, outbox
from ietf.utils.test_data import make_test_data
from ietf.utils.test_runner import get_template_paths from ietf.utils.test_runner import get_template_paths
from ietf.group.models import Group
class PyFlakesTestCase(TestCase): class PyFlakesTestCase(TestCase):
@ -186,6 +190,46 @@ class TemplateChecksTestCase(TestCase):
settings.DEBUG = saved_debug settings.DEBUG = saved_debug
class TestWikiGlueManagementCommand(TestCase):
def setUp(self):
self.wiki_dir_pattern = os.path.abspath('tmp-wiki-dir-root/%s')
if not os.path.exists(self.wiki_dir_pattern):
os.mkdir(os.path.dirname(self.wiki_dir_pattern))
def tearDown(self):
shutil.rmtree(os.path.dirname(self.wiki_dir_pattern))
def test_wiki_create_output(self):
make_test_data()
groups = Group.objects.filter(
type__slug__in=['wg','rg','area'],
state__slug='active'
).order_by('acronym')
out = StringIO()
call_command('create_group_wikis', stdout=out, verbosity=2, wiki_dir_pattern=self.wiki_dir_pattern)
command_output = out.getvalue()
for group in groups:
self.assertIn("Processing group %s" % group.acronym, command_output)
# Do a bit of verification using trac-admin, too
admin_code, admin_output, admin_error = pipe('trac-admin %s permission list' % (self.wiki_dir_pattern % group.acronym))
self.assertEqual(admin_code, 0)
roles = group.role_set.filter(name_id__in=['chair', 'secr', 'ad'])
for role in roles:
user = role.email.address.lower()
self.assertIn("Granting admin permission for %s" % user, command_output)
self.assertIn(user, admin_output)
docs = group.document_set.filter(states__slug='active', type_id='draft')
for doc in docs:
name = doc.name
name = name.replace('draft-','')
name = name.replace(doc.stream_id+'-', '')
name = name.replace(group.acronym+'-', '')
self.assertIn("Adding component %s"%name, command_output)
for page in settings.TRAC_WIKI_PAGES_TEMPLATES:
self.assertIn("Adding page %s" % os.path.basename(page), command_output)
self.assertIn("Indexing default repository", command_output)
## One might think that the code below would work, but it doesn't ... ## One might think that the code below would work, but it doesn't ...
# def list_static_files(path): # def list_static_files(path):

View file

@ -44,7 +44,7 @@ import sys
path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Virtualenv support # Virtualenv support
virtualenv_activation = os.path.join(path, "bin", "activate_this.py") virtualenv_activation = os.path.join(path, "env", "bin", "activate_this.py")
if os.path.exists(virtualenv_activation): if os.path.exists(virtualenv_activation):
execfile(virtualenv_activation, dict(__file__=virtualenv_activation)) execfile(virtualenv_activation, dict(__file__=virtualenv_activation))

View file

@ -34,6 +34,7 @@ pyzmail>=1.0.3
selenium>=2.42 selenium>=2.42
six>=1.8.0 six>=1.8.0
tqdm>=3.7.0 tqdm>=3.7.0
Trac>=1.0.10
Unidecode>=0.4.18 Unidecode>=0.4.18
#wsgiref>=0.1.2 #wsgiref>=0.1.2
xml2rfc>=2.5. xml2rfc>=2.5.