From 78adac8d175fecf76492513fe16cd85d0ea0fc6f Mon Sep 17 00:00:00 2001 From: Sergio Talens-Oliag Date: Tue, 11 Mar 2025 17:49:38 +0100 Subject: [PATCH] Initial commit. --- .forgejo/package.json.tmpl | 13 ++++ .forgejo/workflows/build-image-from-tag.yaml | 71 ++++++++++++++++++ .../workflows/multi-semantic-release.yaml | 73 +++++++++++++++++++ .forgejo/ws-package.json.tmpl | 57 +++++++++++++++ README.md | 26 +++++++ alpine-mixinet/Dockerfile | 43 +++++++++++ multi-semantic-release/Dockerfile | 13 ++++ node-mixinet/Dockerfile | 13 ++++ node-mixinet/msr.yaml | 1 + 9 files changed, 310 insertions(+) create mode 100644 .forgejo/package.json.tmpl create mode 100644 .forgejo/workflows/build-image-from-tag.yaml create mode 100644 .forgejo/workflows/multi-semantic-release.yaml create mode 100644 .forgejo/ws-package.json.tmpl create mode 100644 README.md create mode 100644 alpine-mixinet/Dockerfile create mode 100644 multi-semantic-release/Dockerfile create mode 100644 node-mixinet/Dockerfile create mode 100644 node-mixinet/msr.yaml diff --git a/.forgejo/package.json.tmpl b/.forgejo/package.json.tmpl new file mode 100644 index 0000000..dcf073d --- /dev/null +++ b/.forgejo/package.json.tmpl @@ -0,0 +1,13 @@ +{{- $paths_list := list -}} +{{- range get . "images" -}} +{{- $paths_list = append $paths_list .path -}} +{{- end -}} +{ + "name": "multi-semantic-release", + "version": "0.0.0-semantically-released", + "private": true, + "multi-release": { + "tagFormat": "${name}-v${version}" + }, + "workspaces": {{ $paths_list | toJson }} +} diff --git a/.forgejo/workflows/build-image-from-tag.yaml b/.forgejo/workflows/build-image-from-tag.yaml new file mode 100644 index 0000000..8d14683 --- /dev/null +++ b/.forgejo/workflows/build-image-from-tag.yaml @@ -0,0 +1,71 @@ +name: build-image-from-tag + +# The build job is triggered manually (we trigger it from the multi-semantic-release workflow on tag creation) +on: + workflow_dispatch: + +jobs: + build: + # Don't build the image if the registry credentials are not set, the ref is not a tag or it doesn't contain '-v' + if: ${{ vars.REGISTRY_USER != '' && secrets.REGISTRY_PASS != '' && startsWith(github.ref, 'refs/tags/') && contains(github.ref, '-v') }} + runs-on: docker + container: + image: forgejo.mixinet.net/oci/node-mixinet:latest + # Mount the /dind/docker.sock in the container to use it (avoids LXC) + options: -v /dind/docker.sock:/var/run/docker.sock + steps: + - name: Extract image name and tag from the git tag and get registry name from env + id: job_data + run: | + echo "::set-output name=img_name::${GITHUB_REF_NAME%%-v*}" + echo "::set-output name=img_tag::${GITHUB_REF_NAME##*-v}" + echo "::set-output name=registry::$(echo "${{ github.server_url }}" | sed -e 's%https://%%')" + echo "::set-output name=oci_registry_prefix::$(echo "${{ github.server_url }}/oci" | sed -e 's%https://%%')" + + - name: Checkout the repo + uses: actions/checkout@v4 + + - name: Export build dir and Dockerfile + id: build_data + run: | + img="${{ steps.job_data.outputs.img_name }}" + build_dir="$(pwd)/${img}" + dockerfile="${build_dir}/Dockerfile" + if [ -f "$dockerfile" ]; then + echo "::set-output name=build_dir::$build_dir" + echo "::set-output name=dockerfile::$dockerfile" + else + echo "Couldn't find the Dockerfile for the '$img' image" + exit 1 + fi + + - name: Login to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ steps.job_data.outputs.registry }} + username: ${{ vars.REGISTRY_USER }} + password: ${{ secrets.REGISTRY_PASS }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and Push + uses: docker/build-push-action@v6 + with: + push: true + tags: | + ${{ steps.job_data.outputs.oci_registry_prefix }}/${{ steps.job_data.outputs.img_name }}:${{ steps.job_data.outputs.img_tag }} + ${{ steps.job_data.outputs.oci_registry_prefix }}/${{ steps.job_data.outputs.img_name }}:latest + context: ${{ steps.build_data.outputs.build_dir }} + file: ${{ steps.build_data.outputs.dockerfile }} + build-args: | + OCI_REGISTRY_PREFIX=${{ steps.job_data.outputs.oci_registry_prefix }}/ + + - name: List dind images and cleanup dangling ones, if present + shell: sh + run: | + docker image ls + images_to_remove="$(docker image ls -q --filter dangling=true)" + for img in $images_to_remove; do + docker rmi $img + done diff --git a/.forgejo/workflows/multi-semantic-release.yaml b/.forgejo/workflows/multi-semantic-release.yaml new file mode 100644 index 0000000..d6a4c44 --- /dev/null +++ b/.forgejo/workflows/multi-semantic-release.yaml @@ -0,0 +1,73 @@ +name: multi-semantic-release + +# This monorepo only tags releases from the main branch +on: + push: + branches: + - 'main' + +jobs: + multi-semantic-release: + runs-on: docker + container: + image: forgejo.mixinet.net/oci/multi-semantic-release:latest + steps: + - name: Checkout the repo + uses: actions/checkout@v4 + + - name: Generate multi-semantic-release configuration + shell: sh + run: | + # Get the list of images to work with (the folders that have a Dockerfile) + images="$(for img in */Dockerfile; do dirname "$img"; done)" + # Generate a values.yaml file for the main packages.json file + package_json_values_yaml=".package.json-values.yaml" + echo "images:" >"$package_json_values_yaml" + for img in $images; do + echo " - name: $img" >>"$package_json_values_yaml" + echo " path: $img" >>"$package_json_values_yaml" + done + echo "::group::Generated values.yaml for the project" + cat "$package_json_values_yaml" + echo "::endgroup::" + # Generate the package.json file validating that is a good json file with jq + tmpl -f "$package_json_values_yaml" ".forgejo/package.json.tmpl" | jq . > "package.json" + echo "::group::Generated package.json for the project" + cat "package.json" + echo "::endgroup::" + # Remove the temporary values file + rm -f "$package_json_values_yaml" + # Generate the package.json file for each image + for img in $images; do + tmpl -v "img_name=$img" -v "img_path=$img" ".forgejo/ws-package.json.tmpl" | jq . > "$img/package.json" + echo "::group::Generated package.json for the '$img' image" + cat "$img/package.json" + echo "::endgroup::" + done + + - name: Run multi-semantic-release + shell: sh + run: | + multi-semantic-release | tee .multi-semantic-release.log + + - name: Trigger builds + shell: sh + run: | + # Get the list of tags published on the previous steps + tags="$( + sed -n -e 's/^\[.*\] \[\(.*\)\] .* Published release \([0-9]\+\.[0-9]\+\.[0-9]\+\) on .*$/\1-v\2/p' \ + .multi-semantic-release.log + )" + rm -f .multi-semantic-release.log + if [ "$tags" ]; then + # Prepare the url for building the images + workflow="build-image-from-tag.yaml" + dispatch_url="${{ github.api_url }}/repos/${{ github.repository }}/actions/workflows/$workflow/dispatches" + echo "$tags" | while read -r tag; do + echo "Triggering build for tag '$tag'" + curl \ + -H "Content-Type:application/json" \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -d "{\"ref\":\"$tag\"}" "$dispatch_url" + done + fi diff --git a/.forgejo/ws-package.json.tmpl b/.forgejo/ws-package.json.tmpl new file mode 100644 index 0000000..d2707aa --- /dev/null +++ b/.forgejo/ws-package.json.tmpl @@ -0,0 +1,57 @@ +{ + "name": "{{ .img_name }}", + "license": "UNLICENSED", + "release": { + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "preset": "conventionalcommits", + "releaseRules": [ + { + "breaking": true, + "release": "major" + }, + { + "revert": true, + "release": "patch" + }, + { + "type": "feat", + "release": "minor" + }, + { + "type": "fix", + "release": "patch" + }, + { + "type": "perf", + "release": "patch" + } + ] + } + ], + [ + "semantic-release-replace-plugin", + { + "replacements": [ + { + "files": [ "{{ .img_path }}/msr.yaml" ], + "from": "^version:.*$", + "to": "version: ${nextRelease.version}", + "allowEmptyPaths": true + } + ] + } + ], + [ + "@semantic-release/git", + { + "assets": [ "msr.yaml" ], + "message": "ci(release): {{ .img_name }}-v${nextRelease.version}\n\n${nextRelease.notes}" + } + ] + ], + "branches": [ "main" ] + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..fe9ac69 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# Mixinet OCI images repository + +This repository contains `Dockerfiles` for images created for the [mixinet forgejo](https://forgejo.mixinet.net) +instance, all the images are available from the [OCI](https://forgejo.mixinet.dev/oci/) organization (the packages +section also contains mirrored images from other sources, see the [mirrors +project](https://forgejo.mixinet.net/oci/mirrors) for those). + +The repository is a monorepo managed using [multi-semantic-release](https://github.com/qiwi/multi-semantic-release). + +## Bootstraping + +As some of the workflows use images generated on the repository itself, the first step is to build the required images +locally and push them to the registry (we are assuming that the user has already done a `docker login` with the right +credentials, of course): + +```bash +for img in alpine-mixinet node-mixinet multi-semantic-release; do + docker build -t forgejo.mixinet.net/oci/$img:1.0.0 $img + docker tag forgejo.mixinet.net/oci/$img:1.0.0 forgejo.mixinet.net/oci/$img:latest + docker push forgejo.mixinet.net/oci/$img:1.0.0 + docker push forgejo.mixinet.net/oci/$img:latest +done +``` + +Once the images are pushed we should run the mirrors workflow to make sure that things will work as expected once we try +to build any image, as the `OCI_MIRROR_PREFIX` is passed to the build image job. diff --git a/alpine-mixinet/Dockerfile b/alpine-mixinet/Dockerfile new file mode 100644 index 0000000..6efaa19 --- /dev/null +++ b/alpine-mixinet/Dockerfile @@ -0,0 +1,43 @@ +# Image used to run actions on forgejo.mixinet.net that don't need nodejs + +# This arg could be passed by the container build command (used with mirrors) +ARG OCI_REGISTRY_PREFIX + +# Latest tested version of alpine +FROM ${OCI_REGISTRY_PREFIX}alpine:3.21.3 + +# Tool versions +ARG REGCLIENT_VERS=0.8.2 +ARG TMPL_VERSION=0.4.0-sto.3 + +# Update dist & install commands and non packaged tools +RUN apk update &&\ + apk upgrade &&\ + apk add \ + bash \ + ca-certificates \ + curl \ + docker-cli \ + gettext-envsubst \ + git \ + jq \ + openssl \ + openssh-keygen \ + yq \ + zip \ + &&\ + rm -rf /var/cache/apk/* &&\ + case "$(apk --print-arch)" in "aarch64") ARCH="arm64";; "x86_64") ARCH="amd64";; esac && \ + for app in regctl regsync; do \ + REGCLIENT_URL="https://github.com/regclient/regclient/releases/download/v${REGCLIENT_VERS}/${app}-linux-$ARCH"; \ + curl -fsSL -o "/tmp/$app" "$REGCLIENT_URL";\ + install /tmp/$app /usr/local/bin;\ + rm -f /tmp/$app; \ + done &&\ + TMPL_URL="https://github.com/sto/tmpl/releases/download/v${TMPL_VERSION}/tmpl-linux_$ARCH" &&\ + curl -fsSL -o "/tmp/tmpl" "$TMPL_URL" &&\ + install /tmp/tmpl /usr/local/bin &&\ + rm -f /tmp/tmpl + +# Set the entrypoint to /bin/sh +CMD ["/bin/sh"] diff --git a/multi-semantic-release/Dockerfile b/multi-semantic-release/Dockerfile new file mode 100644 index 0000000..505a460 --- /dev/null +++ b/multi-semantic-release/Dockerfile @@ -0,0 +1,13 @@ +FROM forgejo.mixinet.net/oci/node-mixinet:1.0.0 + +RUN npm install --location=global\ + conventional-changelog-conventionalcommits@6.1.0\ + @qiwi/multi-semantic-release@7.0.0\ + semantic-release@21.0.7\ + @semantic-release/changelog@6.0.3\ + semantic-release-export-data@1.0.1\ + @semantic-release/git@10.0.1\ + @semantic-release/gitlab@9.5.1\ + @semantic-release/release-notes-generator@11.0.4\ + semantic-release-replace-plugin@1.2.7\ + semver@7.5.4 diff --git a/node-mixinet/Dockerfile b/node-mixinet/Dockerfile new file mode 100644 index 0000000..4a6f608 --- /dev/null +++ b/node-mixinet/Dockerfile @@ -0,0 +1,13 @@ +# Image used to run actions on forgejo.mixinet.net that need nodejs + +# We base this image on the alpine-mixinet image +FROM forgejo.mixinet.net/oci/alpine-mixinet:1.0.0 + +# Update dist & install nodejs & npm +RUN apk update &&\ + apk upgrade &&\ + apk add \ + nodejs \ + npm \ + &&\ + rm -rf /var/cache/apk/* diff --git a/node-mixinet/msr.yaml b/node-mixinet/msr.yaml new file mode 100644 index 0000000..f7fefdb --- /dev/null +++ b/node-mixinet/msr.yaml @@ -0,0 +1 @@ +version: 1.0.2