|
3 | 3 | Contributing to Code Development |
4 | 4 | ================================ |
5 | 5 |
|
| 6 | +TL;DR: |
| 7 | + |
| 8 | +- Contributions comes as bugs/questions/issues and as pull requests. |
| 9 | +- Source code and runtime data are in the /src/ directory. |
| 10 | +- Test code and test data are in the /tests/ directory. |
| 11 | +- Datasets (inluding licenses) and test data are in /data/ sub-directories. |
| 12 | +- We use DCO signoff in commit messages, like Linux does. |
| 13 | +- Porting ScanCode to other OS (FreeBSD is supported, etc.) is possible. Enter an issue for help. |
| 14 | + |
6 | 15 | See `CONTRIBUTING.rst <https://github.com/nexB/scancode-toolkit/blob/master/CONTRIBUTING.rst>`_ |
7 | 16 | for details. |
8 | 17 |
|
| 18 | + |
9 | 19 | .. _contrib_code_conven: |
10 | 20 |
|
11 | 21 | Code layout and conventions |
12 | 22 | --------------------------- |
13 | 23 |
|
14 | | -Source code is in ``src/`` Tests are in ``tests/``. |
| 24 | +Source code is in the ``src/`` directory, tests are in the ``tests/`` directory. |
| 25 | +Miscellaneous scripts and configuration files are in the ``etc/`` directory. |
15 | 26 |
|
16 | | -There is one Python package for each major feature under ``src/`` and a corresponding directory |
17 | | -with the same name under ``tests`` (but this is not a package by design). |
| 27 | +There is one Python package for each major feature under ``src/`` and a |
| 28 | +corresponding directory with the same name under ``tests`` (but this is not a |
| 29 | +package by design as it would not make sense to have a top level "tests" package |
| 30 | +which is a name that's too common). |
18 | 31 |
|
19 | | -Each test script is named ``test_XXXX`` and while we love to use ``py.test`` as a test runner, |
20 | | -most tests have no dependencies on ``py.test``, only on the ``unittest`` module (with the exception |
21 | | -of some command line tests that depend on pytest monkeypatching capabilities. |
| 32 | +Each test script is named ``test_XXXX``; we prefer organizing tests in subclasses |
| 33 | +of the standard library ``unittest`` module. But we also use plain functions |
| 34 | +that are discovered nicely by ``pytest``. |
22 | 35 |
|
23 | 36 | When source or tests need data files, we store these in a ``data`` subdirectory. |
| 37 | +This is used extensively in tests and also in source code for the reference |
| 38 | +license texts and data and license detection rules files. |
24 | 39 |
|
25 | | -We use PEP8 conventions with a relaxed line length that can be up to 90'ish characters long when |
26 | | -needed to keep the code clear and readable. |
| 40 | +We use PEP8 conventions with a relaxed line length that can be up to 90'ish |
| 41 | +characters long when needed to keep the code clear and readable. |
27 | 42 |
|
28 | | -We store pre-built bundled native binaries in ``bin/`` sub-directories of each ``src/`` packages. |
29 | | -These binaries are organized by OS and architecture. This ensures that ScanCode works out of the box |
30 | | -either using a checkout or a download, without needing a compiler and toolchain to be installed. |
31 | | -The corresponding source code for the pre-built binaries are stored in a separate repository at |
32 | | -https://github.com/nexB/scancode-thirdparty-src. |
| 43 | +We write tests, a lot of tests, thousands of tests. When finding bugs or adding |
| 44 | +new features, we add tests. See existing test code for examples which form also |
| 45 | +a good specification for the supported features. |
33 | 46 |
|
34 | | -We store bundled thirdparty components and libraries in the ``thirdparty`` directory. Python |
35 | | -libraries are stored as wheels, eventually pre-built if the corresponding wheel is not available |
36 | | -in the Pypi repository. Some of these components may be advanced builds with bug fixes or advanced |
37 | | -patches. |
| 47 | +The tests should pass on Linux 64 bits, Windows 64 bits and on |
| 48 | +macOS 10.14 and up. We maintain multiple CI loops with Azure (all OSes) |
| 49 | +at https://dev.azure.com/nexB/scancode-toolkit/_build and Appveyor (Windows) at |
| 50 | +https://ci.appveyor.com/project/nexB/scancode-toolkit . |
38 | 51 |
|
39 | | -We write tests, a lot of tests, thousands of tests. Several tests are data-driven and use data |
40 | | -files as test input and sometimes data files as test expectation (in this case using either |
41 | | -JSON or YAML files). The tests should pass on Linux 64 bits, Windows 32 and 64 bits and on |
42 | | -MacOS 10.9 and up. We maintain two CI loops with Travis (Linux) at |
43 | | -https://travis-ci.org/nexB/scancode-toolkit and Appveyor (Windows) at |
44 | | -https://ci.appveyor.com/project/nexB/scancode-toolkit. |
45 | 52 |
|
46 | | -When finding bugs or adding new features, we add tests. See existing test code for examples. |
| 53 | +Several tests are data-driven and use data files as test input and sometimes |
| 54 | +data files as test expectation (in this case using either JSON or YAML files); |
| 55 | +a large number of copyright, license and package manifest parsing tests are such |
| 56 | +data-driven tests. |
47 | 57 |
|
48 | | -More info: |
49 | 58 |
|
50 | | -- Source code and license datasets are in the /src/ directory. |
51 | | -- Test code and test data are in the /tests/ directory. |
52 | | -- Datasets and test data are in /data/ sub-directories. |
53 | | -- Third-party components are vendored in the /thirdparty/ directory. ScanCode is self contained |
54 | | - and should not require network access for installation or configuration of third-party libraries. |
55 | | -- Additional pre-compiled vendored binaries are stored in bin/ sub-directories of the /src/ |
56 | | - directory with their sources in this repo: https://github.com/nexB/scancode-thirdparty-src/ |
57 | | -- Porting ScanCode to other OS (FreeBSD, etc.) is possible. Enter an issue for help. |
58 | | -- Bugs and pull requests are welcomed. |
59 | | -- See the wiki and CONTRIBUTING.rst for more info. |
60 | 59 |
|
61 | | -.. _scancode_toolkit_developement_running_tests: |
| 60 | +.. _scancode_toolkit_development_running_tests: |
| 61 | + |
62 | 62 |
|
63 | 63 | Running tests |
64 | 64 | ------------- |
65 | 65 |
|
66 | | -ScanCode comes with over 13,000 unit tests to ensure detection accuracy and stability across Linux, |
67 | | -Windows and macOS OSes: we kinda love tests, do we? |
| 66 | +ScanCode comes with over 29,000 unit tests to ensure detection accuracy and |
| 67 | +stability across Linux, Windows and macOS OSes: we kinda love tests, do we? |
68 | 68 |
|
69 | | -We use pytest to run the tests: call the ``py.test`` script to run the whole test suite. This is |
70 | | -installed by ``pytest``, which is bundled with a ScanCode checkout and installed when you |
71 | | -run ``./configure``). |
| 69 | +We use pytest to run the tests: call the ``pytest`` script to run the whole |
| 70 | +test suite. This is installed with the ``pytest`` package which is installed |
| 71 | +when you run ``./configure --dev``). |
72 | 72 |
|
73 | 73 | If you are running from a fresh git clone and you run ``./configure`` and then |
74 | | -``source bin/activate`` the ``py.test`` command will be available in your path. |
| 74 | +``source bin/activate`` the ``pytest`` command will be available in your path. |
75 | 75 |
|
76 | | -Alternatively, if you have already configured but are not in an activated "virtualenv" the |
77 | | -``py.test`` command is available under ``<root of your checkout>/bin/py.test`` |
| 76 | +Alternatively, if you have already configured but are not in an activated |
| 77 | +"virtualenv" the ``pytest`` command is available under |
| 78 | +``<root of your checkout>/bin/pytest`` |
78 | 79 |
|
79 | 80 | (Note: paths here are for POSIX, but mostly the same applies to Windows) |
80 | 81 |
|
81 | | -If you have a multiprocessor machine you might want to run the tests in parallel (and faster) |
82 | | -For instance: ``py.test -n4`` runs the tests on 4 CPUs. We typically run the tests in |
83 | | -verbose mode with ``py.test -vvs -n4``. |
| 82 | +If you have a multiprocessor machine you might want to run the tests in parallel |
| 83 | +(and faster). For instance: ``pytest -n4`` runs the tests on 4 CPUs. We |
| 84 | +typically run the tests in verbose mode with ``pytest -vvs -n4``. |
84 | 85 |
|
85 | 86 | You can also run a subset of the test suite as shown in the CI configs |
86 | 87 | https://github.com/nexB/scancode-toolkit/blob/develop/appveyor.yml#L6 e,g, |
87 | | -``py.test -n 2 -vvs tests/scancode`` runs only the test scripts present in the ``tests/scancode`` |
88 | | -directory. (You can pass a path to a specific test script file there too). |
89 | | - |
90 | | -See also https://docs.pytest.org for details or use the ``py.test -h`` command to show the many |
91 | | -other options available. |
92 | | - |
93 | | -One useful option is to run a select subset of the test functions matching a pattern with the |
94 | | -``-k`` option, for instance: ``py.test -vvs -k tcpdump`` would only run test functions that contain |
95 | | -the string "tcpdump" in their name or their class name or module name . |
96 | | - |
97 | | -Another useful option after a test run with some failures is to re-run only the failed tests with |
98 | | -the ``--lf`` option, for instance: ``py.test -vvs --lf`` would only run only test functions that |
99 | | -failed in the previous run. |
100 | | - |
101 | | -.. _contrib_dev_pip_and_configure: |
102 | | - |
103 | | -pip requirements and the configure script |
104 | | ------------------------------------------ |
105 | | - |
106 | | -ScanCode use the ``configure`` and ``configure.bat`` (and ``etc/configure.py`` behind the scenes) |
107 | | -scripts to install a `virtualenv <https://virtualenv.pypa.io/en/stable/>`_ , install required |
108 | | -packaged dependencies as `pip <https://github.com/pypa/pip>`_ requirements and more configure tasks |
109 | | -such that ScanCode can be installed in a self-contained way with no network connectivity required. |
110 | | - |
111 | | -Earlier unreleased versions of ScanCode where using ``buildout`` to install and configure |
112 | | -eventually complex dependencies. We had some improvements that were merged in the upstream |
113 | | -``buildout`` to support bootstrapping and installing without a network connection and When we |
114 | | -migrated to use ``pip`` and ``wheels`` as new, improved and faster way to install and configure |
115 | | -dependencies we missed some of the features of ``buildout`` like the ``recipes``, being able to |
116 | | -invoke arbitrary Python or shell scripts after installing packages and have scripts or requirements |
117 | | -that are operating system-specific. |
118 | | - |
119 | | -ScanCode requirements and third-party Python libraries |
120 | | ------------------------------------------------------- |
| 88 | +``pytest -n 2 -vvs tests/scancode`` runs only the test scripts present in the |
| 89 | +``tests/scancode`` directory. (You can give the path to a specific test script |
| 90 | +file there too). |
| 91 | + |
| 92 | +See also https://docs.pytest.org for details or use the ``pytest -h`` command |
| 93 | +to show the many other options available. |
| 94 | + |
| 95 | +One useful option is to run a select subset of the test functions matching a |
| 96 | +pattern with the ``-k`` option, for instance: ``pytest -vvs -k tcpdump`` would |
| 97 | +only run test functions that contain the string "tcpdump" in their name or their |
| 98 | +class name or module name. |
| 99 | + |
| 100 | +Another useful option after a test run with some failures is to re-run only the |
| 101 | +failed tests with the ``--lf`` option, for instance: ``pytest -vvs --lf`` would |
| 102 | +only run only test functions that failed in the previous run. |
| 103 | + |
| 104 | +Because we have a lot of tests (over 29,000), we organized theses in test suites |
| 105 | +using pytest markers that are defined in the ``conftest.py`` pytest plugin. |
| 106 | +These are enabled by adding a ``--test-suite`` option to the pytest command. |
| 107 | + |
| 108 | +- ``--test-suite=standard`` is the default and runs a decent but basic test suite |
| 109 | +- ``--test-suite=all`` runs the ``standard`` test and adds a comprehensive test suite |
| 110 | +- ``--test-suite=validate`` runs the ``standra`` and ``all`` test and adds |
| 111 | + extensive data-driven and data validations (for package, copyright and license |
| 112 | + detection) |
| 113 | + |
| 114 | + |
| 115 | + |
| 116 | +.. _scancode_toolkit_development_thirdparty_libraries: |
| 117 | + |
| 118 | +Thirdparty libraries and dependencies management |
| 119 | +----------------------------------------------------- |
| 120 | + |
| 121 | +ScanCode uses the ``configure`` and ``configure.bat`` scripts to install a |
| 122 | +`virtualenv <https://virtualenv.pypa.io/en/stable/>`_ , install required |
| 123 | +packaged dependencies using `setuptools <https://github.com/pypa/setuptools>`_ |
| 124 | +and such that ScanCode can be installed in a repeatable and consistent manner on |
| 125 | +all OSes and Python versions. |
| 126 | + |
| 127 | +For this we maintain a ``setup.cfg`` with our direct dependencies with loose |
| 128 | +minimum version constraints; and we keep pinned exact versions of these |
| 129 | +dependencies in the ``requirements.txt`` and ``requirements-dev.txt`` (for |
| 130 | +testing and development). |
| 131 | + |
| 132 | +Note: we also have a ``setup-mini.cfg`` used to create a ScanCode PyPI package |
| 133 | +with minimal dependencies (and limited features). This is mostly duplicated |
| 134 | +from ``setup.cfg``. |
| 135 | + |
| 136 | +And to ensure that we also all use well known version of the core virtualenv, |
| 137 | +pip, setuptools and wheel libraries, we use the ``virtualenv.pyz`` Python |
| 138 | +zipp app from https://github.com/pypa/get-virtualenv/tree/master/public and |
| 139 | +store it in the Git repo in the ``etc/thirdparty`` directory. |
| 140 | + |
| 141 | +We bundle pre-built bundled native binaries as plugins which are installed as |
| 142 | +wheels. These binaries are organized by OS and architecture; they ensure that |
| 143 | +ScanCode works out of the box either using a checkout or a download, without |
| 144 | +needing a compiler and toolchain to be installed. |
| 145 | + |
| 146 | +The corresponding source code and build scripts for all for the |
| 147 | +pre-built binaries are stored in a separate repository at |
| 148 | +https://github.com/nexB/scancode-plugins |
| 149 | + |
| 150 | +ScanCode app archives should not require network access for installation or |
| 151 | +configuration of its third-party libraries and dependencies. To enable this, |
| 152 | +we store bundled thirdparty components and libraries in the ``thirdparty`` |
| 153 | +directory of released app archives; this is done at build time. |
| 154 | +These dependencies are stored as pre-built wheels. These wheels are sometimes |
| 155 | +built by us when there is no wheel available upstream on PyPI. We store all |
| 156 | +these prebuilt wheels with corresponding .ABOUT and .LICENSE files in |
| 157 | +https://github.com/nexB/thirdparty-packages/tree/main/pypi which is published |
| 158 | +for download at https://thirdparty.aboutcode.org/pypi/ |
| 159 | + |
| 160 | +Because this is used by the configure script, all the thirdparty dependencies |
| 161 | +used in ScanCode MUST be available there first. Therefore adding a new |
| 162 | +dependency means requesting a merge/PR in |
| 163 | +https://github.com/nexB/thirdparty-packages/ first that contains all the |
| 164 | +recursive dependencies. |
| 165 | + |
| 166 | +There are utility scripts in ``etc/release`` that can help with the dependencies |
| 167 | +management process in particular to build or update wheels with native code for |
| 168 | +multiple OSes (Linux, macOS and Windows) and multiple Python versions (3.6+), |
| 169 | +which is not a completely simple operation (and requires eventually 12 wheels |
| 170 | +and one source distribution to be published as we support 3 OSes and 4 Python |
| 171 | +versions). |
121 | 172 |
|
122 | | -In a somewhat unconventional way, all the required libraries are bundled aka. Copied in the repo |
123 | | -itself in the thirdparty/ directory. If ScanCode were only a library it would not make sense. But |
124 | | -it is first an application and having a well defined frozen set of dependent packages is important |
125 | | -for an app. The benefit of this approach (combined with the ``configure`` script) means that a mere |
126 | | -checkout of the repository contains everything needed to run ScanCode except for a |
127 | | -Python interpreter. |
128 | 173 |
|
129 | 174 | Using ScanCode as a Python library |
130 | 175 | ---------------------------------- |
131 | 176 |
|
132 | | -ScanCode can be used alright as a Python library and is available as as a Python wheel in Pypi and |
133 | | -installed with ``pip install scancode-toolkit``. |
| 177 | +ScanCode can be used alright as a Python library and is available as as a |
| 178 | +Python wheel in Pypi and installed with ``pip install scancode-toolkit`` or |
| 179 | +``pip install scancode-toolkit-mini``. |
0 commit comments