CI/CD for Webmin modules and Virtualmin plugins

This thread introduces a new CI/CD pipelines that automate the building and distribution of Webmin modules and Virtualmin plugins.

The discussed system, hosted in the webmin/webmin-ci-cd repository, is designed to produce unstable builds for developers to test the latest updates and pre-release builds for users to try upcoming releases before they are added to stable repositories.

Objective

The goal of this automation is to make building and distributing Webmin modules and Virtualmin plugins easy and reliable, enabling developers and users always have access to the latest updates and features without needing to handle everything manually.

Even though GitHub Actions is used to manage builds, the entire process is handled by custom scripts within this project. These scripts—around 2,500 lines of carefully written and tested Bash code—give us full control over the build process.

This setup isn’t tied to GitHub, making it possible to run the same code seamlessly on other platforms like GitLab or even a local machine, making the system flexible, portable, and easy to migrate without being locked into any single platform.

Design

The repositories design works to make accessing and managing packages as straightforward as possible. Each repository provides a clean, single-page list of built packages, allowing users to download packages manually by simply clicking on the package name. This makes finding and grabbing the package you need quick and easy without navigating through multiple confusing pages and directories.

To support a wide range of systems, the repositories provide packages for all major architectures, including older ones like i386 (i686), popular options like amd64 (x86_64), and the increasingly widespread arm64 (aarch64).

Despite providing a single directory for all architectures, modern package managers like APT and DNF handle this effortlessly, automatically picking the correct package for installation. Since only one package is architecture-dependent, splitting repositories by architecture would add unnecessary complexity without any real advantage.

All repositories and packages are signed with the Webmin Developers signing key, the same one used for standard Webmin installations. This makes configuration straightforward, with just a single repository file and a simple, easy-to-remember URL.

In the unstable repositories, only the latest package versions are kept, with older ones removed on every push. The pre-release repositories, on the other hand, keep all versions so users can go back to older releases if needed.

Versioning

The repositories use a structured versioning system to differentiate between unstable and pre-release packages while maintaining consistency with production repositories.

For unstable repositories, the versioning always follows the full semantic format with three numeric segments separated by periods. The last segment, usually reserved for bug fixes, is replaced with a timestamp in YYYYMMDDHHMM format. This creates a version like 7.30.202501111200, where the timestamp reflects the exact build time.

For pre-release repositories, the package version is derived directly from the module or plugin itself. These versions may use standard versioning, like 7.30.4, or other schemes, such as 3.6, depending on the package.

For RPM-based packages, some include an epoch due to historical reasons. The epoch is consistent with production repositories, providing full compatibility across unstable, pre-release, and production repositories. This consistency allows packages to seamlessly replace one another based solely on their version, regardless of the repository they originate from.

Workflows

Currently, we use GitHub Actions to manage builds, which brings several advantages. As mentioned earlier, we intentionally avoid relying on third-party projects beyond GitHub Actions to keep the build process independent and easily migratable to other platforms if needed.

At the core of the system is a master workflow, which is also stored in webmin/webmin-ci-cd repository. This master workflow is the single source of truth, containing all the logic for builds. There are no additional templates for Webmin modules or Virtualmin plugins, making it straightforward to manage. Any changes to the build process only need to be made in the master workflow.

Each product repository includes a child workflow that reuses the master workflow. The primary role of the child workflow is to define when builds should be triggered, such as on a push to a specific branch or when a release is created. Additionally, the child workflow is responsible for passing repository-specific secrets to the master workflow. This is necessary because, for security reasons, GitHub restricts the sharing of secrets across organizations and user accounts, requiring each child workflow located elsewhere to explicitly set and pass its own secrets.

In some cases, fine-grained tokens are required for builds involving private repositories. For instance, if changes in a public repository rely on a private one, GitHub’s permission model prevents workflows from accessing the private repository unless an additional token with the necessary permissions is provided for cloning the private repository. Conversely, when a workflow is triggered directly by a private repository, GitHub automatically provides an authentication token, making it easy to clone the repository without any additional steps.

Repositories

Webmin unstable repository

  • URL: download.webmin.dev
  • Description:
    • Unstable packages for Webmin and Usermin, including the latest changes to Authentic Theme
    • Built automatically on each push to the master branch of Webmin, Usermin, or Authentic Theme
    • Intended for developers who need early access to the latest code updates

Webmin pre-release repository

  • URL: rc.download.webmin.dev
  • Description:
    • Pre-release packages for Webmin and Usermin, including the latest Authentic Theme release
    • Built automatically when a tagged release is created for Webmin or Usermin
    • Intended for users who want to try upcoming features before the final release

Virtualmin unstable repository

  • URL: software.virtualmin.dev
  • Description:
    • Unstable packages for Virtualmin and its plugins
    • Built automatically on each push to the master branch of Virtualmin or its plugins
    • Intended for developers who need early access to the latest code updates

Virtualmin pre-release repository

  • URL: rc.software.virtualmin.dev
  • Description:
    • Pre-release packages for Virtualmin and its plugins
    • Built automatically when a tagged release is created for any Virtualmin or its plugins
    • Intended for users who want to try upcoming features before the final release

Screenshots

Light pallet

Webmin Development Unstable Repo Screenshot Webmin Development Prerelease Repo Screenshot
Virtualmin Development Unstable Repo Screenshot Virtualmin Development Prerelease Repo Screenshot

Dark pallet

Webmin Development Unstable Repo Screenshot Webmin Development Prerelease Repo Screenshot
Virtualmin Development Unstable Repo Screenshot Virtualmin Development Prerelease Repo Screenshot

Architecture

This is a quick overview of the key files involved in the build process, highlighting their roles, functionality, and purpose.

  • bootstrap.bash — this script bootstraps the build process by downloading and preparing all necessary dependencies and files required for the build. It acts as the single entry point to initiate the build, making it easier to make changes to the project. Additionally, it loads essential environment variables and includes all required functions.

  • environment.bash — this script configures and exports the environment variables needed for the build, some of which are derived from the GitHub Actions workflow. It controls verbosity and determines the build type based on parameters passed by the calling script.

  • functions.bash — this script includes all the functions used throughout the build process, with over two dozen functions.

  • build-product-deb.bash, build-product-rpm.bash, build-module-deb.bash, build-module-rpm.bash — these scripts are designed specifically to handle builds for either a product (e.g., Webmin or Usermin) or a plugin (e.g., Virtualmin GPL, Virtualmin Nginx, Virtualmin AWStats, etc.). They are called directly from the workflow and manage the build process for the respective product or plugin.

  • sync-github-secrets.bash — this script dynamically updates, deletes, or lists GitHub secrets for a given repository or all repositories. It’s especially useful for batch updating secrets across all projects in one go. The script expects a ZIP file containing the secrets, either specified via the ENV_SECRETS_ZIP environment variable or placed in ~/Git/.secrets/gh-secrets.zip file.

    The ZIP file should follow a specific structure where secrets are named using the file format organization__SECRET_NAME.

    For example:

    • webmin__UPLOAD_SSH_DIR: Sets UPLOAD_SSH_DIR secret for webmin organization for all repositories listed in the webmin_repos variable
    • virtualmin__IP_KNOWN_HOSTS: Sets IP_KNOWN_HOSTS secret for virtualmin organization for all repositories listed in the virtualmin_repos variable
  • sign-and-build-repos.bash — this script signs and builds repositories on a remote system. It’s called at the final stage of the workflow, after all packages have been uploaded to the remote server. It’s versatile and can be reused independently.

  • module-groups.txt — this text file defines groups of modules that need to be rebuilt if certain modules are changed. For instance, changes in the Virtualmin GPL module will trigger a rebuild of the Virtualmin Pro package.

  • modules-mapping.txt — this text file provides a mapping between repository names and package names, addressing cases where the package name differs from the repository name. It also allows configuration of the package edition, license type, and other options, such as the package target directory.

  • rpm-modules-epoch.txt — this text file lists the epoch values for each RPM package that needs one.

  • install-ci-cd-repo.sh — this script installs the unstable or prerelease repository on the system, making it simple for developers and users to access the latest packages.

Thank you for reading! If you have any questions, suggestions, or comments, feel free to share them!

6 Likes

Today is an epic day and it will make it easier to get more developers involved.

Related discussion: How to test with the latest Virtualmin code from Git? (CI)

Congrats and thanks!!!

2 Likes

will this give us access to the various xxx.min.css and xxx.min.js SOURCE files?

1 Like

This is very a complete description. Will this be added to docs so it is not lost in the forum?

Its on github. See link.
But a link or replication in docs will help search engines find it.

Awesome, thanks for setting this up!

1 Like

Thanks! You’re most welcome! :blush:

Is this the wrong time to ask for a catalogue of plugins to be on the webmin website similar to how WordPress extensions are listed, I feel this would be a natural next step.

just a thought, and yes I do appreciate this would take time and effort to set up, but I feel it might help external developers feel recognised and motivate to make webmin plugins.

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.

The work has now been fully completed, enabling virtualmin-install.sh to configure multiple branches. By default, the installer always sets up stable software. However, it’s now possible to enable or disable unstable and prerelease repositories during the initial installation or afterward.

The primary change (not yet released to the public) is the introduction of the new --branch or -B flag in the installer. This flag accepts stable (default), unstable and prerelease modes. If the unstable option is selected during the initial installation, the installer will make it explicitly clear that using unstable repositories is highly risky, such as with the following warning:

sh virtualmin-install.sh -B unstable -b LEMP -t micro

Using the prerelease option, as shown below, will show a more moderate notice:

sh virtualmin-install.sh -B prerelease -b LAMP -t nano

Furthermore, if the install script is run with the --setup flag but without the new --branch flag, the setup process will now not only reconfigure the Virtualmin repositories, as before, but also remove all unstable or prerelease repositories, in case they were previously configured. However, if it is run with --branch unstable or --branch prerelease, it will configure corresponding unstable or prerelease repository, for example:

sh virtualmin-install.sh --setup --branch unstable

sh virtualmin-install.sh --setup --branch prerelease

sh virtualmin-install.sh --setup

When using the virtualmin-install.sh script to configure the unstable or prerelease branches, the system will be configured to get access to both Webmin and Virtualmin repositories of the chosen type.

This makes testing or trying new prerelease packages much simpler and more straightforward.

By the way, the unstable and prerelease repositories also support ARM architectures.

If you have any questions, feel free to ask!

2 Likes