diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..97d23d4d613b86347c8abc54c8971718606a33af --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,66 @@ +image: containers.ethitter.com:443/docker/images/golang:latest + +variables: + REPO_NAME: git.ethitter.com/open-source/dyndnsd-client + +cache: + paths: + - /apt-cache + - $GOPATH/src/github.com + - $GOPATH/src/golang.org + - $GOPATH/src/google.golang.org + - $GOPATH/src/gopkg.in + +stages: + - test + - build + +before_script: + - mkdir -p $GOPATH/src/$(dirname $REPO_NAME) + - cp -R $CI_PROJECT_DIR $GOPATH/src/$REPO_NAME + - cd $GOPATH/src/$REPO_NAME + - cp config-sample.json config.json + + - export CC=clang-5.0 + + - make dep + +unit_tests: + stage: test + script: + - make test + +race_detector: + stage: test + script: + - make race + +memory_sanitizer: + stage: test + script: + - make msan + +code_coverage: + stage: test + script: + - make coverage + +code_coverage_report: + stage: test + script: + - make coverhtml + only: + - master + +lint_code: + stage: test + script: + - make lint + +build: + stage: build + script: + - make + artifacts: + paths: + - dyndnsd-client/ \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bcb249972c4443bf82ac452084d359fed73bb146 --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ +PROJECT_NAME := "dyndnsd-client" +PKG := "git.ethitter.com/debian/$(PROJECT_NAME)" +PKG_LIST := $(shell go list ${PKG}/... | grep -v /vendor/) +GO_FILES := $(shell find . -name '*.go' | grep -v /vendor/ | grep -v _test.go) + +.PHONY: all dep build clean test coverage coverhtml lint + +all: build + +lint: + @golint -set_exit_status ${PKG_LIST} + +test: + @go test -v ${PKG_LIST} + +race: dep + @go test -v -race ${PKG_LIST} + +msan: dep + @go test -v -msan ${PKG_LIST} + +coverage: + ./tools/coverage.sh; + +coverhtml: + ./tools/coverage.sh html; + +dep: + @go get -v -d ./... + @go get github.com/mitchellh/gox + +build: dep + @gox -output="${CI_PROJECT_DIR}/${PROJECT_NAME}/{{.Dir}}_{{.OS}}_{{.Arch}}" -parallel=6 + +clean: + @rm -f $(PROJECT_NAME) + +help: + @grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' diff --git a/README.md b/README.md index 9d0730094985161eb0e18e8a4b94bdfb1e5384ff..897ed93c529bb895bfe88758500b3e6e2d950f48 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -`dyndnsd-client` +`dyndnsd-client` [](https://git.ethitter.com/open-source/dyndnsd-client/commits/master) ================ Client for the [`dyndnsd`](https://github.com/cmur2/dyndnsd) daemon. Set up `dyndnsd` first, otherwise this is useless. diff --git a/dyndnsd-client.go b/dyndnsd-client.go index 1d7e40f8d928f0a585842817ee24d3b2cacabeba..7cd62a15f2d1f9da536a4d3ba62d2d2640987386 100644 --- a/dyndnsd-client.go +++ b/dyndnsd-client.go @@ -35,7 +35,7 @@ func init() { flag.Parse() if _, err := os.Stat(configPath); os.IsNotExist(err) { - fmt.Println("Config path does not exist. Aborting!\n") + fmt.Println("Config path does not exist. Aborting!") flag.Usage() os.Exit(3) } @@ -48,7 +48,7 @@ func init() { // Do the update! func main() { // Base URL - endpoint, err := buildEndpointUrl() + endpoint, err := buildEndpointURL() if err != nil { logger.Println("Couldn't build endpoint URL") logger.Printf("%s", err) @@ -56,16 +56,17 @@ func main() { } // IPv4 is required - if ipv4, err := getUrl(ipv4Endpoint); err == nil { - if ipv4Valid := net.ParseIP(ipv4); ipv4Valid == nil { + if ipv4, err := getURL(ipv4Endpoint); err == nil { + ipv4Valid := net.ParseIP(ipv4) + if ipv4Valid == nil { logger.Println("Invalid IPv4 address returned by endpoint") logger.Printf("%s", err) return - } else { - query := endpoint.Query() - query.Set("myip", ipv4Valid.String()) - endpoint.RawQuery = query.Encode() } + + query := endpoint.Query() + query.Set("myip", ipv4Valid.String()) + endpoint.RawQuery = query.Encode() } else { logger.Println("Couldn't retrieve IPv4 address") logger.Printf("%s", err) @@ -75,7 +76,7 @@ func main() { // IPv6 is optional // Leave empty to skip if len(ipv6Endpoint) > 0 { - if ipv6, err := getUrl(ipv6Endpoint); err == nil { + if ipv6, err := getURL(ipv6Endpoint); err == nil { if ipv6Valid := net.ParseIP(ipv6); ipv6Valid == nil { logger.Println("Invalid IPv6 address returned by endpoint") logger.Printf("%s", err) @@ -103,7 +104,7 @@ func main() { } // Send the update - dyndns, err := getUrl(endpoint.String()) + dyndns, err := getURL(endpoint.String()) if err != nil { logger.Println("Couldn't update dyndnsd endpoint") logger.Printf("%s", err) @@ -115,7 +116,7 @@ func main() { } // Build endpoint URL from configuration -func buildEndpointUrl() (*url.URL, error) { +func buildEndpointURL() (*url.URL, error) { var username string var password string var protocol string @@ -132,27 +133,27 @@ func buildEndpointUrl() (*url.URL, error) { cfg.Get("path", &path) cfg.Get("dns_hostname", &hostname) - daemonUrl, err := url.Parse("") + daemonURL, err := url.Parse("") if err != nil { return nil, err } - daemonUrl.Scheme = protocol - daemonUrl.Host = fmt.Sprintf("%s:%d", host, port) - daemonUrl.Path = path + daemonURL.Scheme = protocol + daemonURL.Host = fmt.Sprintf("%s:%d", host, port) + daemonURL.Path = path userInfo := url.UserPassword(username, password) - daemonUrl.User = userInfo + daemonURL.User = userInfo - query := daemonUrl.Query() + query := daemonURL.Query() query.Set("hostname", hostname) - daemonUrl.RawQuery = query.Encode() + daemonURL.RawQuery = query.Encode() - return daemonUrl, nil + return daemonURL, nil } // Retrieve given URL -func getUrl(url string) (string, error) { +func getURL(url string) (string, error) { resp, err := http.Get(url) if err != nil { return "", err diff --git a/tools/coverage.sh b/tools/coverage.sh new file mode 100755 index 0000000000000000000000000000000000000000..0afd4f114465980f501559be19b79ac2ad39fe7f --- /dev/null +++ b/tools/coverage.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# +# Code coverage generation + +COVERAGE_DIR="${COVERAGE_DIR:-coverage}" +PKG_LIST=$(go list ./... | grep -v /vendor/) + +# Create the coverage files directory +mkdir -p "$COVERAGE_DIR"; + +# Create a coverage file for each package +for package in ${PKG_LIST}; do + go test -covermode=count -coverprofile "${COVERAGE_DIR}/${package##*/}.cov" "$package" ; +done ; + +# Merge the coverage profile files +echo 'mode: count' > "${COVERAGE_DIR}"/coverage.cov ; +tail -q -n +2 "${COVERAGE_DIR}"/*.cov >> "${COVERAGE_DIR}"/coverage.cov ; + +# Display the global code coverage +go tool cover -func="${COVERAGE_DIR}"/coverage.cov ; + +# If needed, generate HTML report +if [ "$1" == "html" ]; then + go tool cover -html="${COVERAGE_DIR}"/coverage.cov -o coverage.html ; +fi + +# Remove the coverage files directory +rm -rf "$COVERAGE_DIR";