name: release on: push: branches: - 'master' workflow_dispatch: permissions: contents: write packages: write jobs: setup: runs-on: ubuntu-latest outputs: version_tag: ${{ steps.version_check.outputs.version_tag }} webapp_release: ${{ steps.webapp.outputs.webapp_release }} build_date: ${{ steps.env.outputs.build_date }} should_build: ${{ steps.version_check.outputs.should_build }} steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: '0' - name: Set env variables id: env run: | echo "build_date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT - name: Get latest Webapp release version id: webapp run: | WEBAPP_RELEASE=$(curl -sX GET "https://api.github.com/repos/netbootxyz/webapp/releases/latest" | jq -r '. | .tag_name') echo "webapp_release=${WEBAPP_RELEASE}" >> $GITHUB_OUTPUT - name: Determine version numbers id: version_check run: | WEBAPP_RELEASE="${{ steps.webapp.outputs.webapp_release }}" IMAGE=netbootxyz/netbootxyz TOKEN=$(curl -sX GET \ "https://ghcr.io/token?scope=repository%3Anetbootxyz%2Fnetbootxyz%3Apull" \ | jq -r '.token') TAG=$(curl -s --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ --header "Authorization: Bearer ${TOKEN}" \ "https://ghcr.io/v2/${IMAGE}/tags/list?n=1000" \ | jq -r '.tags[] | select(test("^[0-9]+\\.[0-9]+\\.[0-9]+-nbxyz[0-9]+$"))' | sort -V | tail -1) echo LATEST_TAG: $TAG MULTIDIGEST=$(curl -s \ --header "Accept: application/vnd.oci.image.index.v1+json" \ --header "Authorization: Bearer ${TOKEN}" \ "https://ghcr.io/v2/${IMAGE}/manifests/${TAG}" \ | jq -r 'first(.manifests[].digest)') DIGEST=$(curl -s \ --header "Accept: application/vnd.oci.image.manifest.v1+json" \ --header "Authorization: Bearer ${TOKEN}" \ "https://ghcr.io/v2/${IMAGE}/manifests/${MULTIDIGEST}" \ | jq -r '.config.digest') IMAGE_INFO=$(curl -sL \ --header "Authorization: Bearer ${TOKEN}" \ "https://ghcr.io/v2/${IMAGE}/blobs/${DIGEST}" \ | jq -r '.config') IMAGE_RELEASE=${TAG} IMAGE_VERSION=$(echo ${IMAGE_RELEASE} | awk -F'-nbxyz' '{print $1}') NB_RELEASE_NUMBER=$(echo ${IMAGE_RELEASE} | awk -F'-nbxyz' '{print $2}') TAG_SHA=$(git rev-list -n 1 "v${IMAGE_RELEASE}" 2>/dev/null || echo "") if [ -z "${MULTIDIGEST}" ] || [ "${MULTIDIGEST}" == "null" ]; then echo "**** No existing container build found, assuming first build ****" VERSION_TAG=${WEBAPP_RELEASE}-nbxyz1 elif [ "${WEBAPP_RELEASE}" == "${IMAGE_VERSION}" ]; then echo "**** Version ${WEBAPP_RELEASE} unchanged, checking if there is anything to build..." if [ "${TAG_SHA}" == "${{ github.sha }}" ]; then echo "**** Nothing to do, exiting build... ****" echo "should_build=false" >> $GITHUB_OUTPUT exit 0 else echo "**** Changes found... incrementing build number version... ****" NB_RELEASE_NUMBER=$((NB_RELEASE_NUMBER + 1)) VERSION_TAG=${IMAGE_VERSION}-nbxyz${NB_RELEASE_NUMBER} fi else echo "**** New version ${WEBAPP_RELEASE} found; old version was ${IMAGE_VERSION}. Generating new webapp release... ****" VERSION_TAG=${WEBAPP_RELEASE}-nbxyz1 fi # Ensure we don't create duplicate tags while git rev-parse "v${VERSION_TAG}" >/dev/null 2>&1; do echo "**** Tag v${VERSION_TAG} already exists, incrementing... ****" NB_RELEASE_NUMBER=$(echo ${VERSION_TAG} | awk -F'-nbxyz' '{print $2}') NB_RELEASE_NUMBER=$((NB_RELEASE_NUMBER + 1)) VERSION_TAG=$(echo ${VERSION_TAG} | awk -F'-nbxyz' '{print $1}')-nbxyz${NB_RELEASE_NUMBER} done echo "version_tag=${VERSION_TAG}" >> $GITHUB_OUTPUT echo "should_build=true" >> $GITHUB_OUTPUT build-amd64: needs: setup if: needs.setup.outputs.should_build == 'true' runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: '0' - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - name: Login to the Docker Container Registry uses: docker/login-action@v4 with: username: ${{ secrets.DOCKERHUB_USER }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to the GitHub Container Registry uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ secrets.GHCR_USER }} password: ${{ secrets.GHCR_TOKEN }} - name: Build and push (amd64) id: build uses: docker/build-push-action@v7 with: context: . file: ./Dockerfile platforms: linux/amd64 build-args: | WEBAPP_VERSION=${{ needs.setup.outputs.webapp_release }} VERSION=${{ needs.setup.outputs.version_tag }} BUILD_DATE=${{ needs.setup.outputs.build_date }} labels: | maintainer=antonym org.opencontainers.image.created=${{ needs.setup.outputs.build_date }} org.opencontainers.image.authors=netboot.xyz org.opencontainers.image.url=https://github.com/netbootxyz/docker-netbootxyz/packages org.opencontainers.image.documentation=https://netboot.xyz org.opencontainers.image.source=https://github.com/netbootxyz/docker-netbootxyz org.opencontainers.image.version=${{ needs.setup.outputs.version_tag }} org.opencontainers.image.revision=${{ github.sha }} org.opencontainers.image.vendor=netboot.xyz org.opencontainers.image.licenses=Apache-2.0 org.opencontainers.image.ref.name=${{ github.sha }} org.opencontainers.image.title=netbootxyz org.opencontainers.image.description=netboot.xyz official docker container - Your favorite operating systems in one place. A network-based bootable operating system installer based on iPXE. outputs: type=image,name=ghcr.io/netbootxyz/netbootxyz,push-by-digest=true,name-canonical=true,push=true - name: Export digest run: | mkdir -p /tmp/digests digest="${{ steps.build.outputs.digest }}" touch "/tmp/digests/${digest#sha256:}" - name: Upload digest uses: actions/upload-artifact@v7 with: name: digests-amd64 path: /tmp/digests/* if-no-files-found: error retention-days: 1 build-arm64: needs: setup if: needs.setup.outputs.should_build == 'true' runs-on: ubuntu-24.04-arm steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: '0' - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - name: Login to the Docker Container Registry uses: docker/login-action@v4 with: username: ${{ secrets.DOCKERHUB_USER }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to the GitHub Container Registry uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ secrets.GHCR_USER }} password: ${{ secrets.GHCR_TOKEN }} - name: Build and push (arm64) id: build uses: docker/build-push-action@v7 with: context: . file: ./Dockerfile platforms: linux/arm64 build-args: | WEBAPP_VERSION=${{ needs.setup.outputs.webapp_release }} VERSION=${{ needs.setup.outputs.version_tag }} BUILD_DATE=${{ needs.setup.outputs.build_date }} labels: | maintainer=antonym org.opencontainers.image.created=${{ needs.setup.outputs.build_date }} org.opencontainers.image.authors=netboot.xyz org.opencontainers.image.url=https://github.com/netbootxyz/docker-netbootxyz/packages org.opencontainers.image.documentation=https://netboot.xyz org.opencontainers.image.source=https://github.com/netbootxyz/docker-netbootxyz org.opencontainers.image.version=${{ needs.setup.outputs.version_tag }} org.opencontainers.image.revision=${{ github.sha }} org.opencontainers.image.vendor=netboot.xyz org.opencontainers.image.licenses=Apache-2.0 org.opencontainers.image.ref.name=${{ github.sha }} org.opencontainers.image.title=netbootxyz org.opencontainers.image.description=netboot.xyz official docker container - Your favorite operating systems in one place. A network-based bootable operating system installer based on iPXE. outputs: type=image,name=ghcr.io/netbootxyz/netbootxyz,push-by-digest=true,name-canonical=true,push=true - name: Export digest run: | mkdir -p /tmp/digests digest="${{ steps.build.outputs.digest }}" touch "/tmp/digests/${digest#sha256:}" - name: Upload digest uses: actions/upload-artifact@v7 with: name: digests-arm64 path: /tmp/digests/* if-no-files-found: error retention-days: 1 manifest: needs: [setup, build-amd64, build-arm64] runs-on: ubuntu-latest steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - name: Login to the Docker Container Registry uses: docker/login-action@v4 with: username: ${{ secrets.DOCKERHUB_USER }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to the GitHub Container Registry uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ secrets.GHCR_USER }} password: ${{ secrets.GHCR_TOKEN }} - name: Download digests uses: actions/download-artifact@v8 with: path: /tmp/digests pattern: digests-* merge-multiple: true - name: Create manifest list and push (GHCR) working-directory: /tmp/digests run: | VERSION_TAG="${{ needs.setup.outputs.version_tag }}" docker buildx imagetools create \ -t "ghcr.io/netbootxyz/netbootxyz:latest" \ -t "ghcr.io/netbootxyz/netbootxyz:${{ github.sha }}" \ -t "ghcr.io/netbootxyz/netbootxyz:${VERSION_TAG}" \ $(printf 'ghcr.io/netbootxyz/netbootxyz@sha256:%s ' *) - name: Create manifest list and push (Docker Hub) working-directory: /tmp/digests run: | VERSION_TAG="${{ needs.setup.outputs.version_tag }}" docker buildx imagetools create \ -t "netbootxyz/netbootxyz:latest" \ -t "netbootxyz/netbootxyz:${{ github.sha }}" \ -t "netbootxyz/netbootxyz:${VERSION_TAG}" \ $(printf 'ghcr.io/netbootxyz/netbootxyz@sha256:%s ' *) tag: needs: [setup, manifest] runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: '0' - name: Bump version and push tag uses: anothrNick/github-tag-action@1.75.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CUSTOM_TAG: ${{ needs.setup.outputs.version_tag }} WITH_V: true RELEASE_BRANCHES: master