Contributing
============

.. note:: **Abstract**

   This document describes the development process of {kiwi}
   and how you can be part of it. This description applies
   to version |version|.

.. toctree::
   :maxdepth: 1

   contributing/kiwi_from_python
   contributing/kiwi_plugin_architecture
   contributing/scripts_testing
   contributing/schema_extensions.rst

The Basics
----------

The core appliance builder is developed in Python and follows the test-
driven development rules.

If you want to implement a bigger feature, consider opening an issue on
GitHub first to discuss the changes. Or, join the discussion in the
`#kiwi` channel on `Matrix <https://matrix.to/#kiwi:matrix.org>`_.

Fork the upstream repository
----------------------------

1. On GitHub, navigate to: https://github.com/OSInside/kiwi.

2. In the top-right corner of the page, click :command:`Fork`.

Create a local clone of the forked repository
---------------------------------------------

.. code:: shell-session

    $ git clone https://github.com/YOUR-USERNAME/kiwi

    $ git remote add upstream https://github.com/OSInside/kiwi.git

Install Required Operating System Packages
------------------------------------------

{kiwi} requires additional packages at runtime that are not
provided by `pip`. Those will be pulled in by installing
the following package:

* kiwi-systemdeps

The package is provided on the Open Build Service in the
`Virtualization:Appliances:Builder
<https://download.opensuse.org/repositories/Virtualization:/Appliances:/Builder>`__
project. For manual inspection of the packages
that are pulled in from the above `kiwi-systemdeps` package, please refer
to the `package/python-kiwi-spec-template` spec file from the checked-
out Git repository.

Create a Python Virtual Development Environment
-----------------------------------------------

The following commands initialize and activate a development
environment for Python 3:

.. code:: shell-session

   $ poetry install

The command above automatically creates the application script
called :command:`kiwi-ng`, which allows you to run {kiwi} from the
Python sources inside the virtual environment using Poetry:

.. code:: shell-session

    $ poetry run kiwi-ng --help

Running the Unit Tests
----------------------

Before submitting your changes via a pull request, ensure that all tests
pass and that the code has the required test coverage via the command:

.. code:: shell-session

    $ make check
    $ make test

Create a Branch for each Feature or Bugfix
------------------------------------------

Code changes should be done in an extra Git branch. This allows for
creating GitHub pull requests in a clean way. See also: `Collaborating with
issues and pull requests
<https://help.github.com/en/categories/collaborating-with-issues-and-pull-requests>`_.

.. code:: shell-session

    $ git checkout -b my-topic-branch

Make and commit your changes.

.. note::

    You can make multiple commits, which is generally useful to
    give your changes a clear structure and to allow us to better
    review your work.

.. note::

    Your work is important and must be signed to ensure the integrity of
    the repository and the code. Thus, we recommend setting up a signing key
    as documented in :ref:`Signing_Git_Patches`.

.. code:: shell-session

    $ git commit -S -a

Once everything is done, push your local branch to your forked repository and
create a pull request into the upstream repository.

.. code:: shell-session

    $ git push origin my-topic-branch

Thank you much for contributing to {kiwi}. Your time and work effort are very
much appreciated!

AI policy
---------

{kiwi} accepts contributions created using gen-AI tools. Contributions
using AI tools need to be clearly labeled with the tool used set as
co-author. If the tool used offers a selection of models set the model
as co-author. Ultimately the submitter, a human, is still responsible
for the quality of the code. It is expected that code contributions are
self reviewed prior to creating a pull request.

The co-author is set using the `Co-authored-by:` trailer in the commit
comment, for example `Co-authored-by: qwen2.5-coder`

Coding Style
------------

{kiwi} follows the general PEP8 guidelines with the following exceptions:

- We do not use free functions at all. Even utility functions must be part
  of a class but should be either prefixed with the `@classmethod` or
  `@staticmethod` decorators (whichever is more appropriate).

- Do not set module and class-level variables; put these into the class's
  `__init__` method.

Documentation
~~~~~~~~~~~~~

{kiwi} uses `Sphinx <https://www.sphinx-doc.org/en/master/>`_ for the API,
user documentation, and man pages.

.. code:: shell-session

    $ make docs

API documentation is created from type hints. Even though python is
not a strong typed language we value if all parameters and return
values uses proper type hints.

.. code:: python

   class Example:
       """
       **Example class**

       This class has a single responsibility and provides...
       """
       def __init__(self, names: List[str], set_names: bool = False):
           """
           Initialize instance of Example with a list of some
           example names. If param_w_default is set to True the
           instance is initialized with an empty name list
           """
           self.some_names = names if set_names else []

       def is_retired(self, age: int = 0) -> bool:
           """
           A method that implements...
           """
           return len(age) > 70

Try to stick to the following guidelines when documenting source code:

- Classes should be documented directly in their main docstring and not in
  `__init__`.

- Document function parameters unless their name makes it clear

- Only public methods should be documented; private methods don't have to be,
  unless they are complex and it is not easy to grasp what they do (which
  should be avoided anyway).

Please also document any user-facing changes that you are implementing
(e.g., adding a new build type) in the user documentation, which can be
found in `doc/source`.

Additional Information
----------------------

The following sections provide further information about the repository
integrity, version, package, and documentation management.

.. _Signing_Git_Patches:

Signing Git Patches
~~~~~~~~~~~~~~~~~~~

To ensure the integrity of the repository and the codebase, patches sent
for inclusion should be signed with a GPG key.

To prepare Git to sign commits, follow these instructions:

#. Create a key suitable for signing (it is not recommended to use
   existing keys to not mix it with your email environment):

   .. code:: shell-session

    $ gpg2 --expert --full-gen-key

#. Either choose an RSA key for signing (option `(4)`) or an ECC key for
   signing (option `(10)`). For an RSA key, choose a key size of 4096 bits,
   and for an ECC key, choose Curve 25519 (option `(1)`). Enter a reasonable
   validity period (we recommend 2 to 5 years). Complete the key generation
   by entering your name and email address.

#. Add the key ID to your git configuration by running the following
   :command:`git config` commands:

   .. code:: shell-session

      $ git config --local user.signingkey $YOUR_SIGN_KEY_ID
      $ git config --local commit.gpgSign true

   Omitting the `--local` flag will make these settings global for all
   repositories (they will be added to :file:`~/.gitconfig`). You can find
   your signkey's ID via:

   .. code:: shell-session

      $ gpg2 --list-keys --keyid-format long $YOUR_EMAIL
      pub   rsa4096/AABBCCDDEEFF0011 2019-04-26 [S] [expires: 2021-04-16]
      AAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBB
      uid                 [ultimate] YOU <$YOUR_EMAIL>

   The key's ID in this case would be `AABBCCDDEEFF0011`. Note that your
   sign key will have only a `[S]` after the creation date, not a `[SC]`
   (then you are looking at your ordinary GPG key that can also encrypt).

Bumping the Version
~~~~~~~~~~~~~~~~~~~

The {kiwi} project follows the `Semantic Versioning <https://semver.org>`_
scheme. We use the :command:`bumpversion` tool for consistent versioning.

Follow these instructions to bump the major, minor, or patch part of the
{kiwi} version. Ensure that your repository is clean (i.e., no modified and
unknown files exist) before running :command:`bumpversion`.

*  For backward-compatible bug fixes:

   .. code:: shell-session

    $ bumpversion patch

*  For additional functionality in a backward-compatible manner. When
   changed, the patch level is reset to zero:

   .. code:: shell-session

    $ bumpversion minor

*  For incompatible API changes. When changed, the patch and minor
   levels are reset to zero:

   .. code:: shell-session

    $ bumpversion major

Creating an RPM Package
~~~~~~~~~~~~~~~~~~~~~~~

We provide a template for an RPM spec file in
:file:`package/python-kiwi-spec-template` alongside a `rpmlint`
configuration file and an automatically updated
:file:`python-kiwi.changes`.

To create the necessary files to build an RPM package via `rpmbuild`, run:

.. code:: shell-session

   $ make build

The sources are collected in the :file:`dist/` directory. These can be
directly built with :command:`rpmbuild`, :command:`fedpkg`, or submitted
to the Open Build Service using :command:`osc`.
