Skip to content

Commit 65e7ea8

Browse files
authored
docker: fix publish workflow (#552)
Since a credential rotation, the GitHub Action responsible for pushing the [src-batch-change-volume-workspace][1] has been failing. This action works as expected when used via Docker outside of the GitHub Action infrastructure; I suspect there's an issue with the handling of a particular character in the action-specific entry script. That said, there's not _much_ reason to pull in a third party action here; the push script already has the required credentials, and the Docker Hub API, while undocumented, is straightforward. I've added the required urllib-foo to make this happen. (I'd normally pull in Python's excellent requests library for this kind of thing, but that means we'd have to start installing dependencies in the GitHub Action that runs this script, and that feels like more effort than I'm really willing to go to here.) Fixes #548. [1]: https://hub.docker.com/r/sourcegraph/src-batch-change-volume-workspace
1 parent 22898ff commit 65e7ea8

File tree

4 files changed

+65
-16
lines changed

4 files changed

+65
-16
lines changed

.github/workflows/docker.yml

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,7 @@ jobs:
2828
with:
2929
platforms: arm64
3030

31-
- run: ./docker/batch-change-volume-workspace/push.py -d ./docker/batch-change-volume-workspace/Dockerfile -i sourcegraph/src-batch-change-volume-workspace -p linux/amd64,linux/arm64,linux/386
31+
- run: ./docker/batch-change-volume-workspace/push.py -d ./docker/batch-change-volume-workspace/Dockerfile -i sourcegraph/src-batch-change-volume-workspace -p linux/amd64,linux/arm64,linux/386 --readme ./docker/batch-change-volume-workspace/README.md
3232
env:
3333
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
3434
DOCKER_USERNAME: sourcegraphci
35-
36-
- name: Update Docker Hub description
37-
uses: peter-evans/dockerhub-description@v2
38-
with:
39-
username: sourcegraphci
40-
password: ${{ secrets.DOCKER_PASSWORD }}
41-
repository: sourcegraph/src-batch-change-volume-workspace
42-
readme-filepath: ./docker/batch-change-volume-workspace/README.md

.github/workflows/goreleaser-check.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: GoReleaser
1+
name: GoReleaser check
22

33
on:
44
- push

.github/workflows/goreleaser.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Goreleaser
1+
name: GoReleaser
22

33
on:
44
push:

docker/batch-change-volume-workspace/push.py

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,17 @@
2929
# More instructions on this can be found at
3030
# https://docs.docker.com/buildx/working-with-buildx/#build-multi-platform-images.
3131

32+
from __future__ import annotations
33+
3234
import argparse
3335
import itertools
36+
import json
3437
import os
3538
import subprocess
3639

37-
from typing import BinaryIO, Optional, Sequence
40+
from ssl import SSLContext
41+
from typing import BinaryIO, Optional, Sequence, TextIO
42+
from urllib.request import urlopen, Request
3843

3944

4045
def calculate_tags(ref: str) -> Sequence[str]:
@@ -65,7 +70,7 @@ def calculate_tags(ref: str) -> Sequence[str]:
6570
return tags
6671

6772

68-
def docker_build(
73+
def docker_cli_build(
6974
dockerfile: BinaryIO, platform: Optional[str], image: str, tags: Sequence[str]
7075
):
7176
args = ["docker", "buildx", "build", "--push"]
@@ -84,14 +89,55 @@ def docker_build(
8489
run(args, stdin=dockerfile)
8590

8691

87-
def docker_login(username: str, password: str):
92+
def docker_cli_login(username: str, password: str):
8893
run(
8994
["docker", "login", f"-u={username}", "--password-stdin"],
9095
input=password,
9196
text=True,
9297
)
9398

9499

100+
class DockerHub:
101+
context: SSLContext
102+
token: str
103+
104+
@staticmethod
105+
def login(username: str, password: str) -> DockerHub:
106+
context = SSLContext()
107+
context.load_default_certs()
108+
109+
with urlopen(
110+
Request(
111+
"https://hub.docker.com/v2/users/login",
112+
method="POST",
113+
data=json.dumps({"username": username, "password": password}).encode(
114+
"utf-8"
115+
),
116+
headers={"Content-Type": "application/json; charset=utf-8"},
117+
),
118+
context=context,
119+
) as resp:
120+
hub = DockerHub()
121+
hub.context = context
122+
hub.token = json.load(resp)["token"]
123+
124+
return hub
125+
126+
def update_description(self, image: str, file: TextIO) -> None:
127+
urlopen(
128+
Request(
129+
f"https://hub.docker.com/v2/repositories/{image}/",
130+
method="PATCH",
131+
data=json.dumps({"full_description": file.read()}).encode("utf-8"),
132+
headers={
133+
"Content-Type": "application/json; charset=utf-8",
134+
"Authorization": f"JWT {self.token}",
135+
},
136+
),
137+
context=self.context,
138+
)
139+
140+
95141
def run(args: Sequence[str], /, **kwargs) -> subprocess.CompletedProcess:
96142
print(f"+ {' '.join(args)}")
97143
return subprocess.run(args, check=True, **kwargs)
@@ -114,20 +160,31 @@ def main():
114160
default=os.environ.get("GITHUB_REF"),
115161
help="current ref in refs/heads/... or refs/tags/... form",
116162
)
163+
parser.add_argument(
164+
"--readme",
165+
default="./README.md",
166+
help="README to update the Docker Hub description from",
167+
)
117168
args = parser.parse_args()
118169

119170
tags = calculate_tags(args.ref)
120171
print(f"will push tags: {', '.join(tags)}")
121172

122173
print("logging into Docker Hub")
123174
try:
124-
docker_login(os.environ["DOCKER_USERNAME"], os.environ["DOCKER_PASSWORD"])
175+
docker_cli_login(os.environ["DOCKER_USERNAME"], os.environ["DOCKER_PASSWORD"])
125176
except KeyError as e:
126177
print(f"error retrieving environment variables: {e}")
127178
raise
128179

129180
print("building and pushing image")
130-
docker_build(open(args.dockerfile, "rb"), args.platform, args.image, tags)
181+
docker_cli_build(open(args.dockerfile, "rb"), args.platform, args.image, tags)
182+
183+
print("acquiring token to update description")
184+
hub = DockerHub.login(os.environ["DOCKER_USERNAME"], os.environ["DOCKER_PASSWORD"])
185+
186+
print("updating description")
187+
hub.update_description(args.image, open(args.readme, "r"))
131188

132189
print("success!")
133190

0 commit comments

Comments
 (0)