diff --git a/changelogs/fragments/distlib-dataclass-annotation.yml b/changelogs/fragments/distlib-dataclass-annotation.yml new file mode 100644 index 00000000000..d86496dfac0 --- /dev/null +++ b/changelogs/fragments/distlib-dataclass-annotation.yml @@ -0,0 +1,3 @@ +bugfixes: +- ansible-galaxy - Resolve issue with the dataclass used for galaxy.yml manifest caused by using + future annotations diff --git a/lib/ansible/galaxy/collection/__init__.py b/lib/ansible/galaxy/collection/__init__.py index 99e493a1585..24707b1e731 100644 --- a/lib/ansible/galaxy/collection/__init__.py +++ b/lib/ansible/galaxy/collection/__init__.py @@ -8,6 +8,7 @@ from __future__ import annotations import errno import fnmatch import functools +import inspect import json import os import pathlib @@ -25,7 +26,7 @@ import typing as t from collections import namedtuple from contextlib import contextmanager -from dataclasses import dataclass, fields as dc_fields +from dataclasses import dataclass from hashlib import sha256 from io import BytesIO from importlib.metadata import distribution @@ -151,9 +152,9 @@ class ManifestControl: # Allow a dict representing this dataclass to be splatted directly. # Requires attrs to have a default value, so anything with a default # of None is swapped for its, potentially mutable, default - for field in dc_fields(self): - if getattr(self, field.name) is None: - super().__setattr__(field.name, field.type()) + for field_name, field_type in inspect.get_annotations(type(self), eval_str=True).items(): + if getattr(self, field_name) is None: + super().__setattr__(field_name, field_type()) class CollectionSignatureError(Exception): diff --git a/test/integration/targets/ansible-galaxy-collection-cli/files/empty_manifest_galaxy.yml b/test/integration/targets/ansible-galaxy-collection-cli/files/empty_manifest_galaxy.yml new file mode 100644 index 00000000000..e43ba4160c9 --- /dev/null +++ b/test/integration/targets/ansible-galaxy-collection-cli/files/empty_manifest_galaxy.yml @@ -0,0 +1,8 @@ +namespace: ns +name: col +version: 3.0.0 +readme: README.rst +license_file: GPL +authors: + - Ansible +manifest: diff --git a/test/integration/targets/ansible-galaxy-collection-cli/files/expected_empty.txt b/test/integration/targets/ansible-galaxy-collection-cli/files/expected_empty.txt new file mode 100644 index 00000000000..f1e0f8fc9b4 --- /dev/null +++ b/test/integration/targets/ansible-galaxy-collection-cli/files/expected_empty.txt @@ -0,0 +1,117 @@ +foo.txt +MANIFEST.json +FILES.json +README.rst +GPL +LICENSES/ +LICENSES/MIT.txt +.reuse/ +.reuse/dep5 +changelogs/ +docs/ +playbooks/ +plugins/ +roles/ +tests/ +changelogs/fragments/ +changelogs/fragments/bar.yaml +changelogs/fragments/foo.yml +docs/docsite/ +docs/docsite/apple.j2 +docs/docsite/bar.yml +docs/docsite/baz.yaml +docs/docsite/foo.rst +docs/docsite/orange.txt +docs/docsite/qux.json +docs/foobar/ +docs/foobar/qux/ +docs/foobar/qux/baz.txt +playbooks/bar.yaml +playbooks/baz.json +playbooks/foo.yml +plugins/action/ +plugins/become/ +plugins/cache/ +plugins/callback/ +plugins/cliconf/ +plugins/connection/ +plugins/doc_fragments/ +plugins/filter/ +plugins/httpapi/ +plugins/inventory/ +plugins/lookup/ +plugins/module_utils/ +plugins/modules/ +plugins/netconf/ +plugins/shell/ +plugins/strategy/ +plugins/terminal/ +plugins/test/ +plugins/vars/ +plugins/action/test.py +plugins/become/bar.yml +plugins/become/baz.yaml +plugins/become/test.py +plugins/cache/bar.yml +plugins/cache/baz.yaml +plugins/cache/test.py +plugins/callback/bar.yml +plugins/callback/baz.yaml +plugins/callback/test.py +plugins/cliconf/bar.yml +plugins/cliconf/baz.yaml +plugins/cliconf/test.py +plugins/connection/bar.yml +plugins/connection/baz.yaml +plugins/connection/test.py +plugins/doc_fragments/test.py +plugins/filter/bar.yml +plugins/filter/baz.yaml +plugins/filter/test.py +plugins/httpapi/bar.yml +plugins/httpapi/baz.yaml +plugins/httpapi/test.py +plugins/inventory/bar.yml +plugins/inventory/baz.yaml +plugins/inventory/test.py +plugins/lookup/bar.yml +plugins/lookup/baz.yaml +plugins/lookup/test.py +plugins/module_utils/bar.ps1 +plugins/module_utils/test.py +plugins/modules/bar.yaml +plugins/modules/test2.py +plugins/modules/foo.yml +plugins/modules/qux.ps1 +plugins/netconf/bar.yml +plugins/netconf/baz.yaml +plugins/netconf/test.py +plugins/shell/bar.yml +plugins/shell/baz.yaml +plugins/shell/test.py +plugins/strategy/bar.yml +plugins/strategy/baz.yaml +plugins/strategy/test.py +plugins/terminal/test.py +plugins/test/bar.yml +plugins/test/baz.yaml +plugins/test/test.py +plugins/vars/bar.yml +plugins/vars/bar.yml.license +plugins/vars/baz.yaml +plugins/vars/test.py +roles/foo/ +roles/foo/tasks/ +roles/foo/templates/ +roles/foo/vars/ +roles/foo/tasks/main.yml +roles/foo/templates/foo.j2 +roles/foo/vars/main.yaml +tests/integration/ +tests/units/ +tests/integration/targets/ +tests/integration/targets/foo/ +tests/integration/targets/foo/aliases +tests/integration/targets/foo/tasks/ +tests/integration/targets/foo/tasks/main.yml +tests/units/test_foo.py diff --git a/test/integration/targets/ansible-galaxy-collection-cli/tasks/manifest.yml b/test/integration/targets/ansible-galaxy-collection-cli/tasks/manifest.yml index 5f37c7237e7..ee0a4abd922 100644 --- a/test/integration/targets/ansible-galaxy-collection-cli/tasks/manifest.yml +++ b/test/integration/targets/ansible-galaxy-collection-cli/tasks/manifest.yml @@ -3,7 +3,7 @@ args: executable: '{{ ansible_facts.python.executable }}' -- name: Copy galaxy.yml with manifest_directives_full +- name: Copy galaxy.yml copy: src: galaxy.yml dest: '{{ output_dir }}/test_manifest_collection/galaxy.yml' @@ -55,3 +55,32 @@ - assert: that: - artifact_contents.stdout_lines|sort == lookup('file', 'expected_full_manifest.txt').splitlines()|sort + +- name: Create test collection dir + script: make_collection_dir.py "{{ output_dir }}/test_manifest_empty_collection" + args: + executable: '{{ ansible_facts.python.executable }}' + +- name: Copy galaxy.yml with empty_manifest_galaxy + copy: + src: empty_manifest_galaxy.yml + dest: '{{ output_dir }}/test_manifest_empty_collection/galaxy.yml' + +- name: Build collection + command: ansible-galaxy collection build --output-path {{ output_dir|quote }} -vvv + args: + chdir: '{{ output_dir }}/test_manifest_empty_collection' + +- name: Get artifact contents + command: tar tzf '{{ output_dir }}/ns-col-3.0.0.tar.gz' + register: artifact_contents + +- debug: + var: artifact_contents.stdout_lines|sort + +- debug: + var: lookup('file', 'expected_empty.txt').splitlines()|sort + +- assert: + that: + - artifact_contents.stdout_lines|sort == lookup('file', 'expected_empty.txt').splitlines()|sort