From 555eaec14e687057c1cd4069bf34e2ba42ca3465 Mon Sep 17 00:00:00 2001 From: Martyn Welch <martyn.welch@collabora.com> Date: Wed, 12 May 2021 09:20:15 +0100 Subject: [PATCH] Rework component guide The workflows in component guide target Apertis maintainers more than developers, it is also out-of-date in some places. Update this guide and make it more relevant to non-maintainers in the process. Signed-off-by: Martyn Welch <martyn.welch@collabora.com> --- content/guides/component_guide.md | 528 ++++++++++++++++---------- static/images/run-pipeline-button.png | Bin 6229 -> 2562 bytes 2 files changed, 320 insertions(+), 208 deletions(-) diff --git a/content/guides/component_guide.md b/content/guides/component_guide.md index be04955b9..ef2556dfc 100644 --- a/content/guides/component_guide.md +++ b/content/guides/component_guide.md @@ -7,102 +7,220 @@ toc = true title = "Adding and Updating Components" +++ -# Apertis Packaging CI - Apertis stores the source of all the shipped packages in GitLab and uses a [GitLab CI pipeline](https://gitlab.apertis.org/infrastructure/ci-package-builder/-/blob/master/ci-package-builder.yml) to manage the workflows and automate many of the tasks that are required to -release a package: +release a package, thus for many tasks such as adding or updating packages, +interaction is only required with GitLab, with automation taking care of the +rest of the process. -* Pull updates from upstream distributions like Debian 10 Buster. -* Test any changes made to development and release branches. -* Push updated sources for release branches that pass testing to OBS. From here, - fresh binary packages will either be built and added to the relevant Debian - repository or snapshot repository, depending on the release state of the - component. +{{% notice info %}} +Please see the [Apertis workflow]({{< ref "workflow-guide.md" >}}) for more +information regarding the automation provided by Apertis. +{{% /notice %}} -## License scans +# Adding new components -As contributors submit merge requests to packaged software, the CI pipeline performs -license scans on those packages, scanning all files in the package, -not just the new submission. The pipeline fails or emits a warning (depending on -the configuration) when it finds files with unknown or unclear licensing terms, -or files under licenses not allowed in the package. When such situation arises, -it is the responsibility of the submitter to perform the review of the license -scan results and make updates to the package if necessary. +The software components used in Apertis images are packaged in the +[`deb` packaging format](https://wiki.debian.org/Packaging), as used by Debian. +It is preferred, where possible, to add additional packages from Debian as +covered by the +[contribution policy]({{< ref "contributions.md#adding-components-to-apertis" >}}). -When the license scan mistakenly identifies a file as being under an incorrect -license, or fails to process it correctly, there are three ways to fix this: +## Adding new packages from Debian - 1. Specify the correct copyright and the license in `debian/apertis/copyright.yml`. - The format of the file is specified in the - [Dpkg::Copyright::Scanner](https://manpages.debian.org/buster/libconfig-model-dpkg-perl/Dpkg::Copyright::Scanner.3pm.en.html) - manpage. - In short, it’s a YAML file mapping paths to their licensing information: +{{% notice info %}} +As the adding of existing Debian packages is mostly scripted/automated it is +expected that such actions will be carried out by maintainers after a request +made in line with the +[contribution policy]({{< ref "contributions.md#adding-components-to-apertis" >}}). +{{% /notice %}} - debian: - copyright: 2015, Marcel - license: Expat - src/: - copyright: 2016, Joe - license: Expat - .*/NOTICE: - skip: 1 - src/garbled/: - 'override-copyright': 2016 Marcel MeXzigue +This is the process to import a new package from Debian to Apertis: - File patterns follow the Perl regular expression rules, and are matched - from the beginning of a path. Patterns are used in the order from the most - specific to the least specific ones. +* Create a folder, in the name of the package to import. + * Eg. for package `hello`, run: - Please also verify `debian/copyright` specifies the correct license, and if it - doesn’t, submit a patch to Debian. + mkdir hello - 2. Add the file to the list of ignored files. - `debian/apertis/copyright.whitelist` is formatted the same way as `gitignore`, - please refer to the [gitignore](https://manpages.debian.org/buster/git-man/gitignore.5.en.html) - manpage for more information. + * chdir to created folder: - 3. If the file is under a license not suitable for Apertis, it can be removed from - the package by either repackaging the tarball or patching it out, in which case - the scanner will not take it into account. + cd hello -The license scanner will store the automatically generated copyright report file -under `debian/apertis/copyright`, updating the merge request when necessary. +* Invoke `import-debian-package` from the + [packaging-tools repository](https://gitlab.apertis.org/infrastructure/packaging-tools/). + To fetch the latest version: -[Dpkg::Copyright::Scanner]: https://manpages.debian.org/testing/libconfig-model-dpkg-perl/Dpkg::Copyright::Scanner.3pm.en.html -[gitignore]: https://manpages.debian.org/testing/git-man/gitignore.5.en.html + import-debian-package --upstream buster --downstream apertis/v2020dev0 --component target --package hello -## Custom pipelines + To fetch a specific version, add the `--version` option: -When using the packaging pipeline, developers cannot put their CI/CD automation -in `.gitlab-ci.yml` anymore, as the CI config path points to the -ci-package-builder definition. + import-debian-package --upstream buster --downstream apertis/v2020dev0 --component target --package hello --version 2.10-2 -However, developers can put their jobs in the -`debian/apertis/local-gitlab-ci.yml` file and have them executed in a child -pipeline whenever the main packaging pipeline is executed. This is especially -handy to run tests before the actual packaging process begins. + * The argument to `--component` reflects the repository component it is part + of (for instance, `target`); it will be stored in + `debian/apertis/component`. + * Multiple downstream branches can be specified, in which case all of them + will be updated to point to the newly imported package version. + * The Apertis version of the package will have a local suffix (`apertis0`) + appended. -{{% notice tip %}} -The instructions below assume an Apertis development enviroment. Either boot -the [Apertis SDK]( {{< ref "virtualbox.md" >}} ) or run the -Apertis `package-source-builder` Docker container: + {{% notice warning %}} + Don't use `import-debian-package` on existing repositories, it does not + attempt to merge `apertis/*` branches and instead it re-sets them to new + branches based on the freshly imported Debian package. + {{% /notice %}} - APERTIS_RELEASE=v2021 - docker pull registry.gitlab.apertis.org/infrastructure/apertis-docker-images/${APERTIS_RELEASE}-package-source-builder - docker run -it --rm --env HOME -w "$(pwd)" -v "$HOME:$HOME" -v "$HOME:/root" --security-opt label=disable registry.gitlab.apertis.org/infrastructure/apertis-docker-images/${APERTIS_RELEASE}-package-source-builder bash +* Create an empty project on GitLab under the `pkg` namespace (for instance, + `pkg/hello`). +* Configure the origin remote on your local git: + + git remote add origin git@gitlab.apertis.org:pkg/hello + +* Push your local git contents to the newly created GitLab project: + + git push --all --follow-tags origin + +* Set it up with `gitlab-rulez` from the + [gitlab-rulez repository](https://gitlab.apertis.org/infrastructure/gitlab-rulez): + + gitlab-rulez apply rulez.yaml --filter pkg/hello + + {{% notice info %}} + This: + - sets the CI config path to + `ci-package-builder.yml@infrastructure/ci-package-builder` + - changes the merge request settings to: + - only allow fast-forward merges + - ensure merges are only allowed if pipelines succeed + - marks the `apertis/*` and `debian/*` branches as protected + {{% /notice %}} + +* As the CI configuration was set by `gitlab-rulez` after the initial commit, + it will be necessary to run the CI/CD pipeline on each `apertis/*` branch to + push the package through to OBS. + + {{% notice warning %}} + Ensure that one branch successfully completes it's upload to OBS before + starting other branches to ensure that the different branches don't conflict + over uploading the tarballs. + {{% /notice %}} + +## Adding new packages from upstream sources + +There are likely to be instances where it is desirable to import the latest +version of a piece of software into Apertis directly from it's original authors +or maintainers. This may be as a result of the software in question not being +packaged by Apertis' default upstream distribution, Debian, or their being a +mismatch between the desired version in the upstream distribution and what is +required for a specific goal. + +{{% notice info %}} +The [Apertis release flow]( {{< ref "release-flow.md#apertis-release-flow" >}}) +stipulates that each Apertis release should include the latest mainline kernel +LTS release. Due to Debian's release cadence being approximately half that of +Apertis', there are 2 Apertis releases for each Debian stable release and no +guarantees that the kernel's packaged for Debian's current stable or in +progress releases will align with Apertis' requirements. As a result it is +expected that Apertis will need to pull from the mainline kernel LTS tree to +satisfy it's requirements. {{% /notice %}} -# Adding new components +{{% notice warning %}} +Such packages will require special attention to assure that they remain +up-to-date with any security releases made by the upstream and updated as and +when apropriate. +{{% /notice %}} -The software components used in Apertis images are packaged in the -[packaging format](https://wiki.debian.org/Packaging) used by Debian. +Unless the imported package can be used as-is without any modification, there +will be a +[patch series]( {{< ref "buildingpatchingandmaintainingtheapertiskernel.md#packaging" >}} ) +that potentially needs tweaking to apply after the update. The workflow set +out below takes this into consideration. + +Below we use the process of importing +[GNU Hello](https://www.gnu.org/software/hello/) application as an example. -## Adding new packages from Scratch +- Using the Gitlab Web UI, create an empty project in your personal area, for + example called `hello`. -To package a component from scratch, Debian provides [a short guide to get -started](https://wiki.debian.org/Packaging/Intro). +- Download the latest release tarball from upstream. At the time of writing + this is [`hello-2.10.tar.gz`](https://ftp.gnu.org/gnu/hello/) for GNU Hello. + +- Extract the tarball and enter the extracted folder + + $ tar xf hello-2.10.tar.gz + $ cd hello-2.10 + +- Create a new git repository and commit the whole source tree; this will + create the `upstream/apertis` branch containing the untouched upstream source + code: + + $ git init + $ git checkout -b upstream/apertis + $ git add . + $ git commit -m "Initial commit of GNU Hello 2.10" + +- Commit the original tarball to the `pristine-lfs` branch: + + $ pristine-lfs commit ../hello-2.10.tar.gz + +- Create the packaging branch for the Apertis version you're targetting, for + example if you are targetting Apertis v2021, create the `apertis/v2021` + branch: + + $ git checkout -b apertis/v2021 + +- Add packaging files and commit them to the packaging branch. + + {{% notice info %}} + Debian packaging is not covered by this document, users interested in that + matter should refer to the + [Debian Packaging Intro](https://wiki.debian.org/Packaging/Intro), + [Debian Policy Manual](https://www.debian.org/doc/debian-policy/) and + [Debian Developer's Reference](https://www.debian.org/doc/manuals/developers-reference/). + {{% /notice %}} + + {{% notice tip %}} + If you are packaging a newer version of a component which is already + available in Debian, starting from the existing Debian packaging may save you + considerable time. + {{% /notice %}} + +- Ensure that the package builds for you locally: + + $ gbp buildpackage -uc -us --git-debian-branch=apertis/v2021 --git-upstream-tree=upstream/apertis + +- Add the Gitlab project you created earlier as the `origin` git remote + (replacing `<username>` with your GitLab username): + + $ git remote add origin git@gitlab.apertis.org:<username>/hello.git + +- Push your branches to the repository: + + $ git push --all --follow-tags origin + +- Setup the repository using `gitlab-rulez` from the + [gitlab-rulez repository](https://gitlab.apertis.org/infrastructure/gitlab-rulez) + (replacing `<username>` with your GitLab username): + + gitlab-rulez apply rulez.yaml --filter <username>/hello + +- As the CI configuration was set by `gitlab-rulez` after the initial commit, + it will be necessary to run the CI/CD pipeline on each `apertis/*` branch to + push the package through to OBS. + + {{% notice warning %}} + Ensure that one branch successfully completes it's upload to OBS before + starting other branches to ensure that the different branches don't conflict + over uploading the tarballs. + {{% /notice %}} + +- If submitting this for inclusion in the Apertis packages (and a version of + this package doesn't exist already in Apertis), ask a maintainer to create an + empty repository under `pkg/`. + +- Submit a merge request to have your package added to the `pkg/` repository. {{% notice tip %}} The VirtualBox-based @@ -111,98 +229,75 @@ all the needed tools installed, providing a reliable, self-contained environment ready to be used. {{% /notice %}} -Once the component has been packaged, its sources can be uploaded to GitLab in -a personal project, such that the developer is free to experiment and iterate -until the component is ready to be submitted to the appropriate GitLab project. -## Adding new packages from Debian +# Updating existing components -This is the process to import a new package from Debian to Apertis: +Once we have components added to Apertis, it is important that we keep them up +to date with any security updates that are made available. -* create a folder, in the name of the package to import. - * Eg. for package `hello`, run: `mkdir hello` - * chdir to created folder: `cd hello` -* invoke `import-debian-package` from the [packaging-tools - repository:](https://gitlab.apertis.org/infrastructure/packaging-tools/) - * fetch a specific version: `import-debian-package --upstream buster --downstream apertis/v2020dev0 --component target --package hello --version 2.10-2` - * fetch the latest version: `import-debian-package --upstream buster --downstream apertis/v2020dev0 --component target --package hello` - * the argument to `--component` reflects the repository component it is part of (for instance, `target`); it will be stored in `debian/apertis/component` - * multiple downstream branches can be specified, in which case all of them - will be updated to point to the newly imported package version - * the Apertis version of the package will have a local suffix (`apertis0`) appended - * don't use `import-debian-package` on existing repositories, it does not - attempt to merge `apertis/*` branches and instead it re-sets them to new - branches based on the freshly imported Debian package -* create an empty project on GitLab under the `pkg/*` namespaces (for instance, `pkg/hello`) -* configure the origin remote on your local git: `git remote add origin git@gitlab.apertis.org:pkg/hello` -* push your local git contents to the newly created GitLab project: `git push --all --follow-tags origin` -* set it up with `gitlab-rulez apply rulez.yaml --filter pkg/hello` from - the [gitlab-rulez repository](https://gitlab.apertis.org/infrastructure/gitlab-rulez) - * sets the CI config path to `ci-package-builder.yml@infrastructure/ci-package-builder` - * changes the merge request settings: - * only allow fast-forward merges - * ensure merges are only allowed if pipelines succeed - * marks the `apertis/*` and `debian/*` branches as protected -* follow the process described in the [section about landing downstream changes - to the main archive](#landing-downstream-changes-to-the-main-archive) above to - publish the package on OBS. +## Updating components from Debian -# Updating existing components +Updates coming from Debian have been automated using a CI/CD pipeline. Such +updates are usually triggered from the +[infrastructure dashboard](https://infrastructure.pages.apertis.org/dashboard/) +but can be manually triggered from the GitLab web UI. -## Pulling updates or security fixes from upstream distributions +{{% notice note %}} +This functionality will only be available to users with sufficient GitLab +privileges to enable them to run CI/CD pipelines. +{{% /notice %}} -Updates coming from upstream can be pulled it by triggering a CI pipeline on a -branches like `debian/buster` or `debian/bullseye`. +To trigger the updates pipeline: +- Navigate to the "Pipelines" page of the component in GitLab. +- Click on the `Run pipeline` button in the top right-hand corner. + +- Select the relevant `debian/*` branch that you would like to update (such as + `debian/bullseye`) under `Run for branch name or tag` and click the `Run + pipeline` button shown on that page. -The pipeline will check the Debian archive for updates, pull them in the +The pipeline will check the Debian archive for updates, pull them in to the `debian/$RELEASE`-like branch (for instance, `debian/bullseye` or `debian/bullseye-security`), try to merge the new contents with the matching -`apertis/*` branches and, if successful, push a -proposed updates branch while creating a Merge Request for each `apertis/*` -branches it should be landed on. - -The upstream update pipeline is usually triggered from -[the infrastructure dashboard](https://infrastructure.pages.apertis.org/dashboard/) -but can be manually triggered from the GitLab web UI by selecting the -`Run Pipeline` button in the `Pipelines` page of each repository under `pkg/*` -and selecting the `debian/bullseye` branch as the reference. +`apertis/*` branches and, if successful, will create a merge request for +each `apertis/*` branch that requires updating. - +## Updating components to a new Debian release +The CI/CD pipeline can also be used to pull in a new release of Debian. If the needed `debian/$RELEASE` branch doesn't exist (for example, there is a `debian/buster` branch but no `debian/bullseye`), the Gitlab Web UI can be used -to create it. In the `Create from` field of the branch creation page, users -should select `debian/${RELEASE-1}`. In this case, the new branch named -`debian/bullseye` will be created from `debian/buster`. - -Reviewers can then force-push to the proposed update branch in the Merge -Request to fixup any issue caused by the automated merge, and ultimately land -the MRs to the `apertis/*` branches. - -In some situations the automated merge machinery may ask to -`PLEASE SUMMARIZE remaining Apertis Changes`, and in that case -reviewers should: -* check out the proposed update branch -* edit the changelog to list **all** the downstream changes the package still - ships compared to the newly merged upstream package and their reason, - describing the purpose of each downstream patch and of any other change - shown by `git diff` against the `debian/*` branch -* amend the merge commit -* force-push to the proposed update branch -* land the associated Merge Requests as described above - -Remember to check that the updated package gets included in the next daily -reference image build and wait for its [QA test -results](https://lavaphabbridge.apertis.org/) to catch regressions timely -and act accordingly. - -## Adding updates from a non-default upstream repository of a distribution - -There are circumstances, when we deviate from the default upstream. This usually happens -when: -* Packages are not available in the default distribution repository -* Packages in the default distribution repository are outdated -* Newer version of package, available in the non-default repository, is needed +to create it: +- Navigate to the `Branches` page and click on the `New branch` button. +- Enter the new branch name as `debian/$RELEASE`, where `$RELEASE` is the new + release name, for example `debian/bullseye`. +- In the `Create from` field select the previous Debian release. For example, + the release that preceeds Debian Bullseye is Buster, so pick `debian/buster`. +- Click the `Create branch` button. + +In some situations manual intervention may be required to tweak the packaging, +patches or the automated merge machinery may ask to `PLEASE SUMMARIZE remaining +Apertis Changes`. When this happens: + +- Check out the proposed update branch. +- If asked to summarize the changes, edit the changelog to list **all** the + downstream changes the package still ships compared to the newly merged + upstream package and their reason, describing the purpose of each downstream + patch and of any other change shown by `git diff` against the `debian/*` + branch. +- Where other issues are found, either modify the packaging data or add/modify + the Apertis patch series to address the issue. +- Amend the merge commit. +- Force-push to the proposed update branch +- If changes beyond summarizing the changelog are made, the update branch + should be reviewed before it is merged. + +## Updating from a non-default upstream repository of a distribution + +There are circumstances, when we deviate from the default upstream. This +usually happens when: +- Packages are not available in the default distribution repository +- Packages in the default distribution repository are outdated +- Newer version of package, available in the non-default repository, is needed For example, Apertis v2020 ships with a newer version of the Linux kernel (5.4.x) than Debian Buster (4.9.x) on which it is based. In such cases, special @@ -304,8 +399,7 @@ such repository, the package was picked from Debian Unstable instead running ./import-tarballs /tmp/pull-updatesywrcg0_m/libgpiod_1.4.1-4.dsc Importing /tmp/pull-updatesywrcg0_m/libgpiod_1.4.1.orig.tar.xz - -## Adding updates from distribution development repositories +## Updating from distribution development repositories This is another scenario, wherein the user may need updates which are not yet released into the Upstream Distributions' repositories. @@ -325,62 +419,7 @@ is not released into any of the Debian releases. In such case, we can try: * Use the `pristine-lfs` tool to import the source package generated from the Debian repository into Apertis packaging repository. Eg. `pristine-lfs import-dsc libgpiod-1.4.2-1.dsc` * Note: The `import-dsc` subcommand imports the new tarball into the git repository and commits it to the `pristine-lfs` branch. While a user can commit to the branch manually by-hand, we recommend the use of `import-dsc` to import new tarballs and committing them to the packaging repository -## Maintaining package from upstream sources - -There are likely to be instances where it is desirable to import the latest version of a piece of software into Apertis directly from it's original authors or maintainers. -This may be as a result of the software in question not being packaged by Apertis' default upstream distribution, Debian, or their being a mismatch between the desired version in the upstream distribution and what is required for a specific goal. - -The [Apertis release flow]( {{< ref "release-flow.md#apertis-release-flow" >}} ) stipulates that each Apertis release should include the latest mainline kernel LTS release. -Due to Debian's release cadence being approximately half that of Apertis', there are 2 Apertis' releases for each Debian stable release and no guarantees that the kernel's packaged for Debian's current stable or in progress releases will align with Apertis' requirements. -As a result Apertis will need to pull from the mainline kernel LTS tree to satisfy it's requirements. - -Such packages will require special attention to assure that they remain up-to-date with any security releases made by the upstream and updated as and when apropriate. - -Unless the imported package can be used as-is without any modification, there will be a [patch series]( {{< ref "buildingpatchingandmaintainingtheapertiskernel.md#packaging" >}} ) that potentially needs tweaking to apply after the update. -The workflow set out below takes this into consideration. - -Below we use the process of importing the Linux kernel for `v2020` as an example, where we track the `linux-5.4.y` stable branch: - -- Using the Gitlab Web UI, create an empty project under `pkg/`, for example, `pkg/linux`. - -- Download the latest release tarball from upstream. For the `linux-5.4.y` stable branch, it would be `linux-5.4.115.tar.xz` from [kernel.org](https://www.kernel.org/) at the time of this writing. - -- Extract the tarball and enter the extracted folder - - $ tar xf linux-5.4.114.tar.xz - $ cd linux-5.4.114 - -- Create a new git repository and commit the whole source tree; this will create the `upstream/apertis` branch containing the untouched upstream source code: - - $ git init - $ git checkout -b upstream/apertis - $ git add . - $ git commit - -- Commit the original tarball to the `pristine-lfs` branch: - - $ pristine-lfs commit ../linux-5.4.114.tar.xz - -- Create the packaging branch for the Apertis version you're targetting and add packaging files - -{{% notice info %}} -Debian packaging is not covered by this document, users interested in that matter -should refer to the [Debian Policy Manual](https://www.debian.org/doc/debian-policy/) -and [Debian Developer's Reference](https://www.debian.org/doc/manuals/developers-reference/). -{{% /notice %}} - -- Add the Gitlab project you created earlier as the `origin` git remote: - - $ git remote add origin git@gitlab.apertis.org:pkg/linux.git - -- Push your branches to the repository: - - $ git push --all --follow-tags origin - -- Setup the repository as instructed in the [Adding new packages from Debian](#adding-new-packages-from-debian) section: - - $ gitlab-rulez apply rulez.yaml --filter pkg/linux - +## Updating a package from upstream sources You can then subsequently update this package by following these steps: - Using the GitLab web UI, check to ensure that the relevant update branch exists, in the case of the Apertis `v2020` release, kernel updates should be made on the `apertis/v2020-security` branch. Create the required branch if it doesn't exist. @@ -688,3 +727,76 @@ Note that `dpkg` considers `2020.0` to be newer than `2020pre.0`, so the Apertis release identifiers can be used with no modification (if in doubt, check with `dpkg --compare-versions 2020pre.0 '<<' 2020.0 && echo ok`). +# Potential issues + +## License scans + +As merge requests to packaged software are submitted, the CI pipeline performs +license scans on the package. The scans are performed on all files in the package, +not just the new submission. The pipeline fails or emits a warning (depending on +the configuration) when if finds files with unknown or unclear licensing terms, +or files under licenses not allowed in the package. When such situation arises, +it is the responsibility of the submitter to perform the review of the license +scan results and make updates to the package if necessary. + +When the license scan mistakenly identifies a file as being under an incorrect +license, or fails to process it correctly, there are three ways to fix this: + + 1. Specify the correct copyright and the license in `debian/apertis/copyright.yml`. + The format of the file is specified in the + [Dpkg::Copyright::Scanner](https://manpages.debian.org/buster/libconfig-model-dpkg-perl/Dpkg::Copyright::Scanner.3pm.en.html) + manpage. + In short, it’s a YAML file mapping paths to their licensing information: + + debian: + copyright: 2015, Marcel + license: Expat + src/: + copyright: 2016, Joe + license: Expat + .*/NOTICE: + skip: 1 + src/garbled/: + 'override-copyright': 2016 Marcel MeXzigue + + Patterns follow the Perl regular expression rules. + + Please also verify `debian/copyright` specifies the correct license, and if it + doesn’t, submit a patch to Debian. + + 2. Add the file to the list of ignored files. + `debian/apertis/copyright.whitelist` is formatted the same way as `gitignore`, + please refer to the [gitignore](https://manpages.debian.org/buster/git-man/gitignore.5.en.html) + manpage for more information. + + 3. If the file is under a license not suitable for Apertis, it can be removed from + the package by either repackaging the tarball or patching it out, in which case + the scanner will not take it into account. + +The license scanner will store the automatically generated copyright report file +under `debian/apertis/copyright`, updating the merge request when necessary. + +[Dpkg::Copyright::Scanner]: https://manpages.debian.org/testing/libconfig-model-dpkg-perl/Dpkg::Copyright::Scanner.3pm.en.html +[gitignore]: https://manpages.debian.org/testing/git-man/gitignore.5.en.html + +## Custom pipelines + +When using the packaging pipeline, developers cannot put their CI/CD automation +in `.gitlab-ci.yml` anymore, as the CI config path points to the +ci-package-builder definition. + +However, developers can put their jobs in the +`debian/apertis/local-gitlab-ci.yml` file and have them executed in a child +pipeline whenever the main packaging pipeline is executed. This is specially +handy to run tests before the actual packaging process begins. + +{{% notice tip %}} +The instructions below assume an Apertis development enviroment. Either boot +the [Apertis SDK]( {{< ref "virtualbox.md" >}} ) or run the +Apertis `package-source-builder` Docker container: + + APERTIS_RELEASE=v2021 + docker pull registry.gitlab.apertis.org/infrastructure/apertis-docker-images/${APERTIS_RELEASE}-package-source-builder + docker run -it --rm --env HOME -w "$(pwd)" -v "$HOME:$HOME" -v "$HOME:/root" --security-opt label=disable registry.gitlab.apertis.org/infrastructure/apertis-docker-images/${APERTIS_RELEASE}-package-source-builder bash +{{% /notice %}} + diff --git a/static/images/run-pipeline-button.png b/static/images/run-pipeline-button.png index 36f707d5d295e32297b8827540f4466e29642455..8b6fd4b127c09e2b7cef5dcdfb4f74037250c031 100644 GIT binary patch literal 2562 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 Y2Q!j=IsXuC;Q#;t07*qoM6N<$f`Y}x0RR91 literal 6229 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 -- GitLab