#1201 initial Ansible Collection guidelines
Merged a year ago by james. Opened 2 years ago by gotmax23.
gotmax23/packaging-committee ansible-collections  into  master

@@ -65,6 +65,7 @@ 

  ** xref:Tcl.adoc[Tcl/Tk extensions]

  

  * Other Domain-specific Guidelines

+ ** xref:Ansible_collections.adoc[Ansible Collections]

  ** xref:BLAS_LAPACK.adoc[BLAS/LAPACK]

  ** xref:CronFiles.adoc[CronFiles]

  ** xref:Drupal7.adoc[Drupal7]

@@ -0,0 +1,446 @@ 

+ = Ansible Collection Packaging Guidelines

+ :last-reviewed: 2022-09-25

+ :toc:

+ 

+ == Forward

+ 

+ Ansible collections are packaged units of Ansible content,

+ including modules and other types of plugins.

+ Most Ansible Plugins are written in Python or Powershell.

+ 

+ Some collections are also included in Ansible Community's `+ansible+`

+ collection bundle, which is packaged in Fedora.

+ All collections, whether or not they are included in the `+ansible+` package,

+ MAY be packaged in Fedora.

+ 

+ `+ansible+` depends on `+ansible-core+`, which contains the core engine and

+ CLI programs (e.g. `+ansible+`, `+ansible-playbook+`).

+ The `+ansible+` package has a different release cycle than individual collections,

+ and it may contain older versions of the individual components.

+ `+ansible+` installs collections in a different namespace and is parallel

+ installable with individual collections.

+ The Ansible engine searches for collections in the standalone collections

+ directory first.

+ 

+ See https://fedoraproject.org/wiki/Changes/Ansible5[Changes/Ansible5]

+ for more information about the split between `+ansible+` and `+ansible-core+`.

+ 

+ == Naming

+ 

+ Collection packages MUST be named `+ansible-collection-NAMESPACE-NAME+`.

+ For example, the `+community.general+` collection package is named

+ `+ansible-collection-community-general+`.

+ 

+ 

+ == Collection Source

+ 

+ Collection source code MUST be downloaded from the collection's respective

+ Git forge/other SCM repository.

+ While the tarballs published to Ansible Galaxy contain all of the

+ collection's Python/Powershell source code as well as some development files,

+ they do not include the `+galaxy.yml+` build configuration

+ and development files (e.g. unit tests) that the author may choose to remove.

+ Note that the Ansible Community collection requirements mandate that

+ collections tag releases in a public SCM repository.

+ 

+ Collection packages SHOULD use `+%{ansible_collection_url NAMESPACE NAME}+`

+ as the package's `+URL:+`.

+ This points to the collection's homepage on Ansible Galaxy.

+ 

+ 

+ == Dependencies

+ 

+ === Buildtime

+ 

+ Collections MUST have `+BuildRequires: ansible-packaging+`.

+ `+ansible-packaging+` provides macros and a dependency generator for packaging

+ Ansible Collections.

+ It also pulls in `+ansible-core+`,

+ so `+BuildRequires: ansible-core+` SHOULD NOT be added manually.

+ 

+ === Runtime

+ 

+ The dependency generator will generate the appropriate dependency on the Ansible engine.

+ This ensures compatibility with Fedora 35

+ which contains the classic `+ansible+` 2.9 package (instead of the collections bundle)

+ and `+ansible-core+`. Both versions of the Ansible engine support collections,

+ but they are not parallel installable.

+ Packages MUST NOT manually `+Require+` `+ansible-core+` or `+ansible+`,

+ unless they are known to require a specific version,

+ in which case the appropriate version constraints should be used.

+ 

+ The dependency generator also handles inter-collection dependencies.

+ 

+ ==== External dependencies of plugins

+ 

+ Ansible collections may contain various plugins that have

+ various external dependencies.

+ The Ansible dev guide

+ https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_best_practices.html#importing-and-using-shared-code[mandates]

+ that plugins fail cleanly if these dependencies are not installed.

+ Many times, external dependencies are only needed for a small subset of the

+ collection which may or may not be widely used.

+ Therefore, collection packages SHOULD weakly depend on these external libraries,

+ i.e. use Recommends instead of Requires.

+ 

+ Module dependencies are only needed on the target node not the controller node.

+ Therefore, collection packages SHOULD NOT depend on these dependencies at all,

+ weakly or strongly.

+ Users are responsible for installing these dependencies on the target host.

+ Modules that are intended to be used with `+delegate_to: localhost+` are an

+ exception to this rule.

+ 

+ The situation is a bit different for controller plugins, such as

+ filter plugins, lookup plugins, connection plugins, or inventory plugins.

+ Collections MAY add `+Recommends+` for dependencies of controller plugins.

+ However, packagers should use discretion when adding any type of dependency

+ and only do so when it is required for

+ the central functionality of the collection.

+ For instance, it makes sense for `+ansible-collection-community-docker+`

+ to Recommend `+python3-docker+`,

+ but it doesn't make sense for the larger, more general

+ ansible-collection-community-general collection to Recommend `+python3-redis+`

+ for the `+redis+` lookup plugin.

+ This guideline seeks to prevent ballooning collection packages.

+ `+ansible-core+` and `+ansible+` follow this same principal.

+ 

+ 

+ == Build and Installation

+ 

+ To build the collection artifact,

+ packages MUST use `+%ansible_collection_build+` in `+%build+`.

+ `+%ansible_collection_install+` MUST be used in `+%install+` to install the

+ artifact.

+ 

+ Packagers SHOULD use `+%files -f %{ansible_collection_filelist}+` to install

+ the collection.

+ The `+%{ansible_collection_filelist}+` is populated by `+%ansible_collection_install+`.

+ 

+ == Unit Tests

+ 

+ As per xref:index.adoc#_test_suites[the general Fedora Packaging Guidelines],

+ collection packages SHOULD run upstream unit tests in `+%check+` if practical.

+ Integration tests are impossible to run in the RPM build environment.

+ In order to run unit tests, collections MUST `+BuildRequire+`

+ `+ansible-packaging-tests+`, which pulls in the necessary dependencies.

+ Some collections have other testing dependencies,

+ which are usually specified in `+tests/unit/requirements.txt+`.

+ These have to be added manually.

+ The `+%ansible_test_unit+` macro MUST be used to run tests.

+ 

+ [NOTE]

+ .EPEL Compatibility

+ ====

+ It is currently impossible to run unit tests on EPEL 8 and 9.

+ 

+ ansible-core in RHEL 8.6 is built against python38. In c8s and the next RHEL

+ 8 minor release, it will be built against python39. The testing dependencies

+ are not yet packaged for either Python version in EPEL 8.

+ 

+ ansible-test in RHEL 9.0 still needs python3-mock, but this

+ requirement has been removed in CentOS 9 Stream.

+ 

+ The rest of these guidelines are applicable to EPEL 8 and 9,

+ and `+ansible-packaging+` itself is available there.

+ ====

+ 

+ == Unnecessary Files

+ 

+ By default, collections ship with all of the files in the repository root,

+ unless they are manually excluded.

+ Therefore, many collections contain development files that are unwanted by users.

+ 

+ Packagers SHOULD exclude these files, which SHOULD be done by patching the

+ collection's `+galaxy.yml+` to add these files to the `+build_ignore+`

+ configuration.

+ These files SHOULD NOT be removed with `+rm+`.

+ See the https://docs.ansible.com/ansible/latest/dev_guide/collections_galaxy_meta.html#collection-galaxy-metadata-structure[Ansible documentation]

+ for more information on the `+galaxy.yml+` syntax.

+ 

+ Common development files include:

+ 

+ * The `+tests+` directory containing unit and integration tests

+ * SCM configuration such as `+.gitignore+` and `+.keep+` files

+ * The `+.azure-pipelines+` and `+.github+` directories that contain CI configuration

+ 

+ These files often have to be removed downstream, as there are some unresolved

+ issues with pushing these changes to upstream community collections. These

+ issues are irrelevant in the Fedora context.

+ 

+ == Shebangs

+ 

+ Ansible plugins are not executable. However, many of them have `+#!/usr/bin/python+`

+ shebangs for legacy reasons.

+ These shebangs MUST be removed for the following reasons:

+ 

+ 1. Non-executable files shouldn't have shebangs

+ 2. Keeping the shebangs results in an unnecessary dependency

+ on `+python-unversioned-command+`.

+ 

+ `+%py3_shebang_fix+` MUST NOT be used, as it will break compatibility

+ with certain Ansible target nodes.

+ It won't fix the non-executable file issue, either.

+ 

+ Shebangs can be removed with:

+ 

+ [source,bash]

+ ----

+ find -type f ! -executable -name '*.py' -print -exec sed -i -e '1{\@^#!.*@d}' '{}' +

+ ----

+ 

+ 

+ == Documentation and License Files

+ 

+ License files and documentation for collections are installed to the

+ collection's directory in `+/usr/share/ansible+`, by default.

+ Packagers MAY choose to either

+ mark the license and documentation files in this directory with `+%license+`

+ and `+%doc+`

+ or to add the correct paths to `+build_ignore+` in `+galaxy.yml+` and

+ install them into the standard directories.

+ Avoid duplicating these files in both places.

+ 

+ Note that some multi-licensed collections store licenses in a `+LICENSES+`

+ directory. This whole directory MUST be marked with `+%license+`.

+ 

+ Refer to the xref:legal::index.adoc[Legal docs] for the rules about

+ allowed licenses and determining the `+License:+` field.

+ 

+ 

+ == Example Specfile

+ 

+ [source,RPMSpec]

+ ----

+ # Only run tests where the dependencies are available

+ %if %{defined fedora}

+ %bcond_without tests

+ %else

+ %bcond_with tests

+ %endif

+ 

+ Name:           ansible-collection-community-rabbitmq

+ Version:        1.2.2

+ Release:        1%{?dist}

+ Summary:        RabbitMQ collection for Ansible

+ 

+ # plugins/module_utils/_version.py: Python Software Foundation License version 2

+ License:        GPL-3.0-or-later and PSF-2.0

+ URL:            %{ansible_collection_url community rabbitmq}

+ %global forgeurl https://github.com/ansible-collections/community.rabbitmq

+ Source0:        %{forgeurl}/archive/%{version}/%{name}-%{version}.tar.gz

+ # Patch galaxy.yml to exclude unnecessary files from the built collection.

+ # This is a downstream only patch.

+ Patch0:         build_ignore.patch

+ 

+ BuildRequires:  ansible-packaging

+ %if %{with tests}

+ BuildRequires:  ansible-packaging-tests

+ # Collection specific test dependency

+ BuildRequires:  glibc-all-langpacks

+ %endif

+ 

+ BuildArch:      noarch

+ 

+ %description

+ %{summary}.

+ 

+ 

+ %prep

+ %autosetup -n community.rabbitmq-%{version} -p1

+ find -type f ! -executable -name '*.py' -print -exec sed -i -e '1{\@^#!.*@d}' '{}' +

+ 

+ 

+ %build

+ %ansible_collection_build

+ 

+ 

+ %install

+ %ansible_collection_install

+ 

+ 

+ %if %{with tests}

+ %check

+ %ansible_test_unit

+ %endif

+ 

+ 

+ %files -f %{ansible_collection_filelist}

+ %license COPYING PSF-license.txt

+ %doc README.md CHANGELOG.rst

+ 

+ %changelog

+ ----

+ 

+ build_ignore.patch:

+ 

+ [source, patch]

+ ----

+ diff --git a/galaxy.yml b/galaxy.yml

+ index 0b37162..acd029a 100644

+ --- a/galaxy.yml

+ +++ b/galaxy.yml

+ @@ -13,3 +13,13 @@ repository: https://github.com/ansible-collections/community.rabbitmq

+  documentation: https://docs.ansible.com/ansible/latest/collections/community/rabbitmq/

+  homepage: https://github.com/ansible-collections/community.rabbitmq

+  issues: https://github.com/ansible-collections/community.rabbitmq/issues

+ +build_ignore:

+ +  # Remove unnecessary development files from the built package.

+ +  - tests

+ +  - .azure-pipelines

+ +  - .gitignore

+ +  # Licenses and docs are installed with %%doc and %%license

+ +  - PSF-license.txt

+ +  - COPYING

+ +  - README.md

+ +  - CHANGELOG.rst

+ ----

+ 

+ 

+ == Macro Breakdown

+ 

+ Here is a short breakdown of exactly what each macro included in

+ `+ansible-packaging+` does.

+ 

+ 

+ [#ansible_collection_url]

+ ===== `+%ansible_collection_url+`

+ 

+ *Usage:*

+ 

+ [source,RPMSpec]

+ ----

+ URL:            %{ansible_collection_url NAMESPACE NAME}

+ ----

+ 

+ This macro points to a collection's Ansible Galaxy page.

+ It is intended to be used for the `+URL:+` tag in the specfile preamble.

+ It takes the collection namespace and collection name as arguments.

+ 

+ If no arguments are passed to this macro, it falls back to the values

+ of `+%{collection_namespace}+` and `+%{collection_name}+` if they are set in the specfile.

+ New packages SHOULD explicitly pass the namespace and name as arguments.

+ The fallback may be removed in the future.

+ See the link:#legacy_macros[Legacy Macros] section for more information.

+ 

+ 

+ [#ansible_collection_build]

+ 

+ ===== `+%ansible_collection_build+`

+ 

+ *Usage:*

+ 

+ [source,RPMSpec]

+ ----

+ %build

+ %ansible_collection_build

+ ----

+ 

+ This macro simply runs `+ansible-galaxy collection build+`.

+ 

+ 

+ [#ansible_collection_install]

+ ===== `+%ansible_collection_install+`

+ 

+ *Usage:*

+ 

+ [source,RPMSpec]

+ ----

+ %install

+ %ansible_collection_install

+ ----

+ 

+ This macro pulls out the collection namespace, name, and version from `+galaxy.yml+`

+ and then uses it to run `+ansible-galaxy collection install+`.

+ After that, it writes out `+%{ansible_collection_filelist}` based on the

+ metadata it previously extracted

+ 

+ 

+ [#ansible_test_unit]

+ ===== `+%ansible_test_unit+`

+ 

+ *Usage:*

+ 

+ [source,RPMSpec]

+ ----

+ %check

+ %ansible_test_unit

+ ----

+ This macro parses galaxy.yml to determine the collection namespace and name

+ that's needed to create the directory structure that ansible-test expects.

+ After creating a temporary build directory with the needed structure, the

+ script runs ansible-test units with the provided arguments.

+ 

+ 

+ [#ansible_collection_filelist]

+ ===== `+%{ansible_collection_filelist}+`

+ 

+ *Usage:*

+ 

+ [source,RPMSpec]

+ ----

+ %files -f %{ansible_collection_filelist}

+ %doc ...

+ %license ...

+ ----

+ 

+ This macro points a file list that's written out by `+%ansible_collection_install+`.

+ Currently, it only contains a single entry to own the collection's entire

+ directory in `+%{ansible_collections_dir}+`

+ 

+ 

+ [#ansible_collections_dir]

+ 

+ This macro expands to `+%{_datadir}/ansible/collections/ansible_collections+`.

+ It is used internally by the other macros.

+ Packagers are expected to use `+%ansible_collection_install+` and

+ `+%ansible_collection_filelist+` instead of directly referencing this directory.

+ 

+ [#legacy_macros]

+ === Legacy macros

+ 

+ [#collection_namespace]

+ ===== `+%{collection_namepsace}+`

+ *Usage:*

+ 

+ [source,RPMSpec]

+ ----

+ %global collection_namespace NAMESPACE

+ ----

+ 

+ The ansible-packaging macros previously required

+ packagers to manually set `+%collection_namespace+` in specfiles.

+ Now, the macros extract the collection namespace from the `galaxy.yml`.

+ 

+ 

+ [#collection_name]

+ ===== `+%{collection_name}+`

+ 

+ *Usage:*

+ 

+ [source,RPMSpec]

+ ----

+ %global collection_name NAME

+ ----

+ 

+ The ansible-packaging macros previously required

+ packagers to manually set `+%collection_namespace+` in specfiles.

+ Now, the macros extract the collection namespace from the `galaxy.yml`.

+ 

+ 

+ [#ansible_collection_files]

+ ===== `+%{ansible_collection_files}+`

+ 

+ *Usage:*

+ 

+ [source,RPMSpec]

+ ----

+ %files

+ %doc ...

+ %license ...

+ %{ansible_collection_files}

+ ----

+ 

+ New specfiles should use `+%files -f %{ansible_collection_filelist}+` instead

+ of this macro.

+ `+%{ansible_collection_files}+` requires setting

+ `+%collection_namespace+` and `+%collection_name+`.

We've had Ansible collection packaging macros for two years now, so I figured it was time to write up some guidelines. This is marked as a draft, as I'm still soliciting feedback and tying up some loose ends:

Mainly, I'm thinking about removing the need for the %global collection_* boilerplate and having the macros read from the metadata, instead. For that to happen, %{ansible_collection_files} would need to be replaced with an approach that passes a file list to %files -f so it could be dynamically generated. This is a nice side effect, IMO, because this would align the ansible macros with other ecosystems.

To give credit where credit is due, @ignatenkobrain initially wrote these macros.

/cc @kevin @dmsimard @ngompa @ignatenkobrain

rebased onto c0b7667b17dadeb9ef298096b60910563ff238ec

2 years ago

Typo for shebang ?

Fixed.

Excellent summary.

Thanks :).

Since recently, Docs stylesheet automatically generates a table of contents.
There is no need to specify :toc: any more.

Is % prefix missing from ansible_collection_build and ansible_collection here?
Other macros in this document are written with that prefix,
and using it seems to be the standard way to do that also elsewhere.

In my opinion, this statement does not add anything here.
It goes without saying that tooling and Guidelines are subject to change and improvement.

In my opinion, this statement does not add anything here.
All packages must follow the rules for the License: field.
That does not have to be repeated for Ansible packages repeatedly.

Disclaimer for all my comments above:
I am not a member of the Packaging Committee.
My review comments are completely unofficial.

rebased onto fc3bdf287aa2c8e71ca8abddc84657eadf949e06

2 years ago

Is % prefix missing from ansible_collection_build and ansible_collection here?
Other macros in this document are written with that prefix,
and using it seems to be the standard way to do that also elsewhere.

Fixed.

Is %check missing from this example?

Indeed, it is. I've fixed it.

In my opinion, this statement does not add anything here.
It goes without saying that tooling and Guidelines are subject to change and improvement.

I guess you kind of have a point. The idea was for packagers to be prepared for this to change in the future. I'm thinking that I might have this fixed before the "final draft," so I'll leave it here more as a reminder for now.

Since recently, Docs stylesheet automatically generates a table of contents.
There is no need to specify :toc: any more.

It adds a table of contents to the beginning of the page. Notice the difference between https://docs.fedoraproject.org/en-US/packaging-guidelines/CMake/ (has :toc:) and https://docs.fedoraproject.org/en-US/packaging-guidelines/JavaScript/ (does not).

In my opinion, this statement does not add anything here.
All packages must follow the rules for the License: field.
That does not have to be repeated for Ansible packages repeatedly.

I mainly added it here so the legal team didn't complain about there being legal guidelines within the packaging guidelines. I'll remove that if there's consensus to do so.

rebased onto f45c3518c71345192ebcfdfb660b5260ec4e732e

2 years ago

I've force pushed to add two newlines between specfile sections in the example.

2 new commits added

  • ansible example: Use patch file to edit metadata
  • Explicitly state that all collections can be packaged
2 years ago

3 new commits added

  • ansible example: Use patch file to edit metadata
  • Explicitly state that all collections can be packaged
  • Initial Ansible Collection guidelines
2 years ago

Since recently, Docs stylesheet automatically generates a table of contents.
There is no need to specify :toc: any more.

It adds a table of contents to the beginning of the page. Notice the difference between https://docs.fedoraproject.org/en-US/packaging-guidelines/CMake/ (has :toc:) and https://docs.fedoraproject.org/en-US/packaging-guidelines/JavaScript/ (does not).

That it does. My point was that even without it, there is a table of contents visible.
Either on the right, or on top, depending on viewport width.
And for narrow viewports, the automatic one is only visible if :toc: is not specified.

Anyhow, I just wanted to point out that :toc: is not needed to get a table of contents any more.
I am not aware of any style guide or such saying that you should not include it,
so please do if you prefer to do so.

rebased onto 275e6cf4988c9108cc645a9673f067eb24a51351

2 years ago

Metadata Update from @tibbs:
- Pull-request tagged with: meeting

2 years ago

Are these really named without the "ansible_" prefix? If so, the inconsistency seems a bit odd.

This caveat is interesting; now I wonder if one method is preferred. From a macro standpoint is it simpler to just stuff a list of files in a string than to write out a file (which probably needs Lua) and so having consistency across different sets of macros might be difficult if it's even something we wanted.

Yes; currently, %ansible_collection_install, %ansible_test_unit, and %ansible_collection_files rely on the %collection_namespace and %collection_name macros being set in the specfile. I am working on refactoring the macros to extract these values from the galaxy.yml metadata file and remove the need for these macros. This will require a file list.

From a macro standpoint is it simpler to just stuff a list of files in a string

That's true in some cases, but it won't work if you need to dynamically populate the %files section based on content from the extracted sources.

rebased onto 5fba15afc683951b2672f08017de6646e969bed5

2 years ago

@gotmax23:

I am working on refactoring the macros to extract these values from the galaxy.yml metadata file and remove the need for these macros. This will require a file list.

Okay, I have completed this refactoring. The changes are available here if anyone has comments on it before I merge. The refactoring removes the need for %collection_namespace and %collection_name. This guidelines PR reflects the macro changes.

1 new commit added

  • ansible: Clarify %ansible_collection_url guideline
2 years ago

10 new commits added

  • Fix wording and typos
  • ansible: Clarify %ansible_collection_url guideline
  • Add new Macro breakdown section
  • Update example specfile
  • ansible: Document %ansible_collection_filelist
  • ansible: Remove section about boilerplate
  • ansible: Expand Dependencies guidelines
  • ansible example: Use patch file to edit metadata
  • Explicitly state that all collections can be packaged
  • Initial Ansible Collection guidelines
2 years ago

10 new commits added

  • Fix wording and typos
  • ansible: Clarify %ansible_collection_url guideline
  • Add new Macro breakdown section
  • Update example specfile
  • ansible: Document %ansible_collection_filelist
  • ansible: Remove section about boilerplate
  • ansible: Expand Dependencies guidelines
  • ansible example: Use patch file to edit metadata
  • Explicitly state that all collections can be packaged
  • Initial Ansible Collection guidelines
2 years ago

10 new commits added

  • Fix wording and typos
  • ansible: Clarify %ansible_collection_url guideline
  • Add new Macro breakdown section
  • Update example specfile
  • ansible: Document %ansible_collection_filelist
  • ansible: Remove section about boilerplate
  • ansible: Expand Dependencies guidelines
  • ansible example: Use patch file to edit metadata
  • Explicitly state that all collections can be packaged
  • Initial Ansible Collection guidelines
2 years ago

1 new commit added

  • Move Ansible to Other Domain-specific Guidelines
2 years ago

11 new commits added

  • Move Ansible to Other Domain-specific Guidelines
  • ansible: Fix wording and typos
  • ansible: Clarify %ansible_collection_url guideline
  • ansible: Add new Macro breakdown section
  • ansible: Update example specfile
  • ansible: Document %ansible_collection_filelist
  • ansible: Remove section about boilerplate
  • ansible: Expand Dependencies guidelines
  • ansible example: Use patch file to edit metadata
  • Explicitly state that all collections can be packaged
  • Initial Ansible Collection guidelines
2 years ago

I'm removing the draft status. The ansible-packaging changes have been merged and the new version is now available in the buildroot, and I'm satisfied with the current state of the guideline text.

rebased onto 8edb6a4870a632cd037479b9650cd490d47a5fee

2 years ago

rebased onto 097a1a5

a year ago

I've rebased this. What are the next steps here?

Commit 136e8f9 fixes this pull-request

Pull-Request has been merged by james

a year ago

Pull-Request has been merged by james

a year ago