diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml new file mode 100644 index 0000000..eb92842 --- /dev/null +++ b/.github/workflows/build-packages.yml @@ -0,0 +1,95 @@ +name: build-packages + +on: + workflow_dispatch: + workflow_call: + push: + paths: + - "files/xfce-winxp-tc.env" + - ".github/workflows/build-packages.yml" + pull_request: + paths: + - "files/xfce-winxp-tc.env" + - ".github/workflows/build-packages.yml" + +jobs: + build-packages: + name: Build xfce-winxp-tc RPMs + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Read xfce-winxp-tc version + id: version + run: | + # shellcheck source=files/xfce-winxp-tc.env + source files/xfce-winxp-tc.env + echo "version=${XFCE_WINXP_TC_VERSION}" >> "$GITHUB_OUTPUT" + echo "XFCE_WINXP_TC_VERSION=${XFCE_WINXP_TC_VERSION}" >> "$GITHUB_ENV" + + - name: Read Fedora version + id: fedora + run: | + echo "version=$(grep 'image-version:' recipes/recipe.yml | awk '{print $2}')" >> "$GITHUB_OUTPUT" + + - name: Set artifact tag + id: tag + run: | + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + echo "tag=pr-${{ github.event.number }}-${{ steps.fedora.outputs.version }}" >> "$GITHUB_OUTPUT" + else + echo "tag=${{ steps.version.outputs.version }}-${{ steps.fedora.outputs.version }}" >> "$GITHUB_OUTPUT" + fi + + - name: Install just + uses: extractions/setup-just@v2 + + - name: Clone xfce-winxp-tc source + run: | + git clone https://github.com/rozniak/xfce-winxp-tc.git vendor/xfce-winxp-tc + cd vendor/xfce-winxp-tc + git checkout "$XFCE_WINXP_TC_VERSION" + + - name: Assert build-deps.txt is up to date + run: just check-build-deps + + - name: Build RPMs + run: just build-rpms + env: + CONTAINER_ENGINE: docker + + - name: Collect RPMs + run: | + mkdir -p rpms + find vendor/xfce-winxp-tc/xptc -name "*.rpm" -path "*/rpm/std/x86_64/fre/*" -exec cp {} rpms/ \; + echo "RPMs collected:" + ls -la rpms/ + if [ -z "$(ls -A rpms/)" ]; then + echo "ERROR: RPM output directory is empty after build" + exit 1 + fi + + - name: Install oras + run: | + ORAS_VERSION="1.2.0" + curl -sSLO "https://github.com/oras-project/oras/releases/download/v${ORAS_VERSION}/oras_${ORAS_VERSION}_linux_amd64.tar.gz" + tar -zxf "oras_${ORAS_VERSION}_linux_amd64.tar.gz" oras + sudo mv oras /usr/local/bin/oras + + - name: Log in to GHCR + run: | + echo "${{ github.token }}" | oras login ghcr.io \ + --username "${{ github.actor }}" \ + --password-stdin + + - name: Push RPMs to GHCR + run: | + cd rpms + oras push \ + "ghcr.io/winblues/xfce-winxp-tc-rpms:${{ steps.tag.outputs.tag }}" \ + --artifact-type application/vnd.bluexp.rpms \ + . diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d8f8d77..b16cc8a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,8 +15,53 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref || github.run_id }} cancel-in-progress: true jobs: + check-changes: + name: Check for xfce-winxp-tc.env changes + runs-on: ubuntu-latest + outputs: + changed: ${{ steps.check.outputs.changed }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Check if xfce-winxp-tc.env changed + id: check + run: | + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + git fetch origin "${{ github.event.pull_request.base.sha }}" --depth=1 2>/dev/null || true + CHANGED=$(git diff --name-only "${{ github.event.pull_request.base.sha }}" HEAD -- files/xfce-winxp-tc.env | wc -l) + elif [[ "${{ github.event_name }}" == "push" ]]; then + BEFORE="${{ github.event.before }}" + if [[ "$BEFORE" == "0000000000000000000000000000000000000000" ]]; then + CHANGED=0 + else + CHANGED=$(git diff --name-only "$BEFORE" "${{ github.sha }}" -- files/xfce-winxp-tc.env | wc -l) + fi + else + # schedule, workflow_dispatch: use already-published artifact + CHANGED=0 + fi + if [[ "$CHANGED" -gt 0 ]]; then + echo "changed=true" >> "$GITHUB_OUTPUT" + else + echo "changed=false" >> "$GITHUB_OUTPUT" + fi + + build-packages: + name: Build xfce-winxp-tc packages + needs: check-changes + if: needs.check-changes.outputs.changed == 'true' + uses: ./.github/workflows/build-packages.yml + permissions: + contents: read + packages: write + build-image: name: Build image + needs: [check-changes, build-packages] + if: ${{ needs.check-changes.result == 'success' && (needs.build-packages.result == 'success' || needs.build-packages.result == 'skipped') }} runs-on: ubuntu-latest permissions: contents: read @@ -40,3 +85,44 @@ jobs: # enabled by default, disable if your image is small and you want faster builds maximize_build_space: true + + smoke-test: + name: Smoke test + needs: build-image + runs-on: ubuntu-latest + if: false + timeout-minutes: 15 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Enable KVM + run: sudo chmod 666 /dev/kvm + + - name: Install prerequisites + run: | + ORAS_VERSION="1.2.0" + curl -LO "https://github.com/oras-project/oras/releases/download/v${ORAS_VERSION}/oras_${ORAS_VERSION}_linux_amd64.tar.gz" + tar -zxf "oras_${ORAS_VERSION}_linux_amd64.tar.gz" + sudo mv oras /usr/local/bin/ + sudo apt-get install -y qemu-system-x86 + + - name: Read Fedora version + id: fedora + run: | + echo "version=$(grep 'image-version:' recipes/recipe.yml | awk '{print $2}')" >> "$GITHUB_OUTPUT" + + - name: Determine image reference + id: image-ref + run: | + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + echo "ref=ghcr.io/winblues/bluexp:pr-${{ github.event.number }}-${{ steps.fedora.outputs.version }}" >> "$GITHUB_OUTPUT" + else + echo "ref=ghcr.io/winblues/bluexp:latest" >> "$GITHUB_OUTPUT" + fi + + - name: Pull image into local storage + run: sudo podman pull "${{ steps.image-ref.outputs.ref }}" + + - name: Run smoke test + run: scripts/smoke-test.sh "${{ steps.image-ref.outputs.ref }}" diff --git a/files/scripts/20-xfce-winxp-tc.sh b/files/scripts/20-xfce-winxp-tc.sh index b4aff86..cc14281 100644 --- a/files/scripts/20-xfce-winxp-tc.sh +++ b/files/scripts/20-xfce-winxp-tc.sh @@ -2,25 +2,17 @@ set -xueo pipefail -# Ideally, we would build and package this outside of the image build process. -# However, it's probably not possible to package this in on Fedora's COPR -# because of licensing concerns with some of the assets -# -# TODO: package this using a separate GitHub repo maybe? +# shellcheck disable=SC1091 +source "${CONFIG_DIRECTORY}/xfce-winxp-tc.env" -dnf5 install -y $(cat packages/xfce-winxp-tc/build-deps.txt) +dnf5 install -y golang-oras -XFCE_WINXP_TC_VERSION="1a2f8d5b1e43bafaa29d95718274f6080ee0908b" +RPM_DIR=$(mktemp -d) +cd "$RPM_DIR" -mkdir -p /tmp/xfce-winxp-tc -cd /tmp/xfce-winxp-tc -git clone https://github.com/rozniak/xfce-winxp-tc.git -cd xfce-winxp-tc -git checkout $XFCE_WINXP_TC_VERSION -bash packaging/buildall.sh +FEDORA_MAJOR_VERSION=$(awk -F= '/^VERSION_ID/ {print $2}' /etc/os-release) +oras pull "ghcr.io/winblues/xfce-winxp-tc-rpms:${XFCE_WINXP_TC_VERSION}-${FEDORA_MAJOR_VERSION}" -rpm-ostree install xptc/*/rpm/std/x86_64/fre/wintc-*.rpm - -# TODO: remove build packages +dnf5 install ./*.rpm plymouth-set-default-theme bootvid diff --git a/files/scripts/90-finalize.sh b/files/scripts/90-finalize.sh index 1164249..cbaacf2 100644 --- a/files/scripts/90-finalize.sh +++ b/files/scripts/90-finalize.sh @@ -4,7 +4,7 @@ set -ouex pipefail update-mime-database /usr/share/mime gdk-pixbuf-query-loaders-64 --update-cache gtk-update-icon-cache /usr/share/icons/hicolor -gtk-update-icon-cache --force --ignore-theme-index /usr/share/icons/luna +#gtk-update-icon-cache --force --ignore-theme-index /usr/share/icons/luna systemctl --global preset-all systemctl preset-all diff --git a/files/scripts/packages/xfce-winxp-tc/Containerfile b/files/scripts/packages/xfce-winxp-tc/Containerfile index 567f350..b7f9308 100644 --- a/files/scripts/packages/xfce-winxp-tc/Containerfile +++ b/files/scripts/packages/xfce-winxp-tc/Containerfile @@ -1,20 +1,4 @@ FROM quay.io/fedora/fedora-toolbox:41 -RUN dnf install -y \ - cmake \ - garcon-devel \ - gcc-g++ \ - gdk-pixbuf2-devel \ - glib2-devel \ - gtk3-devel \ - libcanberra-devel \ - libzip-devel \ - lightdm-gobject-devel \ - NetworkManager-libnm-devel \ - pulseaudio-libs-devel \ - python3-virtualenv \ - rpmdevtools \ - rubygem-sass \ - sqlite-devel \ - upower-devel \ - webkit2gtk4.1-devel \ - xcursorgen +COPY build-deps.txt /tmp/build-deps.txt +RUN dnf install -y cmake gcc-g++ rpmdevtools && \ + xargs dnf install -y < /tmp/build-deps.txt diff --git a/files/scripts/packages/xfce-winxp-tc/build-deps.txt b/files/scripts/packages/xfce-winxp-tc/build-deps.txt index 5ccca7b..f9a4e5c 100644 --- a/files/scripts/packages/xfce-winxp-tc/build-deps.txt +++ b/files/scripts/packages/xfce-winxp-tc/build-deps.txt @@ -1,16 +1,21 @@ -cmake +NetworkManager-libnm-devel garcon-devel -gcc-g++ gdk-pixbuf2-devel +gettext glib2-devel +gstreamer1-devel +gstreamer1-plugins-base-devel gtk3-devel +gtk4-devel libcanberra-devel +libcanberra-gtk3 +libxml2-devel libzip-devel lightdm-gobject-devel -NetworkManager-libnm-devel pulseaudio-libs-devel +python3-packaging +python3-pillow python3-virtualenv -rpmdevtools rubygem-sass sqlite-devel upower-devel diff --git a/files/scripts/packages/xfce-winxp-tc/justfile b/files/scripts/packages/xfce-winxp-tc/justfile index 3f39496..14ba07c 100644 --- a/files/scripts/packages/xfce-winxp-tc/justfile +++ b/files/scripts/packages/xfce-winxp-tc/justfile @@ -1,4 +1,4 @@ -XFCE_WINXP_TC_VERSION := "4f73e4a740041635eecd30abccc2fdafabb21582" +set dotenv-filename := "files/xfce-winxp-tc.env" initialize-workspace: #!/bin/bash @@ -7,7 +7,7 @@ initialize-workspace: cd workspace git clone https://github.com/rozniak/xfce-winxp-tc.git cd xfce-winxp-tc - git checkout {{ XFCE_WINXP_TC_VERSION }} + git checkout "$XFCE_WINXP_TC_VERSION" build-dev-image: diff --git a/files/xfce-winxp-tc.env b/files/xfce-winxp-tc.env new file mode 100644 index 0000000..68f256c --- /dev/null +++ b/files/xfce-winxp-tc.env @@ -0,0 +1 @@ +XFCE_WINXP_TC_VERSION=9c5d28667608f81c5b1d03f5217e77bc69d8b6ec diff --git a/justfile b/justfile index 959767e..7a702fd 100644 --- a/justfile +++ b/justfile @@ -1,8 +1,93 @@ +container_engine := env_var_or_default("CONTAINER_ENGINE", "podman") + build: bluebuild build -B podman --tempdir /var/tmp recipes/recipe.yml +build-rpms: + #!/bin/bash + set -euo pipefail + REPO="vendor/xfce-winxp-tc" + + if [[ ! -d "$REPO" ]]; then + echo "error: ${REPO} not found — clone xfce-winxp-tc there first" >&2 + exit 1 + fi + + source files/xfce-winxp-tc.env + git -C "$REPO" checkout "$XFCE_WINXP_TC_VERSION" + + {{container_engine}} build \ + -f files/scripts/packages/xfce-winxp-tc/Containerfile \ + -t xfce-winxp-tc-dev-image \ + files/scripts/packages/xfce-winxp-tc/ + + cd "$REPO" + {{container_engine}} run --rm \ + --volume "$PWD:/app:Z" \ + --workdir /app \ + xfce-winxp-tc-dev-image \ + bash /app/packaging/buildall.sh + +update-build-deps: + #!/bin/bash + set -euo pipefail + REPO="vendor/xfce-winxp-tc" + DEPMAP="${REPO}/tools/bldutils/depmap/depmap.py" + OUT="files/scripts/packages/xfce-winxp-tc/build-deps.txt" + + if [[ ! -d "$REPO" ]]; then + echo "error: ${REPO} not found — clone xfce-winxp-tc there first" >&2 + exit 1 + fi + + source files/xfce-winxp-tc.env + git -C "$REPO" checkout "$XFCE_WINXP_TC_VERSION" + + while IFS= read -r deps_file; do + dir=$(dirname "$deps_file") + first=$(head -1 "$deps_file") + [[ ! "$first" =~ ^(bt|rt|bt,rt): ]] && deps_file="${dir}/${first}" + python3 "$DEPMAP" "$deps_file" rpm 2>/dev/null || true + done < <(find "$REPO" -name "deps" -not -path "*/.git/*") \ + | grep '^bt:' | sed 's/^bt://' | grep -v '^wintc-' | LC_ALL=C sort -u > "$OUT" + + echo "updated ${OUT}" + +check-build-deps: update-build-deps + #!/bin/bash + set -euo pipefail + if ! git diff --exit-code files/scripts/packages/xfce-winxp-tc/build-deps.txt > /dev/null; then + echo "error: build-deps.txt is out of date — run 'just update-build-deps' and commit the result" >&2 + exit 1 + fi + echo "build-deps.txt is up to date" + test-local: bluebuild rebase --tempdir /var/tmp recipes/recipe.yml +smoke-test: + #!/bin/bash + sudo podman pull ghcr.io/winblues/bluexp:latest + bash scripts/smoke-test.sh ghcr.io/winblues/bluexp:latest + generate-iso: sudo bluebuild generate-iso --iso-name bluexp-latest.iso image ghcr.io/ledif/bluexp:latest + +vm: + #!/bin/bash + mkdir output + sudo podman pull ghcr.io/winblues/bluexp:latest + sudo podman run \ + --rm \ + -it \ + --privileged \ + --pull=newer \ + --security-opt label=type:unconfined_t \ + -v ./config.toml:/config.toml:ro \ + -v ./output:/output \ + -v /var/lib/containers/storage:/var/lib/containers/storage \ + quay.io/centos-bootc/bootc-image-builder:latest \ + --type qcow2 \ + --rootfs xfs \ + --use-librepo=True \ + ghcr.io/winblues/bluexp:latest diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..b5c15eb --- /dev/null +++ b/renovate.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:recommended"], + "customManagers": [ + { + "customType": "regex", + "fileMatch": ["^files/xfce-winxp-tc\\.env$"], + "matchStrings": [ + "XFCE_WINXP_TC_VERSION=(?[a-f0-9]+)" + ], + "depNameTemplate": "xfce-winxp-tc", + "datasourceTemplate": "git-refs", + "packageNameTemplate": "https://github.com/rozniak/xfce-winxp-tc", + "currentValueTemplate": "HEAD" + } + ], + "packageRules": [ + { + "matchPackageNames": ["xfce-winxp-tc"], + "commitMessageTopic": "xfce-winxp-tc", + "commitMessageExtra": "to {{newDigest}}" + } + ] +} diff --git a/scripts/smoke-test.sh b/scripts/smoke-test.sh new file mode 100755 index 0000000..832190e --- /dev/null +++ b/scripts/smoke-test.sh @@ -0,0 +1,114 @@ +#!/bin/bash +set -euo pipefail + +# Usage: smoke-test.sh +# Boots the given bootc container image in QEMU and verifies system health. +IMAGE="${1:?Usage: $0 }" + +WORK_DIR="$(mktemp -d)" +QEMU_PID="" + +cleanup() { + local exit_code=$? + if [[ -n "$QEMU_PID" ]]; then + kill "$QEMU_PID" 2>/dev/null || true + fi + sudo rm -rf "$WORK_DIR" + exit "$exit_code" +} +trap cleanup EXIT + +fail() { + echo "FAIL: $1" + exit 1 +} + +# Generate a throwaway ed25519 SSH keypair for this run +ssh-keygen -t ed25519 -f "${WORK_DIR}/smoke-key" -N "" -C "smoke-test" >/dev/null +PUBKEY="$(cat "${WORK_DIR}/smoke-key.pub")" + +# Write a test-specific bootc-image-builder config with the generated public key +cat > "${WORK_DIR}/config.toml" </dev/null; do + sleep 5 + ELAPSED=$((ELAPSED + 5)) + if [[ $ELAPSED -ge $TIMEOUT ]]; then + fail "SSH unreachable after ${TIMEOUT}s" + fi +done + +echo "SSH reachable after ${ELAPSED}s, checking system health..." + +run_ssh() { + ssh \ + -o StrictHostKeyChecking=no \ + -o ConnectTimeout=10 \ + -o BatchMode=yes \ + -i "${WORK_DIR}/smoke-key" \ + -p 2222 \ + core@localhost \ + "$@" +} + +# Verify overall system state (running or degraded are both acceptable) +SYSTEM_STATUS="$(run_ssh 'systemctl is-system-running' 2>/dev/null || true)" +if [[ "$SYSTEM_STATUS" != "running" && "$SYSTEM_STATUS" != "degraded" ]]; then + fail "systemctl is-system-running returned '${SYSTEM_STATUS}' (expected: running or degraded)" +fi + +# Verify the display manager is active +LIGHTDM_STATUS="$(run_ssh 'systemctl is-active lightdm' 2>/dev/null || true)" +if [[ "$LIGHTDM_STATUS" != "active" ]]; then + fail "lightdm not active (systemctl is-active returned: '${LIGHTDM_STATUS}')" +fi + +echo "PASS"