Skip to content

Commit

Permalink
Merge pull request #30 from marcellodesales/develop
Browse files Browse the repository at this point in the history
Release - Docker Remote debugger + Breaking API changes
  • Loading branch information
marcellodesales authored Oct 20, 2020
2 parents 982d0f5 + add07c8 commit 5dc3574
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 31 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#first stage - builder
FROM golang:1.13.0-stretch as builder
FROM golang:1.15.3-buster as builder

WORKDIR /build

Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,6 @@ endif
$(eval BUILD_IMAGE_TAG=$(shell BIN_VERSION=$(BIN_VERSION) docker-compose config | grep image | awk '{print $$2}'))
mkdir -p ./.github/scripts/.ssh/
gpg --quiet --batch --yes --decrypt --passphrase="${ID_CLONER_TEST_PASSPHRASE}" --output ./.github/scripts/.ssh/id_cloner_test ./.github/scripts/id_cloner_test.pgp
docker run -v $(PWD)/.github/scripts/.ssh:/tests/certs -v $(PWD)/.github/test-cloned-repos/:/root/cloner $(BUILD_IMAGE_TAG) -v debug git --repo [email protected]:marcellodesales/cloner.git -k /tests/certs/id_cloner_test
docker run -v $(PWD)/.github/scripts/.ssh:/tests/certs -v $(PWD)/.github/test-cloned-repos/:/root/cloner $(BUILD_IMAGE_TAG) -v debug local -r [email protected]:marcellodesales/cloner.git -k /tests/certs/id_cloner_test
rm -rf ./.github/scripts/.ssh/
[ -d "$(PWD)/.github/test-cloned-repos" ] || echo "Clone from docker did not work!"
[ -d "$(PWD)/.github/test-cloned-repos" ] || echo "Clone from docker did not work!"
42 changes: 30 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ in a location for all of your git projects based on the host.

* You don't need to change to the directory where your github repos are located.
* The base git repo will be based on the host, so they all are on the same place.
* Commands are idempotent
* For repeated repos, you must use the force option

```shell
cloner git --repo https://github.com/comsysto/redis-locks-with-grafana
cloner git --repo [email protected]:marcellodesales/alpine-git-hub-docker-image.git
cloner git --repo https://github.com/intuit/intuit-spring-cloud-config-inspector
cloner git --repo [email protected]:intuit/unmazedboot
cloner git --repo https://gitlab.com:supercash/services/sms-gateway-service.git
cloner local -r https://github.com/comsysto/redis-locks-with-grafana
cloner local --repo [email protected]:marcellodesales/alpine-git-hub-docker-image.git
cloner local -r https://github.com/intuit/intuit-spring-cloud-config-inspector
cloner local -r [email protected]:intuit/unmazedboot
cloner local -r https://gitlab.com:supercash/services/sms-gateway-service.git
cloner local -r https://github.com/comsysto/redis-locks-with-grafana -f

tree -L 4 ~/dev/
/Users/marcellodesales/dev/
Expand Down Expand Up @@ -54,11 +57,11 @@ When the CLI runs, it will create the dirs `git.cloneBaseDir/git.host/git.org/gi
* Just run the help to see the current options

```
cloner git --help
cloner local --help
Clones a given git repo URL

Usage:
cloner git [flags]
cloner local [flags]

Flags:
-f, --force Forces cloning by deleting existing dir
Expand All @@ -76,7 +79,7 @@ Global Flags:
* Clone for the first time
```shell
cloner git --repo https://github.com/comsysto/redis-locks-with-grafana
cloner local --repo https://github.com/comsysto/redis-locks-with-grafana
INFO[0000] Loading the config object 'git' from '/Users/marcellodesales/.cloner.yaml'
INFO[2020-09-08T12:28:11-03:00] Cloning into '/Users/marcellodesales/dev/github.com/comsysto/redis-locks-with-grafana'
Enumerating objects: 233, done.
Expand All @@ -87,7 +90,7 @@ INFO[2020-09-08T12:28:18-03:00] Done...
* Existing cloned repos will fail

```
cloner git --repo https://github.com/comsysto/redis-locks-with-grafana
cloner local --repo https://github.com/comsysto/redis-locks-with-grafana
INFO[0000] Loading the config object 'git' from '/Users/marcellodesales/.cloner.yaml'
ERRO[2020-09-08T12:29:58-03:00] Can't clone repo: clone location '/Users/marcellodesales/dev/github.com/comsysto/redis-locks-with-grafana' exists and it's not empty
ERRO[2020-09-08T12:29:58-03:00] You can specify --force or -f to delete the existing dir and clone again. Make sure there are no panding changes!
Expand All @@ -96,7 +99,7 @@ ERRO[2020-09-08T12:29:58-03:00] You can specify --force or -f to delete the exis
* Force the clone if needed

```
cloner git --repo https://github.com/comsysto/redis-locks-with-grafana -f
cloner local --repo https://github.com/comsysto/redis-locks-with-grafana -f
INFO[0000] Loading the config object 'git' from '/Users/marcellodesales/.cloner.yaml'
INFO[2020-09-08T12:30:42-03:00] Forcing clone...
INFO[2020-09-08T12:30:42-03:00] Deleted dir '/Users/marcellodesales/dev/github.com/comsysto/redis-locks-with-grafana'
Expand All @@ -109,7 +112,7 @@ INFO[2020-09-08T12:28:18-03:00] Done...
* You can provide a private key for `git@host:org/repo` URLs

```
cloner git --repo [email protected]/marcellodesales/cloner --privateKey ~/.ssh/id_gmail
cloner local --repo [email protected]/marcellodesales/cloner --privateKey ~/.ssh/id_gmail
INFO[0000] Loading the config object 'git' from '/Users/marcellodesales/.cloner.yaml'
INFO[2020-09-08T12:30:42-03:00] Forcing clone...
INFO[2020-09-08T12:30:42-03:00] Deleted dir '/Users/marcellodesales/dev/github.com/marcellodesales/cloner'
Expand Down Expand Up @@ -212,6 +215,21 @@ The CLI will print the help
$ ./dist/cloner-darwin-amd64
```

## Remote Debug

* Use `debug.docker-compose.yaml` to start a Delve container that listens to port `:40000`.
* https://github.com/igor-kupczynski/remote-debug-example
* Details at PR #29

```
$ docker-compose -f debug.docker-compose.yaml up
Recreating cloner_cli-debug_1 ... done
Attaching to cloner_cli-debug_1
cli-debug_1 | API server listening at: [::]:40000
```

* For example, open Goland and use a `Go Remote` debug instance with port `40000`.

## Bug Reports & Feature Requests

Please use the [issue tracker](https://github.com/marcellodesales/cloner/issues) to report any bugs or file feature requests.
Expand Down Expand Up @@ -406,4 +424,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
```
```
28 changes: 15 additions & 13 deletions cmd/git.go → cmd/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,22 @@ import (
)

// initCmd represents the init command
var initCmd = &cobra.Command{
Use: "git",
Short: "Clones a given git repo",
Long: `Clones a given git repo URL`,
Run: GitCloneCmd,
var localCloneCmd = &cobra.Command{
Use: "local REPO",
Short: "Clones a given git repo locally",
Long: `Clones a given git repo URL to the local file-system`,
Run: CloneGitRepoLocallyCmd,
}

// Exposed command for testing
// https://stackoverflow.com/questions/59709345/how-to-implement-unit-tests-for-cli-commands-in-go/59714127#59714127
func GitCloneCmd(cmd *cobra.Command, args []string) {
repo, _ := cmd.Flags().GetString("repo")
func CloneGitRepoLocallyCmd(cmd *cobra.Command, args []string) {
// https://github.com/spf13/cobra/issues/378#issuecomment-304014202
repoToClone, _ := cmd.Flags().GetString("repo")
forceClone, _ := cmd.Flags().GetBool("force")
privateKey, _ := cmd.Flags().GetString("privateKey")

exitCode, errors := executeGitClone(repo, privateKey, forceClone)
exitCode, errors := executeGitClone(repoToClone, privateKey, forceClone)

// Show any errors if any
if len(errors) > 0 {
Expand All @@ -64,7 +65,7 @@ func executeGitClone(repo, privateKeyPath string, forceClone bool) (int, []error
}

func init() {
rootCmd.AddCommand(initCmd)
rootCmd.AddCommand(localCloneCmd)

// Here you will define your flags and configuration settings.

Expand All @@ -74,10 +75,11 @@ func init() {

// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
initCmd.Flags().StringP("repo", "r", "", "The repo URL to clone")
initCmd.Flags().StringP("privateKey", "k", "", "The private key associated to the public key to clone 'git@' repos")
// https://github.com/spf13/cobra/issues/378#issuecomment-304014202 param value to command
localCloneCmd.Flags().StringP("repo", "r", "", "The repo URL to clone prefixed with git@ or https://")
localCloneCmd.Flags().StringP("privateKey", "k", "", "The private key associated to the public key to clone 'git@' repos")

var verbose = false
var force = false
// https://github.com/spf13/cobra/issues/818#issuecomment-489021216
initCmd.Flags().BoolVarP(&verbose, "force", "f", false, "Forces cloning by deleting existing dir")
localCloneCmd.Flags().BoolVarP(&force, "force", "f", false, "Forces cloning by deleting existing dir")
}
File renamed without changes.
10 changes: 7 additions & 3 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ it can place software in specific location designed.`,
// Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
//Execute adds all child commands to the root command and sets flags appropriately.
//This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
Expand All @@ -56,7 +56,7 @@ func init() {
// will be global for your application.

// Setup Viper Configuration file type
rootCmd.PersistentFlags().StringVar(&cfgFile, "cloner", "cloner",
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", ".cloner",
"Config file (default is $HOME/.cloner.yaml)")

// Callbacks to initilize, in order, for cobra-viper-anything else
Expand Down Expand Up @@ -87,4 +87,8 @@ func init() {
// Cobra also supports local flags, which will only run
// when this action is called directly.
//rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

var verbose = false
// https://github.com/spf13/cobra/issues/818#issuecomment-489021216
rootCmd.Flags().BoolVarP(&verbose, "force", "f", false, "Forces cloning by deleting existing dir")
}
97 changes: 97 additions & 0 deletions debug.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#first stage - builder
FROM golang:1.15.3-buster AS dependencies

WORKDIR /build

# Install the file util
RUN apt-get update && apt-get install -y file && \
go get github.com/go-delve/delve/cmd/dlv
# upx removed due to binary corruption
#libc6-compat make upx

# https://stackoverflow.com/questions/32232655/go-get-results-in-terminal-prompts-disabled-error-for-github-private-repo/44247040#44247040
#RUN git config --global url."https://fcc***03:@github.company.com/".insteadOf "https://github.company.com/"
#ENV GOPRIVATE github.company.com

# Resolve and build Go dependencies as Docker cache
COPY go.mod /build/go.mod
COPY go.sum /build/go.sum
ENV GO111MODULE=on
RUN go mod download

FROM dependencies AS compilation

# Add the main
COPY main.go /build/main.go

##################
################## ATTENTION
##################
# Add the modules dirs to avoid errors
# cannot load github.company.com/user/repo/api/git: no matching versions for query "latest"
COPY api /build/api
COPY cmd /build/cmd
COPY config /build/config
COPY util /build/util

ARG BIN_NAME
ARG BIN_VERSION

# Cross-compile all versions
ENV BIN_NAME ${BIN_NAME:-unknown}
ENV BUILD_VERSION ${BIN_VERSION:-0.1.0}
ENV PLATFORMS "darwin linux windows"
ENV ARCHS "amd64"
#ENV ARCHS "386 amd64"
# Debugging with delv options using GC_FLAGS -gcflags="all=-N -l"
# More at https://kupczynski.info/2020/05/17/remote-debug-go-code.html
# https://github.com/igor-kupczynski/remote-debug-example/blob/master/Dockerfile.debug#L9
ENV GC_FLAGS "all=-N -l"

# Build the module name
COPY .git/ /build/.git/

# Injecting version info into the golang build https://github.com/Ropes/go-linker-vars-example
# https://github.com/Ropes/go-linker-vars-example, https://stackoverflow.com/questions/11354518/application-auto-build-versioning/11355611#11355611
# https://medium.com/@joshroppo/setting-go-1-5-variables-at-compile-time-for-versioning-5b30a965d33e
RUN export export FULL_NAME_GIT=$(git -C /build/.git remote -v | grep fetch | awk '{print $2}' | sed -En "s/git@//p" | sed -En "s/.git//p" | sed -En "s/:/\//p") && \
export export FULL_NAME_HTTP=$(git -C /build/.git remote -v | grep fetch | awk '{print $2}' | sed -En "s/https:\/\///p") && \
export GO_MODULE_FULL_NAME=$(if [ ! -z "$FULL_NAME_GIT" ]; then echo "$FULL_NAME_GIT"; else echo "$FULL_NAME_HTTP"; fi) && \
export BUILD_GIT_SHA=$(git rev-parse --short HEAD) && \
for GOOS in ${PLATFORMS}; do for GOARCH in ${ARCHS}; do BINARY="${BIN_NAME}-$GOOS-$GOARCH"; if [ $GOOS = "windows" ]; then BINARY="${BINARY}.exe"; fi; export BUILD_TIME="$(date -u +"%Y-%m-%d_%H:%M:%S_GMT")"; echo "Cross-compiling $GO_MODULE_FULL_NAME@$BUILD_GIT_SHA as ${BINARY}@$BUILD_VERSION at $BUILD_TIME"; GO_MODULE_FULL_NAME=$GO_MODULE_FULL_NAME BUILD_GIT_SHA=$BUILD_GIT_SHA BUILD_VERSION=$BUILD_VERSION BUILD_TIME=$BUILD_TIME GO111MODULE=$GO111MODULE CGO_ENABLED=0 GOARCH=$GOARCH GOOS=$GOOS GOPRIVATE=$GOPRIVATE go build -o ${BINARY} -gcflags="${GC_FLAGS}" -a -ldflags "-X ${GO_MODULE_FULL_NAME}/config.VersionBuildGoModule=${GO_MODULE_FULL_NAME} -X ${GO_MODULE_FULL_NAME}/config.VersionBuildNumber=${BUILD_VERSION} -X ${GO_MODULE_FULL_NAME}/config.VersionBuildGitSha=${BUILD_GIT_SHA} -X ${GO_MODULE_FULL_NAME}/config.VersionBuildTime=${BUILD_TIME}"; ls -la "/build/${BINARY}"; file "/build/${BINARY}"; chmod +x "/build/${BINARY}"; if [ $GOOS = "linux" ]; then sh -c "/build/${BINARY}"; sh -c "/build/${BINARY} version"; fi; done; done

# Compress the binaries
# It is not working with errors like https://github.com/golang/go/issues/19625
#RUN upx --lzma /build/${BIN_NAME}*

# Build the main container (Linux Runtime)
FROM ubuntu:20.04
WORKDIR /root/

ARG BIN_NAME
ENV BIN_NAME ${BIN_NAME:-unknown}

# Copy the linux amd64 binary, based on the arg (or else all files are copied) inspect with https://github.com/wagoodman/dive
COPY --from=compilation /build/${BIN_NAME}* /usr/local/bin/

# Debugging with delve https://kupczynski.info/2020/05/17/remote-debug-go-code.html
COPY --from=dependencies /go/bin/dlv /

# Debugging information based on the CG_FLAGS with delve https://kupczynski.info/2020/05/17/remote-debug-go-code.html
ENV CG_FLAGS_PORT ${CG_FLAGS_PORT:-40000}

# Command to be provided to the debugger, as it is required (CLIs not Servers)
ARG DEBUG_COMMAND
ENV DEBUG_COMMAND ${DEBUG_COMMAND}

# Move the bin to /usr/local/bin and make the entrypoint to point to it passing the params
# https://stackoverflow.com/questions/33439230/how-to-write-commands-with-multiple-lines-in-dockerfile-while-preserving-the-new/33439625#33439625
RUN echo "#!/bin/sh" > /usr/local/bin/entrypoint.sh && \
# https://stackoverflow.com/questions/32727594/how-to-pass-arguments-to-shell-script-through-docker-run/40312311#40312311
echo "/dlv --listen=:${CG_FLAGS_PORT} --headless=true --api-version=2 --accept-multiclient exec /usr/local/bin/${BIN_NAME} -- ${DEBUG_COMMAND}" >> /usr/local/bin/entrypoint.sh && \
chmod +x /usr/local/bin/entrypoint.sh && \
ln -s /usr/local/bin/${BIN_NAME}-linux-amd64 /usr/local/bin/${BIN_NAME}
# Delete all binarines that are not the linux one https://www.cyberciti.biz/faq/find-command-exclude-ignore-files/
# find /bin -type f -name "cloner-*" ! -path "*linux*" | xargs rm -f && \

ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
18 changes: 18 additions & 0 deletions debug.docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: "3"

services:

# Debug the CLI with Golang Delve https://kupczynski.info/2020/05/17/remote-debug-go-code.html
# Based on https://github.com/igor-kupczynski/remote-debug-example
cli-debug:
image: marcellodesales/cloner-debug:${BIN_VERSION:-0.1.0}
build:
context: .
dockerfile: debug.Dockerfile
args:
- BIN_NAME=cloner
- BIN_VERSION=${BIN_VERSION:-0.1.0}
# Change the command to debug, as it runs with Delv
- DEBUG_COMMAND=-v debug local https://github.com/igor-kupczynski/remote-debug-example -f
ports:
- 40000:40000

0 comments on commit 5dc3574

Please sign in to comment.