import base64 import os import time import requests import gitlab LOGIN = "root" PASSWORD = "5iveL!fe" SSH_KEY = ( "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDZAjAX8vTiHD7Yi3/EzuVaDChtih" "79HyJZ6H9dEqxFfmGA1YnncE0xujQ64TCebhkYJKzmTJCImSVkOu9C4hZgsw6eE76n" "+Cg3VwEeDUFy+GXlEJWlHaEyc3HWioxgOALbUp3rOezNh+d8BDwwqvENGoePEBsz5l" "a6WP5lTi/HJIjAl6Hu+zHgdj1XVExeH+S52EwpZf/ylTJub0Bl5gHwf/siVE48mLMI" "sqrukXTZ6Zg+8EHAIvIQwJ1dKcXe8P5IoLT7VKrbkgAnolS0I8J+uH7KtErZJb5oZh" "S4OEwsNpaXMAr+6/wWSpircV2/e7sFLlhlKBC4Iq1MpqlZ7G3p foo@bar" ) DEPLOY_KEY = ( "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFdRyjJQh+1niBpXqE2I8dzjG" "MXFHlRjX9yk/UfOn075IdaockdU58sw2Ai1XIWFpZpfJkW7z+P47ZNSqm1gzeXI" "rtKa9ZUp8A7SZe8vH4XVn7kh7bwWCUirqtn8El9XdqfkzOs/+FuViriUWoJVpA6" "WZsDNaqINFKIA5fj/q8XQw+BcS92L09QJg9oVUuH0VVwNYbU2M2IRmSpybgC/gu" "uWTrnCDMmLItksATifLvRZwgdI8dr+q6tbxbZknNcgEPrI2jT0hYN9ZcjNeWuyv" "rke9IepE7SPBT41C+YtUX4dfDZDmczM1cE0YL/krdUCfuZHMa4ZS2YyNd6slufc" "vn bar@foo" ) GPG_KEY = """-----BEGIN PGP PUBLIC KEY BLOCK----- mQENBFn5mzYBCADH6SDVPAp1zh/hxmTi0QplkOfExBACpuY6OhzNdIg+8/528b3g Y5YFR6T/HLv/PmeHskUj21end1C0PNG2T9dTx+2Vlh9ISsSG1kyF9T5fvMR3bE0x Dl6S489CXZrjPTS9SHk1kF+7dwjUxLJyxF9hPiSihFefDFu3NeOtG/u8vbC1mewQ ZyAYue+mqtqcCIFFoBz7wHKMWjIVSJSyTkXExu4OzpVvy3l2EikbvavI3qNz84b+ Mgkv/kiBlNoCy3CVuPk99RYKZ3lX1vVtqQ0OgNGQvb4DjcpyjmbKyibuZwhDjIOh au6d1OyEbayTntd+dQ4j9EMSnEvm/0MJ4eXPABEBAAG0G0dpdGxhYlRlc3QxIDxm YWtlQGZha2UudGxkPokBNwQTAQgAIQUCWfmbNgIbAwULCQgHAgYVCAkKCwIEFgID AQIeAQIXgAAKCRBgxELHf8f3hF3yB/wNJlWPKY65UsB4Lo0hs1OxdxCDqXogSi0u 6crDEIiyOte62pNZKzWy8TJcGZvznRTZ7t8hXgKFLz3PRMcl+vAiRC6quIDUj+2V eYfwaItd1lUfzvdCaC7Venf4TQ74f5vvNg/zoGwE6eRoSbjlLv9nqsxeA0rUBUQL LYikWhVMP3TrlfgfduYvh6mfgh57BDLJ9kJVpyfxxx9YLKZbaas9sPa6LgBtR555 JziUxHmbEv8XCsUU8uoFeP1pImbNBplqE3wzJwzOMSmmch7iZzrAwfN7N2j3Wj0H B5kQddJ9dmB4BbU0IXGhWczvdpxboI2wdY8a1JypxOdePoph/43iuQENBFn5mzYB CADnTPY0Zf3d9zLjBNgIb3yDl94uOcKCq0twNmyjMhHzGqw+UMe9BScy34GL94Al xFRQoaL+7P8hGsnsNku29A/VDZivcI+uxTx4WQ7OLcn7V0bnHV4d76iky2ufbUt/ GofthjDs1SonePO2N09sS4V4uK0d5N4BfCzzXgvg8etCLxNmC9BGt7AaKUUzKBO4 2QvNNaC2C/8XEnOgNWYvR36ylAXAmo0sGFXUsBCTiq1fugS9pwtaS2JmaVpZZ3YT pMZlS0+SjC5BZYFqSmKCsA58oBRzCxQz57nR4h5VEflgD+Hy0HdW0UHETwz83E6/ U0LL6YyvhwFr6KPq5GxinSvfABEBAAGJAR8EGAEIAAkFAln5mzYCGwwACgkQYMRC x3/H94SJgwgAlKQb10/xcL/epdDkR7vbiei7huGLBpRDb/L5fM8B5W77Qi8Xmuqj cCu1j99ZCA5hs/vwVn8j8iLSBGMC5gxcuaar/wtmiaEvT9fO/h6q4opG7NcuiJ8H wRj8ccJmRssNqDD913PLz7T40Ts62blhrEAlJozGVG/q7T3RAZcskOUHKeHfc2RI YzGsC/I9d7k6uxAv1L9Nm5F2HaAQDzhkdd16nKkGaPGR35cT1JLInkfl5cdm7ldN nxs4TLO3kZjUTgWKdhpgRNF5hwaz51ZjpebaRf/ZqRuNyX4lIRolDxzOn/+O1o8L qG2ZdhHHmSK2LaQLFiSprUkikStNU9BqSQ== =5OGa -----END PGP PUBLIC KEY BLOCK-----""" AVATAR_PATH = os.path.join(os.path.dirname(__file__), "avatar.png") # token authentication from config file gl = gitlab.Gitlab.from_config(config_files=["/tmp/python-gitlab.cfg"]) gl.auth() assert isinstance(gl.user, gitlab.v4.objects.CurrentUser) # markdown (need to wait for gitlab 11 to enable the test) # html = gl.markdown('foo') # assert('foo' in html) success, errors = gl.lint("Invalid") assert success is False assert errors # sidekiq out = gl.sidekiq.queue_metrics() assert isinstance(out, dict) assert "pages" in out["queues"] out = gl.sidekiq.process_metrics() assert isinstance(out, dict) assert "hostname" in out["processes"][0] out = gl.sidekiq.job_stats() assert isinstance(out, dict) assert "processed" in out["jobs"] out = gl.sidekiq.compound_metrics() assert isinstance(out, dict) assert "jobs" in out assert "processes" in out assert "queues" in out # settings settings = gl.settings.get() settings.default_projects_limit = 42 settings.save() settings = gl.settings.get() assert settings.default_projects_limit == 42 # users new_user = gl.users.create( { "email": "foo@bar.com", "username": "foo", "name": "foo", "password": "foo_password", "avatar": open(AVATAR_PATH, "rb"), } ) avatar_url = new_user.avatar_url.replace("gitlab.test", "localhost:8080") uploaded_avatar = requests.get(avatar_url).content assert uploaded_avatar == open(AVATAR_PATH, "rb").read() users_list = gl.users.list() for user in users_list: if user.username == "foo": break assert new_user.username == user.username assert new_user.email == user.email new_user.block() new_user.unblock() # user projects list assert len(new_user.projects.list()) == 0 # events list new_user.events.list() foobar_user = gl.users.create( { "email": "foobar@example.com", "username": "foobar", "name": "Foo Bar", "password": "foobar_password", } ) assert gl.users.list(search="foobar")[0].id == foobar_user.id expected = [new_user, foobar_user] actual = list(gl.users.list(search="foo")) assert len(expected) == len(actual) assert len(gl.users.list(search="asdf")) == 0 foobar_user.bio = "This is the user bio" foobar_user.save() # GPG keys gkey = new_user.gpgkeys.create({"key": GPG_KEY}) assert len(new_user.gpgkeys.list()) == 1 # Seems broken on the gitlab side # gkey = new_user.gpgkeys.get(gkey.id) gkey.delete() assert len(new_user.gpgkeys.list()) == 0 # SSH keys key = new_user.keys.create({"title": "testkey", "key": SSH_KEY}) assert len(new_user.keys.list()) == 1 key.delete() assert len(new_user.keys.list()) == 0 # emails email = new_user.emails.create({"email": "foo2@bar.com"}) assert len(new_user.emails.list()) == 1 email.delete() assert len(new_user.emails.list()) == 0 # custom attributes attrs = new_user.customattributes.list() assert len(attrs) == 0 attr = new_user.customattributes.set("key", "value1") assert len(gl.users.list(custom_attributes={"key": "value1"})) == 1 assert attr.key == "key" assert attr.value == "value1" assert len(new_user.customattributes.list()) == 1 attr = new_user.customattributes.set("key", "value2") attr = new_user.customattributes.get("key") assert attr.value == "value2" assert len(new_user.customattributes.list()) == 1 attr.delete() assert len(new_user.customattributes.list()) == 0 # impersonation tokens user_token = new_user.impersonationtokens.create( {"name": "token1", "scopes": ["api", "read_user"]} ) l = new_user.impersonationtokens.list(state="active") assert len(l) == 1 user_token.delete() l = new_user.impersonationtokens.list(state="active") assert len(l) == 0 l = new_user.impersonationtokens.list(state="inactive") assert len(l) == 1 new_user.delete() foobar_user.delete() assert len(gl.users.list()) == 3 # current user mail mail = gl.user.emails.create({"email": "current@user.com"}) assert len(gl.user.emails.list()) == 1 mail.delete() assert len(gl.user.emails.list()) == 0 # current user GPG keys gkey = gl.user.gpgkeys.create({"key": GPG_KEY}) assert len(gl.user.gpgkeys.list()) == 1 # Seems broken on the gitlab side gkey = gl.user.gpgkeys.get(gkey.id) gkey.delete() assert len(gl.user.gpgkeys.list()) == 0 # current user key key = gl.user.keys.create({"title": "testkey", "key": SSH_KEY}) assert len(gl.user.keys.list()) == 1 key.delete() assert len(gl.user.keys.list()) == 0 # templates assert gl.dockerfiles.list() dockerfile = gl.dockerfiles.get("Node") assert dockerfile.content is not None assert gl.gitignores.list() gitignore = gl.gitignores.get("Node") assert gitignore.content is not None assert gl.gitlabciymls.list() gitlabciyml = gl.gitlabciymls.get("Nodejs") assert gitlabciyml.content is not None assert gl.licenses.list() license = gl.licenses.get( "bsd-2-clause", project="mytestproject", fullname="mytestfullname" ) assert "mytestfullname" in license.content # groups user1 = gl.users.create( { "email": "user1@test.com", "username": "user1", "name": "user1", "password": "user1_pass", } ) user2 = gl.users.create( { "email": "user2@test.com", "username": "user2", "name": "user2", "password": "user2_pass", } ) group1 = gl.groups.create({"name": "group1", "path": "group1"}) group2 = gl.groups.create({"name": "group2", "path": "group2"}) p_id = gl.groups.list(search="group2")[0].id group3 = gl.groups.create({"name": "group3", "path": "group3", "parent_id": p_id}) assert len(gl.groups.list()) == 3 assert len(gl.groups.list(search="oup1")) == 1 assert group3.parent_id == p_id assert group2.subgroups.list()[0].id == group3.id group1.members.create({"access_level": gitlab.const.OWNER_ACCESS, "user_id": user1.id}) group1.members.create({"access_level": gitlab.const.GUEST_ACCESS, "user_id": user2.id}) group2.members.create({"access_level": gitlab.const.OWNER_ACCESS, "user_id": user2.id}) # Administrator belongs to the groups assert len(group1.members.list()) == 3 assert len(group2.members.list()) == 2 group1.members.delete(user1.id) assert len(group1.members.list()) == 2 assert len(group1.members.all()) member = group1.members.get(user2.id) member.access_level = gitlab.const.OWNER_ACCESS member.save() member = group1.members.get(user2.id) assert member.access_level == gitlab.const.OWNER_ACCESS group2.members.delete(gl.user.id) # group custom attributes attrs = group2.customattributes.list() assert len(attrs) == 0 attr = group2.customattributes.set("key", "value1") assert len(gl.groups.list(custom_attributes={"key": "value1"})) == 1 assert attr.key == "key" assert attr.value == "value1" assert len(group2.customattributes.list()) == 1 attr = group2.customattributes.set("key", "value2") attr = group2.customattributes.get("key") assert attr.value == "value2" assert len(group2.customattributes.list()) == 1 attr.delete() assert len(group2.customattributes.list()) == 0 # group notification settings settings = group2.notificationsettings.get() settings.level = "disabled" settings.save() settings = group2.notificationsettings.get() assert settings.level == "disabled" # group badges badge_image = "http://example.com" badge_link = "http://example/img.svg" badge = group2.badges.create({"link_url": badge_link, "image_url": badge_image}) assert len(group2.badges.list()) == 1 badge.image_url = "http://another.example.com" badge.save() badge = group2.badges.get(badge.id) assert badge.image_url == "http://another.example.com" badge.delete() assert len(group2.badges.list()) == 0 # group milestones gm1 = group1.milestones.create({"title": "groupmilestone1"}) assert len(group1.milestones.list()) == 1 gm1.due_date = "2020-01-01T00:00:00Z" gm1.save() gm1.state_event = "close" gm1.save() gm1 = group1.milestones.get(gm1.id) assert gm1.state == "closed" assert len(gm1.issues()) == 0 assert len(gm1.merge_requests()) == 0 # group variables group1.variables.create({"key": "foo", "value": "bar"}) g_v = group1.variables.get("foo") assert g_v.value == "bar" g_v.value = "baz" g_v.save() g_v = group1.variables.get("foo") assert g_v.value == "baz" assert len(group1.variables.list()) == 1 g_v.delete() assert len(group1.variables.list()) == 0 # hooks hook = gl.hooks.create({"url": "http://whatever.com"}) assert len(gl.hooks.list()) == 1 hook.delete() assert len(gl.hooks.list()) == 0 # projects admin_project = gl.projects.create({"name": "admin_project"}) gr1_project = gl.projects.create({"name": "gr1_project", "namespace_id": group1.id}) gr2_project = gl.projects.create({"name": "gr2_project", "namespace_id": group2.id}) sudo_project = gl.projects.create({"name": "sudo_project"}, sudo=user1.name) assert len(gl.projects.list(owned=True)) == 2 assert len(gl.projects.list(search="admin")) == 1 # test pagination l1 = gl.projects.list(per_page=1, page=1) l2 = gl.projects.list(per_page=1, page=2) assert len(l1) == 1 assert len(l2) == 1 assert l1[0].id != l2[0].id # group custom attributes attrs = admin_project.customattributes.list() assert len(attrs) == 0 attr = admin_project.customattributes.set("key", "value1") assert len(gl.projects.list(custom_attributes={"key": "value1"})) == 1 assert attr.key == "key" assert attr.value == "value1" assert len(admin_project.customattributes.list()) == 1 attr = admin_project.customattributes.set("key", "value2") attr = admin_project.customattributes.get("key") assert attr.value == "value2" assert len(admin_project.customattributes.list()) == 1 attr.delete() assert len(admin_project.customattributes.list()) == 0 # project pages domains domain = admin_project.pagesdomains.create({"domain": "foo.domain.com"}) assert len(admin_project.pagesdomains.list()) == 1 assert len(gl.pagesdomains.list()) == 1 domain = admin_project.pagesdomains.get("foo.domain.com") assert domain.domain == "foo.domain.com" domain.delete() assert len(admin_project.pagesdomains.list()) == 0 # project content (files) admin_project.files.create( { "file_path": "README", "branch": "master", "content": "Initial content", "commit_message": "Initial commit", } ) readme = admin_project.files.get(file_path="README", ref="master") readme.content = base64.b64encode(b"Improved README").decode() time.sleep(2) readme.save(branch="master", commit_message="new commit") readme.delete(commit_message="Removing README", branch="master") admin_project.files.create( { "file_path": "README.rst", "branch": "master", "content": "Initial content", "commit_message": "New commit", } ) readme = admin_project.files.get(file_path="README.rst", ref="master") # The first decode() is the ProjectFile method, the second one is the bytes # object method assert readme.decode().decode() == "Initial content" data = { "branch": "master", "commit_message": "blah blah blah", "actions": [{"action": "create", "file_path": "blah", "content": "blah"}], } admin_project.commits.create(data) assert "@@" in admin_project.commits.list()[0].diff()[0]["diff"] # commit status commit = admin_project.commits.list()[0] size = len(commit.statuses.list()) status = commit.statuses.create({"state": "success", "sha": commit.id}) assert len(commit.statuses.list()) == size + 1 assert commit.refs() assert commit.merge_requests() is not None # commit comment commit.comments.create({"note": "This is a commit comment"}) assert len(commit.comments.list()) == 1 # commit discussion count = len(commit.discussions.list()) discussion = commit.discussions.create({"body": "Discussion body"}) assert len(commit.discussions.list()) == (count + 1) d_note = discussion.notes.create({"body": "first note"}) d_note_from_get = discussion.notes.get(d_note.id) d_note_from_get.body = "updated body" d_note_from_get.save() discussion = commit.discussions.get(discussion.id) assert discussion.attributes["notes"][-1]["body"] == "updated body" d_note_from_get.delete() discussion = commit.discussions.get(discussion.id) assert len(discussion.attributes["notes"]) == 1 # housekeeping admin_project.housekeeping() # repository tree = admin_project.repository_tree() assert len(tree) != 0 assert tree[0]["name"] == "README.rst" blob_id = tree[0]["id"] blob = admin_project.repository_raw_blob(blob_id) assert blob.decode() == "Initial content" archive1 = admin_project.repository_archive() archive2 = admin_project.repository_archive("master") assert archive1 == archive2 snapshot = admin_project.snapshot() # project file uploads filename = "test.txt" file_contents = "testing contents" uploaded_file = admin_project.upload(filename, file_contents) assert uploaded_file["alt"] == filename assert uploaded_file["url"].startswith("/uploads/") assert uploaded_file["url"].endswith("/" + filename) assert uploaded_file["markdown"] == "[{}]({})".format( uploaded_file["alt"], uploaded_file["url"] ) # environments admin_project.environments.create( {"name": "env1", "external_url": "http://fake.env/whatever"} ) envs = admin_project.environments.list() assert len(envs) == 1 env = envs[0] env.external_url = "http://new.env/whatever" env.save() env = admin_project.environments.list()[0] assert env.external_url == "http://new.env/whatever" env.stop() env.delete() assert len(admin_project.environments.list()) == 0 # project events admin_project.events.list() # forks fork = admin_project.forks.create({"namespace": user1.username}) p = gl.projects.get(fork.id) assert p.forked_from_project["id"] == admin_project.id forks = admin_project.forks.list() assert fork.id in map(lambda p: p.id, forks) # project hooks hook = admin_project.hooks.create({"url": "http://hook.url"}) assert len(admin_project.hooks.list()) == 1 hook.note_events = True hook.save() hook = admin_project.hooks.get(hook.id) assert hook.note_events is True hook.delete() # deploy keys deploy_key = admin_project.keys.create({"title": "foo@bar", "key": DEPLOY_KEY}) project_keys = list(admin_project.keys.list()) assert len(project_keys) == 1 sudo_project.keys.enable(deploy_key.id) assert len(sudo_project.keys.list()) == 1 sudo_project.keys.delete(deploy_key.id) assert len(sudo_project.keys.list()) == 0 # labels label1 = admin_project.labels.create({"name": "label1", "color": "#778899"}) label1 = admin_project.labels.list()[0] assert len(admin_project.labels.list()) == 1 label1.new_name = "label1updated" label1.save() assert label1.name == "label1updated" label1.subscribe() assert label1.subscribed == True label1.unsubscribe() assert label1.subscribed == False label1.delete() # milestones m1 = admin_project.milestones.create({"title": "milestone1"}) assert len(admin_project.milestones.list()) == 1 m1.due_date = "2020-01-01T00:00:00Z" m1.save() m1.state_event = "close" m1.save() m1 = admin_project.milestones.get(m1.id) assert m1.state == "closed" assert len(m1.issues()) == 0 assert len(m1.merge_requests()) == 0 # issues issue1 = admin_project.issues.create({"title": "my issue 1", "milestone_id": m1.id}) issue2 = admin_project.issues.create({"title": "my issue 2"}) issue3 = admin_project.issues.create({"title": "my issue 3"}) assert len(admin_project.issues.list()) == 3 issue3.state_event = "close" issue3.save() assert len(admin_project.issues.list(state="closed")) == 1 assert len(admin_project.issues.list(state="opened")) == 2 assert len(admin_project.issues.list(milestone="milestone1")) == 1 assert m1.issues().next().title == "my issue 1" size = len(issue1.notes.list()) note = issue1.notes.create({"body": "This is an issue note"}) assert len(issue1.notes.list()) == size + 1 emoji = note.awardemojis.create({"name": "tractor"}) assert len(note.awardemojis.list()) == 1 emoji.delete() assert len(note.awardemojis.list()) == 0 note.delete() assert len(issue1.notes.list()) == size assert isinstance(issue1.user_agent_detail(), dict) assert issue1.user_agent_detail()["user_agent"] assert issue1.participants() assert type(issue1.closed_by()) == list assert type(issue1.related_merge_requests()) == list # issues labels and events label2 = admin_project.labels.create({"name": "label2", "color": "#aabbcc"}) issue1.labels = ["label2"] issue1.save() events = issue1.resourcelabelevents.list() assert events event = issue1.resourcelabelevents.get(events[0].id) assert event size = len(issue1.discussions.list()) discussion = issue1.discussions.create({"body": "Discussion body"}) assert len(issue1.discussions.list()) == size + 1 d_note = discussion.notes.create({"body": "first note"}) d_note_from_get = discussion.notes.get(d_note.id) d_note_from_get.body = "updated body" d_note_from_get.save() discussion = issue1.discussions.get(discussion.id) assert discussion.attributes["notes"][-1]["body"] == "updated body" d_note_from_get.delete() discussion = issue1.discussions.get(discussion.id) assert len(discussion.attributes["notes"]) == 1 # tags tag1 = admin_project.tags.create({"tag_name": "v1.0", "ref": "master"}) assert len(admin_project.tags.list()) == 1 tag1.set_release_description("Description 1") tag1.set_release_description("Description 2") assert tag1.release["description"] == "Description 2" tag1.delete() # project snippet admin_project.snippets_enabled = True admin_project.save() snippet = admin_project.snippets.create( { "title": "snip1", "file_name": "foo.py", "code": "initial content", "visibility": gitlab.v4.objects.VISIBILITY_PRIVATE, } ) assert snippet.user_agent_detail()["user_agent"] size = len(snippet.discussions.list()) discussion = snippet.discussions.create({"body": "Discussion body"}) assert len(snippet.discussions.list()) == size + 1 d_note = discussion.notes.create({"body": "first note"}) d_note_from_get = discussion.notes.get(d_note.id) d_note_from_get.body = "updated body" d_note_from_get.save() discussion = snippet.discussions.get(discussion.id) assert discussion.attributes["notes"][-1]["body"] == "updated body" d_note_from_get.delete() discussion = snippet.discussions.get(discussion.id) assert len(discussion.attributes["notes"]) == 1 snippet.file_name = "bar.py" snippet.save() snippet = admin_project.snippets.get(snippet.id) assert snippet.content().decode() == "initial content" assert snippet.file_name == "bar.py" size = len(admin_project.snippets.list()) snippet.delete() assert len(admin_project.snippets.list()) == (size - 1) # triggers tr1 = admin_project.triggers.create({"description": "trigger1"}) assert len(admin_project.triggers.list()) == 1 tr1.delete() # variables v1 = admin_project.variables.create({"key": "key1", "value": "value1"}) assert len(admin_project.variables.list()) == 1 v1.value = "new_value1" v1.save() v1 = admin_project.variables.get(v1.key) assert v1.value == "new_value1" v1.delete() # branches and merges to_merge = admin_project.branches.create({"branch": "branch1", "ref": "master"}) admin_project.files.create( { "file_path": "README2.rst", "branch": "branch1", "content": "Initial content", "commit_message": "New commit in new branch", } ) mr = admin_project.mergerequests.create( {"source_branch": "branch1", "target_branch": "master", "title": "MR readme2"} ) # discussion size = len(mr.discussions.list()) discussion = mr.discussions.create({"body": "Discussion body"}) assert len(mr.discussions.list()) == size + 1 d_note = discussion.notes.create({"body": "first note"}) d_note_from_get = discussion.notes.get(d_note.id) d_note_from_get.body = "updated body" d_note_from_get.save() discussion = mr.discussions.get(discussion.id) assert discussion.attributes["notes"][-1]["body"] == "updated body" d_note_from_get.delete() discussion = mr.discussions.get(discussion.id) assert len(discussion.attributes["notes"]) == 1 # mr labels and events mr.labels = ["label2"] mr.save() events = mr.resourcelabelevents.list() assert events event = mr.resourcelabelevents.get(events[0].id) assert event # rebasing assert mr.rebase() # basic testing: only make sure that the methods exist mr.commits() mr.changes() assert mr.participants() mr.merge() admin_project.branches.delete("branch1") try: mr.merge() except gitlab.GitlabMRClosedError: pass # protected branches p_b = admin_project.protectedbranches.create({"name": "*-stable"}) assert p_b.name == "*-stable" p_b = admin_project.protectedbranches.get("*-stable") # master is protected by default when a branch has been created assert len(admin_project.protectedbranches.list()) == 2 admin_project.protectedbranches.delete("master") p_b.delete() assert len(admin_project.protectedbranches.list()) == 0 # stars admin_project.star() assert admin_project.star_count == 1 admin_project.unstar() assert admin_project.star_count == 0 # project boards # boards = admin_project.boards.list() # assert(len(boards)) # board = boards[0] # lists = board.lists.list() # begin_size = len(lists) # last_list = lists[-1] # last_list.position = 0 # last_list.save() # last_list.delete() # lists = board.lists.list() # assert(len(lists) == begin_size - 1) # project badges badge_image = "http://example.com" badge_link = "http://example/img.svg" badge = admin_project.badges.create({"link_url": badge_link, "image_url": badge_image}) assert len(admin_project.badges.list()) == 1 badge.image_url = "http://another.example.com" badge.save() badge = admin_project.badges.get(badge.id) assert badge.image_url == "http://another.example.com" badge.delete() assert len(admin_project.badges.list()) == 0 # project wiki wiki_content = "Wiki page content" wp = admin_project.wikis.create({"title": "wikipage", "content": wiki_content}) assert len(admin_project.wikis.list()) == 1 wp = admin_project.wikis.get(wp.slug) assert wp.content == wiki_content # update and delete seem broken # wp.content = 'new content' # wp.save() # wp.delete() # assert(len(admin_project.wikis.list()) == 0) # namespaces ns = gl.namespaces.list(all=True) assert len(ns) != 0 ns = gl.namespaces.list(search="root", all=True)[0] assert ns.kind == "user" # features # Disabled as this fails with GitLab 11.11 # feat = gl.features.set("foo", 30) # assert feat.name == "foo" # assert len(gl.features.list()) == 1 # feat.delete() # assert len(gl.features.list()) == 0 # broadcast messages msg = gl.broadcastmessages.create({"message": "this is the message"}) msg.color = "#444444" msg.save() msg = gl.broadcastmessages.list(all=True)[0] assert msg.color == "#444444" msg = gl.broadcastmessages.get(1) assert msg.color == "#444444" msg.delete() assert len(gl.broadcastmessages.list()) == 0 # notification settings settings = gl.notificationsettings.get() settings.level = gitlab.NOTIFICATION_LEVEL_WATCH settings.save() settings = gl.notificationsettings.get() assert settings.level == gitlab.NOTIFICATION_LEVEL_WATCH # services service = admin_project.services.get("asana") service.api_key = "whatever" service.save() service = admin_project.services.get("asana") assert service.active == True service.delete() service = admin_project.services.get("asana") assert service.active == False # snippets snippets = gl.snippets.list(all=True) assert len(snippets) == 0 snippet = gl.snippets.create( {"title": "snippet1", "file_name": "snippet1.py", "content": "import gitlab"} ) snippet = gl.snippets.get(snippet.id) snippet.title = "updated_title" snippet.save() snippet = gl.snippets.get(snippet.id) assert snippet.title == "updated_title" content = snippet.content() assert content.decode() == "import gitlab" assert snippet.user_agent_detail()["user_agent"] snippet.delete() snippets = gl.snippets.list(all=True) assert len(snippets) == 0 # user activities gl.user_activities.list(query_parameters={"from": "2019-01-01"}) # events gl.events.list() # rate limit settings = gl.settings.get() settings.throttle_authenticated_api_enabled = True settings.throttle_authenticated_api_requests_per_period = 1 settings.throttle_authenticated_api_period_in_seconds = 3 settings.save() projects = list() for i in range(0, 20): projects.append(gl.projects.create({"name": str(i) + "ok"})) error_message = None for i in range(20, 40): try: projects.append( gl.projects.create({"name": str(i) + "shouldfail"}, obey_rate_limit=False) ) except gitlab.GitlabCreateError as e: error_message = e.error_message break assert "Retry later" in error_message [current_project.delete() for current_project in projects] settings.throttle_authenticated_api_enabled = False settings.save() # project import/export ex = admin_project.exports.create({}) ex.refresh() count = 0 while ex.export_status != "finished": time.sleep(1) ex.refresh() count += 1 if count == 10: raise Exception("Project export taking too much time") with open("/tmp/gitlab-export.tgz", "wb") as f: ex.download(streamed=True, action=f.write) output = gl.projects.import_project( open("/tmp/gitlab-export.tgz", "rb"), "imported_project" ) project_import = gl.projects.get(output["id"], lazy=True).imports.get() count = 0 while project_import.import_status != "finished": time.sleep(1) project_import.refresh() count += 1 if count == 10: raise Exception("Project import taking too much time")