Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
bugzilla
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ivan Ivlev
bugzilla
Commits
c8c170b9
Commit
c8c170b9
authored
Feb 13, 2002
by
justdave%syndicomm.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adding jb2bz.py to contrib (bug 124869).
Conversion script to import bugs from Jitterbug into Bugzilla contributed by Tom Emerson <tree@basistech.com>
parent
bf2b3d23
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
303 additions
and
0 deletions
+303
-0
jb2bz.py
contrib/jb2bz.py
+303
-0
No files found.
contrib/jb2bz.py
0 → 100644
View file @
c8c170b9
#!/usr/local/bin/python
# -*- mode: python -*-
"""
jb2bz.py - a nonce script to import bugs from JitterBug to Bugzilla
Written by Tom Emerson, tree@basistech.com
This script is provided in the hopes that it will be useful. No
rights reserved. No guarantees expressed or implied. Use at your own
risk. May be dangerous if swallowed. If it doesn't work for you, don't
blame me. It did what I needed it to do.
This code requires a recent version of Andy Dustman's MySQLdb interface,
http://sourceforge.net/projects/mysql-python
Share and enjoy.
"""
import
rfc822
,
mimetools
,
multifile
,
mimetypes
import
sys
,
re
,
glob
,
StringIO
,
os
,
stat
,
time
import
MySQLdb
,
getopt
# mimetypes doesn't include everything we might encounter, yet.
if
not
mimetypes
.
types_map
.
has_key
(
'.doc'
):
mimetypes
.
types_map
[
'.doc'
]
=
'application/msword'
if
not
mimetypes
.
encodings_map
.
has_key
(
'.bz2'
):
mimetypes
.
encodings_map
[
'.bz2'
]
=
"bzip2"
bug_status
=
'NEW'
component
=
"default"
version
=
""
product
=
""
# this is required, the rest of these are defaulted as above
"""
Each bug in JitterBug is stored as a text file named by the bug number.
Additions to the bug are indicated by suffixes to this:
<bug>
<bug>.followup.*
<bug>.reply.*
<bug>.notes
The dates on the files represent the respective dates they were created/added.
All <bug>s and <bug>.reply.*s include RFC 822 mail headers. These could include
MIME file attachments as well that would need to be extracted.
There are other additions to the file names, such as
<bug>.notify
which are ignored.
Bugs in JitterBug are organized into directories. At Basis we used the following
naming conventions:
<product>-bugs Open bugs
<product>-requests Open Feature Requests
<product>-resolved Bugs/Features marked fixed by engineering, but not verified
<product>-verified Resolved defects that have been verified by QA
where <product> is either:
<product-name>
or
<product-name>-<version>
"""
def
process_notes_file
(
current
,
fname
):
try
:
new_note
=
{}
notes
=
open
(
fname
,
"r"
)
s
=
os
.
fstat
(
notes
.
fileno
())
new_note
[
'text'
]
=
notes
.
read
()
new_note
[
'timestamp'
]
=
time
.
gmtime
(
s
[
stat
.
ST_MTIME
])
notes
.
close
()
current
[
'notes'
]
.
append
(
new_note
)
except
IOError
:
pass
def
process_reply_file
(
current
,
fname
):
new_note
=
{}
reply
=
open
(
fname
,
"r"
)
msg
=
rfc822
.
Message
(
reply
)
new_note
[
'text'
]
=
"
%
s
\n
%
s"
%
(
msg
[
'From'
],
msg
.
fp
.
read
())
new_note
[
'timestamp'
]
=
rfc822
.
parsedate_tz
(
msg
[
'Date'
])
current
[
"notes"
]
.
append
(
new_note
)
def
add_notes
(
current
):
"""Add any notes that have been recorded for the current bug."""
process_notes_file
(
current
,
"
%
d.notes"
%
current
[
'number'
])
for
f
in
glob
.
glob
(
"
%
d.reply.*"
%
current
[
'number'
]):
process_reply_file
(
current
,
f
)
for
f
in
glob
.
glob
(
"
%
d.followup.*"
%
current
[
'number'
]):
process_reply_file
(
current
,
f
)
def
maybe_add_attachment
(
current
,
file
,
submsg
):
"""Adds the attachment to the current record"""
cd
=
submsg
[
"Content-Disposition"
]
m
=
re
.
search
(
r'filename="([^"]+)"'
,
cd
)
if
m
==
None
:
return
attachment_filename
=
m
.
group
(
1
)
if
(
submsg
.
gettype
()
==
'application/octet-stream'
):
# try get a more specific content-type for this attachment
type
,
encoding
=
mimetypes
.
guess_type
(
m
.
group
(
1
))
if
type
==
None
:
type
=
submsg
.
gettype
()
else
:
type
=
submsg
.
gettype
()
try
:
data
=
StringIO
.
StringIO
()
mimetools
.
decode
(
file
,
data
,
submsg
.
getencoding
())
except
:
return
current
[
'attachments'
]
.
append
(
(
attachment_filename
,
type
,
data
.
getvalue
()
)
)
def
process_mime_body
(
current
,
file
,
submsg
):
data
=
StringIO
.
StringIO
()
mimetools
.
decode
(
file
,
data
,
submsg
.
getencoding
())
current
[
'description'
]
=
data
.
getvalue
()
def
process_text_plain
(
msg
,
current
):
print
"Processing:
%
d"
%
current
[
'number'
]
current
[
'description'
]
=
msg
.
fp
.
read
()
def
process_multi_part
(
file
,
msg
,
current
):
print
"Processing:
%
d"
%
current
[
'number'
]
mf
=
multifile
.
MultiFile
(
file
)
mf
.
push
(
msg
.
getparam
(
"boundary"
))
while
mf
.
next
():
submsg
=
mimetools
.
Message
(
file
)
if
submsg
.
has_key
(
"Content-Disposition"
):
maybe_add_attachment
(
current
,
mf
,
submsg
)
else
:
# This is the message body itself (always?), so process
# accordingly
process_mime_body
(
current
,
mf
,
submsg
)
def
process_jitterbug
(
filename
):
current
=
{}
current
[
'number'
]
=
int
(
filename
)
current
[
'notes'
]
=
[]
current
[
'attachments'
]
=
[]
current
[
'description'
]
=
''
current
[
'date-reported'
]
=
()
current
[
'short-description'
]
=
''
file
=
open
(
filename
,
"r"
)
msg
=
mimetools
.
Message
(
file
)
msgtype
=
msg
.
gettype
()
add_notes
(
current
)
current
[
'date-reported'
]
=
rfc822
.
parsedate_tz
(
msg
[
'Date'
])
current
[
'short-description'
]
=
msg
[
'Subject'
]
if
msgtype
[:
5
]
==
'text/'
:
process_text_plain
(
msg
,
current
)
elif
msgtype
[:
10
]
==
"multipart/"
:
process_multi_part
(
file
,
msg
,
current
)
else
:
# Huh? This should never happen.
print
"Unknown content-type:
%
s"
%
msgtype
sys
.
exit
(
1
)
# At this point we have processed the message: we have all of the notes and
# attachments stored, so it's time to add things to the database.
# The schema for JitterBug 2.14 can be found at:
#
# http://www.trilobyte.net/barnsons/html/dbschema.html
#
# The following fields need to be provided by the user:
#
# bug_status
# product
# version
# reporter
# component
# resolution
# change this to the user_id of the Bugzilla user who is blessed with the
# imported defects
reporter
=
6
# the resolution will need to be set manually
resolution
=
""
db
=
MySQLdb
.
connect
(
db
=
'bugs'
,
user
=
'root'
,
host
=
'localhost'
)
cursor
=
db
.
cursor
()
cursor
.
execute
(
"INSERT INTO bugs SET "
\
"bug_id=
%
s,"
\
"bug_severity='normal',"
\
"bug_status=
%
s,"
\
"creation_ts=
%
s,"
\
"short_desc=
%
s,"
\
"product=
%
s,"
\
"rep_platform='All',"
\
"assigned_to=
%
s,"
"reporter=
%
s,"
\
"version=
%
s,"
\
"component=
%
s,"
\
"resolution=
%
s"
,
[
current
[
'number'
],
bug_status
,
time
.
strftime
(
"
%
Y-
%
m-
%
d
%
H:
%
M:
%
S"
,
current
[
'date-reported'
][:
9
]),
current
[
'short-description'
],
product
,
reporter
,
reporter
,
version
,
component
,
resolution
]
)
# This is the initial long description associated with the bug report
cursor
.
execute
(
"INSERT INTO longdescs VALUES (
%
s,
%
s,
%
s,
%
s)"
,
[
current
[
'number'
],
reporter
,
time
.
strftime
(
"
%
Y-
%
m-
%
d
%
H:
%
M:
%
S"
,
current
[
'date-reported'
][:
9
]),
current
[
'description'
]
]
)
# Add whatever notes are associated with this defect
for
n
in
current
[
'notes'
]:
cursor
.
execute
(
"INSERT INTO longdescs VALUES (
%
s,
%
s,
%
s,
%
s)"
,
[
current
[
'number'
],
reporter
,
time
.
strftime
(
"
%
Y-
%
m-
%
d
%
H:
%
M:
%
S"
,
n
[
'timestamp'
][:
9
]),
n
[
'text'
]])
# add attachments associated with this defect
for
a
in
current
[
'attachments'
]:
cursor
.
execute
(
"INSERT INTO attachments SET "
\
"bug_id=
%
s, creation_ts=
%
s, description='', mimetype=
%
s,"
\
"filename=
%
s, thedata=
%
s, submitter_id=
%
s"
,
[
current
[
'number'
],
time
.
strftime
(
"
%
Y-
%
m-
%
d
%
H:
%
M:
%
S"
,
current
[
'date-reported'
][:
9
]),
a
[
1
],
a
[
0
],
a
[
2
],
reporter
])
cursor
.
close
()
db
.
close
()
def
usage
():
print
"""Usage: jb2bz.py [OPTIONS] Product
Where OPTIONS are one or more of the following:
-h This help information.
-s STATUS One of UNCONFIRMED, NEW, ASSIGNED, REOPENED, RESOLVED, VERIFIED, CLOSED
(default is NEW)
-c COMPONENT The component to attach to each bug as it is important. This should be
valid component for the Product.
-v VERSION Version to assign to these defects.
Product is the Product to assign these defects to.
All of the JitterBugs in the current directory are imported, including replies, notes,
attachments, and similar noise.
"""
sys
.
exit
(
1
)
def
main
():
global
bug_status
,
component
,
version
,
product
opts
,
args
=
getopt
.
getopt
(
sys
.
argv
[
1
:],
"hs:c:v:"
)
for
o
,
a
in
opts
:
if
o
==
"-s"
:
if
a
in
(
'UNCONFIRMED'
,
'NEW'
,
'ASSIGNED'
,
'REOPENED'
,
'RESOLVED'
,
'VERIFIED'
,
'CLOSED'
):
bug_status
=
a
elif
o
==
'-c'
:
component
=
a
elif
o
==
'-v'
:
version
=
a
elif
o
==
'-h'
:
usage
()
if
len
(
args
)
!=
1
:
sys
.
stderr
.
write
(
"Must specify the Product.
\n
"
)
sys
.
exit
(
1
)
product
=
args
[
0
]
for
bug
in
filter
(
lambda
x
:
re
.
match
(
r"\d+$"
,
x
),
glob
.
glob
(
"*"
)):
process_jitterbug
(
bug
)
if
__name__
==
"__main__"
:
main
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment