diff --git a/cmd/tk/check.go b/cmd/tk/check.go
index 02e6f434b16c223d690c9715ff93affccbd319b7..b201c05f967ec3391b0d75c33e7631164334f9e3 100644
--- a/cmd/tk/check.go
+++ b/cmd/tk/check.go
@@ -1,7 +1,6 @@
 package main
 
 import (
-	"fmt"
 	"os"
 	"os/exec"
 	"strings"
@@ -32,6 +31,7 @@ func init() {
 }
 
 func runCheckCmd(cmd *cobra.Command, args []string) error {
+	logAction("starting verification")
 	checkFailed := false
 	if !sshCheck() {
 		checkFailed = true
@@ -49,7 +49,7 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
 		if checkFailed {
 			os.Exit(1)
 		}
-		fmt.Println(`✔`, "all prerequisites checks passed")
+		logSuccess("all prerequisites checks passed")
 		return nil
 	}
 
@@ -60,7 +60,7 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
 	if checkFailed {
 		os.Exit(1)
 	}
-	fmt.Println(`✔`, "all checks passed")
+	logSuccess("all checks passed")
 	return nil
 }
 
@@ -69,10 +69,10 @@ func sshCheck() bool {
 	for _, cmd := range []string{"ssh-keygen", "ssh-keyscan"} {
 		_, err := exec.LookPath(cmd)
 		if err != nil {
-			fmt.Println(`✗`, cmd, "not found")
+			logFailure("%s not found", cmd)
 			ok = false
 		} else {
-			fmt.Println(`✔`, cmd, "found")
+			logSuccess("%s found", cmd)
 		}
 	}
 
@@ -82,94 +82,94 @@ func sshCheck() bool {
 func kubectlCheck(version string) bool {
 	_, err := exec.LookPath("kubectl")
 	if err != nil {
-		fmt.Println(`✗`, "kubectl not found")
+		logFailure("kubectl not found")
 		return false
 	}
 
 	output, err := execCommand("kubectl version --client --short | awk '{ print $3 }'")
 	if err != nil {
-		fmt.Println(`✗`, "kubectl version can't be determined")
+		logFailure("kubectl version can't be determined")
 		return false
 	}
 
 	v, err := semver.ParseTolerant(output)
 	if err != nil {
-		fmt.Println(`✗`, "kubectl version can't be parsed")
+		logFailure("kubectl version can't be parsed")
 		return false
 	}
 
 	rng, _ := semver.ParseRange(version)
 	if !rng(v) {
-		fmt.Println(`✗`, "kubectl version must be", version)
+		logFailure("kubectl version must be %s", version)
 		return false
 	}
 
-	fmt.Println(`✔`, "kubectl", v.String(), version)
+	logSuccess("kubectl %s %s", v.String(), version)
 	return true
 }
 
 func kustomizeCheck(version string) bool {
 	_, err := exec.LookPath("kustomize")
 	if err != nil {
-		fmt.Println(`✗`, "kustomize not found")
+		logFailure("kustomize not found")
 		return false
 	}
 
 	output, err := execCommand("kustomize version --short | awk '{ print $1 }' | cut -c2-")
 	if err != nil {
-		fmt.Println(`✗`, "kustomize version can't be determined")
+		logFailure("kustomize version can't be determined")
 		return false
 	}
 
 	if strings.Contains(output, "kustomize/") {
 		output, err = execCommand("kustomize version --short | awk '{ print $1 }' | cut -c12-")
 		if err != nil {
-			fmt.Println(`✗`, "kustomize version can't be determined")
+			logFailure("kustomize version can't be determined")
 			return false
 		}
 	}
 
 	v, err := semver.ParseTolerant(output)
 	if err != nil {
-		fmt.Println(`✗`, "kustomize version can't be parsed")
+		logFailure("kustomize version can't be parsed")
 		return false
 	}
 
 	rng, _ := semver.ParseRange(version)
 	if !rng(v) {
-		fmt.Println(`✗`, "kustomize version must be", version)
+		logFailure("kustomize version must be %s", version)
 		return false
 	}
 
-	fmt.Println(`✔`, "kustomize", v.String(), version)
+	logSuccess("kustomize %s %s", v.String(), version)
 	return true
 }
 
 func kubernetesCheck(version string) bool {
 	client, err := kubernetesClient()
 	if err != nil {
-		fmt.Println(`✗`, "kubernetes client initialization failed", err.Error())
+		logFailure("kubernetes client initialization failed: %s", err.Error())
 		return false
 	}
 
 	ver, err := client.Discovery().ServerVersion()
 	if err != nil {
-		fmt.Println(`✗`, "kubernetes API call failed", err.Error())
+		logFailure("kubernetes API call failed %s", err.Error())
 		return false
 	}
 
 	v, err := semver.ParseTolerant(ver.String())
 	if err != nil {
-		fmt.Println(`✗`, "kubernetes version can't be determined")
+		logFailure("kubernetes version can't be determined")
 		return false
 	}
 
 	rng, _ := semver.ParseRange(version)
 	if !rng(v) {
-		fmt.Println(`✗`, "kubernetes version must be", version)
+		logFailure("kubernetes version must be %s", version)
 		return false
 	}
 
-	fmt.Println(`✔`, "kubernetes", v.String(), version)
+	logSuccess("kubernetes %s %s", v.String(), version)
 	return true
 }
diff --git a/cmd/tk/create_source.go b/cmd/tk/create_source.go
index c3cb26cd8b041e6939b32160d0aa22469784b57f..543a6777de8f90a38188ff9f57c27c2225919aed 100644
--- a/cmd/tk/create_source.go
+++ b/cmd/tk/create_source.go
@@ -3,6 +3,7 @@ package main
 import (
 	"bufio"
 	"bytes"
+	"context"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -78,6 +79,9 @@ func createSourceCmdRun(cmd *cobra.Command, args []string) error {
 		return fmt.Errorf("git URL parse failed: %w", err)
 	}
 
+	ctx, cancel := context.WithTimeout(context.Background(), timeout)
+	defer cancel()
+
 	withAuth := false
 	if strings.HasPrefix(sourceGitURL, "ssh") {
 		if err := generateSSH(name, u.Host, tmpDir); err != nil {
@@ -91,7 +95,7 @@ func createSourceCmdRun(cmd *cobra.Command, args []string) error {
 		withAuth = true
 	}
 
-	fmt.Println(`✚`, "generating source resource")
+	logAction("generating source %s in %s namespace", name, namespace)
 
 	t, err := template.New("tmpl").Parse(gitSource)
 	if err != nil {
@@ -130,7 +134,7 @@ func createSourceCmdRun(cmd *cobra.Command, args []string) error {
 	}
 
 	command := fmt.Sprintf("echo '%s' | kubectl apply -f-", data.String())
-	c := exec.Command("/bin/sh", "-c", command)
+	c := exec.CommandContext(ctx, "/bin/sh", "-c", command)
 
 	var stdoutBuf, stderrBuf bytes.Buffer
 	c.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
@@ -138,11 +142,10 @@ func createSourceCmdRun(cmd *cobra.Command, args []string) error {
 
 	err = c.Run()
 	if err != nil {
-		fmt.Println(`✗`, "source apply failed")
-		os.Exit(1)
+		return fmt.Errorf("source apply failed")
 	}
 
-	fmt.Println(`✚`, "waiting for source sync")
+	logAction("waiting for source sync")
 	if output, err := execCommand(fmt.Sprintf(
 		"kubectl -n %s wait gitrepository/%s --for=condition=ready --timeout=1m",
 		namespace, name)); err != nil {
@@ -155,7 +158,7 @@ func createSourceCmdRun(cmd *cobra.Command, args []string) error {
 }
 
 func generateBasicAuth(name string) error {
-	fmt.Println(`✚`, "saving credentials")
+	logAction("saving credentials")
 	credentials := fmt.Sprintf("--from-literal=username='%s' --from-literal=password='%s'",
 		sourceUsername, sourcePassword)
 	secret := fmt.Sprintf("kubectl -n %s create secret generic %s %s --dry-run=client -oyaml | kubectl apply -f-",
@@ -169,14 +172,14 @@ func generateBasicAuth(name string) error {
 }
 
 func generateSSH(name, host, tmpDir string) error {
-	fmt.Println(`✚`, "generating host key for", host)
+	logAction("generating host key for %s", host)
 
 	keyscan := fmt.Sprintf("ssh-keyscan %s > %s/known_hosts", host, tmpDir)
 	if output, err := execCommand(keyscan); err != nil {
 		return fmt.Errorf("ssh-keyscan failed: %s", output)
 	}
 
-	fmt.Println(`✚`, "generating deploy key")
+	logAction("generating deploy key")
 
 	keygen := fmt.Sprintf("ssh-keygen -b 2048 -t rsa -f %s/identity -q -N \"\"", tmpDir)
 	if output, err := execCommand(keygen); err != nil {
@@ -194,11 +197,11 @@ func generateSSH(name, host, tmpDir string) error {
 		IsConfirm: true,
 	}
 	if _, err := prompt.Run(); err != nil {
-		fmt.Println(`✗`, "aborting")
+		logFailure("aborting")
 		os.Exit(1)
 	}
 
-	fmt.Println(`✚`, "saving deploy key")
+	logAction("saving deploy key")
 	files := fmt.Sprintf("--from-file=%s/identity --from-file=%s/identity.pub --from-file=%s/known_hosts",
 		tmpDir, tmpDir, tmpDir)
 	secret := fmt.Sprintf("kubectl -n %s create secret generic %s %s --dry-run=client -oyaml | kubectl apply -f-",
diff --git a/cmd/tk/install.go b/cmd/tk/install.go
index ee3df1b1bbc01dc7b985ee773337317b158a860e..1cb12467f07668ff59529152fb40f66726828a85 100644
--- a/cmd/tk/install.go
+++ b/cmd/tk/install.go
@@ -62,19 +62,19 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
 	c.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
 	c.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)
 
-	fmt.Println(`✚`, "installing...")
+	logAction("installing components in %s namespace", namespace)
 	err := c.Run()
 	if err != nil {
-		fmt.Println(`✗`, "install failed")
+		logFailure("install failed")
 		os.Exit(1)
 	}
 
 	if installDryRun {
-		fmt.Println(`✔`, "install dry-run finished")
+		logSuccess("install dry-run finished")
 		return nil
 	}
 
-	fmt.Println(`✚`, "verifying installation...")
+	logAction("verifying installation")
 	for _, deployment := range []string{"source-controller", "kustomize-controller"} {
 		command = fmt.Sprintf("kubectl -n %s rollout status deployment %s --timeout=%s",
 			namespace, deployment, timeout.String())
@@ -83,11 +83,11 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
 		c.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)
 		err := c.Run()
 		if err != nil {
-			fmt.Println(`✗`, "install failed")
+			logFailure("install failed")
 			os.Exit(1)
 		}
 	}
 
-	fmt.Println(`✔`, "install finished")
+	logSuccess("install finished")
 	return nil
 }
diff --git a/cmd/tk/main.go b/cmd/tk/main.go
index c0ceb44c14e70743d6efb0e44ae1f8cd9181c221..33aa2178d9e89f6db32d97a4517b5db9e297540a 100644
--- a/cmd/tk/main.go
+++ b/cmd/tk/main.go
@@ -47,7 +47,7 @@ func init() {
 func main() {
 	log.SetFlags(0)
 	if err := rootCmd.Execute(); err != nil {
-		fmt.Println(err)
+		logFailure("%v", err)
 		os.Exit(1)
 	}
 }
@@ -81,3 +81,15 @@ func execCommand(command string) (string, error) {
 	}
 	return string(output), nil
 }
+
+func logAction(format string, a ...interface{}) {
+	fmt.Println(`✚`, fmt.Sprintf(format, a...))
+}
+
+func logSuccess(format string, a ...interface{}) {
+	fmt.Println(`✔`, fmt.Sprintf(format, a...))
+}
+
+func logFailure(format string, a ...interface{}) {
+	fmt.Println(`✗`, fmt.Sprintf(format, a...))
+}
diff --git a/cmd/tk/uninstall.go b/cmd/tk/uninstall.go
index 1459d011645416ca63f5d755ed9e557b58223fd5..aeea68cff02ea72ef4a45d70fa09e4dc8e685d9c 100644
--- a/cmd/tk/uninstall.go
+++ b/cmd/tk/uninstall.go
@@ -49,7 +49,7 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
 			IsConfirm: true,
 		}
 		if _, err := prompt.Run(); err != nil {
-			fmt.Println(`✗`, "aborting")
+			logFailure("aborting")
 			os.Exit(1)
 		}
 	}
@@ -67,13 +67,13 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
 	c.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
 	c.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)
 
-	fmt.Println(`✚`, "uninstalling...")
+	logAction("uninstalling components")
 	err := c.Run()
 	if err != nil {
-		fmt.Println(`✗`, "uninstall failed")
+		logFailure("uninstall failed")
 		os.Exit(1)
 	}
 
-	fmt.Println(`✔`, "uninstall finished")
+	logSuccess("uninstall finished")
 	return nil
 }