import uuid import pytest import gitlab from gitlab.const import AccessLevel from gitlab.v4.objects.projects import ProjectStorage def test_projects_head(gl): headers = gl.projects.head() assert headers["x-total"] def test_project_head(gl, project): headers = gl.projects.head(project.id) assert headers["content-type"] == "application/json" def test_create_project(gl, user): # Moved from group tests chunk in legacy tests, TODO cleanup admin_project = gl.projects.create({"name": "admin_project"}) assert isinstance(admin_project, gitlab.v4.objects.Project) assert admin_project in gl.projects.list(search="admin_project") sudo_project = gl.projects.create({"name": "sudo_project"}, sudo=user.id) created = gl.projects.list() created_gen = gl.projects.list(iterator=True) owned = gl.projects.list(owned=True) assert admin_project in created and sudo_project in created assert admin_project in owned and sudo_project not in owned assert len(created) == len(list(created_gen)) admin_project.delete() sudo_project.delete() def test_project_members(user, project): member = project.members.create( {"user_id": user.id, "access_level": AccessLevel.DEVELOPER} ) assert member in project.members.list() assert member.access_level == 30 member.delete() assert member not in project.members.list() def test_project_badges(project): badge_image = "http://example.com" badge_link = "http://example/img.svg" badge = project.badges.create({"link_url": badge_link, "image_url": badge_image}) assert badge in project.badges.list() badge.image_url = "http://another.example.com" badge.save() badge = project.badges.get(badge.id) assert badge.image_url == "http://another.example.com" badge.delete() assert badge not in project.badges.list() @pytest.mark.skip(reason="Commented out in legacy test") def test_project_boards(project): boards = project.boards.list() assert boards board = boards[0] lists = board.lists.list() last_list = lists[-1] last_list.position = 0 last_list.save() last_list.delete() assert last_list not in board.lists.list() def test_project_custom_attributes(gl, project): attrs = project.customattributes.list() assert not attrs attr = project.customattributes.set("key", "value1") assert attr.key == "key" assert attr.value == "value1" assert attr in project.customattributes.list() assert project in gl.projects.list(custom_attributes={"key": "value1"}) attr = project.customattributes.set("key", "value2") attr = project.customattributes.get("key") assert attr.value == "value2" assert attr in project.customattributes.list() attr.delete() assert attr not in project.customattributes.list() def test_project_environments(project): environment = project.environments.create( {"name": "env1", "external_url": "http://fake.env/whatever"} ) environments = project.environments.list() assert environment in environments environment = environments[0] environment.external_url = "http://new.env/whatever" environment.save() environment = project.environments.list()[0] assert environment.external_url == "http://new.env/whatever" environment.stop() environment.delete() assert environment not in project.environments.list() def test_project_events(project): events = project.events.list() assert isinstance(events, list) def test_project_file_uploads(project): filename = "test.txt" file_contents = "testing contents" uploaded_file = project.upload(filename, file_contents) alt, url = uploaded_file["alt"], uploaded_file["url"] assert alt == filename assert url.startswith("/uploads/") assert url.endswith(f"/{filename}") assert uploaded_file["markdown"] == f"[{alt}]({url})" def test_project_forks(gl, project, user): fork = project.forks.create({"namespace": user.username}) fork_project = gl.projects.get(fork.id) assert fork_project.forked_from_project["id"] == project.id forks = project.forks.list() assert fork.id in map(lambda fork_project: fork_project.id, forks) def test_project_hooks(project): hook = project.hooks.create({"url": "http://hook.url"}) assert hook in project.hooks.list() hook.note_events = True hook.save() hook = project.hooks.get(hook.id) assert hook.note_events is True hook.delete() assert hook not in project.hooks.list() def test_project_housekeeping(project): project.housekeeping() def test_project_labels(project): label = project.labels.create({"name": "label", "color": "#778899"}) labels = project.labels.list() assert label in labels label = project.labels.get("label") assert label == labels[0] label.new_name = "Label:that requires:encoding" label.save() assert label.name == "Label:that requires:encoding" label = project.labels.get("Label:that requires:encoding") assert label.name == "Label:that requires:encoding" label.subscribe() assert label.subscribed is True label.unsubscribe() assert label.subscribed is False label.delete() assert label not in project.labels.list() def test_project_label_promotion(gl, group): """ Label promotion requires the project to be a child of a group (not in a user namespace) """ _id = uuid.uuid4().hex data = { "name": f"test-project-{_id}", "namespace_id": group.id, } project = gl.projects.create(data) label_name = "promoteme" promoted_label = project.labels.create({"name": label_name, "color": "#112233"}) promoted_label.promote() assert any(label.name == label_name for label in group.labels.list()) group.labels.delete(label_name) assert not any(label.name == label_name for label in group.labels.list()) def test_project_milestones(project): milestone = project.milestones.create({"title": "milestone1"}) assert milestone in project.milestones.list() milestone.due_date = "2020-01-01T00:00:00Z" milestone.save() milestone.state_event = "close" milestone.save() milestone = project.milestones.get(milestone.id) assert milestone.state == "closed" assert not milestone.issues() assert not milestone.merge_requests() def test_project_milestone_promotion(gl, group): """ Milestone promotion requires the project to be a child of a group (not in a user namespace) """ _id = uuid.uuid4().hex data = { "name": f"test-project-{_id}", "namespace_id": group.id, } project = gl.projects.create(data) milestone_title = "promoteme" promoted_milestone = project.milestones.create({"title": milestone_title}) promoted_milestone.promote() assert any( milestone.title == milestone_title for milestone in group.milestones.list() ) def test_project_pages_domains(gl, project): domain = project.pagesdomains.create({"domain": "foo.domain.com"}) assert domain in project.pagesdomains.list() assert domain in gl.pagesdomains.list() domain = project.pagesdomains.get("foo.domain.com") assert domain.domain == "foo.domain.com" domain.delete() assert domain not in project.pagesdomains.list() def test_project_protected_branches(project): p_b = project.protectedbranches.create({"name": "*-stable"}) assert p_b.name == "*-stable" assert p_b in project.protectedbranches.list() p_b = project.protectedbranches.get("*-stable") p_b.delete() assert p_b not in project.protectedbranches.list() def test_project_remote_mirrors(project): mirror_url = "https://gitlab.example.com/root/mirror.git" mirror = project.remote_mirrors.create({"url": mirror_url}) assert mirror.url == mirror_url mirror.enabled = True mirror.save() mirror = project.remote_mirrors.list()[0] assert isinstance(mirror, gitlab.v4.objects.ProjectRemoteMirror) assert mirror.url == mirror_url assert mirror.enabled is True def test_project_services(project): # Use 'update' to create a service as we don't have a 'create' method and # to add one is somewhat complicated so it hasn't been done yet. project.services.update("asana", api_key="foo") service = project.services.get("asana") assert service.active is True service.api_key = "whatever" service.save() service = project.services.get("asana") assert service.active is True service.delete() service = project.services.get("asana") assert service.active is False def test_project_stars(project): project.star() assert project.star_count == 1 project.unstar() assert project.star_count == 0 def test_project_storage(project): storage = project.storage.get() assert isinstance(storage, ProjectStorage) assert storage.repository_storage == "default" def test_project_tags(project, project_file): tag = project.tags.create({"tag_name": "v1.0", "ref": "main"}) assert tag in project.tags.list() tag.delete() assert tag not in project.tags.list() def test_project_triggers(project): trigger = project.triggers.create({"description": "trigger1"}) assert trigger in project.triggers.list() trigger.delete() assert trigger not in project.triggers.list() def test_project_wiki(project): content = "Wiki page content" wiki = project.wikis.create({"title": "wikipage", "content": content}) assert wiki in project.wikis.list() wiki = project.wikis.get(wiki.slug) assert wiki.content == content # update and delete seem broken wiki.content = "new content" wiki.save() wiki.delete() assert wiki not in project.wikis.list() def test_project_groups_list(gl, group): """Test listing groups of a project""" # Create a subgroup of our top-group, we will place our new project inside # this group. group2 = gl.groups.create( {"name": "group2_proj", "path": "group2_proj", "parent_id": group.id} ) data = { "name": "test-project-tpsg", "namespace_id": group2.id, } project = gl.projects.create(data) groups = project.groups.list() group_ids = set([x.id for x in groups]) assert {group.id, group2.id} == group_ids def test_project_transfer(gl, project, group): assert project.namespace["path"] != group.full_path project.transfer(group.id) project = gl.projects.get(project.id) assert project.namespace["path"] == group.full_path gl.auth() project.transfer(gl.user.username) project = gl.projects.get(project.id) assert project.namespace["path"] == gl.user.username