You've already forked docker-hub-description-updater
							
							Initial Commit
This commit is contained in:
		
							
								
								
									
										12
									
								
								.editorconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								.editorconfig
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| root = true | ||||
|  | ||||
| [*] | ||||
| indent_style = space | ||||
| indent_size = 2 | ||||
| end_of_line = lf | ||||
| charset = utf-8 | ||||
| trim_trailing_whitespace = true | ||||
| insert_final_newline = false | ||||
|  | ||||
| [Makefile] | ||||
| indent_style = tab | ||||
							
								
								
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| Makefile eol=lf | ||||
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| /bin | ||||
| /dhd | ||||
|  | ||||
| **/bindata*.go | ||||
							
								
								
									
										20
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| language: go | ||||
|  | ||||
| services: | ||||
| - docker | ||||
|  | ||||
| jobs: | ||||
|   include: | ||||
|   - stage: build | ||||
|     script: make container-run/all | ||||
|  | ||||
| deploy: | ||||
|   - provider: script | ||||
|     script: make container-image/push | ||||
|     on: | ||||
|       tags: true | ||||
|  | ||||
| notifications: | ||||
|   email: | ||||
|     on_success: change | ||||
|     on_failure: change | ||||
							
								
								
									
										9
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| FROM volkerraschek/build-image:1.4.0 AS build-env | ||||
|  | ||||
| ADD ./ /workspace | ||||
|  | ||||
| RUN make bin/linux/amd64/dhd | ||||
|  | ||||
| FROM busybox:latest | ||||
| COPY --from=build-env /workspace/bin/linux/amd64/dhd /usr/bin/dhd | ||||
| ENTRYPOINT [ "/usr/bin/dhd" ] | ||||
							
								
								
									
										154
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
| # VERSION/RELEASE | ||||
| # If no version is specified as a parameter of make, the last git hash | ||||
| # value is taken. | ||||
| # VERSION?=$(shell git describe --abbrev=0)+hash.$(shell git rev-parse --short HEAD) | ||||
| VERSION?=$(shell git rev-parse --short HEAD) | ||||
| RELEASE?=1 | ||||
|  | ||||
| # EXECUTABLE | ||||
| # Executable binary which should be compiled for different architecures | ||||
| EXECUTABLE:=dhdu | ||||
|  | ||||
| # LINUX_EXECUTABLES AND TARGETS | ||||
| LINUX_EXECUTABLES:=\ | ||||
| 	linux/amd64/$(EXECUTABLE) \ | ||||
| 	linux/arm/5/$(EXECUTABLE) \ | ||||
| 	linux/arm/7/$(EXECUTABLE) | ||||
|  | ||||
| LINUX_EXECUTABLE_TARGETS:=${LINUX_EXECUTABLES:%=bin/%} | ||||
|  | ||||
| # UNIX_EXECUTABLES AND TARGETS | ||||
| # Define all executables for different architectures and operation systems | ||||
| UNIX_EXECUTABLES:=\ | ||||
| 	${LINUX_EXECUTABLES} | ||||
|  | ||||
| UNIX_EXECUTABLE_TARGETS:=\ | ||||
| 	${LINUX_EXECUTABLE_TARGETS} | ||||
|  | ||||
| # EXECUTABLE_TARGETS | ||||
| # Include all UNIX and Windows targets. | ||||
| EXECUTABLES:=\ | ||||
| 	${UNIX_EXECUTABLES} | ||||
|  | ||||
| EXECUTABLE_TARGETS:=\ | ||||
| 	${UNIX_EXECUTABLE_TARGETS} | ||||
|  | ||||
| # CONTAINER_RUNTIME / BUILD_IMAGE | ||||
| # The CONTAINER_RUNTIME variable will be used to specified the path to a | ||||
| # container runtime. This is needed to start and run a container image defined | ||||
| # by the BUILD_IMAGE variable. The BUILD_IMAGE container serve as build | ||||
| # environment to execute the different make steps inside. Therefore, the bulid | ||||
| # environment requires all necessary dependancies to build this project. | ||||
| CONTAINER_RUNTIME?=$(shell which docker) | ||||
| BUILD_IMAGE:=volkerraschek/build-image:latest | ||||
|  | ||||
| # REGISTRY_MIRROR / REGISTRY_NAMESPACE | ||||
| # The REGISTRY_MIRROR variable contains the name of the registry server to push | ||||
| # on or pull from container images. The REGISTRY_NAMESPACE defines the Namespace | ||||
| # where the CONTAINER_RUNTIME will be search for container images or push them | ||||
| # onto. The most time it's the same as REGISTRY_USER. | ||||
| REGISTRY_MIRROR=docker.io | ||||
| REGISTRY_NAMESPACE:=${REGISTRY_USER} | ||||
| REGISTRY_USER:=volkerraschek | ||||
|  | ||||
| # CONTAINER_IMAGE_VERSION / CONTAINER_IMAGE_NAME / CONTAINER_IMAGE | ||||
| # Defines the name of the new container to be built using several variables. | ||||
| CONTAINER_IMAGE_NAME=${EXECUTABLE} | ||||
| CONTAINER_IMAGE_VERSION?=latest | ||||
| CONTAINER_IMAGE=${REGISTRY_NAMESPACE}/${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_VERSION} | ||||
|  | ||||
| README_FILE:=README.md | ||||
|  | ||||
| # BINARIES | ||||
| # ============================================================================== | ||||
| PHONY:=all | ||||
| all: ${EXECUTABLE_TARGETS} | ||||
|  | ||||
| bin/linux/amd64/$(EXECUTABLE): bindata | ||||
| 	GOARCH=amd64 GOOS=linux go build -ldflags "-X main.version=${VERSION}" -o "$@" | ||||
|  | ||||
| bin/linux/arm/5/$(EXECUTABLE): bindata | ||||
| 	GOARCH=amd64 GOOS=linux go build -ldflags "-X main.version=${VERSION}" -o "$@" | ||||
|  | ||||
| bin/linux/arm/7/$(EXECUTABLE): bindata | ||||
| 	GOARCH=amd64 GOOS=linux go build -ldflags "-X main.version=${VERSION}" -o "$@" | ||||
|  | ||||
| bin/tmp/${EXECUTABLE}: bindata | ||||
| 	go build -ldflags "-X main.version=${VERSION}" -o "$@" | ||||
|  | ||||
| # BINDATA | ||||
| # ============================================================================== | ||||
| BINDATA_TARGETS:=\ | ||||
| 	pkg/hub/bindata_test.go | ||||
|  | ||||
| PHONY+=bindata | ||||
| bindata: ${BINDATA_TARGETS} | ||||
|  | ||||
| pkg/hub/bindata_test.go: | ||||
| 	go-bindata -pkg hub_test -o ${@} README.md | ||||
|  | ||||
| # TEST | ||||
| # ============================================================================== | ||||
| PHONY+=test | ||||
| test: clean bin/tmp/${EXECUTABLE} | ||||
| 	REGISTRY_USER=${REGISTRY_USER} \ | ||||
| 	REGISTRY_PASSWORD=${REGISTRY_PASSWORD} \ | ||||
| 	REGISTRY_NAMESPACE=${REGISTRY_NAMESPACE} \ | ||||
| 	CONTAINER_IMAGE_NAME=${CONTAINER_IMAGE_NAME} \ | ||||
| 	README_FILE=${README_FILE} \ | ||||
| 		go test -v ./pkg/... | ||||
|  | ||||
| # CLEAN | ||||
| # ============================================================================== | ||||
| PHONY+=clean | ||||
| clean: | ||||
| 	rm --force ${EXECUTABLE} || true | ||||
| 	rm --force --recursive bin || true | ||||
| 	rm --force --recursive ${BINDATA_TARGETS} || true | ||||
|  | ||||
| # CONTAINER IMAGE STEPS | ||||
| # ============================================================================== | ||||
| container-image/build: | ||||
| 	${CONTAINER_RUNTIME} build \ | ||||
| 		--tag ${REGISTRY_NAMESPACE}/${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_VERSION} \ | ||||
| 		--tag ${REGISTRY_MIRROR}/${REGISTRY_NAMESPACE}/${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_VERSION} \ | ||||
| 		. | ||||
|  | ||||
| 	if [ -f $(shell which docker) ] && [ "${CONTAINER_RUNTIME}" == "$(shell which podman)" ]; then \ | ||||
| 		podman push ${REGISTRY_MIRROR}/${CONTAINER_IMAGE} docker-daemon:${CONTAINER_IMAGE}; \ | ||||
| 	fi | ||||
|  | ||||
| container-image/push: container-image/build | ||||
| 	${CONTAINER_RUNTIME} push ${REGISTRY_MIRROR}/${REGISTRY_NAMESPACE}/${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_VERSION} | ||||
|  | ||||
| # CONTAINER STEPS - BINARY | ||||
| # ============================================================================== | ||||
| PHONY+=container-run/all | ||||
| container-run/all: | ||||
| 	$(MAKE) container-run COMMAND=${@:container-run/%=%} | ||||
|  | ||||
| PHONY+=${UNIX_EXECUTABLE_TARGETS:%=container-run/%} | ||||
| ${UNIX_EXECUTABLE_TARGETS:%=container-run/%}: | ||||
| 	$(MAKE) container-run COMMAND=${@:container-run/%=%} | ||||
|  | ||||
| # CONTAINER STEPS - CLEAN | ||||
| # ============================================================================== | ||||
| PHONY+=container-run/clean | ||||
| container-run/clean: | ||||
| 	$(MAKE) container-run COMMAND=${@:container-run/%=%} | ||||
|  | ||||
| # GENERAL CONTAINER COMMAND | ||||
| # ============================================================================== | ||||
| PHONY+=container-run | ||||
| container-run: | ||||
| 	${CONTAINER_RUNTIME} run \ | ||||
| 		--rm \ | ||||
| 		--volume ${PWD}:/workspace \ | ||||
| 		${BUILD_IMAGE} \ | ||||
| 			make ${COMMAND} \ | ||||
| 				VERSION=${VERSION} \ | ||||
| 				RELEASE=${RELEASE} | ||||
|  | ||||
| # PHONY | ||||
| # ============================================================================== | ||||
| .PHONY: ${PHONY} | ||||
							
								
								
									
										84
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| # docker hub description updater | ||||
|  | ||||
| [](https://travis-ci.com/volker-raschek/docker-hub-description-updater) | ||||
| [](https://goreportcard.com/report/github.com/volker-raschek/docker-hub-description-updater) | ||||
| [](http://godoc.org/github.com/volker-raschek/docker-hub-description-updater) | ||||
| [](https://hub.docker.com/r/volkerraschek/docker-hub-description-updater) | ||||
|  | ||||
| By specifying the login data for hub.docker.com you can update the short and | ||||
| long description of a docker repository. | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| Several options are available to update the descriptions. Either based on | ||||
| Markdown files or as a normal string, which is passed as argument when calling. | ||||
| The examples below describe two ways, the binary and container based way. | ||||
|  | ||||
| ### Example 1: Update full description of the repository with a Markdown file | ||||
|  | ||||
| ```bash | ||||
| dhdu \ | ||||
|   -user=<username> \ | ||||
|   -password=<password> \ | ||||
|   -namespace=<namespace> \ | ||||
|   -repository=<repository> \ | ||||
|   -full-description-file=./README.md | ||||
| ``` | ||||
|  | ||||
| ```bash | ||||
| docker run \ | ||||
|   --rm \ | ||||
|   --volume $(pwd):/workspace \ | ||||
|     volkerraschek/dhdu \ | ||||
|       -user=<username> \ | ||||
|       -password=<password> \ | ||||
|       -namespace=<namespace> \ | ||||
|       -repository=<repository> \ | ||||
|       -full-description-file=./README.md | ||||
| ``` | ||||
|  | ||||
| ### Example 2: Update full description of the repository over an argument | ||||
|  | ||||
| ```bash | ||||
| dhdu -user=<username> \ | ||||
|      -password=<password> \ | ||||
|      -namespace=<namespace> \ | ||||
|      -repository=<repository> \ | ||||
|      -full-description="My awesome description" | ||||
| ``` | ||||
|  | ||||
| ```bash | ||||
| docker run \ | ||||
|   --rm \ | ||||
|   --volume $(pwd):/workspace \ | ||||
|     volkerraschek/dhdu \ | ||||
|       -user=<username> \ | ||||
|       -password=<password> \ | ||||
|       -namespace=<namespace> \ | ||||
|       -repository=<repository> \ | ||||
|       -full-description="My awesome description" | ||||
| ``` | ||||
|  | ||||
| ## Compiling the source code | ||||
|  | ||||
| There are two different ways to compile dhdu from scratch. The easier ways is | ||||
| to use the pre-defined container image in the Makefile, which has included all | ||||
| dependancies to compile dhdu. Alternatively, if all dependencies are met, | ||||
| dhdu can also be compiled without the container image. Both variants are | ||||
| briefly described. | ||||
|  | ||||
| ### Compiling the source code via container image | ||||
|  | ||||
| To compile dhdu via container image it's necessary, that a container runtime | ||||
| is installed. In the Makefile is predefined docker, but it's can be also used | ||||
| podman. Execute `make container-run/dhdu` to start the compiling process. | ||||
|  | ||||
| ```bash | ||||
| make container-run/dhdu | ||||
| ``` | ||||
|  | ||||
| #### Compiling the source code without container image | ||||
|  | ||||
| Make sure you have installed go >= v1.12. Execute `make dhdu` to compile | ||||
| dhdu without a container-image. There should be a similar output as when | ||||
| compiling dhdu via the container image. | ||||
							
								
								
									
										11
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| module github.com/volker-raschek/dhd | ||||
|  | ||||
| go 1.13 | ||||
|  | ||||
| require ( | ||||
| 	github.com/Masterminds/semver v1.5.0 | ||||
| 	github.com/d2r2/go-logger v0.0.0-20181221090742-9998a510495e | ||||
| 	github.com/davecgh/go-spew v1.1.1 // indirect | ||||
| 	github.com/go-flucky/flucky v0.0.0-20190714170626-0dd156f480be | ||||
| 	github.com/stretchr/testify v1.3.0 | ||||
| ) | ||||
							
								
								
									
										36
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= | ||||
| github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= | ||||
| github.com/d2r2/go-bsbmp v0.0.0-20190515110334-3b4b3aea8375 h1:vdUOwcZdV+bBfGUUh5oPPWSzw9p+lBnNSuGgQwGpCH4= | ||||
| github.com/d2r2/go-bsbmp v0.0.0-20190515110334-3b4b3aea8375/go.mod h1:3iz1WHlYJU9b4NJei+Q8G7DN3K05arcCMlOQ+qNCDjo= | ||||
| github.com/d2r2/go-i2c v0.0.0-20181113114621-14f8dd4e89ce h1:Dog7PLNz1fPaXqHPOHonpERqsF57Oh4X76pM80T1GDY= | ||||
| github.com/d2r2/go-i2c v0.0.0-20181113114621-14f8dd4e89ce/go.mod h1:AwxDPnsgIpy47jbGXZHA9Rv7pDkOJvQbezPuK1Y+nNk= | ||||
| github.com/d2r2/go-logger v0.0.0-20181221090742-9998a510495e h1:ZG3JBA6rPRl0xxQ+nNSfO7tor8w+CNCTs05DNJQYbLM= | ||||
| github.com/d2r2/go-logger v0.0.0-20181221090742-9998a510495e/go.mod h1:oA+9PUt8F1aKJ6o4YU1T120i7sgo1T6/1LWEEBy0BSs= | ||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/go-flucky/flucky v0.0.0-20190714170626-0dd156f480be h1:jCs/SAXdXUA0aqvEVH0wyeGpJzYOZ1XC9Kpm5anSY5E= | ||||
| github.com/go-flucky/flucky v0.0.0-20190714170626-0dd156f480be/go.mod h1:WNT729lCsTFhT6Vyvg6cG8aHV1t6p+DsA8l4omOuaos= | ||||
| github.com/go-flucky/go-dht v0.1.1 h1:dPz9F5D7oUaTd0GUGTvT4lBH2R043h1bkmhTlpQax1Y= | ||||
| github.com/go-flucky/go-dht v0.1.1/go.mod h1:Yk/cct+/u+eCS7pB/kc0tc7MrVXdFI4W15MJCj5FRUc= | ||||
| github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= | ||||
| github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= | ||||
| github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | ||||
| github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | ||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= | ||||
| github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= | ||||
| github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= | ||||
| github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= | ||||
| github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= | ||||
| github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= | ||||
| github.com/stianeikeland/go-rpio v4.2.0+incompatible h1:CUOlIxdJdT+H1obJPsmg8byu7jMSECLfAN9zynm5QGo= | ||||
| github.com/stianeikeland/go-rpio v4.2.0+incompatible/go.mod h1:Sh81rdJwD96E2wja2Gd7rrKM+XZ9LrwvN2w4IXrqLR8= | ||||
| github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= | ||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= | ||||
| github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||||
| gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| periph.io/x/periph v3.4.0+incompatible h1:5gzxE4ryPq52cdqSw0mErR6pyJK8cBF2qdUAcOWh0bo= | ||||
| periph.io/x/periph v3.4.0+incompatible/go.mod h1:EWr+FCIU2dBWz5/wSWeiIUJTriYv9v2j2ENBmgYyy7Y= | ||||
							
								
								
									
										122
									
								
								main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								main.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
|  | ||||
| 	"github.com/Masterminds/semver" | ||||
| 	"github.com/go-flucky/flucky/pkg/logger" | ||||
| 	"github.com/volker-raschek/dhd/pkg/hub" | ||||
| 	"github.com/volker-raschek/dhd/pkg/types" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	dockerHubAPI        string = "https://hub.docker.com/v2" | ||||
| 	dockerHubUser       string | ||||
| 	dockerHubPassword   string | ||||
| 	dockerHubNamespace  string | ||||
| 	dockerHubRepository string | ||||
|  | ||||
| 	shortDescription     string | ||||
| 	shortDescriptionFile string | ||||
| 	fullDescription      string | ||||
| 	fullDescriptionFile  string | ||||
|  | ||||
| 	semVersion *semver.Version | ||||
| 	version    string | ||||
|  | ||||
| 	flogger logger.Logger | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	// sVersion, err := semver.NewVersion(version) | ||||
| 	// if err != nil { | ||||
| 	// 	log.Fatalf("Can not create new semantic version from %v: %v", version, err) | ||||
| 	// } | ||||
| 	// semVersion = sVersion | ||||
|  | ||||
| 	flogger = logger.NewDefaultLogger(logger.LogLevelDebug) | ||||
| } | ||||
|  | ||||
| func main() { | ||||
|  | ||||
| 	flogger.Debug("Parse flags") | ||||
| 	flag.StringVar(&dockerHubUser, "user", "", "Docker Hub Username") | ||||
| 	flag.StringVar(&dockerHubPassword, "password", "", "Docker Hub Password") | ||||
| 	flag.StringVar(&dockerHubNamespace, "namespace", "", "Docker Hub Namespace") | ||||
| 	flag.StringVar(&dockerHubRepository, "repository", "", "Docker Hub Repository") | ||||
| 	flag.StringVar(&shortDescription, "short-description", "", "Short description of the repository ") | ||||
| 	flag.StringVar(&shortDescriptionFile, "short-description-file", "", "Short description of the repository. Override short-description if defined.") | ||||
| 	flag.StringVar(&fullDescription, "full-description", "", "Full description of the repository") | ||||
| 	flag.StringVar(&fullDescriptionFile, "full-description-file", "./README.md", "Full description of the repository. Override full-description if defined.") | ||||
| 	flag.Parse() | ||||
|  | ||||
| 	if len(dockerHubUser) <= 0 { | ||||
| 		flogger.Fatal("No user defined over flags") | ||||
| 	} | ||||
|  | ||||
| 	if len(dockerHubPassword) <= 0 { | ||||
| 		flogger.Fatal("No password defined over flags") | ||||
| 	} | ||||
|  | ||||
| 	if len(dockerHubNamespace) <= 0 { | ||||
| 		flogger.Fatal("No namespace defined over flags") | ||||
| 	} | ||||
|  | ||||
| 	if len(dockerHubRepository) <= 0 { | ||||
| 		flogger.Fatal("No repository defined over flags") | ||||
| 	} | ||||
|  | ||||
| 	hub.SetLogger(flogger) | ||||
|  | ||||
| 	loginCredentials := &types.LoginCredentials{ | ||||
| 		User:     dockerHubUser, | ||||
| 		Password: dockerHubPassword, | ||||
| 	} | ||||
|  | ||||
| 	actualShortDescription := "" | ||||
| 	if len(shortDescription) > 0 { | ||||
| 		actualShortDescription = shortDescription | ||||
| 		flogger.Debug("Select short description from flag") | ||||
| 	} else if len(shortDescriptionFile) > 0 { | ||||
| 		f, err := ioutil.ReadFile(shortDescriptionFile) | ||||
| 		if err != nil { | ||||
| 			log.Fatalf("Can not read file %v", shortDescriptionFile) | ||||
| 		} | ||||
| 		actualShortDescription = string(f) | ||||
| 		flogger.Debug("Select short description from file") | ||||
| 	} | ||||
|  | ||||
| 	actualFullDescription := "" | ||||
| 	if len(fullDescription) > 0 { | ||||
| 		actualFullDescription = fullDescription | ||||
| 		flogger.Debug("Select full description from flag") | ||||
| 	} else if len(fullDescriptionFile) > 0 { | ||||
| 		f, err := ioutil.ReadFile(fullDescriptionFile) | ||||
| 		if err != nil { | ||||
| 			log.Fatalf("Can not read file %v", fullDescriptionFile) | ||||
| 		} | ||||
| 		actualFullDescription = string(f) | ||||
| 		flogger.Debug("Select full description from file") | ||||
| 	} | ||||
|  | ||||
| 	flogger.Debug("Get Token") | ||||
| 	token, err := hub.GetToken(loginCredentials) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("%v", err) | ||||
| 	} | ||||
|  | ||||
| 	repository := &types.Repository{ | ||||
| 		Name:            dockerHubRepository, | ||||
| 		Namespcace:      dockerHubNamespace, | ||||
| 		Description:     actualShortDescription, | ||||
| 		FullDescription: actualFullDescription, | ||||
| 	} | ||||
|  | ||||
| 	flogger.Debug("Send Repository Patch") | ||||
| 	_, err = hub.PatchRepository(repository, token) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("%v", err) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										10
									
								
								pkg/hub/errors.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								pkg/hub/errors.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| package hub | ||||
|  | ||||
| import "errors" | ||||
|  | ||||
| var ( | ||||
| 	errorNoUserDefined       = errors.New("No User defined") | ||||
| 	errorNoPasswordDefined   = errors.New("No Password defined") | ||||
| 	errorNoNamespaceDefined  = errors.New("No Namespace defined") | ||||
| 	errorNoRepositoryDefined = errors.New("No Repository defined") | ||||
| ) | ||||
							
								
								
									
										179
									
								
								pkg/hub/hub.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								pkg/hub/hub.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,179 @@ | ||||
| package hub | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/go-flucky/flucky/pkg/logger" | ||||
| 	"github.com/volker-raschek/dhd/pkg/types" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	dockerHubAPI = "https://hub.docker.com/v2" | ||||
| 	flogger      logger.Logger | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	flogger = logger.NewSilentLogger() | ||||
| } | ||||
|  | ||||
| func GetRepository(namespace string, name string, token *types.Token) (*types.Repository, error) { | ||||
|  | ||||
| 	if len(namespace) <= 0 { | ||||
| 		return nil, errorNoNamespaceDefined | ||||
| 	} | ||||
|  | ||||
| 	if len(name) <= 0 { | ||||
| 		return nil, errorNoRepositoryDefined | ||||
| 	} | ||||
|  | ||||
| 	client := new(http.Client) | ||||
|  | ||||
| 	url, err := url.Parse(fmt.Sprintf("%v/repositories/%v/%v", dockerHubAPI, namespace, name)) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("Can not prase URL: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	req, err := http.NewRequest(http.MethodGet, url.String(), nil) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("Can not create request to get repository: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	if token != nil { | ||||
| 		req.Header.Add("Authorization", fmt.Sprintf("JWT %v", token.Token)) | ||||
| 	} | ||||
|  | ||||
| 	resp, err := client.Do(req) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("An error has occured: %v", err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	if resp.StatusCode != 200 { | ||||
| 		return nil, fmt.Errorf("Invalid HTTP-Statuscode: Get %v but expect 200", resp.StatusCode) | ||||
| 	} | ||||
|  | ||||
| 	repository := new(types.Repository) | ||||
| 	jsonDecoder := json.NewDecoder(resp.Body) | ||||
| 	if err := jsonDecoder.Decode(repository); err != nil { | ||||
| 		return nil, fmt.Errorf("Can not encode JSON from Repository struct: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	return repository, nil | ||||
| } | ||||
|  | ||||
| func GetToken(loginCredentials *types.LoginCredentials) (*types.Token, error) { | ||||
|  | ||||
| 	if len(loginCredentials.User) <= 0 { | ||||
| 		return nil, errorNoUserDefined | ||||
| 	} | ||||
|  | ||||
| 	if len(loginCredentials.Password) <= 0 { | ||||
| 		return nil, errorNoPasswordDefined | ||||
| 	} | ||||
|  | ||||
| 	client := new(http.Client) | ||||
|  | ||||
| 	loginBuffer := new(bytes.Buffer) | ||||
| 	jsonEncoder := json.NewEncoder(loginBuffer) | ||||
| 	if err := jsonEncoder.Encode(loginCredentials); err != nil { | ||||
| 		return nil, fmt.Errorf("Can not encode JSON from LoginCredential struct: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%v/users/login/", dockerHubAPI), loginBuffer) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("Can not create request to get token from %v: %v", dockerHubAPI, err) | ||||
| 	} | ||||
| 	req.Header.Add("Content-Type", "application/json") | ||||
|  | ||||
| 	resp, err := client.Do(req) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("An error has occured after sending the http request to get a JWT token from %v: %v", dockerHubAPI, err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	if resp.StatusCode != 200 { | ||||
| 		return nil, fmt.Errorf("Invalid HTTP-Statuscode while getting the JWT Token: Get %v but expect 200", resp.StatusCode) | ||||
| 	} | ||||
|  | ||||
| 	token := new(types.Token) | ||||
| 	jsonDecoder := json.NewDecoder(resp.Body) | ||||
| 	if err := jsonDecoder.Decode(token); err != nil { | ||||
| 		return nil, fmt.Errorf("Can not decode token: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	return token, nil | ||||
| } | ||||
|  | ||||
| func PatchRepository(repository *types.Repository, token *types.Token) (*types.Repository, error) { | ||||
|  | ||||
| 	if len(repository.Namespcace) <= 0 { | ||||
| 		return nil, errorNoNamespaceDefined | ||||
| 	} | ||||
|  | ||||
| 	if len(repository.Name) <= 0 { | ||||
| 		return nil, errorNoRepositoryDefined | ||||
| 	} | ||||
|  | ||||
| 	repositoryBuffer := new(bytes.Buffer) | ||||
| 	jsonEncoder := json.NewEncoder(repositoryBuffer) | ||||
| 	if err := jsonEncoder.Encode(repository); err != nil { | ||||
| 		return nil, fmt.Errorf("Can not encode JSON from Repository struct: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	client := new(http.Client) | ||||
|  | ||||
| 	// patchURL, err := url.Parse(fmt.Sprintf("%v/repositories/%v/%v", dockerHubAPI, repository.Namespcace, repository.Name)) | ||||
| 	// if err != nil { | ||||
| 	// 	return nil, fmt.Errorf("Can not prase URL: %v", err) | ||||
| 	// } | ||||
|  | ||||
| 	patchURL := "https://httpbin.org/patch" | ||||
|  | ||||
| 	data := url.Values{} | ||||
| 	data.Set("full_description", repository.FullDescription) | ||||
|  | ||||
| 	req, err := http.NewRequest(http.MethodPatch, patchURL, strings.NewReader(data.Encode())) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("Can not create request to update readme: %v", err) | ||||
| 	} | ||||
| 	req.Header.Add("Accept", "*/*") | ||||
| 	req.Header.Add("Authorization", fmt.Sprintf("JWT %v", token.Token)) | ||||
| 	req.Header.Add("Content-Type", "application/x-www-form-urlencoded") | ||||
| 	req.Header.Add("Content-Length", strconv.Itoa(len(data.Encode()))) | ||||
| 	req.Header.Del("Accept-Encoding") | ||||
|  | ||||
| 	flogger.Debug("Content-Length", strconv.Itoa(len(data.Encode()))) | ||||
|  | ||||
| 	resp, err := client.Do(req) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("An error has occured: %v", err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	flogger.Debug("Get Statuscode: %v", resp.StatusCode) | ||||
|  | ||||
| 	if resp.StatusCode == 200 { | ||||
| 		bodyBytes, _ := ioutil.ReadAll(resp.Body) | ||||
| 		//return nil, fmt.Errorf("Invalid HTTP-Statuscode: Get %v but expect 200: %v", resp.StatusCode, string(bodyBytes)) | ||||
| 		flogger.Debug("RESP_BODY: %v", string(bodyBytes)) | ||||
| 	} | ||||
|  | ||||
| 	patchedRepository := new(types.Repository) | ||||
|  | ||||
| 	if err := json.NewDecoder(resp.Body).Decode(patchedRepository); err != nil { | ||||
| 		return nil, fmt.Errorf("Can not encode JSON from Repository struct: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	return patchedRepository, nil | ||||
| } | ||||
|  | ||||
| func SetLogger(l logger.Logger) { | ||||
| 	flogger = l | ||||
| } | ||||
							
								
								
									
										60
									
								
								pkg/hub/hub_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								pkg/hub/hub_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| package hub_test | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
| 	"testing" | ||||
|  | ||||
| 	flogger "github.com/go-flucky/flucky/pkg/logger" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| 	"github.com/volker-raschek/dhd/pkg/hub" | ||||
| 	"github.com/volker-raschek/dhd/pkg/types" | ||||
| ) | ||||
|  | ||||
| func TestPatchRepository(t *testing.T) { | ||||
|  | ||||
| 	hub.SetLogger(flogger.NewDefaultLogger(flogger.LogLevelDebug)) | ||||
|  | ||||
| 	dockerHubUser := os.Getenv("REGISTRY_USER") | ||||
| 	if len(dockerHubUser) <= 0 { | ||||
| 		t.Fatalf("Environment variable REGISTRY_USER is empty") | ||||
| 	} | ||||
|  | ||||
| 	dockerHubPassword := os.Getenv("REGISTRY_PASSWORD") | ||||
| 	if len(dockerHubPassword) <= 0 { | ||||
| 		t.Fatalf("Environment variable REGISTRY_PASSWORD is empty") | ||||
| 	} | ||||
|  | ||||
| 	dockerHubNamespace := os.Getenv("REGISTRY_NAMESPACE") | ||||
| 	if len(dockerHubNamespace) <= 0 { | ||||
| 		t.Fatalf("Environment variable REGISTRY_NAMESPACE is empty") | ||||
| 	} | ||||
|  | ||||
| 	dockerHubRepository := os.Getenv("CONTAINER_IMAGE_NAME") | ||||
| 	if len(dockerHubRepository) <= 0 { | ||||
| 		t.Fatalf("Environment variable CONTAINER_IMAGE_NAME is empty") | ||||
| 	} | ||||
|  | ||||
| 	loginCredentials := &types.LoginCredentials{ | ||||
| 		User:     dockerHubUser, | ||||
| 		Password: dockerHubPassword, | ||||
| 	} | ||||
|  | ||||
| 	require := require.New(t) | ||||
| 	token, err := hub.GetToken(loginCredentials) | ||||
| 	require.NoError(err) | ||||
|  | ||||
| 	readme, err := Asset("README.md") | ||||
| 	require.NoError(err) | ||||
|  | ||||
| 	currentRepository, err := hub.GetRepository(dockerHubNamespace, dockerHubRepository, token) | ||||
| 	require.NoError(err) | ||||
|  | ||||
| 	expectedRepository := *currentRepository | ||||
| 	expectedRepository.FullDescription = string(readme) | ||||
|  | ||||
| 	actualRepository, err := hub.PatchRepository(&expectedRepository, token) | ||||
| 	require.NoError(err) | ||||
|  | ||||
| 	require.NotEqual(currentRepository, actualRepository, "The repository properties have remained the same even though an update was performed") | ||||
| 	require.Equal(&expectedRepository, actualRepository, "The update was successfully") | ||||
| } | ||||
							
								
								
									
										6
									
								
								pkg/types/login.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								pkg/types/login.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| package types | ||||
|  | ||||
| type LoginCredentials struct { | ||||
| 	User     string `json:"username"` | ||||
| 	Password string `json:"password"` | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/types/repository.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/types/repository.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| package types | ||||
|  | ||||
| import "time" | ||||
|  | ||||
| type Repository struct { | ||||
| 	User            string       `json:"user"` | ||||
| 	Name            string       `json:"name"` | ||||
| 	Namespcace      string       `json:"namespace"` | ||||
| 	Type            string       `json:"repository_type"` | ||||
| 	Status          int          `json:"status"` | ||||
| 	Description     string       `json:"description"` | ||||
| 	Private         bool         `json:"is_private"` | ||||
| 	Automated       bool         `json:"is_automated"` | ||||
| 	Edit            bool         `json:"can_edit"` | ||||
| 	StarCount       int          `json:"start_count"` | ||||
| 	PullCount       int          `json:"pull_count"` | ||||
| 	LastUpdated     time.Time    `json:"last_updated"` | ||||
| 	IsMigrated      bool         `json:"is_migrated"` | ||||
| 	HasStarred      bool         `json:"has_starred"` | ||||
| 	FullDescription string       `json:"full_description"` | ||||
| 	Affiliation     string       `json:"affilition"` | ||||
| 	Permissions     *Permissions `json:"permissions"` | ||||
| } | ||||
|  | ||||
| type Permissions struct { | ||||
| 	Read  bool `json:"read"` | ||||
| 	Write bool `json:"write"` | ||||
| 	Admin bool `json:"admin"` | ||||
| } | ||||
							
								
								
									
										6
									
								
								pkg/types/token.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								pkg/types/token.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| package types | ||||
|  | ||||
| type Token struct { | ||||
| 	Token string `json:"token"` | ||||
| } | ||||
|  | ||||
							
								
								
									
										28
									
								
								test.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										28
									
								
								test.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| #!/bin/sh -l | ||||
| set -euo pipefail | ||||
| IFS=$'\n\t' | ||||
|  | ||||
| # Set the default path to README.md | ||||
| README_FILEPATH=${README_FILEPATH:="./README.md"} | ||||
|  | ||||
| DOCKERHUB_PASSWORD=${DOCKER_PASSWORD} | ||||
| DOCKERHUB_USERNAME=volkerraschek | ||||
| DOCKERHUB_REPOSITORY=volkerraschek/dhd | ||||
|  | ||||
| # Acquire a token for the Docker Hub API | ||||
| echo "Acquiring token" | ||||
| LOGIN_PAYLOAD="{\"username\": \"${DOCKERHUB_USERNAME}\", \"password\": \"${DOCKERHUB_PASSWORD}\"}" | ||||
| TOKEN=$(curl -H "Content-Type: application/json" -X POST -d ${LOGIN_PAYLOAD} https://hub.docker.com/v2/users/login/ | jq -r .token) | ||||
|  | ||||
| # Send a PATCH request to update the description of the repository | ||||
| echo "Sending PATCH request" | ||||
| # REPO_URL="https://hub.docker.com/v2/repositories/${DOCKERHUB_REPOSITORY}/" | ||||
| REPO_URL="https://httpbin.org/patch" | ||||
| RESPONSE_CODE=$(curl --write-out %{response_code} -H "Authorization: JWT ${TOKEN}" -X PATCH --data-urlencode full_description@${README_FILEPATH} ${REPO_URL}) | ||||
| echo "Received response code: $RESPONSE_CODE" | ||||
|  | ||||
| if [ $RESPONSE_CODE -eq 200 ]; then | ||||
|   exit 0 | ||||
| else | ||||
|   exit 1 | ||||
| fi | ||||
		Reference in New Issue
	
	Block a user