This is running now:
import redmine
redmine_api_key = open('redmine-verifier-key').read().strip()
redmine_api = redmine.Redmine('https://pulp.plan.io', key=redmine_api_key)
def url(id):
return 'https://pulp.plan.io/issues/{}'.format(id)
def filter_issue(issue):
# if the issue isn't a story or task, skip it
# can only filter issues by one tracker type, so filter here
if issue.tracker.id not in (tracker_i, tracker_s):
return True
# if the issue is already verified, skip it
# .filtering by the value of the "Verified" custom field seems broken, so filter here
for field in issue.custom_fields:
if field.id == field_v and field.value == "1":
return True
return False
# these resources don't support filtering, so ghettofilter out the things we want
for status in redmine_api.issue_status.all():
if status.name == 'CLOSED - CURRENTRELEASE':
# ccr = closed current release
status_ccr = status.id
elif status.name == 'VERIFIED':
status_v = status.id
for tracker in redmine_api.tracker.all():
if tracker.name == 'Issue':
tracker_i = tracker.id
elif tracker.name == 'Story':
tracker_s = tracker.id
for custom_field in redmine_api.custom_field.all():
if custom_field.name == 'Verified':
field_v = custom_field.id
# filter outs issues that aren't current CLOSED - CURRENTRELEASE, and aren't marked verified
filter_kwargs = {
'status_id': status_ccr,
}
closed_issues = redmine_api.issue.filter(**filter_kwargs)
# known closed issue for debugging
# closed_issues = [redmine_api.issue.get(161)]
errors = []
for issue in filter(filter_issue, closed_issues):
# re-get the issue with journals to get status history
issue = redmine_api.issue.get(issue.id, include='journals')
print('processing {}'.format(url(issue.id)))
for issue_change in reversed(issue.journals):
for detail in issue_change.details:
if detail['name'] == 'status_id':
old_value, new_value = (int(v) for v in (detail['old_value'], detail['new_value']))
break
try:
# these might not get set in the detail loop, so go around again if we have to
old_value, new_value
break
except NameError:
# heh
continue
else:
# this should never happen
print(' Unable to determine last status change for {}?'.format(url(issue.id)))
if old_value == status_v and new_value == status_ccr:
# issue's last status transition was from VERIFIED to C - CR, mark verified
print(' {} marked verified.'.format(url(issue.id)))
# actually do the thing
try:
redmine_api.issue.update(issue.id, custom_fields=[{'id': field_v, 'value': '1'}])
except redmine.exception.BaseRedmineException as ex:
print(' {} error on update'.format(url(issue.id)))
errors.append((issue, ex))
else:
print(' {} not marked verified.'.format(url(issue.id)))
# a newline for good luck
print()
for issue, ex in errors:
print('{} raised {} in processing and needs manual intervention'.format(
issue.id, type(ex).__name__)
)
As you might imagine, the "redmine_api_key" file contains a redmine api key. :)
The script should be idempotent, which is useful in case we need to run this again during the transition from using the VERIFIED status to using the Verified custom field.
(Edited Feb 2 with minor script tweaks.)