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