Add milestones using the MilestoneCache object, like this script does (or just use the script, which is what I do either from the command line or from Python3 via subprocess.run, since Trac currently runs on Python2 and not 3)
#!/usr/bin/python2
from trac.env import open_environment
from trac.ticket import Milestone
from trac.ticket.model import MilestoneCache
from trac.core import TracError
import sys, json;
if len(sys.argv)!=2:
print '''
Usage: python2 createMilestone.py2 dir
e.g. python2 createMilestone.py2 ~/trac M3 <<END
{ "name": "M3",
"due": "2021-01-01 04:00:00+00:00",
"completed": "2021-12-31 23:59:59+00:00",
"description": "" }
END
'''
exit(3)
try:
data = json.load(sys.stdin)
except:
sys.stderr.write("Bad input data")
exit(2)
try:
mc=MilestoneCache(open_environment(sys.argv[1]))
mc.factory((data['name'],data['due'],data['completed'],data['description'])).insert()
except:
sys.stderr.write("Can't update "+sys.argv[1]+"\n")
exit(1)
The script takes JSON with all the fields of the milestone as input. It's the same technique I use for creating tickets when writing Python3, since Trac is a Python2 program.
Conversely, if you want to list milestones, you can use this similar script, and you can pipe a milestone listed as jSON from one Trac site to another.
Sometimes I teach courses where I prepare a Trac site for each student, and I dump milestones through this script below and pipe it through the script above to propagate it into student Trac sites.
#!/usr/bin/python2
from trac.env import open_environment
from trac.ticket import Milestone
from trac.ticket.model import MilestoneCache
from trac.core import TracError
import sys, json;
if len(sys.argv)!=3:
print '''
Usage: python2 getMilestone dir milestone
e.g. python2 getMilestone ~/trac M3
'''
exit(3)
try:
name,due,completed,description = MilestoneCache(open_environment(sys.argv[1])).milestones[sys.argv[2]]
print json.dumps({
"name":name,
"due":str(due) if due else None,
"completed":str(completed) if completed else None,
"description":description
},indent=2)
except KeyError:
pass
except TracError:
sys.stderr.write("Can't open "+sys.argv[1]+"\n")
exit(1)