Initial Commit

This commit is contained in:
Markus Pesch 2019-09-16 21:36:27 +02:00
commit a86462206b
Signed by: volker.raschek
GPG Key ID: 852BCC170D81A982
17 changed files with 771 additions and 0 deletions

12
.editorconfig Normal file
View 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
View File

@ -0,0 +1 @@
Makefile eol=lf

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/bin
/dhd
**/bindata*.go

20
.travis.yml Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,6 @@
package types
type Token struct {
Token string `json:"token"`
}

28
test.sh Executable file
View 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