diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 6784fe8b3..674222fd2 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -7,10 +7,17 @@ on: pull_request: branches: - '**' + release: + types: [published] + workflow_dispatch: permissions: contents: read +env: + # How many builds of each package stay in the published index. + KEEP_VERSIONS: 3 + jobs: rpm_test_build: runs-on: ubuntu-latest @@ -47,6 +54,382 @@ jobs: - name: Build image based on Debian 13 run: docker build -t sems_deb13 -f Dockerfile-debian13 . + - name: Build image based on Ubuntu 22.04 + run: docker build -t sems_ubuntu2204 -f Dockerfile-ubuntu22.04 . + + - name: Build image based on Ubuntu 24.04 + run: docker build -t sems_ubuntu2404 -f Dockerfile-ubuntu24.04 . + + list_deb_dockerfiles: + name: Discover Debian/Ubuntu Dockerfiles + if: github.event_name == 'release' || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set.outputs.matrix }} + version: ${{ steps.ver.outputs.version }} + steps: + - uses: actions/checkout@v5 + - id: set + run: | + python3 <<'PY' + import glob, json, os, re + files = sorted( + glob.glob("Dockerfile-debian[0-9]*") + + glob.glob("Dockerfile-ubuntu*") + ) + include = [] + for f in files: + distro = f.replace("Dockerfile-", "") + # debian12 -> debian:12, ubuntu22.04 -> ubuntu:22.04, so the + # verify job installs into the matching base image. + match = re.match(r"(debian|ubuntu)(.+)", distro) + if not match: + raise SystemExit(f"cannot derive a base image from {distro}") + include.append({"dockerfile": f, "distro": distro, + "image": f"{match.group(1)}:{match.group(2)}"}) + if not include: + raise SystemExit("no Dockerfile-debian* / Dockerfile-ubuntu* found") + print("distros:", ", ".join(row["distro"] for row in include)) + matrix = json.dumps({"include": include}, separators=(",", ":")) + with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh: + fh.write(f"matrix={matrix}\n") + PY + + # Computed once here so all five suites and the verify job agree. + # A release publishes its tag as the package version. Anything else is a + # snapshot and gets +ci, which sorts above the release it was + # built from and below the next one - apt compares version strings only, + # so two builds sharing a version would be indistinguishable to clients. + - id: ver + run: | + set -eu + tag="${{ github.event.release.tag_name }}" + if [ -n "$tag" ]; then + # Releases are often tagged v2.1.0; a Debian version has to start + # with a digit, and the packaging is 3.0 (native), so it cannot + # carry a revision either. + version="${tag#v}" + case "$version" in + [0-9]*) ;; + *) echo "::error::release tag '$tag' does not start with a digit"; exit 1 ;; + esac + case "$version" in + *-*) echo "::error::release tag '$tag' has a revision, but the packaging is 3.0 (native)"; exit 1 ;; + esac + else + version="$(cat VERSION)+ci${{ github.run_number }}" + fi + echo "version=${version}" >> "$GITHUB_OUTPUT" + echo "package version: ${version}" + + apt_build: + name: apt ${{ matrix.distro }} + if: github.event_name == 'release' || github.event_name == 'workflow_dispatch' + needs: list_deb_dockerfiles + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.list_deb_dockerfiles.outputs.matrix) }} + steps: + - uses: actions/checkout@v5 + + - name: Build ${{ matrix.dockerfile }} + run: | + docker build -t "sems-${{ matrix.distro }}" \ + --build-arg "PKG_VERSION=${{ needs.list_deb_dockerfiles.outputs.version }}" \ + -f "${{ matrix.dockerfile }}" . + + - name: Extract .deb packages + run: | + mkdir -p debs + docker run --rm --entrypoint bash \ + -v "$PWD/debs:/out" "sems-${{ matrix.distro }}" \ + -lc 'cp -a /debs/*.deb /out/' + + - uses: actions/upload-artifact@v4 + with: + name: sems-${{ matrix.distro }}-debs + path: debs/*.deb + if-no-files-found: error + + apt_assemble: + name: Assemble apt repo + if: always() && !cancelled() && (github.event_name == 'release' || github.event_name == 'workflow_dispatch') + needs: apt_build + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v4 + with: + pattern: sems-*-debs + path: collected + + - name: Build per-distro apt indexes + run: | + sudo apt-get update + sudo apt-get install -y dpkg-dev apt-utils + mkdir -p apt-repo + # Where the current tree is published, so this run can carry it forward. + repo="${{ github.repository }}" + published="https://${{ github.repository_owner }}.github.io/${repo#*/}" + # Debug symbols are ~90% of the payload; they stay in the artifacts + # but never reach the published index. + is_debug() { case "${1##*/}" in *-dbg_*|*-dbgsym_*) return 0 ;; esac; return 1; } + found=0 + for dir in collected/sems-*-debs; do + [ -d "$dir" ] || continue + distro="${dir#collected/sems-}" + distro="${distro%-debs}" + dest="apt-repo/${distro}" + mkdir -p "$dest" + for deb in "$dir"/*.deb; do + if is_debug "$deb"; then continue; fi + cp -a "$deb" "$dest"/ + done + # Carry the already published packages forward so a client can pin + # or roll back; the Pages deploy replaces the tree wholesale, so + # anything not re-uploaded here disappears from the index. + if curl -fsSL "${published}/${distro}/Packages" -o prev-Packages; then + awk '/^Filename: /{print $2}' prev-Packages | while read -r rel; do + if is_debug "$rel"; then continue; fi + [ -e "$dest/${rel##*/}" ] && continue + curl -fsSL "${published}/${distro}/${rel#./}" \ + -o "$dest/${rel##*/}" || rm -f "$dest/${rel##*/}" + done + rm -f prev-Packages + else + echo "no published tree at ${published}/${distro} yet" + fi + + # Keep the newest few versions of each package, dropping the rest. + python3 - "$dest" "$KEEP_VERSIONS" <<'PRUNE' + import functools, os, subprocess, sys + dest, keep = sys.argv[1], int(sys.argv[2]) + groups = {} + for f in os.listdir(dest): + if not f.endswith(".deb"): + continue + name, version, _ = f[:-4].split("_", 2) + groups.setdefault(name, []).append((version, f)) + def newest_first(a, b): + for rel, result in (("gt", -1), ("lt", 1)): + if subprocess.run(["dpkg", "--compare-versions", a[0], rel, b[0]]).returncode == 0: + return result + return 0 + for name, items in sorted(groups.items()): + items.sort(key=functools.cmp_to_key(newest_first)) + print(name, "->", ", ".join(v for v, _ in items[:keep])) + for _, f in items[keep:]: + os.remove(os.path.join(dest, f)) + print(" pruned", f) + PRUNE + + ( + cd "$dest" + dpkg-scanpackages --multiversion . > Packages + gzip -9kf Packages + # Write Release outside the directory first: a redirect would + # create the file before apt-ftparchive walks the tree, and it + # would then hash its own half-written self. + apt-ftparchive \ + -o APT::FTPArchive::Release::Origin=sems \ + -o APT::FTPArchive::Release::Label=sems \ + -o APT::FTPArchive::Release::Suite="$distro" \ + -o APT::FTPArchive::Release::Codename="$distro" \ + -o APT::FTPArchive::Release::Architectures=amd64 \ + -o APT::FTPArchive::Release::Components=main \ + release . > ../Release.tmp + mv ../Release.tmp Release + ) + + # Pages serves no directory listing, so give each suite its own. + # Generated after Release so it is not part of the indexed files. + python3 - "$dest" "$distro" <<'SUITEINDEX' + import os, sys + dest, distro = sys.argv[1], sys.argv[2] + rows, stanza = [], {} + with open(os.path.join(dest, "Packages"), encoding="utf-8") as fh: + for line in fh: + line = line.rstrip("\n") + if not line: + if stanza: + rows.append(stanza); stanza = {} + continue + if not line.startswith(" ") and ": " in line: + key, value = line.split(": ", 1) + stanza[key] = value + if stanza: + rows.append(stanza) + rows.sort(key=lambda r: (r.get("Package", ""), r.get("Version", ""))) + out = ['', + f'sems apt - {distro}', + f'

sems apt repo - {distro}

', + '

suite list and install instructions.', + 'These packages are not signed.

', + '', + ''] + for r in rows: + name = r.get("Filename", "./").rsplit("/", 1)[-1] + size = int(r.get("Size", 0)) / 1048576 + out.append(f'' + f'' + f'') + out += ['
packageversionsizefile
{r.get("Package","")}{r.get("Version","")}{size:.1f} MB{name}
', + '

Packages | Release

', + ''] + with open(os.path.join(dest, "index.html"), "w", encoding="utf-8") as fh: + fh.write("\n".join(out) + "\n") + print(f"index.html for {distro}: {len(rows)} packages") + SUITEINDEX + + found=1 + echo "indexed ${distro}:" + ls -al "$dest" + done + [ "$found" = 1 ] || { echo "no .deb artifacts to index"; exit 1; } + { + echo 'sems apt' + echo '

sems apt repo

' + echo '

These packages are not signed.
' + echo 'There is no GPG key and no InRelease file, so apt cannot verify' + echo 'who produced them - hence [trusted=yes] on the source line' + echo 'below.
' + echo 'Only the HTTPS transport is authenticated; prefer a signed' + echo 'archive where package authenticity matters.

' + echo '

The newest few builds of each package are kept; older ones' + echo 'are removed when a new build is published.

' + echo '

Browse the repository:' + for dest in apt-repo/*/; do + distro="$(basename "$dest")" + echo "${distro}" + done + echo '

' + echo '

Pick the distro matching the host:

'
+            for dest in apt-repo/*/; do
+              distro="$(basename "$dest")"
+              echo "echo \"deb [trusted=yes] https://HOST/${distro} ./\" | sudo tee /etc/apt/sources.list.d/sems.list"
+              echo "sudo apt update && sudo apt install sems   # ${distro}"
+              echo
+            done
+            echo '
' + } > apt-repo/index.html + find apt-repo -type f | sort + + - uses: actions/upload-artifact@v4 + with: + name: apt-repo + path: apt-repo + if-no-files-found: error + + # Publish the apt tree assembled above on GitHub Pages. Reuses the artifact + # from this same run, so no image is built twice. Deliberately not a separate + # workflow: a workflow_run trigger is only read from the default branch, so + # it would never fire while this lives on local_deb_repo. + # + # One-time setup: repo Settings -> Pages -> Source: GitHub Actions. + # + # needs lists apt_build too, so a distro failing skips the deploy instead of + # publishing a repo that silently lost one of its suites (apt_assemble runs + # on always() and would happily index a partial set). + deploy_pages: + name: Deploy apt repo to Pages + if: github.event_name == 'release' || github.event_name == 'workflow_dispatch' + needs: [apt_build, apt_assemble] + runs-on: ubuntu-latest + permissions: + contents: read + pages: write + id-token: write + concurrency: + group: pages + cancel-in-progress: false + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/download-artifact@v4 + with: + name: apt-repo + path: apt-repo + + - name: Prepare Pages tree + run: | + # Keep Pages from treating _-prefixed paths as Jekyll internals. + touch apt-repo/.nojekyll + # apt_assemble writes a HOST placeholder because it does not know + # where the tree gets published; fill in the project page URL. + # github.repository is "owner/repo" on every event type, unlike + # github.event.repository which depends on the payload shape. + repo="${{ github.repository }}" + base="https://${{ github.repository_owner }}.github.io/${repo#*/}" + sed -i "s|https://HOST|${base}|g" apt-repo/index.html + + - uses: actions/upload-pages-artifact@v3 + with: + path: apt-repo + + - id: deployment + uses: actions/deploy-pages@v4 + + # Install from the tree that was just published, in the base image each suite + # targets. This is the only check that exercises the repository the way a user + # does - a broken Release, a package pruned while still indexed, or a wrong + # Filename surface here and nowhere else. + apt_verify: + name: verify ${{ matrix.distro }} + if: github.event_name == 'release' || github.event_name == 'workflow_dispatch' + needs: [list_deb_dockerfiles, deploy_pages] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.list_deb_dockerfiles.outputs.matrix) }} + steps: + - name: Install sems from the published repository + env: + EXPECTED: ${{ needs.list_deb_dockerfiles.outputs.version }} + run: | + set -eu + repo="${{ github.repository }}" + base="https://${{ github.repository_owner }}.github.io/${repo#*/}/${{ matrix.distro }}" + echo "checking ${base} for ${EXPECTED}" + + # Pages needs a moment to start serving a fresh deployment. + for attempt in $(seq 1 12); do + if curl -fsSL "${base}/Packages" | grep -qx "Version: ${EXPECTED}"; then + break + fi + echo "attempt ${attempt}: not served yet" + sleep 15 + done + curl -fsSL "${base}/Packages" | grep -qx "Version: ${EXPECTED}" + + # Origin, Label, Suite and Codename are stored by every client that + # has ever run apt update against this repository, and apt refuses to + # update when one of them changes until the user passes + # --allow-releaseinfo-change. Changing them is therefore a breaking + # change for existing hosts - assert them here so an accidental edit + # fails the run instead of every subscriber's apt. + curl -fsSL "${base}/Release" -o Release + grep -qx "Origin: sems" Release + grep -qx "Label: sems" Release + grep -qx "Suite: ${{ matrix.distro }}" Release + grep -qx "Codename: ${{ matrix.distro }}" Release + + docker run --rm "${{ matrix.image }}" bash -lc " + set -e + export DEBIAN_FRONTEND=noninteractive + apt-get update -qq + apt-get install -y -qq ca-certificates >/dev/null + echo 'deb [trusted=yes] ${base} ./' > /etc/apt/sources.list.d/sems.list + apt-get update + apt-get install -y sems + /usr/sbin/sems -v + installed=\"\$(dpkg-query -W -f='\${Version}' sems)\" + if [ \"\$installed\" != '${EXPECTED}' ]; then + echo \"installed \$installed, expected ${EXPECTED}\" >&2 + exit 1 + fi + " + hardened_builds: runs-on: ubuntu-latest name: Hardened build (${{ matrix.flavor }}) diff --git a/Dockerfile-debian11 b/Dockerfile-debian11 index 511b578ce..e3c4c134d 100644 --- a/Dockerfile-debian11 +++ b/Dockerfile-debian11 @@ -1,30 +1,46 @@ FROM debian:11 -RUN apt update -RUN apt install -y \ - git debhelper g++ make cmake libspandsp-dev flite1-dev \ - libspeex-dev libgsm1-dev libopus-dev libssl-dev python3-dev \ - python3.9-dev libev-dev \ - python3-sip-dev openssl libev-dev libmysqlcppconn-dev libevent-dev \ - libxml2-dev libcurl4-openssl-dev libhiredis-dev \ - cargo rustc - -RUN apt install -y \ - devscripts libbcg729-dev \ - libsamplerate-dev libmp3lame-dev libcodec2-dev +ENV DEBIAN_FRONTEND=noninteractive + +# One dropped connection would otherwise fail a 300+ MB install. +RUN echo 'Acquire::Retries "3";' > /etc/apt/apt.conf.d/80-retries + +RUN apt-get update && apt-get install -y \ + git \ + debhelper devscripts \ + g++ make cmake \ + python3-dev python3.9-dev python3-sip-dev \ + openssl libssl-dev \ + libspandsp-dev flite1-dev libspeex-dev libgsm1-dev libopus-dev \ + libsamplerate-dev libmp3lame-dev libcodec2-dev libbcg729-dev \ + libev-dev libevent-dev libxml2-dev libcurl4-openssl-dev \ + libhiredis-dev libmysqlcppconn-dev \ + cargo rustc \ + && rm -rf /var/lib/apt/lists/* + COPY . /sems WORKDIR /sems RUN mkdir -p build && cd build && cmake .. && make sems_tests && ./core/sems_tests -RUN ls -al pkg/deb/bullseye/* + RUN ln -s pkg/deb/bullseye ./debian -RUN ls -al debian/* -RUN dch -b -v $(cat VERSION) "sems" + +# CI stamps a unique version so apt sees an upgrade; VERSION is the fallback. +ARG PKG_VERSION= +RUN set -eu; \ + v="${PKG_VERSION:-$(cat VERSION)}"; \ + changelog="$(dpkg-parsechangelog -S Version)"; \ + if ! dpkg --compare-versions "$v" ge "$changelog"; then \ + echo "refusing to build $v: older than debian/changelog $changelog" >&2; \ + exit 1; \ + fi; \ + DEBEMAIL="ci@localhost" DEBFULLNAME="CI" dch -b -v "$v" "sems" + RUN dpkg-buildpackage -rfakeroot -us -uc RUN ls -al .. RUN dpkg -i ../sems_*.deb RUN /usr/sbin/sems -v +RUN mkdir -p /debs && cp -a ../*.deb /debs/ -# Run SEMS with the specified configuration CMD ["/usr/sbin/sems", "-E", "-f", "/etc/sems/sems.conf"] diff --git a/Dockerfile-debian12 b/Dockerfile-debian12 index 30a63b747..60ba4e959 100644 --- a/Dockerfile-debian12 +++ b/Dockerfile-debian12 @@ -1,29 +1,47 @@ FROM debian:12 -RUN apt update -RUN apt install -y \ - git debhelper g++ make libspandsp-dev flite1-dev \ - libspeex-dev libgsm1-dev libopus-dev libssl-dev python3-dev \ - python3.11-dev libev-dev \ - python3-sip-dev openssl libev-dev libmysqlcppconn-dev libevent-dev \ - libxml2-dev libcurl4-openssl-dev libhiredis-dev \ - libsamplerate-dev libmp3lame-dev libcodec2-dev \ - cmake dh-cmake dh-cmake-compat dh-sequence-cmake \ - cargo rustc - - -RUN apt install -y \ - devscripts libbcg729-dev +ENV DEBIAN_FRONTEND=noninteractive + +# One dropped connection would otherwise fail a 300+ MB install. +RUN echo 'Acquire::Retries "3";' > /etc/apt/apt.conf.d/80-retries + +RUN apt-get update && apt-get install -y \ + git \ + debhelper devscripts \ + g++ make cmake \ + dh-cmake dh-cmake-compat dh-sequence-cmake \ + python3-dev python3.11-dev python3-sip-dev \ + openssl libssl-dev \ + libspandsp-dev flite1-dev libspeex-dev libgsm1-dev libopus-dev \ + libsamplerate-dev libmp3lame-dev libcodec2-dev libbcg729-dev \ + libev-dev libevent-dev libxml2-dev libcurl4-openssl-dev \ + libhiredis-dev libmysqlcppconn-dev \ + cargo rustc \ + && rm -rf /var/lib/apt/lists/* + COPY . /sems WORKDIR /sems RUN mkdir -p build && cd build && cmake .. && make sems_tests && ./core/sems_tests + RUN ln -s pkg/deb/bookworm ./debian + +# CI stamps a unique version so apt sees an upgrade; VERSION is the fallback. +ARG PKG_VERSION= +RUN set -eu; \ + v="${PKG_VERSION:-$(cat VERSION)}"; \ + changelog="$(dpkg-parsechangelog -S Version)"; \ + if ! dpkg --compare-versions "$v" ge "$changelog"; then \ + echo "refusing to build $v: older than debian/changelog $changelog" >&2; \ + exit 1; \ + fi; \ + DEBEMAIL="ci@localhost" DEBFULLNAME="CI" dch -b -v "$v" "sems" + RUN dpkg-buildpackage -rfakeroot -us -uc RUN ls -al .. RUN dpkg -i ../sems_*.deb RUN /usr/sbin/sems -v +RUN mkdir -p /debs && cp -a ../*.deb /debs/ -# Run SEMS with the specified configuration CMD ["/usr/sbin/sems", "-E", "-f", "/etc/sems/sems.conf"] diff --git a/Dockerfile-debian13 b/Dockerfile-debian13 index 3a864e5f9..831518d68 100644 --- a/Dockerfile-debian13 +++ b/Dockerfile-debian13 @@ -2,29 +2,48 @@ FROM debian:13 ENV DEBIAN_FRONTEND=noninteractive -RUN apt update -RUN apt install -y \ - git debhelper g++ make cmake libspandsp-dev flite1-dev \ - libspeex-dev libgsm1-dev libopus-dev libssl-dev python3-dev \ - python3-pip libev-dev \ - openssl libev-dev libmysqlcppconn-dev libevent-dev \ - libxml2-dev libcurl4-openssl-dev libhiredis-dev - -RUN apt install -y devscripts libbcg729-dev \ - libsamplerate-dev libmp3lame-dev libcodec2-dev \ - cargo rustc +# One dropped connection would otherwise fail a 300+ MB install. +RUN echo 'Acquire::Retries "3";' > /etc/apt/apt.conf.d/80-retries + +RUN apt-get update && apt-get install -y \ + git \ + debhelper devscripts \ + g++ make cmake \ + python3-dev python3-pip \ + openssl libssl-dev \ + libspandsp-dev flite1-dev libspeex-dev libgsm1-dev libopus-dev \ + libsamplerate-dev libmp3lame-dev libcodec2-dev libbcg729-dev \ + libev-dev libevent-dev libxml2-dev libcurl4-openssl-dev \ + libhiredis-dev libmysqlcppconn-dev \ + cargo rustc \ + && rm -rf /var/lib/apt/lists/* + +# trixie has no python3-sip-dev; take sip from pip instead. RUN pip install sip --break-system-packages + COPY . /sems WORKDIR /sems RUN mkdir -p build && cd build && cmake .. && make sems_tests && ./core/sems_tests -RUN mv pkg/deb/trixie ./debian -RUN dch -b -v $(cat VERSION) "sems" + +RUN ln -s pkg/deb/trixie ./debian + +# CI stamps a unique version so apt sees an upgrade; VERSION is the fallback. +ARG PKG_VERSION= +RUN set -eu; \ + v="${PKG_VERSION:-$(cat VERSION)}"; \ + changelog="$(dpkg-parsechangelog -S Version)"; \ + if ! dpkg --compare-versions "$v" ge "$changelog"; then \ + echo "refusing to build $v: older than debian/changelog $changelog" >&2; \ + exit 1; \ + fi; \ + DEBEMAIL="ci@localhost" DEBFULLNAME="CI" dch -b -v "$v" "sems" + RUN dpkg-buildpackage -rfakeroot -us -uc RUN ls -al .. RUN dpkg -i ../sems_*.deb RUN /usr/sbin/sems -v +RUN mkdir -p /debs && cp -a ../*.deb /debs/ -# Run SEMS with the specified configuration -CMD ["/usr/sbin/sems", "-E", "-f", "/etc/sems/sems.conf"] \ No newline at end of file +CMD ["/usr/sbin/sems", "-E", "-f", "/etc/sems/sems.conf"] diff --git a/Dockerfile-ubuntu22.04 b/Dockerfile-ubuntu22.04 new file mode 100644 index 000000000..6ca8a3075 --- /dev/null +++ b/Dockerfile-ubuntu22.04 @@ -0,0 +1,47 @@ +FROM ubuntu:22.04 + +ENV DEBIAN_FRONTEND=noninteractive + +# One dropped connection would otherwise fail a 300+ MB install. +RUN echo 'Acquire::Retries "3";' > /etc/apt/apt.conf.d/80-retries + +RUN apt-get update && apt-get install -y \ + git \ + debhelper devscripts \ + g++ make cmake \ + python3-dev python3-sip-dev \ + openssl libssl-dev \ + libspandsp-dev flite1-dev libspeex-dev libgsm1-dev libopus-dev \ + libsamplerate-dev libmp3lame-dev libcodec2-dev libbcg729-dev \ + libev-dev libevent-dev libxml2-dev libcurl4-openssl-dev \ + libhiredis-dev libmysqlcppconn-dev \ + cargo rustc \ + && rm -rf /var/lib/apt/lists/* + +COPY . /sems +WORKDIR /sems + +RUN mkdir -p build && cd build && cmake .. && make sems_tests && ./core/sems_tests + +# jammy matches Debian 11, so it reuses the bullseye packaging. +RUN ln -s pkg/deb/bullseye ./debian + +# CI stamps a unique version so apt sees an upgrade; VERSION is the fallback. +ARG PKG_VERSION= +RUN set -eu; \ + v="${PKG_VERSION:-$(cat VERSION)}"; \ + changelog="$(dpkg-parsechangelog -S Version)"; \ + if ! dpkg --compare-versions "$v" ge "$changelog"; then \ + echo "refusing to build $v: older than debian/changelog $changelog" >&2; \ + exit 1; \ + fi; \ + DEBEMAIL="ci@localhost" DEBFULLNAME="CI" dch -b -v "$v" "sems" + +RUN dpkg-buildpackage -rfakeroot -us -uc +RUN ls -al .. + +RUN dpkg -i ../sems_*.deb +RUN /usr/sbin/sems -v +RUN mkdir -p /debs && cp -a ../*.deb /debs/ + +CMD ["/usr/sbin/sems", "-E", "-f", "/etc/sems/sems.conf"] diff --git a/Dockerfile-ubuntu24.04 b/Dockerfile-ubuntu24.04 new file mode 100644 index 000000000..bf8b7c498 --- /dev/null +++ b/Dockerfile-ubuntu24.04 @@ -0,0 +1,48 @@ +FROM ubuntu:24.04 + +ENV DEBIAN_FRONTEND=noninteractive + +# One dropped connection would otherwise fail a 300+ MB install. +RUN echo 'Acquire::Retries "3";' > /etc/apt/apt.conf.d/80-retries + +RUN apt-get update && apt-get install -y \ + git \ + debhelper devscripts \ + g++ make cmake \ + dh-cmake dh-cmake-compat dh-sequence-cmake \ + python3-dev python3-sip-dev \ + openssl libssl-dev \ + libspandsp-dev flite1-dev libspeex-dev libgsm1-dev libopus-dev \ + libsamplerate-dev libmp3lame-dev libcodec2-dev libbcg729-dev \ + libev-dev libevent-dev libxml2-dev libcurl4-openssl-dev \ + libhiredis-dev libmysqlcppconn-dev \ + cargo rustc \ + && rm -rf /var/lib/apt/lists/* + +COPY . /sems +WORKDIR /sems + +RUN mkdir -p build && cd build && cmake .. && make sems_tests && ./core/sems_tests + +# noble matches Debian 12, so it reuses the bookworm packaging. +RUN ln -s pkg/deb/bookworm ./debian + +# CI stamps a unique version so apt sees an upgrade; VERSION is the fallback. +ARG PKG_VERSION= +RUN set -eu; \ + v="${PKG_VERSION:-$(cat VERSION)}"; \ + changelog="$(dpkg-parsechangelog -S Version)"; \ + if ! dpkg --compare-versions "$v" ge "$changelog"; then \ + echo "refusing to build $v: older than debian/changelog $changelog" >&2; \ + exit 1; \ + fi; \ + DEBEMAIL="ci@localhost" DEBFULLNAME="CI" dch -b -v "$v" "sems" + +RUN dpkg-buildpackage -rfakeroot -us -uc +RUN ls -al .. + +RUN dpkg -i ../sems_*.deb +RUN /usr/sbin/sems -v +RUN mkdir -p /debs && cp -a ../*.deb /debs/ + +CMD ["/usr/sbin/sems", "-E", "-f", "/etc/sems/sems.conf"]