# Cross-Platform GitHub Action
I would like to announce the first version of a project I've been
working on for a while. It's not anything D specific or
implemented in D, but it can be used with D projects. This
project provides a GitHub action for running GitHub Action
workflows on multiple platforms. This includes platforms that
GitHub Actions don't natively support. It currently supports
FreeBSD and OpenBSD.
https://github.com/cross-platform-actions/action
## Features
Some of the features that are supported include:
* Multiple operating system with one single action
* Multiple versions of each operating system
* Allows to use default shell or Bash shell
* Low boot overhead
* Fast execution
Compared to
[vmactions/freebsd-vm](https://github.com/vmactions/freebsd-vm),
the boot time is around a fifth and the full execution time for
the same job is around half of freebsd-vm.
## Usage
Here's a sample workflow file which will setup a matrix resulting
in two jobs.
One which will run on FreeBSD 12.2 and one which runs on OpenBSD
6.8.
```yaml
name: CI
on: [push]
jobs:
test:
runs-on: macos-10.15
strategy:
matrix:
os:
- name: freebsd
version: 12.2
- name: openbsd
version: 6.8
steps:
- uses: actions/checkout@v2
- name: Test on ${{ matrix.os.name }}
uses: cross-platform-actions/action@v0.0.1
env:
MY_ENV1: MY_VALUE1
MY_ENV2: MY_VALUE2
with:
environment_variables: MY_ENV1 MY_ENV2
operating_system: ${{ matrix.os.name }}
version: ${{ matrix.os.version }}
shell: bash
run: |
uname -a
echo $SHELL
pwd
ls -lah
whoami
env | sort
```
I've been using this action for one of my own projects
([DLP](https://github.com/jacob-carlborg/dlp/runs/2759807903))
for now close to a week and it works fine. It's mostly FreeBSD
that has been tested.
If you're interested in how the sausage is made, read on. Also
see the readmes of the builder repositories:
https://github.com/cross-platform-actions/freebsd-builder
https://github.com/cross-platform-actions/openbsd-builder
## Under the Hood
GitHub Actions currently only support the following platforms:
macOS, Linux and
Windows. To be able to run other platforms, this GitHub action
runs the commands
inside a virtual machine (VM). macOS is used as the host platform
because it
supports nested virtualization.
The VMs run on the [xhyve][xhyve] hypervisor, which is built on
top of Apple's
[Hypervisor][hypervisor_framework] framework. The Hypervisor
framework allows
to implement hypervisors with support for hardware acceleration
without the
need for kernel extensions. xhyve is a lightweight hypervisor
that boots the
guest operating systems quickly and requires no dependencies
outside of what's
provided by the system.
The VM images running inside the hypervisor are built using
[Packer][packer].
It's a tool for automatically creating VM images, installing the
guest
operating system and doing any final provisioning.
The GitHub action uses SSH to communicate and execute commands
inside the VM.
It uses [rsync][rsync] to share files between the guest VM and
the host. xhyve
does not have any native support for sharing files. To
authenticate the SSH
connection a unique key pair is used. This pair is generated each
time the
action is run. The public key is added to the VM image and the
private key is
stored on the host. Since xhyve does not support file sharing, a
secondar hard
drive, which is backed by a file, is created. The public key is
stored on this
hard drive, which is then mounted by the VM. At boot time, the
secondary hard
drive will be identified and the public key will be copied to the
appropriate
location.
To reduce the time it takes for the GitHub action to start
executing the
commands specified by the user, it aims to boot the guest
operating systems as
fast as possible. This is achieved in a couple of ways:
* By downloading [resources][resources], like xhyve and a few
other tools,
instead of installing them through a package manager
* No compression is used for the resources that are downloaded.
The size is
small enough anyway and it's faster to download the
uncompressed data than
it is to download compressed data and then uncompress it.
* It leverages `async`/`await` to perform tasks asynchronously.
Like
downloading the VM image and other resources at the same time
* It performs as much as possible of the setup ahead of time when
the VM image
is provisioned
[xhyve]: https://github.com/machyve/xhyve
[hypervisor_framework]:
https://developer.apple.com/library/mac/documentation/DriversKernelHardware/Reference/Hypervisor/index.html
[rsync]: https://en.wikipedia.org/wiki/Rsync
[resources]: https://github.com/cross-platform-actions/resources
[packer]: https://www.packer.io
[openbsd_builder]:
https://github.com/cross-platform-actions/openbsd-builder
[freebsd_builder]:
https://github.com/cross-platform-actions/freebsd-builder