Skip to content

Commit dc8338d

Browse files
sundaram2021VishwajitNagulkarManjeet-Singh2428anmolnagpal
authoredNov 18, 2024··
Docker (#17)
* cleaned deps * feat: helper function for sdkr subcommand * feat: build cmd for docker * feat: provision cmd , combination for build scan tag and push * feat: push cmd for docker * feat: scan cmd for docker * feat: sdkr subcommand for smurf * feat: tag command for docker * feat: added docker cmd * added deps * refactor: updated the readme with latest changes * refactor: added remove image helper function * feat: added remove cmd for docker * refactor: added -d delete flag in the cmd * refactor: added cloud specific flags to push docker images * refactor: added helper functions for pushing images to all the three clouds aws, azure, gcp * added deps * refactor: subcommand for sdkr used to push images to registries * feat: added subcommand for push, az, to images to acr * feat: added subcommand for push, aws, to images to ecr * feat: added subcommand for push, gcp, to images to gcr * feat: added subcommand for push, hub, to images to docker hub * refactor: added multiarch and build args support * refactor: cleaned up * refactor: added plaform support * refactor: added platform flag * feat: provision cmd for ACR * feat: provision cmd for ECR * feat: provision cmd for GCR * feat: provision cmd for Docker Hub * updated deps * refactor: delete provision , updated it to provisionHub * refactor: updated Readme * refactor: updated docs * fmt: restructure of readme * tested and updated dockerfile (#21) * feat: updated go packages (#22) Co-authored-by: Anmol Nagpal <[email protected]> --------- Co-authored-by: Vishwajit Nagulkar <[email protected]> Co-authored-by: Manjeet-Singh2428 <[email protected]> Co-authored-by: Anmol Nagpal <[email protected]>
1 parent ad13d46 commit dc8338d

21 files changed

+2098
-216
lines changed
 

‎Dockerfile

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
FROM golang:1.23
2-
1+
FROM golang:1.23-alpine
32

43

54
WORKDIR /go/src/app
65
COPY . .
76

87
# Build the Go application
9-
RUN go build -o smurf main.go
10-
RUN chmod +x smurf
11-
8+
RUN go build -o smurf main.go && \
9+
mv smurf /usr/local/bin/ && \
10+
chmod +x /usr/local/bin/smurf
1211

13-
# Set entrypoint to the build binary
14-
ENTRYPOINT ["./go/src/app/smurf"]
12+
ENTRYPOINT ["/usr/local/bin/smurf"]

‎README.md

+131-40
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,57 @@
1-
# Smurf
2-
3-
Smurf is a command-line interface built with Cobra, designed to simplify and automate commands for essential tools like Terraform and Docker. It provides intuitive, unified commands to execute Terraform plans, Docker container management, and other DevOps tasks seamlessly from one interface. Whether you need to spin up environments, manage containers, or apply infrastructure as code, this CLI streamlines multi-tool operations, boosting productivity and reducing context-switching.
4-
1+
![Banner](https://github.com/clouddrove/terraform-module-template/assets/119565952/67a8a1af-2eb7-40b7-ae07-c94cde9ce062)
2+
<h1 align="center">
3+
Smurf
4+
</h1>
5+
6+
<p align="center">
7+
<a href="https://goreportcard.com/report/github.com/clouddrove/smurf">
8+
<img alt="Go Report Status" src="https://goreportcard.com/badge/github.com/clouddrove/smurf">
9+
</a>
10+
<a href="https://github.com/clouddrove/smurf/">
11+
<img alt="Build Status" src="https://img.shields.io/badge/test-passing-green">
12+
</a>
13+
<a href="https://join.slack.com/t/devops-talks/shared_invite/zt-2s2rnal1e-bRStDKSyRC~dpXA~PaJ7vQ">
14+
<img alt="Slack Chat" src="https://img.shields.io/badge/join%20slack-click%20here-blue">
15+
</a>
16+
<a href="https://medium.com/devops-talks/announcing-devopstalks-spectacular-hacktoberfest-2024-363a09223c45">
17+
<img alt="Blog" src="https://img.shields.io/badge/hacktoberfest2024%20blog-8A2BE2">
18+
</a>
19+
<a href="https://choosealicense.com/licenses/mit/">
20+
<img alt="Apache-2.0 License" src="http://img.shields.io/badge/license-MIT-brightgreen.svg">
21+
</a>
22+
</p>
23+
24+
<p align="center">
25+
<a href='https://facebook.com/sharer/sharer.php?u=https://github.com/clouddrove/smurf'>
26+
<img title="Share on Facebook" src="https://user-images.githubusercontent.com/50652676/62817743-4f64cb80-bb59-11e9-90c7-b057252ded50.png" />
27+
</a>
28+
<a href='https://www.linkedin.com/shareArticle?mini=true&title=smurf&url=https://github.com/clouddrove/smurf'>
29+
<img title="Share on LinkedIn" src="https://user-images.githubusercontent.com/50652676/62817742-4e339e80-bb59-11e9-87b9-a1f68cae1049.png" />
30+
</a>
31+
<a href='https://twitter.com/intent/tweet/?text=smurf&url=https://github.com/clouddrove/smurf'>
32+
<img title="Share on Twitter" src="https://user-images.githubusercontent.com/50652676/62817740-4c69db00-bb59-11e9-8a79-3580fbbf6d5c.png" />
33+
</a>
34+
</p>
35+
36+
Smurf is a command-line interface built with Cobra, designed to streamline DevOps workflows by providing unified commands for essential tools like Terraform, Helm, and Docker. With Smurf, you can execute Terraform, Helm, and Docker commands seamlessly from a single interface. This CLI simplifies tasks such as environment provisioning, container management, and infrastructure-as-code deployment, improving productivity and minimizing context-switching.
537
## Features
638

7-
- **Terraform Command Wrapper:** Run `init`, `plan`, `apply`, `output` , `drift` commands and `provision` , which is a wrapper of init, drift, plan, apply, output.
8-
- **Git Integration:** (yet to come)
9-
- **Docker Integration:**(yet to come)
10-
- **Helm Integration:**(yet to come)
39+
- **Terraform Command Wrapper (stf):** Run `init`, `plan`, `apply`, `output`, `drift`, `validate`, `destroy`, `format` commands, and `provision`, a combined operation of `init`, `validate`, and `apply`.
40+
- **Helm Command Wrapper (selm):** Run `create`, `install`, `lint`, `list`, `status`, `template`, `upgrade`, `uninstall` commands, and `provision`, a combination of `install`, `upgrade`, `lint`, and `template`.
41+
- **Docker Command Wrapper (sdkr):** Run `build`, `scan`, `tag`, `publish`, `push` commands, and `provision`, a combination of `build`, `scan`, and `publish`.
42+
- **Multicloud Container registry :** Push images from multiple cloud registries like AWS ECR, GCP GCR, Azure ACR, and Docker Hub.Run `smurf sdkr push --help` to push images from the specified registry.
43+
- **Git Integration:** *(Yet to come)*
44+
- **Unified CLI Interface:** Manage multi-tool operations from one interface, reducing the need for multiple command sets.
1145

1246
## Installation
1347

1448
### Prerequisites
1549

1650
- Go 1.20 or higher
1751
- Git
18-
- Terraform installed and available in your PATH
52+
- Terraform, Helm, and Docker Daemon installed and accessible via your PATH
1953

20-
### Steps
54+
### Installation Steps
2155

2256
1. **Clone the repository:**
2357

@@ -31,60 +65,117 @@ Smurf is a command-line interface built with Cobra, designed to simplify and aut
3165
cd smurf
3266
```
3367

34-
3. **Build and install the tool:**
68+
3. **Build the tool:**
3569

3670
```bash
37-
go build .
71+
go build -o smurf .
3872
```
3973

40-
This will build `smurf` to your project directory.
74+
This will build `smurf` in your project directory.
4175

4276
## Usage
4377

44-
Navigate to your Terraform project directory and use `smurf` commands as follows:
78+
### Terraform Commands
79+
80+
Use `smurf stf <command>` to run Terraform commands. Supported commands include:
4581

46-
### Initialize Terraform
82+
- **Help:** `smurf stf --help`
83+
- **Initialize Terraform:** `smurf stf init`
84+
- **Generate and Show Execution Plan:** `smurf stf plan`
85+
- **Apply Terraform Changes:** `smurf stf apply`
86+
- **Detect Drift in Terraform State:** `smurf stf drift`
87+
- **Provision Terraform Environment:** `smurf stf provision`
4788

48-
```bash
49-
./smurf init
50-
```
89+
The `provision` command for Terraform performs `init`, `validate`, and `apply`.
5190

52-
This initializes your Terraform working directory.
91+
### Helm Commands
5392

54-
### Generate and Show an Execution Plan for Terraform
93+
Use `smurf selm <command>` to run Helm commands. Supported commands include:
5594

56-
```bash
57-
./smurf plan
58-
```
95+
- **Help:** `smurf selm --help`
96+
- **Create a Helm Chart:** `smurf selm create`
97+
- **Install a Chart:** `smurf selm install`
98+
- **Upgrade a Release:** `smurf selm upgrade`
99+
- **Provision Helm Environment:** `smurf selm provision --help`
59100

60-
Generates an execution plan and shows what actions Terraform will take.
101+
The `provision` command for Helm combines `install`, `upgrade`, `lint`, and `template`.
61102

62-
### Apply Terraform Changes
103+
### Docker Commands
63104

64-
```bash
65-
./smurf apply
66-
```
105+
Use `smurf sdkr <command> <flags>` to run Docker commands. Supported commands include:
67106

68-
Applies the changes required to reach the desired state of the configuration.
107+
- **Help:** `smurf sdkr --help`
108+
- **Build an Image:** `smurf sdkr build`
109+
- **Scan an Image:** `smurf sdkr scan`
110+
- **Push an Image:** `smurf sdkr push --help`
111+
- **Provision Registry Environment:** `smurf sdkr provision-hub [flags] `(for Docker Hub)
69112

70-
### Detect Drift in Terraform State
113+
The `provision-hub` command for Docker combines `build`, `scan`, and `publish`.
114+
The `provision-ecr` command for Docker combines `build`, `scan`, and `publish` for AWS ECR.
115+
THE `provision-gcr` command for Docker combines `build`, `scan`, and `publish` for GCP GCR.
116+
THE `provision-acr` command for Docker combines `build`, `scan`, and `publish` for Azure ACR.
71117

72-
```bash
73-
./smurf drift
74-
```
75118

76-
Detects any drift between your Terraform state and the actual infrastructure.
77119

78-
## Important Notes
79120

80-
- **Uncommitted Changes:** `smurf` will check for uncommitted changes in your `.tf` files. If any are detected, it will prompt you to commit or discard them before proceeding. This ensures that only committed changes are applied, maintaining consistency and traceability.
121+
## ✨ Contributors
81122

82-
- **Git Integration:** Make sure your project is initialized as a Git repository (`git init`) and that your `.tf` files are tracked.
123+
Big thanks to our contributors for elevating our project with their dedication and expertise! But, we do not wish to stop there, would like to invite contributions from the community in improving these projects and making them more versatile for better reach. Remember, every bit of contribution is immensely valuable, as, together, we are moving in only 1 direction, i.e. forward.
83124

84-
## Contributing
125+
<a href="https://github.com/clouddrove/smurf/graphs/contributors">
126+
<img src="https://contrib.rocks/image?repo=clouddrove/smurf&max" />
127+
</a>
128+
<br>
129+
<br>
85130

86-
Contributions are welcome! Please open issues or pull requests on the [GitHub repository](https://github.com/clouddrove/smurf).
131+
If you're considering contributing to our project, here are a few quick guidelines that we have been following (Got a suggestion? We are all ears!):
132+
133+
- **Fork the Repository:** Create a new branch for your feature or bug fix.
134+
- **Coding Standards:** You know the drill.
135+
- **Clear Commit Messages:** Write clear and concise commit messages to facilitate understanding.
136+
- **Thorough Testing:** Test your changes thoroughly before submitting a pull request.
137+
- **Documentation Updates:** Include relevant documentation updates if your changes impact it.
87138

88139
## License
89140

90-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
141+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
142+
143+
## Feedback
144+
Spot a bug or have thoughts to share with us? Let's squash it together! Log it in our [issue tracker](https://github.com/clouddrove/smurf/issues), feel free to drop us an email at [hello@clouddrove.com](mailto:hello@clouddrove.com).
145+
146+
Show some love with a ★ on [our GitHub](https://github.com/clouddrove/smurf)! if our work has brightened your day! – your feedback fuels our journey!
147+
148+
## Join Our Slack Community
149+
150+
Join our vibrant open-source slack community and embark on an ever-evolving journey with CloudDrove; helping you in moving upwards in your career path.
151+
Join our vibrant Open Source Slack Community and embark on a learning journey with CloudDrove. Grow with us in the world of DevOps and set your career on a path of consistency.
152+
153+
🌐💬What you'll get after joining this Slack community:
154+
155+
- 🚀 Encouragement to upgrade your best version.
156+
- 🌈 Learning companionship with our DevOps squad.
157+
- 🌱 Relentless growth with daily updates on new advancements in technologies.
158+
159+
Join our tech elites [Join Now][slack] 🚀
160+
161+
## Explore Our Blogs
162+
163+
Click [here][blog] :books: :star2:
164+
165+
## Tap into our capabilities
166+
We provide a platform for organizations to engage with experienced top-tier DevOps & Cloud services. Tap into our pool of certified engineers and architects to elevate your DevOps and Cloud Solutions.
167+
168+
At [CloudDrove][website], has extensive experience in designing, building & migrating environments, securing, consulting, monitoring, optimizing, automating, and maintaining complex and large modern systems. With remarkable client footprints in American & European corridors, our certified architects & engineers are ready to serve you as per your requirements & schedule. Write to us at [business@clouddrove.com](mailto:business@clouddrove.com).
169+
170+
<p align="center">We are <b> The Cloud Experts!</b></p>
171+
<hr />
172+
<p align="center">We ❤️ <a href="https://github.com/clouddrove">Open Source</a> and you can check out <a href="https://registry.terraform.io/namespaces/clouddrove">our other modules</a> to get help with your new Cloud ideas.</p>
173+
174+
[website]: https://clouddrove.com
175+
[blog]: https://blog.clouddrove.com
176+
[slack]: https://www.launchpass.com/devops-talks
177+
[github]: https://github.com/clouddrove
178+
[linkedin]: https://cpco.io/linkedin
179+
[twitter]: https://twitter.com/clouddrove/
180+
[email]: https://clouddrove.com/contact-us.html
181+
[terraform_modules]: https://github.com/clouddrove?utf8=%E2%9C%93&q=terraform-&type=&language=

‎cmd/docker/build.go

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package docker
2+
3+
import (
4+
"strings"
5+
6+
"github.com/clouddrove/smurf/internal/docker"
7+
"github.com/spf13/cobra"
8+
)
9+
10+
var (
11+
dockerfilePath string
12+
noCache bool
13+
buildArgs []string
14+
target string
15+
platform string
16+
)
17+
18+
var buildCmd = &cobra.Command{
19+
Use: "build [IMAGE_NAME] [TAG]",
20+
Short: "Build a Docker image with the given name and tag.",
21+
Args: cobra.ExactArgs(2),
22+
RunE: func(cmd *cobra.Command, args []string) error {
23+
buildArgsMap := make(map[string]string)
24+
for _, arg := range buildArgs {
25+
parts := strings.SplitN(arg, "=", 2)
26+
if len(parts) == 2 {
27+
buildArgsMap[parts[0]] = parts[1]
28+
}
29+
}
30+
31+
opts := docker.BuildOptions{
32+
DockerfilePath: dockerfilePath,
33+
NoCache: noCache,
34+
BuildArgs: buildArgsMap,
35+
Target: target,
36+
Platform: platform,
37+
}
38+
39+
return docker.Build(args[0], args[1], opts)
40+
},
41+
}
42+
43+
func init() {
44+
buildCmd.Flags().StringVarP(&dockerfilePath, "file", "f", "Dockerfile", "Name of the Dockerfile (Default is 'Dockerfile')")
45+
buildCmd.Flags().BoolVar(&noCache, "no-cache", false, "Do not use cache when building the image")
46+
buildCmd.Flags().StringArrayVar(&buildArgs, "build-arg", []string{}, "Set build-time variables")
47+
buildCmd.Flags().StringVar(&target, "target", "", "Set the target build stage to build")
48+
buildCmd.Flags().StringVar(&platform, "platform", "", "Set the platform for the build (e.g., linux/amd64, linux/arm64)")
49+
50+
sdkrCmd.AddCommand(buildCmd)
51+
}

‎cmd/docker/provisionAcr.go

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package docker
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"sync"
7+
8+
"github.com/clouddrove/smurf/internal/docker"
9+
"github.com/pterm/pterm"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
// Flags for the provisionAcr command
14+
var (
15+
provisionAcrSubscriptionID string
16+
provisionAcrResourceGroup string
17+
provisionAcrRegistryName string
18+
provisionAcrImageName string
19+
provisionAcrImageTag string
20+
provisionAcrDockerfilePath string
21+
provisionAcrNoCache bool
22+
provisionAcrBuildArgs []string
23+
provisionAcrTarget string
24+
provisionAcrSarifFile string
25+
provisionAcrTargetTag string
26+
provisionAcrConfirmPush bool
27+
provisionAcrDeleteAfterPush bool
28+
provisionAcrPlatform string
29+
)
30+
31+
var provisionAcrCmd = &cobra.Command{
32+
Use: "provision-acr",
33+
Short: "Build, scan, tag, and push a Docker image to Azure Container Registry.",
34+
RunE: func(cmd *cobra.Command, args []string) error {
35+
if provisionAcrSubscriptionID == "" || provisionAcrResourceGroup == "" || provisionAcrRegistryName == "" {
36+
return fmt.Errorf("ACR provisioning requires --subscription-id, --resource-group, and --registry-name flags")
37+
}
38+
39+
fullAcrImage := fmt.Sprintf("%s.azurecr.io/%s:%s", provisionAcrRegistryName, provisionAcrImageName, provisionAcrImageTag)
40+
41+
buildArgsMap := make(map[string]string)
42+
for _, arg := range provisionAcrBuildArgs {
43+
parts := strings.SplitN(arg, "=", 2)
44+
if len(parts) == 2 {
45+
buildArgsMap[parts[0]] = parts[1]
46+
}
47+
}
48+
49+
buildOpts := docker.BuildOptions{
50+
DockerfilePath: provisionAcrDockerfilePath,
51+
NoCache: provisionAcrNoCache,
52+
BuildArgs: buildArgsMap,
53+
Target: provisionAcrTarget,
54+
Platform: provisionAcrPlatform,
55+
}
56+
57+
pterm.Info.Println("Starting ACR build...")
58+
if err := docker.Build(provisionAcrImageName, provisionAcrImageTag, buildOpts); err != nil {
59+
pterm.Error.Println("Build failed:", err)
60+
return err
61+
}
62+
pterm.Success.Println("Build completed successfully.")
63+
64+
var wg sync.WaitGroup
65+
var scanErr, tagErr error
66+
67+
wg.Add(2)
68+
69+
go func() {
70+
defer wg.Done()
71+
pterm.Info.Println("Starting scan...")
72+
scanErr = docker.Scout(fullAcrImage, provisionAcrSarifFile)
73+
if scanErr != nil {
74+
pterm.Error.Println("Scan failed:", scanErr)
75+
} else {
76+
pterm.Success.Println("Scan completed successfully.")
77+
}
78+
}()
79+
80+
go func() {
81+
defer wg.Done()
82+
if provisionAcrTargetTag != "" {
83+
pterm.Info.Printf("Tagging image as %s...\n", provisionAcrTargetTag)
84+
tagOpts := docker.TagOptions{
85+
Source: fullAcrImage,
86+
Target: provisionAcrTargetTag,
87+
}
88+
tagErr = docker.TagImage(tagOpts)
89+
if tagErr != nil {
90+
pterm.Error.Println("Tagging failed:", tagErr)
91+
} else {
92+
pterm.Success.Println("Tagging completed successfully.")
93+
}
94+
}
95+
}()
96+
97+
wg.Wait()
98+
99+
if scanErr != nil || tagErr != nil {
100+
return fmt.Errorf("ACR provisioning failed due to previous errors")
101+
}
102+
103+
pushImage := provisionAcrTargetTag
104+
if pushImage == "" {
105+
pushImage = fullAcrImage
106+
}
107+
108+
if provisionAcrConfirmPush {
109+
pterm.Info.Printf("Pushing image %s to ACR...\n", pushImage)
110+
if err := docker.PushImageToACR(provisionAcrSubscriptionID, provisionAcrResourceGroup, provisionAcrRegistryName, provisionAcrImageName); err != nil {
111+
pterm.Error.Println("Push to ACR failed:", err)
112+
return err
113+
}
114+
pterm.Success.Println("Push to ACR completed successfully.")
115+
}
116+
117+
if provisionAcrDeleteAfterPush {
118+
pterm.Info.Printf("Deleting local image %s...\n", fullAcrImage)
119+
if err := docker.RemoveImage(fullAcrImage); err != nil {
120+
pterm.Error.Println("Failed to delete local image:", err)
121+
return err
122+
}
123+
pterm.Success.Println("Successfully deleted local image:", fullAcrImage)
124+
}
125+
126+
pterm.Success.Println("ACR provisioning completed successfully.")
127+
return nil
128+
},
129+
}
130+
131+
func init() {
132+
provisionAcrCmd.Flags().StringVarP(&provisionAcrImageName, "image-name", "i", "", "Name of the image to build")
133+
provisionAcrCmd.Flags().StringVarP(&provisionAcrImageTag, "tag", "t", "latest", "Tag for the image")
134+
provisionAcrCmd.Flags().StringVarP(&provisionAcrDockerfilePath, "file", "f", "Dockerfile", "Name of the Dockerfile (default is 'Dockerfile')")
135+
provisionAcrCmd.Flags().BoolVar(&provisionAcrNoCache, "no-cache", false, "Do not use cache when building the image")
136+
provisionAcrCmd.Flags().StringArrayVar(&provisionAcrBuildArgs, "build-arg", []string{}, "Set build-time variables")
137+
provisionAcrCmd.Flags().StringVar(&provisionAcrTarget, "target", "", "Set the target build stage to build")
138+
provisionAcrCmd.Flags().StringVarP(&provisionAcrSarifFile, "output", "o", "", "Output file for SARIF report")
139+
provisionAcrCmd.Flags().StringVar(&provisionAcrTargetTag, "target-tag", "", "Target tag for tagging the image")
140+
provisionAcrCmd.Flags().BoolVarP(&provisionAcrConfirmPush, "yes", "y", false, "Push the image to ACR without confirmation")
141+
provisionAcrCmd.Flags().BoolVarP(&provisionAcrDeleteAfterPush, "delete", "d", false, "Delete the local image after pushing")
142+
provisionAcrCmd.Flags().StringVar(&provisionAcrSubscriptionID, "subscription-id", "", "Azure subscription ID (required)")
143+
provisionAcrCmd.Flags().StringVar(&provisionAcrResourceGroup, "resource-group", "", "Azure resource group name (required)")
144+
provisionAcrCmd.Flags().StringVar(&provisionAcrRegistryName, "registry-name", "", "Azure Container Registry name (required)")
145+
provisionAcrCmd.Flags().StringVar(&provisionAcrPlatform, "platform", "", "Platform for the image")
146+
147+
provisionAcrCmd.MarkFlagRequired("subscription-id")
148+
provisionAcrCmd.MarkFlagRequired("resource-group")
149+
provisionAcrCmd.MarkFlagRequired("registry-name")
150+
provisionAcrCmd.MarkFlagRequired("image-name")
151+
152+
sdkrCmd.AddCommand(provisionAcrCmd)
153+
}

‎cmd/docker/provisionEcr.go

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package docker
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"sync"
7+
8+
"github.com/clouddrove/smurf/internal/docker"
9+
"github.com/pterm/pterm"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
// Flags for the provisionEcr command
14+
var (
15+
provisionEcrImageName string
16+
provisionEcrImageTag string
17+
provisionEcrDockerfilePath string
18+
provisionEcrNoCache bool
19+
provisionEcrBuildArgs []string
20+
provisionEcrTarget string
21+
provisionEcrSarifFile string
22+
provisionEcrTargetTag string
23+
provisionEcrConfirmPush bool
24+
provisionEcrDeleteAfterPush bool
25+
provisionEcrRegion string
26+
provisionEcrRepository string
27+
provisionEcrPlatform string
28+
)
29+
30+
var provisionEcrCmd = &cobra.Command{
31+
Use: "provision-ecr",
32+
Short: "Build, scan, tag, and push a Docker image to AWS ECR.",
33+
RunE: func(cmd *cobra.Command, args []string) error {
34+
if provisionEcrRegion == "" || provisionEcrRepository == "" {
35+
return fmt.Errorf("ECR provisioning requires both --region and --repository flags")
36+
}
37+
38+
fullEcrImage := fmt.Sprintf("%s.dkr.ecr.%s.amazonaws.com/%s:%s", provisionEcrImageName, provisionEcrRegion, provisionEcrRepository, provisionEcrImageTag)
39+
40+
buildArgsMap := make(map[string]string)
41+
for _, arg := range provisionEcrBuildArgs {
42+
parts := strings.SplitN(arg, "=", 2)
43+
if len(parts) == 2 {
44+
buildArgsMap[parts[0]] = parts[1]
45+
}
46+
}
47+
48+
buildOpts := docker.BuildOptions{
49+
DockerfilePath: provisionEcrDockerfilePath,
50+
NoCache: provisionEcrNoCache,
51+
BuildArgs: buildArgsMap,
52+
Target: provisionEcrTarget,
53+
Platform: provisionEcrPlatform,
54+
}
55+
56+
pterm.Info.Println("Starting ECR build...")
57+
if err := docker.Build(provisionEcrImageName, provisionEcrImageTag, buildOpts); err != nil {
58+
pterm.Error.Println("Build failed:", err)
59+
return err
60+
}
61+
pterm.Success.Println("Build completed successfully.")
62+
63+
var wg sync.WaitGroup
64+
var scanErr, tagErr error
65+
66+
wg.Add(2)
67+
68+
go func() {
69+
defer wg.Done()
70+
pterm.Info.Println("Starting scan...")
71+
scanErr = docker.Scout(fullEcrImage, provisionEcrSarifFile)
72+
if scanErr != nil {
73+
pterm.Error.Println("Scan failed:", scanErr)
74+
} else {
75+
pterm.Success.Println("Scan completed successfully.")
76+
}
77+
}()
78+
79+
go func() {
80+
defer wg.Done()
81+
if provisionEcrTargetTag != "" {
82+
pterm.Info.Printf("Tagging image as %s...\n", provisionEcrTargetTag)
83+
tagOpts := docker.TagOptions{
84+
Source: fullEcrImage,
85+
Target: provisionEcrTargetTag,
86+
}
87+
tagErr = docker.TagImage(tagOpts)
88+
if tagErr != nil {
89+
pterm.Error.Println("Tagging failed:", tagErr)
90+
} else {
91+
pterm.Success.Println("Tagging completed successfully.")
92+
}
93+
}
94+
}()
95+
96+
wg.Wait()
97+
98+
if scanErr != nil || tagErr != nil {
99+
return fmt.Errorf("ECR provisioning failed due to previous errors")
100+
}
101+
102+
pushImage := provisionEcrTargetTag
103+
if pushImage == "" {
104+
pushImage = fullEcrImage
105+
}
106+
107+
if provisionEcrConfirmPush {
108+
pterm.Info.Printf("Pushing image %s to ECR...\n", pushImage)
109+
if err := docker.PushImageToECR(provisionEcrImageName, provisionEcrRegion, provisionEcrRepository); err != nil {
110+
pterm.Error.Println("Push to ECR failed:", err)
111+
return err
112+
}
113+
pterm.Success.Println("Push to ECR completed successfully.")
114+
}
115+
116+
if provisionEcrDeleteAfterPush {
117+
pterm.Info.Printf("Deleting local image %s...\n", fullEcrImage)
118+
if err := docker.RemoveImage(fullEcrImage); err != nil {
119+
pterm.Error.Println("Failed to delete local image:", err)
120+
return err
121+
}
122+
pterm.Success.Println("Successfully deleted local image:", fullEcrImage)
123+
}
124+
125+
pterm.Success.Println("ECR provisioning completed successfully.")
126+
return nil
127+
},
128+
}
129+
130+
func init() {
131+
provisionEcrCmd.Flags().StringVarP(&provisionEcrImageName, "image-name", "i", "", "Name of the image to build")
132+
provisionEcrCmd.Flags().StringVarP(&provisionEcrImageTag, "tag", "t", "latest", "Tag for the image")
133+
provisionEcrCmd.Flags().StringVarP(&provisionEcrDockerfilePath, "file", "f", "Dockerfile", "Name of the Dockerfile (default is 'Dockerfile')")
134+
provisionEcrCmd.Flags().BoolVar(&provisionEcrNoCache, "no-cache", false, "Do not use cache when building the image")
135+
provisionEcrCmd.Flags().StringArrayVar(&provisionEcrBuildArgs, "build-arg", []string{}, "Set build-time variables")
136+
provisionEcrCmd.Flags().StringVar(&provisionEcrTarget, "target", "", "Set the target build stage to build")
137+
provisionEcrCmd.Flags().StringVarP(&provisionEcrSarifFile, "output", "o", "", "Output file for SARIF report")
138+
provisionEcrCmd.Flags().StringVar(&provisionEcrTargetTag, "target-tag", "", "Target tag for tagging the image")
139+
provisionEcrCmd.Flags().BoolVarP(&provisionEcrConfirmPush, "yes", "y", false, "Push the image to ECR without confirmation")
140+
provisionEcrCmd.Flags().BoolVarP(&provisionEcrDeleteAfterPush, "delete", "d", false, "Delete the local image after pushing")
141+
provisionEcrCmd.Flags().StringVarP(&provisionEcrRegion, "region", "r", "", "AWS region (required)")
142+
provisionEcrCmd.Flags().StringVarP(&provisionEcrRepository, "repository", "R", "", "AWS ECR repository name (required)")
143+
provisionEcrCmd.Flags().StringVar(&provisionEcrPlatform, "platform", "", "Platform for the build")
144+
145+
provisionEcrCmd.MarkFlagRequired("image-name")
146+
provisionEcrCmd.MarkFlagRequired("region")
147+
provisionEcrCmd.MarkFlagRequired("repository")
148+
149+
sdkrCmd.AddCommand(provisionEcrCmd)
150+
}

‎cmd/docker/provisionGcr.go

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package docker
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"sync"
7+
8+
"github.com/clouddrove/smurf/internal/docker"
9+
"github.com/pterm/pterm"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
// Flags for the provisionGcr command
14+
var (
15+
provisionGcrProjectID string
16+
provisionGcrImageName string
17+
provisionGcrImageTag string
18+
provisionGcrDockerfilePath string
19+
provisionGcrNoCache bool
20+
provisionGcrBuildArgs []string
21+
provisionGcrTarget string
22+
provisionGcrSarifFile string
23+
provisionGcrTargetTag string
24+
provisionGcrConfirmPush bool
25+
provisionGcrDeleteAfterPush bool
26+
provisionGcrPlatform string
27+
)
28+
29+
var provisionGcrCmd = &cobra.Command{
30+
Use: "provision-gcr",
31+
Short: "Build, scan, tag, and push a Docker image to Google Container Registry.",
32+
Long: `Build, scan, tag, and push a Docker image to Google Container Registry.
33+
Set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your service account JSON key file.
34+
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/service-account-key.json"`,
35+
RunE: func(cmd *cobra.Command, args []string) error {
36+
if provisionGcrProjectID == "" {
37+
return fmt.Errorf("GCR provisioning requires --project-id flag")
38+
}
39+
40+
fullGcrImage := fmt.Sprintf("gcr.io/%s/%s:%s", provisionGcrProjectID, provisionGcrImageName, provisionGcrImageTag)
41+
42+
buildArgsMap := make(map[string]string)
43+
for _, arg := range provisionGcrBuildArgs {
44+
parts := strings.SplitN(arg, "=", 2)
45+
if len(parts) == 2 {
46+
buildArgsMap[parts[0]] = parts[1]
47+
}
48+
}
49+
50+
buildOpts := docker.BuildOptions{
51+
DockerfilePath: provisionGcrDockerfilePath,
52+
NoCache: provisionGcrNoCache,
53+
BuildArgs: buildArgsMap,
54+
Target: provisionGcrTarget,
55+
Platform: provisionGcrPlatform,
56+
}
57+
58+
pterm.Info.Println("Starting GCR build...")
59+
if err := docker.Build(provisionGcrImageName, provisionGcrImageTag, buildOpts); err != nil {
60+
pterm.Error.Println("Build failed:", err)
61+
return err
62+
}
63+
pterm.Success.Println("Build completed successfully.")
64+
65+
var wg sync.WaitGroup
66+
var scanErr, tagErr error
67+
68+
wg.Add(2)
69+
70+
go func() {
71+
defer wg.Done()
72+
pterm.Info.Println("Starting scan...")
73+
scanErr = docker.Scout(fullGcrImage, provisionGcrSarifFile)
74+
if scanErr != nil {
75+
pterm.Error.Println("Scan failed:", scanErr)
76+
} else {
77+
pterm.Success.Println("Scan completed successfully.")
78+
}
79+
}()
80+
81+
go func() {
82+
defer wg.Done()
83+
if provisionGcrTargetTag != "" {
84+
pterm.Info.Printf("Tagging image as %s...\n", provisionGcrTargetTag)
85+
tagOpts := docker.TagOptions{
86+
Source: fullGcrImage,
87+
Target: provisionGcrTargetTag,
88+
}
89+
tagErr = docker.TagImage(tagOpts)
90+
if tagErr != nil {
91+
pterm.Error.Println("Tagging failed:", tagErr)
92+
} else {
93+
pterm.Success.Println("Tagging completed successfully.")
94+
}
95+
}
96+
}()
97+
98+
wg.Wait()
99+
100+
if scanErr != nil || tagErr != nil {
101+
return fmt.Errorf("GCR provisioning failed due to previous errors")
102+
}
103+
104+
pushImage := provisionGcrTargetTag
105+
if pushImage == "" {
106+
pushImage = fullGcrImage
107+
}
108+
109+
if provisionGcrConfirmPush {
110+
pterm.Info.Printf("Pushing image %s to GCR...\n", pushImage)
111+
if err := docker.PushImageToGCR(provisionGcrProjectID, provisionGcrImageName); err != nil {
112+
pterm.Error.Println("Push to GCR failed:", err)
113+
return err
114+
}
115+
pterm.Success.Println("Push to GCR completed successfully.")
116+
}
117+
118+
if provisionGcrDeleteAfterPush {
119+
pterm.Info.Printf("Deleting local image %s...\n", fullGcrImage)
120+
if err := docker.RemoveImage(fullGcrImage); err != nil {
121+
pterm.Error.Println("Failed to delete local image:", err)
122+
return err
123+
}
124+
pterm.Success.Println("Successfully deleted local image:", fullGcrImage)
125+
}
126+
127+
pterm.Success.Println("GCR provisioning completed successfully.")
128+
return nil
129+
},
130+
}
131+
132+
func init() {
133+
provisionGcrCmd.Flags().StringVarP(&provisionGcrProjectID, "project-id", "p", "", "GCP project ID (required)")
134+
provisionGcrCmd.Flags().StringVarP(&provisionGcrImageName, "image-name", "i", "", "Name of the image to build")
135+
provisionGcrCmd.Flags().StringVarP(&provisionGcrImageTag, "tag", "t", "latest", "Tag for the image")
136+
provisionGcrCmd.Flags().StringVarP(&provisionGcrDockerfilePath, "file", "f", "Dockerfile", "Name of the Dockerfile (default is 'Dockerfile')")
137+
provisionGcrCmd.Flags().BoolVar(&provisionGcrNoCache, "no-cache", false, "Do not use cache when building the image")
138+
provisionGcrCmd.Flags().StringArrayVar(&provisionGcrBuildArgs, "build-arg", []string{}, "Set build-time variables")
139+
provisionGcrCmd.Flags().StringVar(&provisionGcrTarget, "target", "", "Set the target build stage to build")
140+
provisionGcrCmd.Flags().StringVarP(&provisionGcrSarifFile, "output", "o", "", "Output file for SARIF report")
141+
provisionGcrCmd.Flags().StringVar(&provisionGcrTargetTag, "target-tag", "", "Target tag for tagging the image")
142+
provisionGcrCmd.Flags().BoolVarP(&provisionGcrConfirmPush, "yes", "y", false, "Push the image to GCR without confirmation")
143+
provisionGcrCmd.Flags().BoolVarP(&provisionGcrDeleteAfterPush, "delete", "d", false, "Delete the local image after pushing")
144+
provisionGcrCmd.Flags().StringVar(&provisionGcrPlatform, "platform", "", "Set the platform for the image")
145+
146+
provisionGcrCmd.MarkFlagRequired("project-id")
147+
provisionGcrCmd.MarkFlagRequired("image-name")
148+
149+
sdkrCmd.AddCommand(provisionGcrCmd)
150+
}

‎cmd/docker/provisionHub.go

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package docker
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"sync"
7+
8+
"github.com/clouddrove/smurf/internal/docker"
9+
"github.com/pterm/pterm"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
// Flags for the provision command
14+
var (
15+
provisionImageName string
16+
provisionImageTag string
17+
provisionDockerfilePath string
18+
provisionNoCache bool
19+
provisionBuildArgs []string
20+
provisionTarget string
21+
provisionSarifFile string
22+
provisionTargetTag string
23+
provisionConfirmPush bool
24+
provisionDeleteAfterPush bool
25+
provisionPlatform string
26+
)
27+
28+
var provisionHubCmd = &cobra.Command{
29+
Use: "provision-hub",
30+
Short: "Build, scan, tag, and push a Docker image.",
31+
RunE: func(cmd *cobra.Command, args []string) error {
32+
fullImageName := fmt.Sprintf("%s:%s", provisionImageName, provisionImageTag)
33+
34+
buildArgsMap := make(map[string]string)
35+
for _, arg := range provisionBuildArgs {
36+
parts := strings.SplitN(arg, "=", 2)
37+
if len(parts) == 2 {
38+
buildArgsMap[parts[0]] = parts[1]
39+
}
40+
}
41+
42+
buildOpts := docker.BuildOptions{
43+
DockerfilePath: provisionDockerfilePath,
44+
NoCache: provisionNoCache,
45+
BuildArgs: buildArgsMap,
46+
Target: provisionTarget,
47+
Platform: provisionPlatform,
48+
}
49+
50+
pterm.Info.Println("Starting build...")
51+
if err := docker.Build(provisionImageName, provisionImageTag, buildOpts); err != nil {
52+
pterm.Error.Println("Build failed:", err)
53+
return err
54+
}
55+
pterm.Success.Println("Build completed successfully.")
56+
57+
var wg sync.WaitGroup
58+
var scanErr, tagErr error
59+
60+
wg.Add(2)
61+
62+
go func() {
63+
defer wg.Done()
64+
pterm.Info.Println("Starting scan...")
65+
scanErr = docker.Scout(fullImageName, provisionSarifFile)
66+
if scanErr != nil {
67+
pterm.Error.Println("Scan failed:", scanErr)
68+
} else {
69+
pterm.Success.Println("Scan completed successfully.")
70+
}
71+
}()
72+
73+
go func() {
74+
defer wg.Done()
75+
if provisionTargetTag != "" {
76+
pterm.Info.Printf("Tagging image as %s...\n", provisionTargetTag)
77+
tagOpts := docker.TagOptions{
78+
Source: fullImageName,
79+
Target: provisionTargetTag,
80+
}
81+
tagErr = docker.TagImage(tagOpts)
82+
if tagErr != nil {
83+
pterm.Error.Println("Tagging failed:", tagErr)
84+
} else {
85+
pterm.Success.Println("Tagging completed successfully.")
86+
}
87+
}
88+
}()
89+
90+
wg.Wait()
91+
92+
if scanErr != nil || tagErr != nil {
93+
return fmt.Errorf("provisioning failed due to previous errors")
94+
}
95+
96+
pushImage := provisionTargetTag
97+
if pushImage == "" {
98+
pushImage = fullImageName
99+
}
100+
101+
if provisionConfirmPush {
102+
pterm.Info.Printf("Pushing image %s...\n", pushImage)
103+
pushOpts := docker.PushOptions{
104+
ImageName: pushImage,
105+
}
106+
if err := docker.PushImage(pushOpts); err != nil {
107+
pterm.Error.Println("Push failed:", err)
108+
return err
109+
}
110+
pterm.Success.Println("Push completed successfully.")
111+
} else {
112+
result, _ := pterm.DefaultInteractiveConfirm.
113+
WithDefaultText("Do you want to push the image?").
114+
Show()
115+
if result {
116+
pterm.Info.Printf("Pushing image %s...\n", pushImage)
117+
pushOpts := docker.PushOptions{
118+
ImageName: pushImage,
119+
}
120+
if err := docker.PushImage(pushOpts); err != nil {
121+
pterm.Error.Println("Push failed:", err)
122+
return err
123+
}
124+
pterm.Success.Println("Push completed successfully.")
125+
} else {
126+
pterm.Info.Println("Image push skipped.")
127+
}
128+
}
129+
130+
if provisionDeleteAfterPush {
131+
pterm.Info.Printf("Deleting local image %s...\n", fullImageName)
132+
if err := docker.RemoveImage(fullImageName); err != nil {
133+
pterm.Error.Println("Failed to delete local image:", err)
134+
return err
135+
}
136+
pterm.Success.Println("Successfully deleted local image:", fullImageName)
137+
}
138+
139+
pterm.Success.Println("Provisioning completed successfully.")
140+
return nil
141+
},
142+
}
143+
144+
func init() {
145+
provisionHubCmd.Flags().StringVarP(&provisionImageName, "image-name", "i", "", "Name of the image to build")
146+
provisionHubCmd.Flags().StringVarP(&provisionImageTag, "tag", "t", "latest", "Tag for the image")
147+
provisionHubCmd.Flags().StringVarP(&provisionDockerfilePath, "file", "f", "Dockerfile", "Name of the Dockerfile (default is 'Dockerfile')")
148+
provisionHubCmd.Flags().BoolVar(&provisionNoCache, "no-cache", false, "Do not use cache when building the image")
149+
provisionHubCmd.Flags().StringArrayVar(&provisionBuildArgs, "build-arg", []string{}, "Set build-time variables")
150+
provisionHubCmd.Flags().StringVar(&provisionTarget, "target", "", "Set the target build stage to build")
151+
provisionHubCmd.Flags().StringVarP(&provisionSarifFile, "output", "o", "", "Output file for SARIF report")
152+
provisionHubCmd.Flags().StringVar(&provisionTargetTag, "target-tag", "", "Target tag for tagging the image")
153+
provisionHubCmd.Flags().BoolVarP(&provisionConfirmPush, "yes", "y", false, "Push the image without confirmation")
154+
provisionHubCmd.Flags().BoolVarP(&provisionDeleteAfterPush, "delete", "d", false, "Delete the local image after pushing")
155+
provisionHubCmd.Flags().StringVar(&provisionPlatform, "platform", "", "Set the platform for the image")
156+
157+
provisionHubCmd.MarkFlagRequired("image-name")
158+
159+
sdkrCmd.AddCommand(provisionHubCmd)
160+
}

‎cmd/docker/push.go

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package docker
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
10+
var pushCmd = &cobra.Command{
11+
Use: "push",
12+
Short: "Push cmd helps to push images to Docker Hub, ACR, GCR, ECR",
13+
RunE: func(cmd *cobra.Command, args []string) error {
14+
fmt.Println("Use 'smurf sdkr push [command]' to push images to Docker Hub, ACR, GCR, ECR ")
15+
return nil
16+
},
17+
}
18+
19+
func init() {
20+
21+
sdkrCmd.AddCommand(pushCmd)
22+
}

‎cmd/docker/pushACR.go

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package docker
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/clouddrove/smurf/internal/docker"
7+
"github.com/pterm/pterm"
8+
"github.com/spf13/cobra"
9+
)
10+
11+
var (
12+
acrSubscriptionID string
13+
acrResourceGroup string
14+
acrRegistryName string
15+
acrImageName string
16+
acrImageTag string
17+
acrDeleteAfterPush bool
18+
)
19+
20+
var pushAcrCmd = &cobra.Command{
21+
Use: "az",
22+
Short: "push docker images to acr",
23+
RunE: func(cmd *cobra.Command, args []string) error {
24+
if acrSubscriptionID == "" || acrResourceGroup == "" || acrRegistryName == "" {
25+
return fmt.Errorf("azure requires --subscription-id, --resource-group, and --registry-name flags")
26+
}
27+
28+
acrImage := fmt.Sprintf("%s.azurecr.io/%s:%s", acrRegistryName, acrImageName, acrImageTag)
29+
30+
pterm.Info.Println("Pushing image to Azure Container Registry...")
31+
if err := docker.PushImageToACR(acrSubscriptionID, acrResourceGroup, acrRegistryName, acrImageName); err != nil {
32+
return err
33+
}
34+
pterm.Success.Println("Successfully pushed image to ACR:", acrImage)
35+
36+
if acrDeleteAfterPush {
37+
if err := docker.RemoveImage(acrImageName); err != nil {
38+
return err
39+
}
40+
pterm.Success.Println("Successfully deleted local image:", acrImageName)
41+
}
42+
43+
return nil
44+
},
45+
}
46+
47+
func init() {
48+
pushAcrCmd.Flags().StringVarP(&acrImageName, "image", "i", "", "Image name (e.g., myapp)")
49+
pushAcrCmd.Flags().StringVarP(&acrImageTag, "tag", "t", "latest", "Image tag (default: latest)")
50+
pushAcrCmd.Flags().BoolVarP(&acrDeleteAfterPush, "delete", "d", false, "Delete the local image after pushing")
51+
52+
pushAcrCmd.Flags().StringVar(&acrSubscriptionID, "subscription-id", "", "Azure subscription ID (required with --azure)")
53+
pushAcrCmd.Flags().StringVar(&acrResourceGroup, "resource-group", "", "Azure resource group name (required with --azure)")
54+
pushAcrCmd.Flags().StringVar(&acrRegistryName, "registry-name", "", "Azure Container Registry name (required with --azure)")
55+
56+
pushAcrCmd.MarkFlagRequired("subscription-id")
57+
pushAcrCmd.MarkFlagRequired("resource-group")
58+
pushAcrCmd.MarkFlagRequired("registry-name")
59+
pushAcrCmd.MarkFlagRequired("image")
60+
61+
pushCmd.AddCommand(pushAcrCmd)
62+
}

‎cmd/docker/pushECR.go

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package docker
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/clouddrove/smurf/internal/docker"
7+
"github.com/pterm/pterm"
8+
"github.com/spf13/cobra"
9+
)
10+
11+
var (
12+
ecrImageName string
13+
ecrRepositoryName string
14+
ecrRegionName string
15+
ecrImageTag string
16+
ecrDeleteAfterPush bool
17+
)
18+
19+
var pushEcrCmd = &cobra.Command{
20+
Use: "aws",
21+
Short: "push Docker images to ECR",
22+
RunE: func(cmd *cobra.Command, args []string) error {
23+
if ecrRegionName == "" || ecrRepositoryName == "" {
24+
return fmt.Errorf("aws requires both --region and --repository flags")
25+
}
26+
27+
ecrImage := fmt.Sprintf("%s.dkr.ecr.%s.amazonaws.com/%s:%s", ecrImageName, ecrRegionName, ecrRepositoryName, ecrImageTag)
28+
pterm.Info.Println("Pushing image to AWS ECR...")
29+
if err := docker.PushImageToECR(ecrImageName, ecrRegionName, ecrRepositoryName); err != nil {
30+
return err
31+
}
32+
pterm.Success.Println("Successfully pushed image to ECR:", ecrImage)
33+
34+
if ecrDeleteAfterPush {
35+
if err := docker.RemoveImage(ecrImageName); err != nil {
36+
return err
37+
}
38+
pterm.Success.Println("Successfully deleted local image:", ecrImageName)
39+
}
40+
return nil
41+
},
42+
}
43+
44+
func init() {
45+
pushEcrCmd.Flags().StringVarP(&ecrImageName, "image", "i", "", "Image name (e.g., myapp)")
46+
pushEcrCmd.Flags().StringVarP(&ecrImageTag, "tag", "t", "latest", "Image tag (default: latest)")
47+
pushEcrCmd.Flags().BoolVarP(&ecrDeleteAfterPush, "delete", "d", false, "Delete the local image after pushing")
48+
49+
pushEcrCmd.Flags().StringVarP(&ecrRegionName, "region", "r", "", "AWS region (required with --aws)")
50+
pushEcrCmd.Flags().StringVarP(&ecrRepositoryName, "repository", "R", "", "AWS ECR repository name (required with --aws)")
51+
52+
pushEcrCmd.MarkFlagRequired("region")
53+
pushEcrCmd.MarkFlagRequired("repository")
54+
pushEcrCmd.MarkFlagRequired("image")
55+
56+
pushCmd.AddCommand(pushEcrCmd)
57+
}

‎cmd/docker/pushGCR.go

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package docker
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/clouddrove/smurf/internal/docker"
7+
"github.com/pterm/pterm"
8+
"github.com/spf13/cobra"
9+
)
10+
11+
var (
12+
gcrProjectID string
13+
gcrImageName string
14+
gcrImageTag string
15+
gcrDeleteAfterPush bool
16+
)
17+
18+
var pushGcrCmd = &cobra.Command{
19+
Use: "gcp",
20+
Short: "push Docker images to GCR",
21+
Long: `push Docker images to Google Container Registry
22+
Set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your service account JSON key file.
23+
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/service-account-key.json"`,
24+
RunE: func(cmd *cobra.Command, args []string) error {
25+
if gcrProjectID == "" {
26+
return fmt.Errorf("gcp requires --project-id flag")
27+
}
28+
29+
gcrImage := fmt.Sprintf("gcr.io/%s/%s:%s", gcrProjectID, gcrImageName, gcrImageTag)
30+
31+
pterm.Info.Println("Pushing image to Google Container Registry...")
32+
if err := docker.PushImageToGCR(gcrProjectID, gcrImageName); err != nil {
33+
return err
34+
}
35+
pterm.Success.Println("Successfully pushed image to GCR:", gcrImage)
36+
37+
if gcrDeleteAfterPush {
38+
if err := docker.RemoveImage(gcrImageName); err != nil {
39+
return err
40+
}
41+
pterm.Success.Println("Successfully deleted local image:", gcrImageName)
42+
}
43+
44+
return nil
45+
},
46+
}
47+
48+
func init() {
49+
pushGcrCmd.Flags().StringVarP(&gcrImageName, "image", "i", "", "Image name (e.g., myapp)")
50+
pushGcrCmd.Flags().StringVarP(&gcrImageTag, "tag", "t", "latest", "Image tag (default: latest)")
51+
pushGcrCmd.Flags().BoolVarP(&gcrDeleteAfterPush, "delete", "d", false, "Delete the local image after pushing")
52+
53+
pushGcrCmd.Flags().StringVar(&gcrProjectID, "project-id", "", "GCP project ID (required with --gcp)")
54+
55+
pushGcrCmd.MarkFlagRequired("project-id")
56+
pushGcrCmd.MarkFlagRequired("image")
57+
58+
pushCmd.AddCommand(pushGcrCmd)
59+
}

‎cmd/docker/pushHub.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package docker
2+
3+
import (
4+
"github.com/clouddrove/smurf/internal/docker"
5+
"github.com/pterm/pterm"
6+
"github.com/spf13/cobra"
7+
)
8+
9+
var (
10+
hubImageName string
11+
hubImageTag string
12+
hubDeleteAfterPush bool
13+
)
14+
15+
var pushHubCmd = &cobra.Command{
16+
Use: "hub",
17+
Short: "push Docker images to Docker Hub",
18+
RunE: func(cmd *cobra.Command, args []string) error {
19+
opts := docker.PushOptions{
20+
ImageName: hubImageName,
21+
}
22+
if err := docker.PushImage(opts); err != nil {
23+
return err
24+
}
25+
if hubDeleteAfterPush {
26+
if err := docker.RemoveImage(hubImageName); err != nil {
27+
return err
28+
}
29+
pterm.Success.Println("Successfully deleted local image:", hubImageName)
30+
}
31+
return nil
32+
},
33+
}
34+
35+
func init() {
36+
pushHubCmd.Flags().StringVarP(&hubImageName, "image", "i", "", "Image name (e.g., myapp)")
37+
pushHubCmd.Flags().StringVarP(&hubImageTag, "tag", "t", "latest", "Image tag (default: latest)")
38+
pushHubCmd.Flags().BoolVarP(&hubDeleteAfterPush, "delete", "d", false, "Delete the local image after pushing")
39+
40+
pushHubCmd.MarkFlagRequired("image")
41+
42+
pushCmd.AddCommand(pushHubCmd)
43+
}

‎cmd/docker/remove.go

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package docker
2+
3+
import (
4+
"github.com/clouddrove/smurf/internal/docker"
5+
"github.com/pterm/pterm"
6+
"github.com/spf13/cobra"
7+
)
8+
9+
var imageTag string
10+
var local bool
11+
var hub bool
12+
13+
var remove = &cobra.Command{
14+
Use: "remove",
15+
Short: "Remove Docker images",
16+
RunE: func(cmd *cobra.Command, args []string) error {
17+
18+
err := docker.RemoveImage(imageTag)
19+
if err != nil {
20+
pterm.Error.Println(err)
21+
return err
22+
}
23+
pterm.Success.Println("Image removal completed successfully.")
24+
return nil
25+
},
26+
}
27+
28+
func init() {
29+
remove.Flags().StringVarP(&imageTag, "tag", "t", "", "Docker image tag to remove")
30+
remove.MarkFlagRequired("tag")
31+
32+
sdkrCmd.AddCommand(remove)
33+
}

‎cmd/docker/scan.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package docker
2+
3+
import (
4+
"github.com/clouddrove/smurf/internal/docker"
5+
"github.com/pterm/pterm"
6+
"github.com/spf13/cobra"
7+
)
8+
9+
var dockerTag string
10+
var sarifFile string
11+
12+
var scan = &cobra.Command{
13+
Use: "scan",
14+
Short: "Scan Docker images for known vulnerabilities",
15+
RunE: func(cmd *cobra.Command, args []string) error {
16+
err := docker.Scout(dockerTag, sarifFile)
17+
if err != nil {
18+
pterm.Error.Println(err)
19+
return err
20+
}
21+
return nil
22+
},
23+
}
24+
25+
func init() {
26+
scan.Flags().StringVarP(&dockerTag, "tag", "t", "", "Docker image tag to scan")
27+
scan.Flags().StringVarP(&sarifFile, "output", "o", "", "Output file for SARIF report")
28+
scan.MarkFlagRequired("tag")
29+
30+
sdkrCmd.AddCommand(scan)
31+
}

‎cmd/docker/sdkr.go

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package docker
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/clouddrove/smurf/cmd"
7+
"github.com/spf13/cobra"
8+
)
9+
10+
// sdkrCmd represents the 'sdkr' subcommand command
11+
var sdkrCmd = &cobra.Command{
12+
Use: "sdkr",
13+
Short: "Subcommand for Docker-related actions",
14+
Long: `sdkr is a subcommand that groups various Docker-related actions under a single command.`,
15+
Run: func(cmd *cobra.Command, args []string) {
16+
fmt.Println("Use 'smurf sdkr [command]' to run Docker-related actions")
17+
},
18+
}
19+
20+
func init() {
21+
cmd.RootCmd.AddCommand(sdkrCmd)
22+
}

‎cmd/docker/tag.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package docker
2+
3+
import (
4+
"github.com/clouddrove/smurf/internal/docker"
5+
"github.com/spf13/cobra"
6+
)
7+
8+
var sourceTag string
9+
var targetTag string
10+
11+
var tagCmd = &cobra.Command{
12+
Use: "tag",
13+
Short: "Tag a Docker image for a remote repository",
14+
RunE: func(cmd *cobra.Command, args []string) error {
15+
opts := docker.TagOptions{
16+
Source: sourceTag,
17+
Target: targetTag,
18+
}
19+
return docker.TagImage(opts)
20+
},
21+
}
22+
23+
func init() {
24+
tagCmd.Flags().StringVarP(&sourceTag, "source", "s", "", "Source image tag (format: image:tag)")
25+
tagCmd.Flags().StringVarP(&targetTag, "target", "t", "", "Target image tag (format: repository/image:tag)")
26+
tagCmd.MarkFlagRequired("source")
27+
tagCmd.MarkFlagRequired("target")
28+
29+
sdkrCmd.AddCommand(tagCmd)
30+
}

‎docs/sm/docs/index.md

+39-38
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,24 @@
3434
</p>
3535

3636
Smurf is a command-line interface built with Cobra, designed to simplify and automate commands for essential tools like Terraform and Docker. It provides intuitive, unified commands to execute Terraform plans, Docker container management, and other DevOps tasks seamlessly from one interface. Whether you need to spin up environments, manage containers, or apply infrastructure as code, this CLI streamlines multi-tool operations, boosting productivity and reducing context-switching.
37-
3837
## Features
3938

40-
- **Terraform Command Wrapper:** Run `init`, `plan`, `apply`, `output` , `drift` commands and `provision` , which is a wrapper of init, drift, plan, apply, output.
41-
- **Git Integration:** (yet to come)
42-
- **Docker Integration:**(yet to come)
43-
- **Helm Integration:**(yet to come)
39+
- **Terraform Command Wrapper (stf):** Run `init`, `plan`, `apply`, `output`, `drift`, `validate`, `destroy`, `format` commands, and `provision`, a combined operation of `init`, `validate`, and `apply`.
40+
- **Helm Command Wrapper (selm):** Run `create`, `install`, `lint`, `list`, `status`, `template`, `upgrade`, `uninstall` commands, and `provision`, a combination of `install`, `upgrade`, `lint`, and `template`.
41+
- **Docker Command Wrapper (sdkr):** Run `build`, `scan`, `tag`, `publish`, `push` commands, and `provision`, a combination of `build`, `scan`, and `publish`.
42+
- **Multicloud Container registry :** Push images from multiple cloud registries like AWS ECR, GCP GCR, Azure ACR, and Docker Hub.Run `smurf sdkr push --help` to push images from the specified registry.
43+
- **Git Integration:** *(Yet to come)*
44+
- **Unified CLI Interface:** Manage multi-tool operations from one interface, reducing the need for multiple command sets.
4445

4546
## Installation
4647

4748
### Prerequisites
4849

4950
- Go 1.20 or higher
5051
- Git
51-
- Terraform installed and available in your PATH
52+
- Terraform, Helm, and Docker Daemon installed and accessible via your PATH
5253

53-
### Steps
54+
### Installation Steps
5455

5556
1. **Clone the repository:**
5657

@@ -64,55 +65,55 @@ Smurf is a command-line interface built with Cobra, designed to simplify and aut
6465
cd smurf
6566
```
6667

67-
3. **Build and install the tool:**
68+
3. **Build the tool:**
6869

6970
```bash
70-
go build .
71+
go build -o smurf .
7172
```
7273

73-
This will build `smurf` to your project directory.
74+
This will build `smurf` in your project directory.
7475

7576
## Usage
7677

77-
Navigate to your Terraform project directory and use `smurf` commands as follows:
78-
79-
### Initialize Terraform
80-
81-
```bash
82-
./smurf init
83-
```
84-
85-
This initializes your Terraform working directory.
86-
87-
### Generate and Show an Execution Plan for Terraform
78+
### Terraform Commands
8879

89-
```bash
90-
./smurf plan
91-
```
80+
Use `smurf stf <command>` to run Terraform commands. Supported commands include:
9281

93-
Generates an execution plan and shows what actions Terraform will take.
82+
- **Help:** `smurf stf --help`
83+
- **Initialize Terraform:** `smurf stf init`
84+
- **Generate and Show Execution Plan:** `smurf stf plan`
85+
- **Apply Terraform Changes:** `smurf stf apply`
86+
- **Detect Drift in Terraform State:** `smurf stf drift`
87+
- **Provision Terraform Environment:** `smurf stf provision`
9488

95-
### Apply Terraform Changes
89+
The `provision` command for Terraform performs `init`, `validate`, and `apply`.
9690

97-
```bash
98-
./smurf apply
99-
```
91+
### Helm Commands
10092

101-
Applies the changes required to reach the desired state of the configuration.
93+
Use `smurf selm <command>` to run Helm commands. Supported commands include:
10294

103-
### Detect Drift in Terraform State
95+
- **Help:** `smurf selm --help`
96+
- **Create a Helm Chart:** `smurf selm create`
97+
- **Install a Chart:** `smurf selm install`
98+
- **Upgrade a Release:** `smurf selm upgrade`
99+
- **Provision Helm Environment:** `smurf selm provision --help`
104100

105-
```bash
106-
./smurf drift
107-
```
101+
The `provision` command for Helm combines `install`, `upgrade`, `lint`, and `template`.
108102

109-
Detects any drift between your Terraform state and the actual infrastructure.
103+
### Docker Commands
110104

111-
## Important Notes
105+
Use `smurf sdkr <command> <flags>` to run Docker commands. Supported commands include:
112106

113-
- **Uncommitted Changes:** `smurf` will check for uncommitted changes in your `.tf` files. If any are detected, it will prompt you to commit or discard them before proceeding. This ensures that only committed changes are applied, maintaining consistency and traceability.
107+
- **Help:** `smurf sdkr --help`
108+
- **Build an Image:** `smurf sdkr build`
109+
- **Scan an Image:** `smurf sdkr scan`
110+
- **Push an Image:** `smurf sdkr push --help`
111+
- **Provision Registry Environment:** `smurf sdkr provision-hub [flags] `(for Docker Hub)
114112

115-
- **Git Integration:** Make sure your project is initialized as a Git repository (`git init`) and that your `.tf` files are tracked.
113+
The `provision-hub` command for Docker combines `build`, `scan`, and `publish`.
114+
The `provision-ecr` command for Docker combines `build`, `scan`, and `publish` for AWS ECR.
115+
THE `provision-gcr` command for Docker combines `build`, `scan`, and `publish` for GCP GCR.
116+
THE `provision-acr` command for Docker combines `build`, `scan`, and `publish` for Azure ACR.
116117

117118

118119

‎go.mod

+61-32
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@ module github.com/clouddrove/smurf
33
go 1.23.2
44

55
require (
6+
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0
7+
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerregistry/armcontainerregistry v1.2.0
8+
github.com/aws/aws-sdk-go v1.55.5
9+
github.com/docker/docker v27.3.1+incompatible
610
github.com/fatih/color v1.18.0
711
github.com/hashicorp/terraform-exec v0.21.0
812
github.com/pterm/pterm v0.12.79
913
github.com/spf13/cobra v1.8.1
10-
helm.sh/helm/v3 v3.16.3
14+
golang.org/x/oauth2 v0.24.0
15+
helm.sh/helm/v3 v3.16.2
1116
k8s.io/api v0.31.2
1217
k8s.io/apimachinery v0.31.2
1318
k8s.io/client-go v0.31.2
@@ -17,72 +22,88 @@ require (
1722
atomicgo.dev/cursor v0.2.0 // indirect
1823
atomicgo.dev/keyboard v0.2.9 // indirect
1924
atomicgo.dev/schedule v0.1.0 // indirect
25+
cloud.google.com/go/compute/metadata v0.5.2 // indirect
2026
dario.cat/mergo v1.0.1 // indirect
2127
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
22-
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
23-
github.com/BurntSushi/toml v1.3.2 // indirect
28+
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 // indirect
29+
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
30+
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
31+
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
32+
github.com/BurntSushi/toml v1.4.0 // indirect
2433
github.com/MakeNowJust/heredoc v1.0.0 // indirect
2534
github.com/Masterminds/goutils v1.1.1 // indirect
2635
github.com/Masterminds/semver/v3 v3.3.0 // indirect
2736
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
2837
github.com/Masterminds/squirrel v1.5.4 // indirect
38+
github.com/Microsoft/go-winio v0.6.2 // indirect
39+
github.com/Microsoft/hcsshim v0.12.5 // indirect
2940
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
3041
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
3142
github.com/beorn7/perks v1.0.1 // indirect
3243
github.com/blang/semver/v4 v4.0.0 // indirect
3344
github.com/cespare/xxhash/v2 v2.3.0 // indirect
3445
github.com/chai2010/gettext-go v1.0.2 // indirect
35-
github.com/containerd/console v1.0.3 // indirect
46+
github.com/cloudflare/circl v1.3.8 // indirect
47+
github.com/containerd/console v1.0.4 // indirect
3648
github.com/containerd/containerd v1.7.23 // indirect
49+
github.com/containerd/continuity v0.4.4 // indirect
3750
github.com/containerd/errdefs v0.3.0 // indirect
3851
github.com/containerd/log v0.1.0 // indirect
3952
github.com/containerd/platforms v0.2.1 // indirect
53+
github.com/creack/pty v1.1.21 // indirect
4054
github.com/cyphar/filepath-securejoin v0.3.4 // indirect
4155
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
4256
github.com/distribution/reference v0.6.0 // indirect
43-
github.com/docker/cli v25.0.1+incompatible // indirect
57+
github.com/docker/cli v27.3.1+incompatible // indirect
4458
github.com/docker/distribution v2.8.3+incompatible // indirect
45-
github.com/docker/docker v25.0.6+incompatible // indirect
46-
github.com/docker/docker-credential-helpers v0.7.0 // indirect
59+
github.com/docker/docker-credential-helpers v0.8.2 // indirect
4760
github.com/docker/go-connections v0.5.0 // indirect
4861
github.com/docker/go-metrics v0.0.1 // indirect
62+
github.com/docker/go-units v0.5.0 // indirect
63+
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
4964
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
5065
github.com/evanphx/json-patch v5.9.0+incompatible // indirect
5166
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
5267
github.com/felixge/httpsnoop v1.0.4 // indirect
5368
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
5469
github.com/go-errors/errors v1.4.2 // indirect
70+
github.com/go-git/go-billy/v5 v5.6.0 // indirect
5571
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
5672
github.com/go-logr/logr v1.4.2 // indirect
5773
github.com/go-logr/stdr v1.2.2 // indirect
58-
github.com/go-openapi/jsonpointer v0.19.6 // indirect
59-
github.com/go-openapi/jsonreference v0.20.2 // indirect
60-
github.com/go-openapi/swag v0.22.4 // indirect
74+
github.com/go-openapi/jsonpointer v0.21.0 // indirect
75+
github.com/go-openapi/jsonreference v0.21.0 // indirect
76+
github.com/go-openapi/swag v0.23.0 // indirect
6177
github.com/gobwas/glob v0.2.3 // indirect
6278
github.com/gogo/protobuf v1.3.2 // indirect
79+
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
6380
github.com/golang/protobuf v1.5.4 // indirect
64-
github.com/google/btree v1.0.1 // indirect
65-
github.com/google/gnostic-models v0.6.8 // indirect
81+
github.com/google/btree v1.1.2 // indirect
82+
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
6683
github.com/google/go-cmp v0.6.0 // indirect
6784
github.com/google/gofuzz v1.2.0 // indirect
6885
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
6986
github.com/google/uuid v1.6.0 // indirect
7087
github.com/gookit/color v1.5.4 // indirect
71-
github.com/gorilla/mux v1.8.0 // indirect
88+
github.com/gorilla/mux v1.8.1 // indirect
7289
github.com/gorilla/websocket v1.5.0 // indirect
7390
github.com/gosuri/uitable v0.0.4 // indirect
74-
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
91+
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
7592
github.com/hashicorp/errwrap v1.1.0 // indirect
7693
github.com/hashicorp/go-multierror v1.1.1 // indirect
77-
github.com/hashicorp/go-version v1.6.0 // indirect
94+
github.com/hashicorp/go-version v1.7.0 // indirect
95+
github.com/hashicorp/golang-lru v0.6.0 // indirect
96+
github.com/hashicorp/hc-install v0.9.0 // indirect
7897
github.com/hashicorp/terraform-json v0.22.1 // indirect
7998
github.com/huandu/xstrings v1.5.0 // indirect
8099
github.com/imdario/mergo v0.3.16 // indirect
81100
github.com/inconshreveable/mousetrap v1.1.0 // indirect
101+
github.com/jmespath/go-jmespath v0.4.0 // indirect
82102
github.com/jmoiron/sqlx v1.4.0 // indirect
83103
github.com/josharian/intern v1.0.0 // indirect
84104
github.com/json-iterator/go v1.1.12 // indirect
85-
github.com/klauspost/compress v1.16.7 // indirect
105+
github.com/klauspost/compress v1.17.11 // indirect
106+
github.com/kylelemons/godebug v1.1.0 // indirect
86107
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
87108
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
88109
github.com/lib/pq v1.10.9 // indirect
@@ -91,67 +112,75 @@ require (
91112
github.com/mailru/easyjson v0.7.7 // indirect
92113
github.com/mattn/go-colorable v0.1.13 // indirect
93114
github.com/mattn/go-isatty v0.0.20 // indirect
94-
github.com/mattn/go-runewidth v0.0.15 // indirect
115+
github.com/mattn/go-runewidth v0.0.16 // indirect
95116
github.com/mitchellh/copystructure v1.2.0 // indirect
96117
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
97118
github.com/mitchellh/reflectwalk v1.0.2 // indirect
119+
github.com/moby/docker-image-spec v1.3.1 // indirect
98120
github.com/moby/locker v1.0.1 // indirect
99121
github.com/moby/spdystream v0.4.0 // indirect
122+
github.com/moby/sys/mountinfo v0.7.2 // indirect
100123
github.com/moby/term v0.5.0 // indirect
101124
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
102125
github.com/modern-go/reflect2 v1.0.2 // indirect
103126
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
127+
github.com/morikuni/aec v1.0.0 // indirect
104128
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
105129
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
130+
github.com/onsi/gomega v1.34.1 // indirect
106131
github.com/opencontainers/go-digest v1.0.0 // indirect
107132
github.com/opencontainers/image-spec v1.1.0 // indirect
108133
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
134+
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
109135
github.com/pkg/errors v0.9.1 // indirect
110-
github.com/prometheus/client_golang v1.19.1 // indirect
136+
github.com/prometheus/client_golang v1.20.2 // indirect
111137
github.com/prometheus/client_model v0.6.1 // indirect
112138
github.com/prometheus/common v0.55.0 // indirect
113139
github.com/prometheus/procfs v0.15.1 // indirect
114-
github.com/rivo/uniseg v0.4.4 // indirect
140+
github.com/rivo/uniseg v0.4.7 // indirect
115141
github.com/rubenv/sql-migrate v1.7.0 // indirect
116142
github.com/russross/blackfriday/v2 v2.1.0 // indirect
117143
github.com/shopspring/decimal v1.4.0 // indirect
118144
github.com/sirupsen/logrus v1.9.3 // indirect
119145
github.com/spf13/cast v1.7.0 // indirect
120146
github.com/spf13/pflag v1.0.5 // indirect
147+
github.com/stretchr/objx v0.5.2 // indirect
121148
github.com/x448/float16 v0.8.4 // indirect
122149
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
123150
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
124151
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
125152
github.com/xlab/treeprint v1.2.0 // indirect
126153
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
127-
github.com/zclconf/go-cty v1.14.4 // indirect
154+
github.com/zclconf/go-cty v1.15.0 // indirect
128155
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
129156
go.opentelemetry.io/otel v1.28.0 // indirect
157+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 // indirect
130158
go.opentelemetry.io/otel/metric v1.28.0 // indirect
131159
go.opentelemetry.io/otel/trace v1.28.0 // indirect
132160
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
133-
golang.org/x/crypto v0.27.0 // indirect
134-
golang.org/x/net v0.26.0 // indirect
135-
golang.org/x/oauth2 v0.21.0 // indirect
161+
golang.org/x/crypto v0.28.0 // indirect
162+
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
163+
golang.org/x/net v0.30.0 // indirect
136164
golang.org/x/sync v0.8.0 // indirect
137-
golang.org/x/sys v0.25.0 // indirect
138-
golang.org/x/term v0.24.0 // indirect
139-
golang.org/x/text v0.18.0 // indirect
140-
golang.org/x/time v0.3.0 // indirect
165+
golang.org/x/sys v0.26.0 // indirect
166+
golang.org/x/term v0.25.0 // indirect
167+
golang.org/x/text v0.19.0 // indirect
168+
golang.org/x/time v0.6.0 // indirect
169+
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect
141170
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
142-
google.golang.org/grpc v1.65.0 // indirect
143-
google.golang.org/protobuf v1.34.2 // indirect
171+
google.golang.org/grpc v1.66.2 // indirect
172+
google.golang.org/protobuf v1.35.1 // indirect
144173
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
145174
gopkg.in/inf.v0 v0.9.1 // indirect
146175
gopkg.in/yaml.v2 v2.4.0 // indirect
147176
gopkg.in/yaml.v3 v3.0.1 // indirect
148177
k8s.io/apiextensions-apiserver v0.31.1 // indirect
149178
k8s.io/apiserver v0.31.1 // indirect
150-
k8s.io/cli-runtime v0.31.1 // indirect
151-
k8s.io/component-base v0.31.1 // indirect
179+
k8s.io/cli-runtime v0.31.2 // indirect
180+
k8s.io/component-base v0.31.2 // indirect
152181
k8s.io/klog/v2 v2.130.1 // indirect
153182
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
154-
k8s.io/kubectl v0.31.1 // indirect
183+
k8s.io/kubectl v0.31.2 // indirect
155184
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
156185
oras.land/oras-go v1.2.5 // indirect
157186
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect

‎go.sum

+156-99
Large diffs are not rendered by default.

‎internal/docker/docker.go

+682
Large diffs are not rendered by default.

‎main.go

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/clouddrove/smurf/cmd"
88
_ "github.com/clouddrove/smurf/cmd/terraform"
99
_ "github.com/clouddrove/smurf/cmd/helm"
10+
_ "github.com/clouddrove/smurf/cmd/docker"
1011
)
1112

1213
func main() {

0 commit comments

Comments
 (0)
Please sign in to comment.