Initial Commit
This commit is contained in:
commit
a86462206b
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
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.com/volker-raschek/docker-hub-description-updater.svg?branch=master)](https://travis-ci.com/volker-raschek/docker-hub-description-updater)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/volker-raschek/docker-hub-description-updater)](https://goreportcard.com/report/github.com/volker-raschek/docker-hub-description-updater)
|
||||||
|
[![GoDoc Reference](https://godoc.org/github.com/volker-raschek/docker-hub-description-updater?status.svg)](http://godoc.org/github.com/volker-raschek/docker-hub-description-updater)
|
||||||
|
[![Docker Pulls](https://img.shields.io/docker/pulls/volkerraschek/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
|
Loading…
Reference in New Issue
Block a user