Contributing to kw(kernel workflow)

This is another post of the series of contributions and experiences through the discipline of MAC0470 (Free Software Development).

What is kw or simply kworkflow?

In a very simple way, just like the website suggests: kwhas a simple mission - reduce the environment and setup overhead of developing for Linux.

The tool is made of different components and assists developers working on the Linux kernel. It helps and automates the working flow of developers working on the Linux Kernel.

The coolest part is that a few of the maintainers of the projects are members of the university of são paulo community, which makes any doubts or issues we have quickly solved.

You can check the documentation here.

Finding an issue to contribute - a good first issue :smiley:

If you look up on the documentation mentioned above, you will find more than 150 issues opened by contributors that can (or need) to be solved.

Scrolling around, you can find the ones labelled as good first issue, which helped us find issue #69 to be the one to contribute.

Issue #69 : Improve “kw m –authors” for multiline MODULE_AUTHOR statements

On the documentation we understood that the task was improoving the function responsible to capture and print the authors of the drivers through the macro MODULE_AUTHORS.

However, the old implementation of this function can only do this for single-line statements of this macro. If authors are defined in multi-line statements, no author will be captured by the function.

Or as the issue author of the issue mentioned:

When we run a kw m –authors, only authors found in a single line MODULE_AUTHOR statement are captured and printed. In the future, it would be nice to look for multiline MODULE_AUTHOR statements such as:

MODULE_AUTHOR ("a_long_email@xx.com" \
               "another_long@yy.com" )

and:

MODULE_AUTHOR ("a_long_email@xx.com"
               "another_long@yy.com" )

which are, both, valid C statements. In the currently implementation neither of these four emails would be printed.

Contributing to kw

This part of the post was based on the TA’s pad about kw-contribution-guide.

1) Forking kw

Here we need to create a fork of the kw before doing any modification (differente from adventurous kernel contribution). We need to access the upstream and fork the repository. Note that your fork of kw is not automatically synchronized with the upstream when there are updates in the unstable branch. To do this, in your fork, select unstable and click on Sync fork.

2) Cloning the repo locally

After setting up you ssh key on Github, you can use the following command to git clone the original repository

$ git clone git@github.com:<nome-de-usuario>/kworkflow.git

3) Using the unstable branch

In this project we will any change on a branch called unstable inside the cloned repository.

You can run:

$ git switch unstable

or (if the previous didn’t work out):

$ git checkout --track origin/unstable

You can ask yourself, but what is an unstable brach? An “unstable branch” ia a branch in Git, where ongoing development work is carried out. In other words, it is the “lab” for developers experiments. This branch often contains the latest changes, features, and bug fixes that are still under testing and may not be considered stable for production use. Ideally, after issues fixed and testings are correctly done, this branch is merged to the origin for release.

4) kw installation

Now, with the right repository set, just go to the rpository root and run

  • ./setup.sh --install
  • type y and enter to install all dependencies
  • if you want to install without the man pages (quicker :sunglasses: ), run ./setup.sh --install --skip-docs

5) Developer dependencies installation

For the development tools, there are a few needed dependencies:

Unit Test

We use shUnit2 as the unit testing framework. To run the tests, you can clone the shUnit2 repository here and add the path to this repository in your PATH. Alternatively, you can clone the repository into the tests/ directory within your local kw repository (easier).

Formatter, Linter, and pre-commit:

We use shfmt as the formatter, shellcheck as the linter, and pre-commit for pre-commit hooks. These tools are used to ensure that general coding style rules are followed. After installing them with your package manager, run

pre-commit install

in the root of the kw repository. From there, every time you make a commit, the pre-commit hook will check if your commit follows the general coding style rules. Note that passing the pre-commit does not guarantee that your commit follows all coding style rules, but it greatly speeds up the development process.

A note about the tools:

  • shfmt: It is used as a formatter, meaning it helps ensure that shell scripts are formatted consistently according to predefined style guidelines. This improves code readability and maintainability.
  • shellcheck: This tool serves as a linter, which means it analyzes shell scripts statically to detect and highlight potential issues, errors, or code smells. It helps developers identify and correct problems early in the development process.
  • pre-commit: It is a tool used to set up and manage pre-commit hooks, which are scripts or commands that are run automatically before each commit is made to a version control system. These hooks can perform various tasks such as running tests, checking coding style, or performing static analysis to ensure code quality before changes are committed.

Development flow

1) Update your local unstable branch with upstream unstable

If your kw fork’s unstable branch isn’t synchronized with the upstream, do this on the Git interface. Afterward, run in your local kw repository:

$ git pull origin unstable

2) Create a dedicated branch for the changes

$ git checkout -b <desired-branch-name>

3) Implement the changes - let’s test!

Regardless of the number of commits, each commit should be self-contained and minimal, meaning the implementation and the testing code should be in the same commit, and the commit shouldn’t “do too much at once”

Always run the battery of automated tests to ensure your implementation passes the tests (both existing and new ones). To do this, run:

$ ./run_tests.sh --unit

Don’t underestimate this, unit tests can take a bit too long to finish and depending on the changes you made, it is not necessary to run all the tests all over again. So, you can run a few specific tests with this command:

$ ./run_tests.sh test tests/unit/<test-script-name>

For more details on tests, see here.

4) Creating a remote branch on Fork - updating the repo with changes

After implementing the change, represented by a branch in your local repository, we need to “push” it to your fork using:

$ git push --set-upstream origin

This will add the branch you did your local modification to the remote repository.

5) Open a pull request (PR) on upstream

After creating the remote branch with the push, open a PR through the Git interface. Typically, a green button labeled “Open Pull Request” appears, and you simply click to open the PR on the upstream. Don’t forget to select unstable as the base branch - Always make sure you are on the right place!

6) Update a PR

With the reviewing process you will most likely need to do updated on the Pull Request. To do this, you should update the necessary commits with:

$ git rebase --interactive unstable

Don’t forget to mark the commits you want to edit with ‘e’.

After updating your local branch, update the remote branch with:

$ git push --force-with-lease origin <branch-name>

The PR on GitHub will be automatically updated afterward.:relieved:

A note on git rebase

Git rebase is a command used in Git to integrate changes from one branch onto another by reapplying commits from one branch onto the tip of another. Different from merge, which preserves the original branching structure, rebasing creates a linear history by moving the entire branch to a new base commit. This process can help maintain a cleaner commit history, making it easier to follow the progression of changes.

PR adjustments

Before your PR is accepted and merged into the original project, a kw maintainer will review to ensure everything is in order. This includes aspects like commit messages, organization, readability, etc. They may suggest changes before merging your contribution into the unstable branch.

The GitHub Actions tests, discussions, and adjustments can be seen on the Pull Request page on GitHub.

Our experience with the issue #69 development:

During the unit tests executionsm we faced the following ERROR

Running test [unit/maintainers_test]
=========================================================
test_print_files_authors
test_print_files_authors_from_dir
ASSERT:expected:<
> =========================================================
> MODULE AUTHORS:
> code1.c: John Doe <johndoe@community.com>, Caesar Doe <caesar@community.com>, Michael Doe <michael@community.com>
> code2.c: Bob Hilson <bob@opensource.com>
> but was:<
> =========================================================
> MODULE AUTHORS:
> code1.c: John Doe <johndoe@community.com>, Caesar Doe <caesar@community.com>, Michael Doe <michael@community.com>
> code2.c: Bob Hilson <bob@opensource.com>
>
shunit2:ERROR test_print_files_authors_from_dir() returned non-zero return code.
test_maintainers_main
test_maintainers_main_patch

Ran 4 tests.

FAILED (failures=1)
=========================================================
Total: 1 test file(s)
1 test file(s) FAILED

Take a look at:
-> ./tests/unit/maintainers_test.sh

It was quite easy to fix this error since it was a \newline specification that made extra gaps on the typing. So the diff of the test script didn’t embrace the case, even though it seemed “right”.

In this page you can find our PR.

Besides this specific error, we are now facing a few issues that the maintainers suggested we modify. We are working on that and we are making the needed changes hoping for new feedbacks.

This is it for our first kw contribution :smiley: See you on the next post!