Skip to content

Instantly share code, notes, and snippets.

@adamcharnock
Created April 24, 2018 11:26
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adamcharnock/44b27418ac0b1929f91f7c4c3b1bb86a to your computer and use it in GitHub Desktop.
Save adamcharnock/44b27418ac0b1929f91f7c4c3b1bb86a to your computer and use it in GitHub Desktop.
Python script to move all GitLab issues from one project to another
#!/usr/bin/env python3
import os
import gitlab
GITLAB_API_TOKEN = os.environ['GITLAB_API_TOKEN']
def main():
print("Logging into gitlab and fetching a list of projects...")
gl = gitlab.Gitlab('https://gitlab.com', private_token=GITLAB_API_TOKEN)
projects = gl.projects.list(membership=1, all=True)
print(f"Here are the projects we found ")
for i, project in enumerate(projects):
print(f" {i+1}. {project.name}")
from_project_number = input(f"\nWhich project do you want to move issues FROM? Enter 1 - {len(projects)}: ")
to_project_number = input(f"Which project do you want to move issues TO? Enter 1 - {len(projects)}: ")
from_project = projects[int(from_project_number.strip()) - 1]
to_project = projects[int(to_project_number.strip()) - 1]
print(f'Fetching issues for {from_project.name} (this can take a while)...')
issues = from_project.issues.list(all=True)
issues = sorted(issues, key=lambda i: i.iid)
print(f'Fetching labels for {from_project.name}...')
labels = from_project.labels.list(all=True)
existing_labels = to_project.labels.list(all=True)
print(f'Will move {len(issues)} issues from {from_project.name} to {to_project.name}')
print(f'Will also create {len(labels)} labels in project {to_project.name}')
cont = input('Continue [y/n]? ')
if cont.strip().lower() != 'y':
return
print('Creating labels')
for label in labels:
if [l for l in existing_labels if l.name == label.name]:
print(f'Label {label.name} already exists in {to_project.name}. Skipping.')
continue
to_project.labels.create({
'name': label.name,
'color': label.color,
'description': label.description,
'priority': label.priority,
})
print(f' Created {label.name}')
print(f'Starting moving...')
for issue in issues:
print(f' Moving issue {issue.iid}: {issue.title}... ', end='', flush=True)
while True:
try:
issue.move(to_project.id)
except OSError as e:
print(f'\nError encountered ({e}). Retrying... ', end='', flush=True)
except gitlab.GitlabUpdateError as e:
if e.response_code == 400:
print(
f"\nUpdate error, insufficient permissions. Skipping this issue as this "
f"normally means the issue has already been moved."
)
break
else:
raise
else:
break
print('done')
print('Move complete!')
if __name__ == '__main__':
main()
@wieland-s
Copy link

Thank you! This script saved me a lot of time. For my purpose (self hosted with self signed certificate) i added:

GITLAB_API_TOKEN = os.environ['GITLAB_API_TOKEN']
GITLAB_CA_CERT = os.environ['GITLAB_CA_CERT']
GITLAB_URL = os.environ['GITLAB_URL']


def main():
    print("Logging into gitlab and fetching a list of projects...")
    gl = gitlab.Gitlab(GITLAB_URL, private_token=GITLAB_API_TOKEN, ssl_verify=GITLAB_CA_CERT)

[...]

After the move of ~350 tickets I noticed: I'm now subscriber of each ticket and everybody has got a mail for each participated ticket. 😄

@joelsdc
Copy link

joelsdc commented Aug 5, 2021

I just have to say thank you, you (both, I also use self-managed) just saved me having to write my own version of this script! Works perfectly! Cheers :-)

@vuillaut
Copy link

vuillaut commented Sep 7, 2021

Worked like a charm <3

@Redbot
Copy link

Redbot commented Feb 17, 2022

Can't get it to work.

File "C:\Users\Redbot\AppData\Local\Programs\Python\Python310\lib\os.py", line 679, in __getitem__
    raise KeyError(key) from None```

@jdclarke5
Copy link

Thank you from Newcastle, Australia :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment