diff --git a/.github/workflows/build-composite.yml b/.github/workflows/build-composite.yml new file mode 100644 index 0000000..1443939 --- /dev/null +++ b/.github/workflows/build-composite.yml @@ -0,0 +1,224 @@ +name: "BlueBuild" +description: "Build a custom OS image" +inputs: + recipe: + description: | + The [recipe](https://blue-build.org/reference/recipe/) file to build the image from, relative to the `config/` or `recipes/` directory. + required: true + default: "recipe.yml" + cosign_private_key: + description: | + The Sigstore/cosign secret used to sign the image. + + Example: `${{ secrets.SIGNING_SECRET }}` + required: true + registry_token: + description: | + The token used to sign into the container registry. + + Example: `${{ github.token }}` + required: false + default: "" + registry_username: + description: | + The username used to sign into the container registry. + required: false + default: ${{ github.repository_owner }} + pr_event_number: + description: | + The event number used to tag images pushed from pull requests. + + Example: `${{ github.event.number }}` + required: true + maximize_build_space: + description: | + Whether to run the unwanted software remover to maximize build space in the GitHub builder. + Disable this with 'false' if your image doesn't take up a lot of space and you'd rather have shorter build times. + required: false + default: "true" + use_unstable_cli: + description: | + If true, this action pulls the `main` branch of blue-build/cli instead of the stable version the current action version is configured to use by default. + This feature is useful for testing new features, but should not be used in production. + Input must match the string 'true' for the unstable version to be used. + required: false + default: "false" + cli_version: + description: | + Set this with a tag, sha, or branch name for the blue-build/cli repo to use that particular version of the CLI tool. This will override the `use_unstable_cli` input for the action. + required: false + registry: + description: | + The container registry to push the built image to. + required: false + default: "ghcr.io" + registry_namespace: + description: | + The namespace on the registry to push to. + + Example: `ublue-os` + required: false + default: ${{ github.repository_owner }} + rechunk: + description: | + Rechunk the ostree-based result images with [github.com/hhd-dev/rechunk](https://github.com/hhd-dev/rechunk) for more efficient diffs and updates. (lower image size, better download speed, better update resuming) + + Will make your builds considerably slower. This is an experimental option, as it can cause issues with file permissions in some scenarios, so enable on your own risk. + + Internally builds squashed images with podman to further reduce the image size. + required: false + default: "false" + use_cache: + description: | + Make use of layer cache by pushing the layers to the registry. Input must match the string 'true' for the step to be enabled. + required: false + default: "true" + squash: + description: | + Uses buildah to squash the build's layers into a single layer. Use of this option + disables cache. Conflicts with adding `--build-driver` or `--squash` to the build opts. + required: false + default: "false" + build_opts: + description: | + Provide options to the call to the BlueBuild CLI build command. If you use this with + the squash input set to true and provide either of the `--build-driver` or `--squash` flags + an error will occur and the action will not run. + required: false + default: " " + working_directory: + description: | + Changes working directory for whole build. + For example, setting this to `./abc/` would cause for the recipe to be read from `./abc/recipes/recipe.yml`. + required: false + default: ./ + skip_checkout: + description: | + Set to true to skip doing the actions/checkout step. + This allows you to checkout manually before calling bluebuild/github-action + and to modify files (such as supplying build information to other scripts) before building. + required: false + default: "false" + +runs: + using: "composite" + steps: + - name: Validate inputs + shell: bash + run: "${{ github.action_path }}/build_opts_check.sh" + env: + SQUASH_INPUT_VALUE: "${{ inputs.squash }}" + BUILD_OPTS: "${{ inputs.build_opts }}" + # building custom images might take a lot of space, + # so it's best to remove unneeded softawre + - name: Maximize build space + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + if: ${{ inputs.maximize_build_space == 'true' }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@18ce135bb5112fa8ce4ed6c17ab05699d7f3a5e0 # v3.11.0 + if: ${{ inputs.squash != 'true' && inputs.rechunk != 'true' }} + with: + install: true + driver: docker-container + cache-binary: ${{ inputs.use_cache }} + + - name: Get Ubuntu version + id: ubuntu_version + shell: bash + run: | + VERSION=$(awk -F= '/^VERSION_ID=/ {gsub(/"/, "", $2); print $2}' /etc/os-release) + echo "Ubuntu version is $VERSION" + echo "version=$VERSION" >> $GITHUB_OUTPUT + + # that is compatible with BlueBuild + - name: Setup Podman + if: ${{ (inputs.squash == 'true' || inputs.rechunk == 'true') && steps.ubuntu_version.outputs.version == '22.04' }} + shell: bash + run: | + # from https://askubuntu.com/questions/1414446/whats-the-recommended-way-of-installing-podman-4-in-ubuntu-22-04 + ubuntu_version='22.04' + key_url="https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/unstable/xUbuntu_${ubuntu_version}/Release.key" + sources_url="https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/unstable/xUbuntu_${ubuntu_version}" + echo "deb $sources_url/ /" | sudo tee /etc/apt/sources.list.d/devel-kubic-libcontainers-unstable.list + curl -fsSL $key_url | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/devel_kubic_libcontainers_unstable.gpg > /dev/null + sudo apt-get update + sudo apt-get install -y podman + + - uses: sigstore/cosign-installer@sigstore/cosign-installer # v3.9.0 + with: + install-dir: /usr/bin + use-sudo: true + + # clones user's repo + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + if: ${{ inputs.skip_checkout == 'false' }} + + - name: Determine Vars + id: build_vars + shell: bash + env: + RECIPE: ${{ inputs.recipe }} + run: | + if [[ "${{ inputs.use_unstable_cli }}" == "true" && -z "${{ inputs.cli_version }}" ]]; then + CLI_VERSION_TAG="main" + elif [ -n "${{ inputs.cli_version }}" ]; then + CLI_VERSION_TAG="${{ inputs.cli_version }}" + else + CLI_VERSION_TAG="v0.9" + fi + echo "cli_version=${CLI_VERSION_TAG}" >> ${GITHUB_OUTPUT} + + RECIPE_PATH="" + if [ -f "./config/${RECIPE}" ]; then + RECIPE_PATH="./config/${RECIPE}" + else + RECIPE_PATH="./recipes/${RECIPE}" + fi + echo "recipe_path=${RECIPE_PATH}" >> ${GITHUB_OUTPUT} + + - name: Install BlueBuild + shell: bash + env: + CLI_VERSION_TAG: ${{ steps.build_vars.outputs.cli_version }} + run: | + sudo docker create \ + --name blue-build-installer \ + ghcr.io/blue-build/cli:${{ env.CLI_VERSION_TAG }}-installer + sudo docker cp blue-build-installer:/out/bluebuild /usr/bin/bluebuild + sudo docker rm blue-build-installer + bluebuild --version + + # blue-build/cli does the heavy lifting + - name: Build Image + shell: bash + working-directory: ${{ inputs.working_directory }} + env: + COSIGN_PRIVATE_KEY: ${{ inputs.cosign_private_key }} + GH_TOKEN: ${{ inputs.registry_token }} + BB_PASSWORD: ${{ inputs.registry_token }} + BB_USERNAME: ${{ inputs.registry_username }} + BB_REGISTRY: ${{ inputs.registry }} + BB_REGISTRY_NAMESPACE: ${{ inputs.registry_namespace }} + GH_PR_EVENT_NUMBER: ${{ inputs.pr_event_number }} + BB_CACHE_LAYERS: ${{ inputs.use_cache }} + RECIPE_PATH: ${{ steps.build_vars.outputs.recipe_path }} + RUST_LOG_STYLE: always + CLICOLOR_FORCE: "1" + BUILD_OPTS: ${{ inputs.build_opts }} + run: | + if [ "${{ inputs.squash }}" = "true" ]; then + BUILD_OPTS="--build-driver podman --squash $BUILD_OPTS" + fi + + RUN_SUDO="" + if [ "${{ inputs.rechunk }}" = "true" ]; then + RUN_SUDO=1 + BUILD_OPTS="--rechunk $BUILD_OPTS" + fi + + if [ -n "$RUN_SUDO" ]; then + sudo -E bluebuild build -v --push ${BUILD_OPTS} ${RECIPE_PATH} + else + bluebuild build -v --push ${BUILD_OPTS} ${RECIPE_PATH} + fi \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b51e455..5fbb9f0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,27 +18,80 @@ on: jobs: bluebuild: name: Build Custom Image - runs-on: ubuntu-latest + runs-on: fedora-latest permissions: contents: read packages: write id-token: write strategy: - fail-fast: false # stop GH from cancelling all matrix builds if one fails matrix: recipe: - # !! Add your recipes here - recipe.yml steps: - # the build is fully handled by the reusable github action - - name: Build Custom Image - uses: blue-build/github-action@v1.8 + - name: Install required packages + shell: bash + run: | + sudo dnf install -y nodejs docker-cli docker-buildx containerd + + - uses: sigstore/cosign-installer@v3.9.0 with: - recipe: ${{ matrix.recipe }} - cosign_private_key: ${{ secrets.SIGNING_SECRET }} - registry: 'git.hydrosaber.com' - registry_token: ${{ secrets.PACKAGE_BUILDER_TOKEN }} - pr_event_number: ${{ github.event.number }} + install-dir: /usr/bin + use-sudo: true - # enabled by default, disable if your image is small and you want faster builds - maximize_build_space: true + # clones user's repo + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Determine Vars + id: build_vars + shell: bash + env: + RECIPE: ${{ matrix.recipe }} + run: | + if [[ "${{ inputs.use_unstable_cli }}" == "true" && -z "${{ inputs.cli_version }}" ]]; then + CLI_VERSION_TAG="main" + elif [ -n "${{ inputs.cli_version }}" ]; then + CLI_VERSION_TAG="${{ inputs.cli_version }}" + else + CLI_VERSION_TAG="v0.9" + fi + echo "cli_version=${CLI_VERSION_TAG}" >> ${GITHUB_OUTPUT} + + RECIPE_PATH="" + if [ -f "./config/${RECIPE}" ]; then + RECIPE_PATH="./config/${RECIPE}" + else + RECIPE_PATH="./recipes/${RECIPE}" + fi + echo "recipe_path=${RECIPE_PATH}" >> ${GITHUB_OUTPUT} + + - name: Install BlueBuild + shell: bash + env: + CLI_VERSION_TAG: ${{ steps.build_vars.outputs.cli_version }} + run: | + sudo docker create \ + --name blue-build-installer \ + ghcr.io/blue-build/cli:${{ env.CLI_VERSION_TAG }}-installer + sudo docker cp blue-build-installer:/out/bluebuild /usr/bin/bluebuild + sudo docker rm blue-build-installer + bluebuild --version + + # blue-build/cli does the heavy lifting + - name: Build Image + shell: bash + working-directory: ${{ inputs.working_directory }} + env: + COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }} + GH_TOKEN: ${{ secrets.PACKAGE_BUILDER_TOKEN }} + BB_PASSWORD: ${{ inputs.registry_token }} + BB_USERNAME: ${{ github.repository_owner }} + BB_REGISTRY: 'git.hydrosaber.com' + BB_REGISTRY_NAMESPACE: ${{ github.repository_owner }} + GH_PR_EVENT_NUMBER: ${{ github.event.number }} + BB_CACHE_LAYERS: false + RECIPE_PATH: ${{ steps.build_vars.outputs.recipe_path }} + RUST_LOG_STYLE: always + CLICOLOR_FORCE: "1" + RUST_BACKTRACE: "full" + run: | + sudo -E bluebuild build -v --push ${RECIPE_PATH} \ No newline at end of file