From 8a429b1609b81f78cc36928ee90fda47444a934b Mon Sep 17 00:00:00 2001 From: Louis Orleans Date: Tue, 16 Nov 2021 17:55:48 -0800 Subject: [PATCH 01/11] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20use=20official=20pyt?= =?UTF-8?q?hon=20image=20this=20allows=20for=20ARM=20builds=20now.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ab83d6b..6eaee58 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM frolvlad/alpine-python3 +FROM docker.io/library/python:3-alpine RUN pip3 install docker RUN mkdir /hoster From e6639c8fe217124fa1982e35b9fd38d0462ff448 Mon Sep 17 00:00:00 2001 From: Louis Orleans Date: Thu, 31 Aug 2023 13:59:36 -0700 Subject: [PATCH 02/11] =?UTF-8?q?=F0=9F=90=9B=20fix=20running=20on=20mac?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 19 ++++++++++++------- docker-compose.yaml | 12 ++++++++++++ hoster.py | 18 +++++++++--------- 3 files changed, 33 insertions(+), 16 deletions(-) create mode 100644 docker-compose.yaml diff --git a/Dockerfile b/Dockerfile index 6eaee58..1cbe172 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,16 @@ -FROM docker.io/library/python:3-alpine +# syntax=docker/dockerfile:1 + +ARG BASE_IMAGE=docker.io/library/python:3-alpine +ARG APP_DIR=/hoster + +FROM ${BASE_IMAGE} RUN pip3 install docker -RUN mkdir /hoster -WORKDIR /hoster -ADD hoster.py /hoster/ + +ARG APP_DIR=/hoster +WORKDIR ${APP_DIR} + +ADD hoster.py ./ CMD ["python3", "-u", "hoster.py"] - - - +# CMD "whoami" diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..f4fe945 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,12 @@ +# This file replaces `docker build -t docker-hoster .` +# Run this with `docker-compose build` +version: '3.8' + +services: + host-hostnames: + container_name: 'host-hostnames' + build: + context: '.' + volumes: + - '/var/run/docker.sock:/tmp/docker.sock:ro' + - '/etc/hosts:/tmp/hosts' diff --git a/hoster.py b/hoster.py index d87448a..dc776a4 100644 --- a/hoster.py +++ b/hoster.py @@ -39,9 +39,9 @@ def main(): #listen for events to keep the hosts file updated for e in events: - if e["Type"]!="container": + if e["Type"]!="container": continue - + status = e["status"] if status =="start": container_id = e["id"] @@ -64,16 +64,16 @@ def get_container_data(dockerClient, container_id): container_ip = info["NetworkSettings"]["IPAddress"] if info["Config"]["Domainname"]: container_hostname = container_hostname + "." + info["Config"]["Domainname"] - + result = [] for values in info["NetworkSettings"]["Networks"].values(): - - if not values["Aliases"]: + + if not values["Aliases"]: continue result.append({ - "ip": values["IPAddress"] , + "ip": values["IPAddress"] , "name": container_name, "domains": set(values["Aliases"] + [container_name, container_hostname]) }) @@ -112,11 +112,11 @@ def update_hosts_file(): #append all the domain lines if len(hosts)>0: lines.append("\n\n"+enclosing_pattern) - + for id, addresses in hosts.items(): for addr in addresses: lines.append("%s %s\n"%(addr["ip"]," ".join(addr["domains"]))) - + lines.append("#-----Do-not-add-hosts-after-this-line-----\n\n") #write it on the auxiliar file @@ -125,7 +125,7 @@ def update_hosts_file(): aux_hosts.writelines(lines) #replace etc/hosts with aux file, making it atomic - shutil.move(aux_file_path, hosts_path) + shutil.copyfile(aux_file_path, hosts_path) def parse_args(): From 643a0997e918c5b91c4a3de4264a62e68f41787b Mon Sep 17 00:00:00 2001 From: Louis Orleans Date: Thu, 31 Aug 2023 13:59:56 -0700 Subject: [PATCH 03/11] =?UTF-8?q?=F0=9F=91=B7=20build=20&=20publish=20cont?= =?UTF-8?q?ainer=20image?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-publish.yaml | 66 ++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 .github/workflows/build-publish.yaml diff --git a/.github/workflows/build-publish.yaml b/.github/workflows/build-publish.yaml new file mode 100644 index 0000000..971c94f --- /dev/null +++ b/.github/workflows/build-publish.yaml @@ -0,0 +1,66 @@ +name: 'Publish Container Image' + +# Controls when the action will run. Triggers the workflow on push or pull +# request events but only for the master branch +on: + push: + branches: + - '*' + +permissions: + contents: 'read' + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build-and-publish: + # The type of runner that the job will run on + runs-on: 'ubuntu-latest' + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - name: 'Checkout Repository ๐Ÿ›Ž๏ธ' + uses: 'actions/checkout@v2' + + - name: 'Build ๐Ÿ—๏ธ' + id: 'build' + run: | + image="$( \ + basename "$(echo "${{ github.repository }}")" \ + | tr '[:upper:]' '[:lower:]' \ + | sed 's/docker-//' \ + )" + echo "image=$image" >> "$GITHUB_OUTPUT" + + docker build --file "Dockerfile" --tag "$image" . + + - name: 'Login to GitHub Container Registry ๐Ÿ”‘' + uses: 'docker/login-action@v1' + if: '${{ github.ref_name }} == ${{ github.event.repository.default_branch }}' + with: + registry: 'ghcr.io' + username: '${{ github.repository_owner }}' + password: '${{ secrets.GITHUB_TOKEN }}' + + - name: 'Publish to Registry ๐Ÿณ' + if: '${{ github.ref_name }} == ${{ github.event.repository.default_branch }}' + run: | + image="${{ steps.build.outputs.image }}" + repo="ghcr.io/${{ github.repository_owner }}/$image" + branch="$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')" + version="$branch" + + echo "repo = $repo" + echo "image = $image" + echo "version = $version" + + docker tag "$image" "$repo/$image:$version" + docker push "$repo/$image:$version" + + # Use Docker `latest` tag convention + if [[ "${{ github.event.repository.default_branch }}" == "$branch" ]]; then + docker tag "$image" "$repo/$image:latest" + docker push "$repo/$image:latest" + fi + + echo "registry_uri=$repo/$image" >> "$GITHUB_OUTPUT" From 350efafa5bbf2b623a83ce0d000fc84fcb7c54a0 Mon Sep 17 00:00:00 2001 From: Louis Orleans Date: Thu, 31 Aug 2023 15:27:44 -0700 Subject: [PATCH 04/11] =?UTF-8?q?=F0=9F=92=9A=20add=20package=20write=20pe?= =?UTF-8?q?rms?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-publish.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-publish.yaml b/.github/workflows/build-publish.yaml index 971c94f..cb30400 100644 --- a/.github/workflows/build-publish.yaml +++ b/.github/workflows/build-publish.yaml @@ -9,6 +9,7 @@ on: permissions: contents: 'read' + packages: 'write' # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: From de768d12c169f5e28ea0be9a2bd7eab9a17485bb Mon Sep 17 00:00:00 2001 From: Louis Orleans Date: Thu, 31 Aug 2023 15:57:47 -0700 Subject: [PATCH 05/11] =?UTF-8?q?=F0=9F=91=B7=20rewrite=20CI=20build=20sys?= =?UTF-8?q?tem?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-publish.yaml | 97 ++++++++------- .github/workflows/scripts/get-image-tags.rb | 30 +++++ .github/workflows/scripts/lib.rb | 55 +++++++++ .../scripts/test/get-image-tags.unit.rb | 112 ++++++++++++++++++ 4 files changed, 248 insertions(+), 46 deletions(-) create mode 100755 .github/workflows/scripts/get-image-tags.rb create mode 100644 .github/workflows/scripts/lib.rb create mode 100755 .github/workflows/scripts/test/get-image-tags.unit.rb diff --git a/.github/workflows/build-publish.yaml b/.github/workflows/build-publish.yaml index cb30400..1425ffa 100644 --- a/.github/workflows/build-publish.yaml +++ b/.github/workflows/build-publish.yaml @@ -1,67 +1,72 @@ -name: 'Publish Container Image' +name: 'Build & Publish Container Image' -# Controls when the action will run. Triggers the workflow on push or pull -# request events but only for the master branch on: push: - branches: - - '*' + pull_request: permissions: contents: 'read' - packages: 'write' -# A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: - # This workflow contains a single job called "build" - build-and-publish: - # The type of runner that the job will run on + test-scripts: runs-on: 'ubuntu-latest' - - # Steps represent a sequence of tasks that will be executed as part of the job steps: - name: 'Checkout Repository ๐Ÿ›Ž๏ธ' - uses: 'actions/checkout@v2' + uses: 'actions/checkout@v3' + - name: 'Test ๐Ÿงช' + run: 'ruby .github/workflows/scripts/test/get-image-tags.unit.rb' - - name: 'Build ๐Ÿ—๏ธ' - id: 'build' + container-build: + needs: 'test-scripts' + runs-on: 'ubuntu-latest' + steps: + - name: 'Checkout Repository ๐Ÿ›Ž๏ธ' + uses: 'actions/checkout@v3' + - uses: 'docker/setup-buildx-action@v2' + + - name: 'Get image tag names ๐Ÿท๏ธ' + id: 'tag-image' run: | - image="$( \ - basename "$(echo "${{ github.repository }}")" \ - | tr '[:upper:]' '[:lower:]' \ - | sed 's/docker-//' \ - )" - echo "image=$image" >> "$GITHUB_OUTPUT" + echo "image_tags=$( + .github/workflows/scripts/get-image-tags.rb \ + "${{ github.repository }}" \ + "${{ github.ref_name }}" \ + "${{ github.ref_type }}" \ + "${{ github.event.repository.default_branch }}" \ + )" >> "$GITHUB_OUTPUT" + - name: 'Build container ๐Ÿณ' + uses: 'docker/build-push-action@v3' + with: + file: 'Dockerfile' + tags: '${{ steps.tag-image.outputs.image_tags }}' + cache-from: 'type=gha' + cache-to: 'type=gha,mode=max' - docker build --file "Dockerfile" --tag "$image" . + outputs: + image_tags: '${{ steps.tag-image.outputs.image_tags }}' + publish: + needs: + - 'container-build' + if: contains(needs.container-build.outputs.image_tags, ':latest') + runs-on: 'ubuntu-latest' + permissions: + packages: 'write' + steps: + - name: 'Checkout Repository ๐Ÿ›Ž๏ธ' + uses: 'actions/checkout@v3' + - uses: 'docker/setup-buildx-action@v2' - name: 'Login to GitHub Container Registry ๐Ÿ”‘' - uses: 'docker/login-action@v1' - if: '${{ github.ref_name }} == ${{ github.event.repository.default_branch }}' + uses: 'docker/login-action@v2' with: registry: 'ghcr.io' username: '${{ github.repository_owner }}' password: '${{ secrets.GITHUB_TOKEN }}' - - name: 'Publish to Registry ๐Ÿณ' - if: '${{ github.ref_name }} == ${{ github.event.repository.default_branch }}' - run: | - image="${{ steps.build.outputs.image }}" - repo="ghcr.io/${{ github.repository_owner }}/$image" - branch="$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')" - version="$branch" - - echo "repo = $repo" - echo "image = $image" - echo "version = $version" - - docker tag "$image" "$repo/$image:$version" - docker push "$repo/$image:$version" - - # Use Docker `latest` tag convention - if [[ "${{ github.event.repository.default_branch }}" == "$branch" ]]; then - docker tag "$image" "$repo/$image:latest" - docker push "$repo/$image:latest" - fi - - echo "registry_uri=$repo/$image" >> "$GITHUB_OUTPUT" + - name: 'Publish to Registry ๐Ÿ’จ' + uses: 'docker/build-push-action@v3' + with: + file: 'Dockerfile' + push: true + tags: '${{ needs.container-build.outputs.image_tags }}' + cache-from: 'type=gha' diff --git a/.github/workflows/scripts/get-image-tags.rb b/.github/workflows/scripts/get-image-tags.rb new file mode 100755 index 0000000..bdcb230 --- /dev/null +++ b/.github/workflows/scripts/get-image-tags.rb @@ -0,0 +1,30 @@ +#!/usr/bin/env ruby + +require 'json' +require_relative 'lib' + +def main + git_repo = ARGV[0] + git_ref_name = ARGV[1] + git_ref_type = ARGV[2] + git_default_branch = ARGV[3] + + # log to stderr so that stdout only contains the full tags + $stderr.puts "'#{git_repo}', '#{git_ref_name}', '#{git_ref_type}', '#{git_default_branch}'" + + tags = + get_image_tags( + git_repo: git_repo, + git_ref_name: git_ref_name, + git_ref_type: git_ref_type, + git_default_branch: git_default_branch, + package: JSON.parse(File.read('package.json')), + ).to_a.join(',') + + # log to stderr so that stdout only contains the full tags + $stderr.puts tags + + puts tags +end + +main() diff --git a/.github/workflows/scripts/lib.rb b/.github/workflows/scripts/lib.rb new file mode 100644 index 0000000..d8d0353 --- /dev/null +++ b/.github/workflows/scripts/lib.rb @@ -0,0 +1,55 @@ +require 'set' + +# @param git_repo [String] +# @param git_ref_name [String] +# @param git_ref_type [String] +# @param git_default_branch [String] +# @return [Set[String]] +def get_image_tags( + git_repo: nil, + git_ref_name: nil, + git_ref_type: nil, + git_default_branch: nil, + package: nil +) + container_repo = "ghcr.io/#{git_repo.downcase}" + versions = Set[] + + if git_ref_type == 'branch' + # add safe branch name + versions.add(git_ref_name.downcase.gsub(/[^a-z0-9._\n]+/, '-')) + elsif git_ref_type == 'tag' + # add version tag + versions.add(package['version']) + # TODO: check that this is actually latest + parsed = parse_semver(package['version']) + if parsed.pre == nil + versions.add(parsed.major) + versions.add("#{parsed.major}.#{parsed.minor}") + versions.add("#{parsed.major}.#{parsed.minor}.#{parsed.patch}") + end + + # TODO: if the tag was made on a non-default branch, we still tag with default branch + versions.add(git_default_branch) + end + + # TODO: if `tag`, check that this is actually latest + if git_ref_name == git_default_branch or git_ref_type == 'tag' + # Use Docker `latest` tag convention, only tagging `latest` on default branch. + versions.add('latest') + end + + return versions.map! { |v| "#{container_repo}/bot:#{v}" } +end + +Semver = Struct.new('Semver', :major, :minor, :patch, :pre, :build) + +# @param version [String] +# @return [Semver] +def parse_semver(version) + # Ruby extracts regex named groups to local vars (but only if the regex is inlined). + /^(?\d+)\.(?\d+)\.(?\d+)(?:-(?
[0-9A-Za-z\-.]+))?(?:\+(?[0-9A-Za-z\-]+))?$/ =~
+    version
+
+  Semver.new(major.to_i, minor.to_i, patch.to_i, pre, build)
+end
diff --git a/.github/workflows/scripts/test/get-image-tags.unit.rb b/.github/workflows/scripts/test/get-image-tags.unit.rb
new file mode 100755
index 0000000..32e69b9
--- /dev/null
+++ b/.github/workflows/scripts/test/get-image-tags.unit.rb
@@ -0,0 +1,112 @@
+require 'test/unit'
+require 'json'
+require 'set'
+
+require_relative '../lib'
+
+class TestGetImageTags < Test::Unit::TestCase
+  def test_simple_branch
+    assert_equal(
+      Set['ghcr.io/virginity-bot/virginity-bot/bot:feat-foo-bar'],
+      get_image_tags(
+        git_repo: 'Virginity-Bot/virginity-bot',
+        git_ref_name: 'feat/foo-bar',
+        git_ref_type: 'branch',
+        git_default_branch: 'master',
+        package: JSON.parse('{"version": "1.0.0"}'),
+      ),
+    )
+
+    assert_equal(
+      Set[
+        'ghcr.io/virginity-bot/virginity.bot/bot:latest',
+        'ghcr.io/virginity-bot/virginity.bot/bot:master'
+      ],
+      get_image_tags(
+        git_repo: 'Virginity-Bot/virginity.bot',
+        git_ref_name: 'master',
+        git_ref_type: 'branch',
+        git_default_branch: 'master',
+        package: JSON.parse('{"version": "1.0.0"}'),
+      ),
+    )
+  end
+
+  def test_simple_tag
+    assert_equal(
+      Set[
+        'ghcr.io/virginity-bot/virginity.bot/bot:latest',
+        'ghcr.io/virginity-bot/virginity.bot/bot:master',
+        'ghcr.io/virginity-bot/virginity.bot/bot:1.0.0',
+        'ghcr.io/virginity-bot/virginity.bot/bot:1.0',
+        'ghcr.io/virginity-bot/virginity.bot/bot:1'
+      ],
+      get_image_tags(
+        git_repo: 'Virginity-Bot/virginity.bot',
+        git_ref_name: '1.0.0',
+        git_ref_type: 'tag',
+        git_default_branch: 'master',
+        package: JSON.parse('{"version": "1.0.0"}'),
+      ),
+    )
+  end
+
+  def test_pre_tag
+    assert_equal(
+      Set[
+        'ghcr.io/virginity-bot/virginity.bot/bot:latest',
+        'ghcr.io/virginity-bot/virginity.bot/bot:master',
+        'ghcr.io/virginity-bot/virginity.bot/bot:1.0.0-pre'
+      ],
+      get_image_tags(
+        git_repo: 'Virginity-Bot/virginity.bot',
+        git_ref_name: '1.0.0',
+        git_ref_type: 'tag',
+        git_default_branch: 'master',
+        package: JSON.parse('{"version": "1.0.0-pre"}'),
+      ),
+    )
+  end
+
+  def test_unsafe_branch_name
+    assert_equal(
+      Set['ghcr.io/virginity-bot/virginity.bot/bot:feat-foo-bar'],
+      get_image_tags(
+        git_repo: 'Virginity-Bot/virginity.bot',
+        git_ref_name: 'feat/Foo---bar',
+        git_ref_type: 'branch',
+        git_default_branch: 'master',
+        package: JSON.parse('{"version": "1.0.0"}'),
+      ),
+    )
+  end
+end
+
+class TestParseSemver < Test::Unit::TestCase
+  def test_parse_basic
+    parsed = parse_semver('1.2.3')
+    assert_equal(1, parsed.major)
+    assert_equal(2, parsed.minor)
+    assert_equal(3, parsed.patch)
+    assert_equal(nil, parsed.pre)
+    assert_equal(nil, parsed.build)
+  end
+
+  def test_parse_pre
+    parsed = parse_semver('1.2.3-p.re')
+    assert_equal(1, parsed.major)
+    assert_equal(2, parsed.minor)
+    assert_equal(3, parsed.patch)
+    assert_equal('p.re', parsed.pre)
+    assert_equal(nil, parsed.build)
+  end
+
+  def test_parse_full_semver
+    parsed = parse_semver('1.2.3-p.re+build')
+    assert_equal(1, parsed.major)
+    assert_equal(2, parsed.minor)
+    assert_equal(3, parsed.patch)
+    assert_equal('p.re', parsed.pre)
+    assert_equal('build', parsed.build)
+  end
+end

From d184fef5c0ce46067667082552cfacddc7c696b4 Mon Sep 17 00:00:00 2001
From: Louis Orleans 
Date: Thu, 31 Aug 2023 16:27:50 -0700
Subject: [PATCH 06/11] =?UTF-8?q?=F0=9F=91=B7=20build=20for=20ARM?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .github/workflows/build-publish.yaml | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/.github/workflows/build-publish.yaml b/.github/workflows/build-publish.yaml
index 1425ffa..090faae 100644
--- a/.github/workflows/build-publish.yaml
+++ b/.github/workflows/build-publish.yaml
@@ -34,16 +34,31 @@ jobs:
               "${{ github.ref_type }}" \
               "${{ github.event.repository.default_branch }}" \
           )" >> "$GITHUB_OUTPUT"
+
+      - name: 'Set up QEMU ๐Ÿฆ…'
+        id: 'qemu'
+        uses: 'docker/setup-qemu-action@v2'
+        with:
+          platforms: 'arm64'
+      - name: 'Set target build platforms ๐Ÿ“'
+        id: 'target-platforms'
+        run: |
+          echo "target_platforms=linux/amd64,linux/${{ steps.qemu.outputs.platforms }}" >> "$GITHUB_OUTPUT"
+
       - name: 'Build container ๐Ÿณ'
+        id: 'build'
         uses: 'docker/build-push-action@v3'
         with:
           file: 'Dockerfile'
           tags: '${{ steps.tag-image.outputs.image_tags }}'
+          platforms: '${{ steps.target-platforms.outputs.target_platforms }}'
           cache-from: 'type=gha'
           cache-to: 'type=gha,mode=max'
 
     outputs:
       image_tags: '${{ steps.tag-image.outputs.image_tags }}'
+      qemu_platforms: '${{ steps.qemu.outputs.platforms }}'
+      docker_platforms: '${{ steps.target-platforms.outputs.target_platforms }}'
 
   publish:
     needs:
@@ -63,10 +78,16 @@ jobs:
           username: '${{ github.repository_owner }}'
           password: '${{ secrets.GITHUB_TOKEN }}'
 
+      - name: 'Set up QEMU ๐Ÿฆ…'
+        uses: 'docker/setup-qemu-action@v2'
+        with:
+          platforms: '${{ needs.container-build.outputs.qemu_platforms }}'
+
       - name: 'Publish to Registry ๐Ÿ’จ'
         uses: 'docker/build-push-action@v3'
         with:
           file: 'Dockerfile'
           push: true
           tags: '${{ needs.container-build.outputs.image_tags }}'
+          platforms: '${{ needs.container-build.outputs.docker_platforms }}'
           cache-from: 'type=gha'

From b81255e437d386aa86315ea78f05bcbefc7f516f Mon Sep 17 00:00:00 2001
From: Louis Orleans 
Date: Thu, 31 Aug 2023 16:33:27 -0700
Subject: [PATCH 07/11] =?UTF-8?q?=F0=9F=92=9A=20fix=20package=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .github/workflows/scripts/get-image-tags.rb           |  2 +-
 .github/workflows/scripts/lib.rb                      |  6 +++---
 .github/workflows/scripts/test/get-image-tags.unit.rb | 10 +++++-----
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/.github/workflows/scripts/get-image-tags.rb b/.github/workflows/scripts/get-image-tags.rb
index bdcb230..0bf30cc 100755
--- a/.github/workflows/scripts/get-image-tags.rb
+++ b/.github/workflows/scripts/get-image-tags.rb
@@ -18,7 +18,7 @@ def main
       git_ref_name: git_ref_name,
       git_ref_type: git_ref_type,
       git_default_branch: git_default_branch,
-      package: JSON.parse(File.read('package.json')),
+      semver: '0.0.0',
     ).to_a.join(',')
 
   # log to stderr so that stdout only contains the full tags
diff --git a/.github/workflows/scripts/lib.rb b/.github/workflows/scripts/lib.rb
index d8d0353..462ea24 100644
--- a/.github/workflows/scripts/lib.rb
+++ b/.github/workflows/scripts/lib.rb
@@ -10,7 +10,7 @@ def get_image_tags(
   git_ref_name: nil,
   git_ref_type: nil,
   git_default_branch: nil,
-  package: nil
+  semver: nil
 )
   container_repo = "ghcr.io/#{git_repo.downcase}"
   versions = Set[]
@@ -20,9 +20,9 @@ def get_image_tags(
     versions.add(git_ref_name.downcase.gsub(/[^a-z0-9._\n]+/, '-'))
   elsif git_ref_type == 'tag'
     # add version tag
-    versions.add(package['version'])
+    versions.add(semver)
     # TODO: check that this is actually latest
-    parsed = parse_semver(package['version'])
+    parsed = parse_semver(semver)
     if parsed.pre == nil
       versions.add(parsed.major)
       versions.add("#{parsed.major}.#{parsed.minor}")
diff --git a/.github/workflows/scripts/test/get-image-tags.unit.rb b/.github/workflows/scripts/test/get-image-tags.unit.rb
index 32e69b9..6490d84 100755
--- a/.github/workflows/scripts/test/get-image-tags.unit.rb
+++ b/.github/workflows/scripts/test/get-image-tags.unit.rb
@@ -13,7 +13,7 @@ class TestGetImageTags < Test::Unit::TestCase
         git_ref_name: 'feat/foo-bar',
         git_ref_type: 'branch',
         git_default_branch: 'master',
-        package: JSON.parse('{"version": "1.0.0"}'),
+        semver: '1.0.0',
       ),
     )
 
@@ -27,7 +27,7 @@ class TestGetImageTags < Test::Unit::TestCase
         git_ref_name: 'master',
         git_ref_type: 'branch',
         git_default_branch: 'master',
-        package: JSON.parse('{"version": "1.0.0"}'),
+        semver: '1.0.0',
       ),
     )
   end
@@ -46,7 +46,7 @@ class TestGetImageTags < Test::Unit::TestCase
         git_ref_name: '1.0.0',
         git_ref_type: 'tag',
         git_default_branch: 'master',
-        package: JSON.parse('{"version": "1.0.0"}'),
+        semver: '1.0.0',
       ),
     )
   end
@@ -63,7 +63,7 @@ class TestGetImageTags < Test::Unit::TestCase
         git_ref_name: '1.0.0',
         git_ref_type: 'tag',
         git_default_branch: 'master',
-        package: JSON.parse('{"version": "1.0.0-pre"}'),
+        semver: '1.0.0-pre',
       ),
     )
   end
@@ -76,7 +76,7 @@ class TestGetImageTags < Test::Unit::TestCase
         git_ref_name: 'feat/Foo---bar',
         git_ref_type: 'branch',
         git_default_branch: 'master',
-        package: JSON.parse('{"version": "1.0.0"}'),
+        semver: '1.0.0',
       ),
     )
   end

From 7edbba21767293905932472e02c6374d055c0ab9 Mon Sep 17 00:00:00 2001
From: Louis Orleans 
Date: Thu, 31 Aug 2023 17:31:12 -0700
Subject: [PATCH 08/11] =?UTF-8?q?=F0=9F=92=9A=20fix=20platforms=3F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .github/workflows/build-publish.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/build-publish.yaml b/.github/workflows/build-publish.yaml
index 090faae..549efa7 100644
--- a/.github/workflows/build-publish.yaml
+++ b/.github/workflows/build-publish.yaml
@@ -43,7 +43,7 @@ jobs:
       - name: 'Set target build platforms ๐Ÿ“'
         id: 'target-platforms'
         run: |
-          echo "target_platforms=linux/amd64,linux/${{ steps.qemu.outputs.platforms }}" >> "$GITHUB_OUTPUT"
+          echo "target_platforms=linux/amd64,linux/${{ steps.qemu.outputs.platforms }}/v8" >> "$GITHUB_OUTPUT"
 
       - name: 'Build container ๐Ÿณ'
         id: 'build'

From 33cd306ec29e1006f0623bd8e7655d0356df3595 Mon Sep 17 00:00:00 2001
From: Louis Orleans 
Date: Fri, 1 Sep 2023 11:05:51 -0700
Subject: [PATCH 09/11] =?UTF-8?q?=F0=9F=92=9A=20fix=20platforms=202:=20ele?=
 =?UTF-8?q?ctric=20boogaloo=3F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .github/workflows/build-publish.yaml          |  3 ++-
 .../scripts/convert-arch-to-platform.sh       | 23 +++++++++++++++++++
 2 files changed, 25 insertions(+), 1 deletion(-)
 create mode 100755 .github/workflows/scripts/convert-arch-to-platform.sh

diff --git a/.github/workflows/build-publish.yaml b/.github/workflows/build-publish.yaml
index 549efa7..17a4a03 100644
--- a/.github/workflows/build-publish.yaml
+++ b/.github/workflows/build-publish.yaml
@@ -43,7 +43,8 @@ jobs:
       - name: 'Set target build platforms ๐Ÿ“'
         id: 'target-platforms'
         run: |
-          echo "target_platforms=linux/amd64,linux/${{ steps.qemu.outputs.platforms }}/v8" >> "$GITHUB_OUTPUT"
+          qemu_platforms="$(.github/workflows/scripts/convert-arch-to-platform.sh "${{ steps.qemu.outputs.platforms }}")"
+          echo "target_platforms=$qemu_platforms" >> "$GITHUB_OUTPUT"
 
       - name: 'Build container ๐Ÿณ'
         id: 'build'
diff --git a/.github/workflows/scripts/convert-arch-to-platform.sh b/.github/workflows/scripts/convert-arch-to-platform.sh
new file mode 100755
index 0000000..1f7449e
--- /dev/null
+++ b/.github/workflows/scripts/convert-arch-to-platform.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+
+qemu_platforms=""
+
+for p in $(echo "$1" | tr ',' '\n'); do
+  v=""
+  case "$p" in
+    "linux/arm64")
+      v="$p/v8" ;;
+    # Skip platforms we don't need
+    "linux/386") ;;
+    *)
+      v="$p" ;;
+  esac
+
+  if [ -z "$qemu_platforms" ]; then
+    qemu_platforms="$v"
+  else
+    qemu_platforms="$qemu_platforms,$v"
+  fi
+done
+
+echo "$qemu_platforms"

From 98e188a32f0124836c976bb812b1990f3f6a26a3 Mon Sep 17 00:00:00 2001
From: Louis Orleans 
Date: Fri, 1 Sep 2023 12:02:56 -0700
Subject: [PATCH 10/11] =?UTF-8?q?=F0=9F=90=9B=20generalize=20image=20name?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .github/workflows/scripts/get-image-tags.rb   |  8 ++-
 .github/workflows/scripts/lib.rb              | 18 ++++--
 .../scripts/test/get-image-tags.unit.rb       | 57 +++++++++++--------
 3 files changed, 53 insertions(+), 30 deletions(-)

diff --git a/.github/workflows/scripts/get-image-tags.rb b/.github/workflows/scripts/get-image-tags.rb
index 0bf30cc..50746e3 100755
--- a/.github/workflows/scripts/get-image-tags.rb
+++ b/.github/workflows/scripts/get-image-tags.rb
@@ -12,14 +12,18 @@ def main
   # log to stderr so that stdout only contains the full tags
   $stderr.puts "'#{git_repo}', '#{git_ref_name}', '#{git_ref_type}', '#{git_default_branch}'"
 
+  image_name = get_image_name(git_repo: git_repo)
+
   tags =
     get_image_tags(
-      git_repo: git_repo,
       git_ref_name: git_ref_name,
       git_ref_type: git_ref_type,
       git_default_branch: git_default_branch,
       semver: '0.0.0',
-    ).to_a.join(',')
+    )
+    .to_a
+    .map {|tag| "#{image_name}:#{tag}" }
+    .join(',')
 
   # log to stderr so that stdout only contains the full tags
   $stderr.puts tags
diff --git a/.github/workflows/scripts/lib.rb b/.github/workflows/scripts/lib.rb
index 462ea24..56dc625 100644
--- a/.github/workflows/scripts/lib.rb
+++ b/.github/workflows/scripts/lib.rb
@@ -1,18 +1,15 @@
 require 'set'
 
-# @param git_repo [String]
 # @param git_ref_name [String]
 # @param git_ref_type [String]
 # @param git_default_branch [String]
 # @return [Set[String]]
 def get_image_tags(
-  git_repo: nil,
   git_ref_name: nil,
   git_ref_type: nil,
   git_default_branch: nil,
   semver: nil
 )
-  container_repo = "ghcr.io/#{git_repo.downcase}"
   versions = Set[]
 
   if git_ref_type == 'branch'
@@ -24,7 +21,7 @@ def get_image_tags(
     # TODO: check that this is actually latest
     parsed = parse_semver(semver)
     if parsed.pre == nil
-      versions.add(parsed.major)
+      versions.add(parsed.major.to_s)
       versions.add("#{parsed.major}.#{parsed.minor}")
       versions.add("#{parsed.major}.#{parsed.minor}.#{parsed.patch}")
     end
@@ -39,7 +36,18 @@ def get_image_tags(
     versions.add('latest')
   end
 
-  return versions.map! { |v| "#{container_repo}/bot:#{v}" }
+  return versions
+end
+
+# @param registry [String]
+# @param git_repo [String]
+# @param sub_image [String?]
+# @return String
+def get_image_name(registry: 'ghcr.io', git_repo: nil, sub_image: nil)
+  git_repo = git_repo.downcase
+
+  default_sub_image = File.basename git_repo
+  container_repo = "#{registry}/#{git_repo}/#{sub_image ? sub_image : default_sub_image}"
 end
 
 Semver = Struct.new('Semver', :major, :minor, :patch, :pre, :build)
diff --git a/.github/workflows/scripts/test/get-image-tags.unit.rb b/.github/workflows/scripts/test/get-image-tags.unit.rb
index 6490d84..15536b4 100755
--- a/.github/workflows/scripts/test/get-image-tags.unit.rb
+++ b/.github/workflows/scripts/test/get-image-tags.unit.rb
@@ -1,3 +1,5 @@
+#!/usr/bin/env ruby
+
 require 'test/unit'
 require 'json'
 require 'set'
@@ -7,9 +9,8 @@ require_relative '../lib'
 class TestGetImageTags < Test::Unit::TestCase
   def test_simple_branch
     assert_equal(
-      Set['ghcr.io/virginity-bot/virginity-bot/bot:feat-foo-bar'],
+      Set['feat-foo-bar'],
       get_image_tags(
-        git_repo: 'Virginity-Bot/virginity-bot',
         git_ref_name: 'feat/foo-bar',
         git_ref_type: 'branch',
         git_default_branch: 'master',
@@ -18,12 +19,8 @@ class TestGetImageTags < Test::Unit::TestCase
     )
 
     assert_equal(
-      Set[
-        'ghcr.io/virginity-bot/virginity.bot/bot:latest',
-        'ghcr.io/virginity-bot/virginity.bot/bot:master'
-      ],
+      Set['latest', 'master'],
       get_image_tags(
-        git_repo: 'Virginity-Bot/virginity.bot',
         git_ref_name: 'master',
         git_ref_type: 'branch',
         git_default_branch: 'master',
@@ -34,15 +31,8 @@ class TestGetImageTags < Test::Unit::TestCase
 
   def test_simple_tag
     assert_equal(
-      Set[
-        'ghcr.io/virginity-bot/virginity.bot/bot:latest',
-        'ghcr.io/virginity-bot/virginity.bot/bot:master',
-        'ghcr.io/virginity-bot/virginity.bot/bot:1.0.0',
-        'ghcr.io/virginity-bot/virginity.bot/bot:1.0',
-        'ghcr.io/virginity-bot/virginity.bot/bot:1'
-      ],
+      Set['latest', 'master', '1.0.0', '1.0', '1'],
       get_image_tags(
-        git_repo: 'Virginity-Bot/virginity.bot',
         git_ref_name: '1.0.0',
         git_ref_type: 'tag',
         git_default_branch: 'master',
@@ -53,13 +43,8 @@ class TestGetImageTags < Test::Unit::TestCase
 
   def test_pre_tag
     assert_equal(
-      Set[
-        'ghcr.io/virginity-bot/virginity.bot/bot:latest',
-        'ghcr.io/virginity-bot/virginity.bot/bot:master',
-        'ghcr.io/virginity-bot/virginity.bot/bot:1.0.0-pre'
-      ],
+      Set['latest', 'master', '1.0.0-pre'],
       get_image_tags(
-        git_repo: 'Virginity-Bot/virginity.bot',
         git_ref_name: '1.0.0',
         git_ref_type: 'tag',
         git_default_branch: 'master',
@@ -70,9 +55,8 @@ class TestGetImageTags < Test::Unit::TestCase
 
   def test_unsafe_branch_name
     assert_equal(
-      Set['ghcr.io/virginity-bot/virginity.bot/bot:feat-foo-bar'],
+      Set['feat-foo-bar'],
       get_image_tags(
-        git_repo: 'Virginity-Bot/virginity.bot',
         git_ref_name: 'feat/Foo---bar',
         git_ref_type: 'branch',
         git_default_branch: 'master',
@@ -82,6 +66,33 @@ class TestGetImageTags < Test::Unit::TestCase
   end
 end
 
+class TestGetImageName < Test::Unit::TestCase
+  def test_basic
+    assert_equal(
+      'ghcr.io/octocat/hello-world/hello-world',
+      get_image_name(
+        git_repo: 'Octocat/hello-world',
+      ),
+    )
+
+    assert_equal(
+      'ghcr.io/octocat/hello-world/foobar',
+      get_image_name(
+        git_repo: 'Octocat/hello-world',
+        sub_image: 'foobar',
+      ),
+    )
+
+    assert_equal(
+      'docker.io/octocat/hello-world/hello-world',
+      get_image_name(
+        registry: 'docker.io',
+        git_repo: 'Octocat/hello-world',
+      ),
+    )
+  end
+end
+
 class TestParseSemver < Test::Unit::TestCase
   def test_parse_basic
     parsed = parse_semver('1.2.3')

From 26ae5311d90a2d33ca86d5ddb02f27825c9421e7 Mon Sep 17 00:00:00 2001
From: Louis Orleans 
Date: Fri, 1 Sep 2023 12:21:01 -0700
Subject: [PATCH 11/11] =?UTF-8?q?=F0=9F=90=9B=20clean=20up=20image=20name?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .github/workflows/build-publish.yaml          |  3 +-
 .github/workflows/scripts/get-image-tags.rb   | 13 ++++---
 .github/workflows/scripts/lib.rb              | 20 +++++++---
 .../scripts/test/get-image-tags.unit.rb       | 38 +++++++++++++++++--
 4 files changed, 58 insertions(+), 16 deletions(-)

diff --git a/.github/workflows/build-publish.yaml b/.github/workflows/build-publish.yaml
index 17a4a03..7f3e199 100644
--- a/.github/workflows/build-publish.yaml
+++ b/.github/workflows/build-publish.yaml
@@ -29,7 +29,8 @@ jobs:
         run: |
           echo "image_tags=$(
             .github/workflows/scripts/get-image-tags.rb \
-              "${{ github.repository }}" \
+              "${{ github.repository_owner }}" \
+              "${{ github.event.repository.name }}" \
               "${{ github.ref_name }}" \
               "${{ github.ref_type }}" \
               "${{ github.event.repository.default_branch }}" \
diff --git a/.github/workflows/scripts/get-image-tags.rb b/.github/workflows/scripts/get-image-tags.rb
index 50746e3..1d7454c 100755
--- a/.github/workflows/scripts/get-image-tags.rb
+++ b/.github/workflows/scripts/get-image-tags.rb
@@ -4,15 +4,16 @@ require 'json'
 require_relative 'lib'
 
 def main
-  git_repo = ARGV[0]
-  git_ref_name = ARGV[1]
-  git_ref_type = ARGV[2]
-  git_default_branch = ARGV[3]
+  repo_owner = ARGV[0]
+  repo_name = ARGV[1]
+  git_ref_name = ARGV[2]
+  git_ref_type = ARGV[3]
+  git_default_branch = ARGV[4]
 
   # log to stderr so that stdout only contains the full tags
-  $stderr.puts "'#{git_repo}', '#{git_ref_name}', '#{git_ref_type}', '#{git_default_branch}'"
+  $stderr.puts "'#{repo_owner}', '#{repo_name}', '#{git_ref_name}', '#{git_ref_type}', '#{git_default_branch}'"
 
-  image_name = get_image_name(git_repo: git_repo)
+  image_name = get_image_name(username: repo_owner, project_name: repo_name)
 
   tags =
     get_image_tags(
diff --git a/.github/workflows/scripts/lib.rb b/.github/workflows/scripts/lib.rb
index 56dc625..443fe32 100644
--- a/.github/workflows/scripts/lib.rb
+++ b/.github/workflows/scripts/lib.rb
@@ -40,14 +40,24 @@ def get_image_tags(
 end
 
 # @param registry [String]
-# @param git_repo [String]
+# @param username [String]
 # @param sub_image [String?]
 # @return String
-def get_image_name(registry: 'ghcr.io', git_repo: nil, sub_image: nil)
-  git_repo = git_repo.downcase
+def get_image_name(
+  registry: 'ghcr.io',
+  username: nil,
+  project_name: nil,
+  sub_image: nil
+)
+  username = username.downcase
+  project_name = project_name.downcase.gsub(/^docker-/, '')
 
-  default_sub_image = File.basename git_repo
-  container_repo = "#{registry}/#{git_repo}/#{sub_image ? sub_image : default_sub_image}"
+  case registry
+    when 'ghcr.io'
+      container_repo = "#{registry}/#{username}/#{project_name}/#{sub_image ? sub_image : project_name}"
+    when 'docker.io'
+      container_repo = "#{registry}/#{username}/#{project_name}#{sub_image ? "-#{sub_image}" : ''}"
+  end
 end
 
 Semver = Struct.new('Semver', :major, :minor, :patch, :pre, :build)
diff --git a/.github/workflows/scripts/test/get-image-tags.unit.rb b/.github/workflows/scripts/test/get-image-tags.unit.rb
index 15536b4..f971d6a 100755
--- a/.github/workflows/scripts/test/get-image-tags.unit.rb
+++ b/.github/workflows/scripts/test/get-image-tags.unit.rb
@@ -71,23 +71,53 @@ class TestGetImageName < Test::Unit::TestCase
     assert_equal(
       'ghcr.io/octocat/hello-world/hello-world',
       get_image_name(
-        git_repo: 'Octocat/hello-world',
+        username: 'Octocat',
+        project_name: 'hello-world',
+      ),
+    )
+
+    assert_equal(
+      'ghcr.io/octocat/hello-world/hello-world',
+      get_image_name(
+        username: 'Octocat',
+        project_name: 'docker-hello-world',
       ),
     )
 
     assert_equal(
       'ghcr.io/octocat/hello-world/foobar',
       get_image_name(
-        git_repo: 'Octocat/hello-world',
+        username: 'Octocat',
+        project_name: 'hello-world',
         sub_image: 'foobar',
       ),
     )
 
     assert_equal(
-      'docker.io/octocat/hello-world/hello-world',
+      'ghcr.io/octocat/hello-world/foo',
+      get_image_name(
+        username: 'Octocat',
+        project_name: 'hello-world',
+        sub_image: 'foo'
+      ),
+    )
+
+    assert_equal(
+      'docker.io/octocat/hello-world',
       get_image_name(
         registry: 'docker.io',
-        git_repo: 'Octocat/hello-world',
+        username: 'Octocat',
+        project_name: 'hello-world',
+      ),
+    )
+
+    assert_equal(
+      'docker.io/octocat/hello-world-foo',
+      get_image_name(
+        registry: 'docker.io',
+        username: 'Octocat',
+        project_name: 'hello-world',
+        sub_image: 'foo'
       ),
     )
   end