How to Contribute to Netatalk

This project uses Git for code revision control and collaboration.

This section describes the general workflow and lifecycle of code contributions
in the Netatalk Project, and how to get new code accepted into release branches.
It is applicable to Netatalk Team members and external contributors alike.
Please read this thoroughly and familiarize yourself with the process before
submitting code to the project.

Using Git

If you haven't used git before, you should probably familiarize yourself with
the Git tutorial.

Branching model

  - The main branch is where development of new features is taking place.
  - Branches named branch-netatalk-x-y are for stable releases.
  - Make your code changes in a feature branch, and submit a Pull Request
    against the target branch.
  - Before submitting PRs against stable branches, please make sure an issue
    report has been filed first.
  - When patching stable branches, prioritize submitting PRs for those stable
    branches. The patches can be cherry-picked to main by a maintainer later.
  - We allow rebase merges only; no branch merges or squash merges.

Review process

We require formal peer review of all patches before merging to the main or
stable branches.

The code review can be carried out by any Netatalk Developer.

Commit messages

Commit messages should have a short, descriptive first summary line that begins
with the affected component (i.e. the subdir that houses the majority of changed
code.)

afpd: new options "force user" and "force group"

This is helpful when browsing a git log in oneline mode.

Then the commit message should explain what the change is about, the more
context the better. Each line of the commit message shall be max 80 characters
long.

Basic Netatalk Git

The mother git repository is located at https://github.com/Netatalk/netatalk.git
with a mirror at https://gitlab.com/netatalk-team/netatalk.git.

If you are a Netatalk team member, you create and push work branches directly in
the mother repository on GitHub.

If you are an non-member code contributor (thank you for volunteering!) then
work from your own fork of the Netatalk repository. Please follow the GitHub
workflow to create your fork, and then clone that fork.

.gitignore

The policy in this project is to define .gitignore patterns only for files and
directories that are generated by the netatalk build system. So for instance,
the macOS .DS_Store metadata file, or IDE settings files, should not be filtered
out in the netatalk .gitignore file.

If a developer wants to filter out environment specific files, we recommend
creating a global .gitignore file for your particular setup.

Pull Requests

All new code must go through the GitHub Pull Request workflow, which involves at
least one project member doing code review and signing off on it, before merging
to the target branch.

The description of the workflow can be read in GitHub documentation and will not
be repeated here.

The title of the PR should be descriptive and fit on one line. When it is a PR
against a stable branch, prepend a tag with the major and minor Netatalk
version. For PRs against the main development branch, do not prepend any tags.

A good example for a stable branch:

[3.2] meson: Allow choosing shared or static libraries to build

In the PR summary, make sure you add a description of the purpose of the PR,
with a breakdown of the major changes that it is making.

The PR reviewers will be automatically assigned based on the CODEOWNERS
settings, so sit back and relax while a project member follows up!

All PR feedback must be addressed, either by code changes or by an explanation
that is acceptable to the reviewer. When making code changes, the commit history
in the PR must be rebased for a clean and logical changeset. (As per the policy
above, we only do rebase merges, no squash merges.)

AI assisted contributions

AI tools may be used to assist with code contributions, but AI is a tool, not an
independent author.

  - The submitter is expected to have read and internalized every line of code
    in the changeset, regardless of how it was produced.
  - The submitter is responsible for the correctness, security, maintainability,
    and licensing of all submitted code.
  - The submitter is responsible for ensuring that AI generated code does not
    plagiarize copyrighted code or introduce code with incompatible licensing.

Testing

Pull Requests should be accompanied by tests when appropriate, especially for
bug fixes, new AFP functionality, and changes to shared behavior. Tests should
use the existing structures under test/**, including the test/afpd component
integration tests and the test/testsuite system integration tests.

Novel test failures should be fixed before submitting a PR. It is strongly
recommended to run the relevant tests locally before submitting. For more
details, see the Testing wiki page.

Alternative patch submission

If you are unable to use the GitHub Pull Request workflow for some reason, you
can also submit patches by email to the netatalk-devel mailing list.

Please follow the guidelines in the Developer FAQ for instructions on how to
create and submit patches by email.

Build system

In the stable netatalk release 3.2.0 (and 2.4.0) we introduced the Meson build
system, initially in addition to the traditional GNU autotools build system. As
of version 4.0.0, autotools macros were completely removed, and Meson is now the
only build system option.

See the INSTALL file in the netatalk code tree for more details on how to use
the Meson build system.

Copyright and license

The Netatalk project as a whole is distributed under the GNU GPL v2. Code
covered by other, compatible, FLOSS licenses are also included in the package.

It is strongly recommended that new code contributed to this project is also
licensed under the GNU GPL v2 license. This is an example copyright header that
you can put in the top of new source files, formatted as a C code comment.

/*
 * Copyright (C) Firstname Lastname 20XX
 * All Rights Reserved.  See COPYING.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

For other languages, use the appropriate code comment syntax.

Coding Standards

The baseline C language standard revision for the netatalk codebase is C11.

Note that since the netatalk code was originally written in the early 90s, there
are still parts of the codebase that is archaic. Contributors are welcome and
encouraged to modernize the code and use recent C language conveniences
compliant with C11.

The use of memory safe standard library BSD-isms such as strnlen(), strlcpy(),
and strlcat() is also encouraged. In fact, include/atalkd/compat.h contains
wrappers for these three functions for standard C libraries that don't support
them natively.

C static analysis

Certain coding conventions and best practices are enforced through static
analysis provided by SonarQube.

This project uses a custom Quality Profile, so you can refer to this for the
current list of active static analysis rules.

New code must not introduce any Security, Reliability, or Maintainability bugs.
Changed code must not contain any Security or Reliability bugs, but
Maintainability bugs are tolerated.

Note that project members will get immediate feedback by the CI workflow, while
external contributors' code will only get scanned after being merged for
technical reasons.

C code style

This project has adopted a C coding style guide applied across the entire
codebase. The intended outcome is to make the code more readable, and to make
collaboration and maintenance easier. With automated enforcement of the style
guide, the manual overhead of fiddling with layout is eliminated.

Automatic formatting

The style guide is automatically enforced with astyle v3.6.17 or later. and an
.astylerc options file. Before submitting new code, run astyle --project
--recursive '*.h' '*.c' '*.cc' in the root of the netatalk source tree. You can
also use the ./contrib/scripts/codefmt.sh convenience script to the same effect.

Rules

  - General rules
      - Four space indentation
      - Max 80 char line lengths
      - Variable and function names should be in snake_case
      - Lists of symbols, files etc. should be sorted in alphabetic order,
        unless a constraint dictates otherwise
      - One variable declaration and definition per line
      - Alphanumeric symbols in optarg should be in alphabetical order, with
        unary options first and parameter options second

Ex.

getopt(ac, av, "flsA:D:m:r:")

  - Headers
    
      - Cluster headers in this order: First system libraries, second 3rd party
        libraries, third libatalk headers, fourth local headers
      - Within each cluster: Sort header include directives in alphabetical
        order, unless a particular sequence is required

  - Braces
    
      - Starting braces are broken from function definitions, but attached for
        all other block types
      - When on the same line, one space padding between condition and starting
        brace
      - Always use braces on single-line blocks

Ex.

int return_zero(int i)
{
    if (i == 0) {
        return 0;
    }
}

  - Code comments
      - C style /* comments */, not C++ style // comments
      - Trailing code comments should be used where appropriate, such as
        structure member definitions
      - Multi line comments use vertically aligned * prefixes

Ex.

/*
 * Your comment goes here
 */

  - Code documentation
      - We use a Doxygen based documentation system for code documentation,
        with:
          - QDoc style /*! ... */ markers
          - Use /*!< ... */ to for trailing comments
          - JavaDoc style @ prefixed commanded tags
      - Most comment blocks should include @brief, @param and @returns
      - Indicate input/output status for @param with [in],[out], and [in,out]
        tags
      - Surround code blocks with @code ... @endcode for proper formatting
      - Use CommonMark markdown for rich formatting, for instance for numbered
        and bulleted lists

Ex.

/*!
 * @brief Inititialize rootinfo key (which has CNID 0 as key)
 *
 * @note This also "stamps" the database, which means storing st.st_ctime
 * of the "cnid2.db" file in the rootinfo data at the DEV offset
 *
 * @param[in,out] dbd       database handle
 * @param[in] version       database version number
 *
 * @returns -1 on error, 0 on success
 */
static int dbif_init_rootinfo(DBD *dbd, int version)
{
    ...
}

  - Padding and alignment
    
      - Pointer and reference operators (*, &, or ^) should be aligned to the
        variable name
      - One space padding after comma
      - One space padding after paren headers ('if', 'for', etc.)
      - One space padding before and after operators ('+', '-', etc.)
      - No padding for unary operators ('i++')
      - No padding inside parentheses or brackets ('if (1 == 0)')

  - Empty lines and trailing spaces
    
      - No trailing spaces
      - Max one empty line in sequence
      - Empty line padding before and after unrelated blocks, labels, etc.

Meson code style

We use Muon's opinionated formatter - muon fmt - to format all the meson.build
files as it applies the meson syntax recommendations to all files.

Boolean variable naming

Meson Boolean variables should describe both what the value means and where it
comes from. Use the following prefixes consistently:

  - enable_* for user-requested features or candidate implementations, normally
    read directly from a with-* Meson option.
  - have_* for capabilities confirmed by platform or dependency checks.
  - use_* for providers, backends, or implementations actually selected for the
    build. This may come directly from an option when no availability check is
    required.
  - build_* for build modes or classes of generated artifacts, such as
    documentation and tests.
  - install_* for installation actions or hooks.

For other Boolean actions, use a positive verb phrase such as create_statedirs,
overwrite_config, or regenerate_unicode_data. Avoid negated names and avoid
using with_* for local variables; with-* is reserved for Meson option names.

Example of combining user intent and platform checks to determine whether a
feature is available:

enable_acls = get_option('with-acls')
have_acls = enable_acls and acl_dependencies_found

If an enabled feature requires no platform or dependency check, use its enable_*
variable directly rather than creating an equivalent have_* variable.

Install muon and save the following script as 'muonfmt' in your local bin
directory (chmod +x it too):

#!/bin/bash

find . -type f -name "meson.build" -exec muon fmt -i {} \;

Then all you need to do is:

cd netatalk
muonfmt

You can also use the ./contrib/scripts/codefmt.sh convenience script to the same
effect.

Note: In Debian and derived distros, the muon package and binary are called
muon-meson.

Perl code style

Perl code distributed with netatalk should follow the common style guide,
enforced by perltidy and the .perltidyrc config file.

For example, it should use four space indentation with a max 120 char line
length.

Brace, square bracket, and parentheses tightness should be max, meaning no inner
space padding. The exception is block braces, which should have a one space
padding. Opening braces should always be trailing at the right of the condition
or method definition, with a cuddled else statement.

Shell script code style

First off, we expect all shell scripts distributed with netatalk to be POSIX
compliant and run in the sh interpreter.

As with the other code styles, we expect four space indentation, including for
switch statements. We also like to see a one space padding between all
operators.

The coding style is enforced through an .editorconfig file in the repo root,
together with the shfmt beautifier.
