---
# System prepended metadata

title: Unifying Konveyor

---

---
title: 'Unifying Konveyor'
---

Unifying Konveyor project code conventions
===

[TOC]

## Problem statement
Within number of Konveyor projects and their repositories both [upstream](https://github.com/orgs/konveyor/repositories) and [downstream](https://gitlab.cee.redhat.com/mig-integration) there are no common code conventions and development workflows that would ease the contribution process.

Almost every project requires duplicated effort in automating very simple tasks such as creating development environment, building the source code, running simple test both locally and in the CI ecosystem, generating documentation, etc.

Even minor things like documentation have different naming / paths and it's inconsistent e.g. development instrutions: [docs/Development.md](https://github.com/konveyor/pelorus/blob/master/docs/Development.md) vs [docs/hacking.md](https://github.com/konveyor/mig-operator/blob/master/docs/hacking.md) vs [README.md](https://github.com/konveyor/forklift-ui#development-scripts) vs [contributing.md](https://github.com/konveyor/move2kube/blob/main/contributing.md) and [code-of-conduct.md](https://github.com/konveyor/move2kube/blob/main/code-of-conduct.md)

This leads to more work, maintenance and differences for the parts that could be similar.

Also aspect of projects belonging to one community is reduced by those inconsistencies.

## Proposal
Create a set of common conventions that could be used in automated fashion. For the parts that are not automated the docs should be available for developers to follow.

# Execution
There are couple of areas to address. Proposals are described below. Most of the scripting and development should be stored in one common repository that is available from both upstream and downstream, meaning that [GitHub](https://github.com/konveyor/) is the first choice to consider.

```mermaid
graph
    GitHub_project --> common_repository;
    GitLab_project --> common_repository;
```


## Common way of creating dev env

Every developer who would like to contribute to the Konveyor project should be able to prepare local developer environment with all needed dev and test deps in similar way. 

Proposal is to have a common syntax invoked from the `Makefile`

```
# To create development environment
make dev-env

# To tear down developmen environment
make clean-dev-env
```

We should include snippet for the Makefile together with supporting scripts that allows to install packages from different locations and packaging systems. e.g. `PyPI requirements.txt, test-requirements.txt, Go, dnf, GitHub released binaries, OpenShift CLIs, Ansible roles, collections, etc...`

## Common way of preparing test environment

Simple static code analysis as well as simple test runs that could be ran on the local developer box as well as part of the CI/CD systems should have common way kind of ***entry point*** of running those. This allows to detach test logic from any system runner.

It could be the same as previously mentioned `make dev-env`, but also something more specific to the test scenario.

The repository that holds such test environments should be language agnostic and support different use cases that are adopted in the Konveyor set of projects.

## Common way of running various tests

Each code analysis test as well test frameworks that could be shared *`NOTE that not all of them can be shared and those should live in the per project repository`* should be ran in a similar way.

Proposal is similar to the dev-env and have common section/target invoked from the `Makefile`. One special target ***test*** should run all the tests that are required prior to submission code as the PR, example:

```
.PHONY tests
tests: \
    # code to run all tests via pre-commit.
    # This may be just a list of Makefile targets 
    # 'pylava lint shellcheck' however running them
    # via pre-commit will allow to catch all the errors
    # at once rather then failing entire run on a first error.

.PHONY: pylava lint shellcheck
pylava:
    # code to run pylava via pre-commit

lint:
    # code to run lint via pre-commit

shellcheck:
    # code to run shellcheck via pre-commit
```

Having such entry point will allow us to invoke tests locally and inside CI/CD systems in a very same way, hiding logic behind the scenes by simply running:

```
# To run all tests
make tests

# Or if individual test run is required
make shellcheck
```

## Common configuration files for code analysis

To ensure code is consistent across different Konveyor projects we should store configuration files for each of the linters/tests that will then be used in various projects. Those configuration files should be for various programming languages and selected analysis tools. Of course if the file contains information about project folder structure or files then only applicable rules should be common e.g.:

```
.ansible-lint
pylava.ini
pyproject.toml
lintconf.yaml
[...]
```

## Carefully selected set of pre-commit hooks

[pre-commit](https://pre-commit.com/) is a framework/package manager that allows to easilly install and run multi-language set of static code analysis tools agains the code. This framework can be also used to run a bit more comprehensive set of tests.

There is a wide community supported set of [hooks](https://pre-commit.com/hooks.html) that we should agree on and enable for the applicable konveyor projects storing the configuration files in the common repository.

If there are some missing code test runners or available one is not aligned with our requirements (`for example not accepted hook as it's modifying the source code`) we will write our own version and store in the common repository.

We will store .pre-commit-config.yaml that lists *all* of the selected hooks for all the projects, with manual stage set. This stage will be commented out if the project needs it, e.g.: 

```
- repo: https://github.com/golangci/golangci-lint
  rev: v1.44.2
  hooks:
    - id: golangci-lint
#      stages: [manual]
```

Those hooks will be then wrapped around Makefile to allow common entry point accross different projects.


# Example scenarios

This section lists example scenarios and it's meant to explain better the entire concept.

### Running the tests via Makefile

```$ make tests```
```mermaid
flowchart LR
      CI["CI system (github actions/Praw/gitlab runner)"] --> |make tests|id1
      Developer --> |make tests|id1
      id1 -->  |pre-commit run|pre-commit
      subgraph "Konveyor Project"
        id1{{Makefile}}
      end
      subgraph "pre-commit"
        id2{{pylint}}
        id3{{shellcheck}}
        id4{{other hook runner}}
      end
```

### Running the tests prior to git push
Action done via pre-commit hook installed by the ```pre-commit``` CLI

```mermaid
flowchart LR
      subgraph Konveyor_project
        direction LR
        git-commit{{git commit}} --> id1
        id1{{pre-commit github hook}}
      end
      subgraph pre-commit
        id2{{pylint}}
        id3{{shellcheck}}
        id4{{other hook runner}}
      end
      Konveyor_project --> |pre-commit run|pre-commit
```

### Running individual test

```$ make shellcheck```
```mermaid
flowchart LR
      CI["CI system (github actions/Praw/gitlab runner)"] --> |make shellcheck|id1
      Developer --> |make shellcheck|id1
      id1 -->  |pre-commit run shellcheck|pre-commit
      subgraph "Konveyor Project"
        id1{{Makefile}}
      end    
      subgraph "pre-commit"
        id2{{shellcheck}}
      end
```

### Code analysis config files
Most files are stored in the common repository and synced. Possibly using some `Makefile sync-configs target`. Konveyor Project may even not contain those files and they will be synced before actual run in the test preparation step. Konveyor Project may also store a modified version of config file which is templated from common repository.

```mermaid
flowchart LR
    subgraph Common_repository
      direction LR
      id1(".ansible-lint\npylava.ini\npyproject.toml\nlintconf.yaml\n[...]")
    end
    subgraph Konveyor_Project
      id2{{Makefile}}
      id3{{.ansible-lint\nlintconf.yaml}}
end
    id1 -.-> |sync|id3
```

### Makefile and scripts
`Makefile` and scripts which may live in the common repository should be synced with the Konveyor Project.
All pre-check targets, even those that are not relevant for the programming language should be listed in the Makefile for easy sync.

***Note*** *the common_repository `Makefile` is a subset of Konveyor project*

```mermaid
flowchart LR
    subgraph Common_repository
      direction LR
      id1("Makefile")
      id2("scipts/")
    end
    subgraph Konveyor_Project
      id3{{Makefile}}
      id4{{.ansible-lint\nlintconf.yaml}}
      id5{{scripts/}}
end
    id1 -.-> |"sync (subset)"|id3
    id2 -.-> |"sync"|id5
```

### Custom pre-commit hooks
Similarly to any hook a custom hook will be written and stored in the common repository. Writing a custom hook is relatively easy task and a number of programming languages are supported. Please refer to the [creating new hooks ](https://pre-commit.com/index.html#new-hooks).

Running a custom hook is same as other ones

```$ make customhook```
```mermaid
flowchart LR
      CI["CI system (github actions/Praw/gitlab runner)"] --> |make shellcheck|id1
      Developer --> |make customhook|id1
      id1 -->  |pre-commit run customhook|pre-commit
      subgraph "Konveyor Project"
        id1{{Makefile}}
      end    
      subgraph "pre-commit"
        id2{{shellcheck}}
      end
```

### Putting everything together

```mermaid
flowchart LR
      subgraph ida ["Konveyor GitHub projects"]
      direction LR
          subgraph id1a ["Pelorus"]
            direction LR
            id1b>"python, helm, shell, docs"]
            id1c{{"Makefile"}}
          end
          subgraph id2a ["Crane Operator"]
            direction LR
            id2b>"ansible, podman"]
            id2c{{"Makefile"}}
          end
          subgraph id3a ["Move2Kube"]
            direction LR
            id3b>"go, shell, podman"]
            id3c{{"Makefile"}}
          end
          subgraph id4a ["Other..."]
            direction LR
            id4b>"Fortran"]
            id4c{{"Makefile"}}
          end
      end

      subgraph idb ["Konveyor GitLab projects"]
      direction LR
          subgraph id5a ["minikube-cluster"]
            direction LR
            id5b>"ansible"]
            id5c{{"Makefile"}}
          end
          subgraph  id6a ["oadp-operator-test"]
            direction LR
            id6b>"ansible, python"]
            id6c{{"Makefile"}}
          end
          subgraph id7a ["Other..."]
            direction LR
            id7b>"go"]
            id7c{{"Makefile"}}
          end
      end

      subgraph idc ["Common Repository"]
          id9a{{"Makefile"}}
          subgraph id9x ["Config files"]
              id9b(".ansible-lint\npylava.ini\npyproject.toml\nlintconf.yaml\ngolint.yaml\n[...]")
          end
          subgraph id9h ["Custom pre-check"]
            direction LR
            id9g>"fortran-check"]
          end
          subgraph id7a ["Other..."]
            direction LR
            id7b>"go"]
            id7c{{"Makefile"}}
          end
      end
      subgraph id10a ["pre-commit.com supported hooks"]
      direction LR
          id10b{{"ansible lint\ncheck yaml\ngolint\n[...]"}}
      end

    id9a -.-> |"sync"|ida
    id9a -.-> |"sync"|idb
    id9x -.-> |"sync"|ida
    id9x -.-> |"sync"|idb
    id9a --> |"custom target"|id9h
    id9a --> |"supported hooks"|id10a

```
