Skip to content

Commit

Permalink
push reset to git reset --soft 15bad9a
Browse files Browse the repository at this point in the history
  • Loading branch information
haitham911 committed Jan 20, 2025
1 parent 15bad9a commit 063f955
Show file tree
Hide file tree
Showing 14 changed files with 408 additions and 9 deletions.
40 changes: 40 additions & 0 deletions examples/tests/test-vendor/atmos.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
base_path: "./"

components:
terraform:
base_path: "components/terraform"
apply_auto_approve: false
deploy_run_init: true
init_run_reconfigure: true
auto_generate_backend_file: false

stacks:
base_path: "stacks"
included_paths:
- "deploy/**/*"
excluded_paths:
- "**/_defaults.yaml"
name_pattern: "{stage}"

vendor:
# Single file
base_path: "./vendor.yaml"

# Directory with multiple files
#base_path: "./vendor"

# Absolute path
#base_path: "vendor.d/vendor1.yaml"

logs:
file: "/dev/stderr"
level: Info

# Custom CLI commands

# No arguments or flags are required
commands:
- name: "test"
description: "Run all tests"
steps:
- atmos vendor pull --everything
13 changes: 13 additions & 0 deletions examples/tests/test-vendor/test-components/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Example Terraform IPinfo Component

This Terraform module retrieves data from the IPinfo API for a specified IP address. If no IP address is specified, it retrieves data for the requester's IP address.

## Usage

### Inputs

- `ip_address` (optional): The IP address to retrieve information for. If not specified, the requester's IP address will be used. The default value is an empty string.

### Outputs

- `metadata`: The data retrieved from IPinfo for the specified IP address, in JSON format.
7 changes: 7 additions & 0 deletions examples/tests/test-vendor/test-components/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
data "http" "ipinfo" {
url = var.ip_address != "" ? "https://ipinfo.io/${var.ip_address}" : "https://ipinfo.io"

request_headers = {
Accept = "application/json"
}
}
4 changes: 4 additions & 0 deletions examples/tests/test-vendor/test-components/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output "metadata" {
description = "The data retrieved from IPinfo for the specified IP address"
value = jsondecode(data.http.ipinfo.response_body)
}
1 change: 1 addition & 0 deletions examples/tests/test-vendor/test-components/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
provider "http" {}
5 changes: 5 additions & 0 deletions examples/tests/test-vendor/test-components/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
variable "ip_address" {
description = "The IP address to retrieve information for (optional)"
type = string
default = ""
}
5 changes: 5 additions & 0 deletions examples/tests/test-vendor/test-components/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
terraform {
required_version = ">= 1.0.0"

required_providers {}
}
43 changes: 43 additions & 0 deletions examples/tests/test-vendor/vendor.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
apiVersion: atmos/v1
kind: AtmosVendorConfig
metadata:
name: demo-vendoring
description: Atmos vendoring manifest for Atmos demo component library
spec:
# Import other vendor manifests, if necessary
imports: []

sources:
- component: "github/stargazers"
source: "github.com/cloudposse/atmos.git//examples/demo-library/{{ .Component }}?ref={{.Version}}"
version: "main"
targets:
- "components/terraform/{{ .Component }}/{{.Version}}"
included_paths:
- "**/*.tf"
- "**/*.tfvars"
- "**/*.md"
tags:
- demo
- github

- component: "test-components"
source: "file:///./test-components"
version: "main"
targets:
- "components/terraform/{{ .Component }}/{{.Version}}"
tags:
- demo

- component: "weather"
source: "git::https://github.com/cloudposse/atmos.git//examples/demo-library/{{ .Component }}?ref={{.Version}}"
version: "main"
targets:
- "components/terraform/{{ .Component }}/{{.Version}}"
tags:
- demo
- component: "my-vpc1"
source: "oci://public.ecr.aws/cloudposse/components/terraform/stable/aws/vpc:{{.Version}}"
version: "latest"
targets:
- "components/terraform/infra/my-vpc1"
9 changes: 9 additions & 0 deletions internal/exec/vendor_component_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
"net/url"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -248,6 +249,14 @@ func ExecuteComponentVendorInternal(
sourceIsLocalFile = true
}
}
u, err := url.Parse(uri)
if err == nil && u.Scheme != "" {
if u.Scheme == "file" {
trimmedPath := strings.TrimPrefix(filepath.ToSlash(u.Path), "/")
uri = filepath.Clean(trimmedPath)
useLocalFileSystem = true
}
}
}

var pType pkgType
Expand Down
2 changes: 1 addition & 1 deletion internal/exec/vendor_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ func downloadAndInstall(p *pkgAtmosVendor, dryRun bool, atmosConfig schema.Atmos
}
}
// Create temp directory
tempDir, err := os.MkdirTemp("", fmt.Sprintf("atmos-vendor-%d-*", time.Now().Unix()))
tempDir, err := os.MkdirTemp("", "atmos-vendor")
if err != nil {
return installedPkgMsg{
err: fmt.Errorf("failed to create temp directory: %w", err),
Expand Down
127 changes: 125 additions & 2 deletions internal/exec/vendor_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package exec

import (
"fmt"
"net/url"
"os"
"path/filepath"
"sort"
"strings"

"github.com/bmatcuk/doublestar/v4"
tea "github.com/charmbracelet/bubbletea"
"github.com/hashicorp/go-getter"
cp "github.com/otiai10/copy"
"github.com/samber/lo"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -384,7 +386,7 @@ func ExecuteAtmosVendorInternal(
if err != nil {
return err
}
targetPath := filepath.Join(vendorConfigFilePath, target)
targetPath := filepath.Join(filepath.ToSlash(vendorConfigFilePath), filepath.ToSlash(target))
pkgName := s.Component
if pkgName == "" {
pkgName = uri
Expand Down Expand Up @@ -514,12 +516,22 @@ func determineSourceType(uri *string, vendorConfigFilePath string) (bool, bool,
useLocalFileSystem := false
sourceIsLocalFile := false
if !useOciScheme {
if absPath, err := u.JoinAbsolutePathWithPath(vendorConfigFilePath, *uri); err == nil {
if absPath, err := u.JoinAbsolutePathWithPath(filepath.ToSlash(vendorConfigFilePath), *uri); err == nil {
uri = &absPath
useLocalFileSystem = true
sourceIsLocalFile = u.FileExists(*uri)
}
u, err := url.Parse(*uri)
if err == nil && u.Scheme != "" {
if u.Scheme == "file" {
trimmedPath := strings.TrimPrefix(filepath.ToSlash(u.Path), "/")
*uri = filepath.Clean(trimmedPath)
useLocalFileSystem = true
}
}

}

return useOciScheme, useLocalFileSystem, sourceIsLocalFile
}

Expand Down Expand Up @@ -556,6 +568,8 @@ func generateSkipFunction(atmosConfig schema.AtmosConfiguration, tempDir string,
if filepath.Base(src) == ".git" {
return true, nil
}
tempDir = filepath.ToSlash(tempDir)
src = filepath.ToSlash(src)

trimmedSrc := u.TrimBasePathFromPath(tempDir+"/", src)

Expand Down Expand Up @@ -608,3 +622,112 @@ func generateSkipFunction(atmosConfig schema.AtmosConfiguration, tempDir string,
return false, nil
}
}

func validateURI(uri string) error {
if uri == "" {
return fmt.Errorf("URI cannot be empty")
}
if strings.Contains(uri, " ") {
return fmt.Errorf("URI cannot contain spaces")
}
// Validate scheme-specific format
if strings.HasPrefix(uri, "oci://") {
if !strings.Contains(uri[6:], "/") {
return fmt.Errorf("invalid OCI URI format")
}
}
return nil
}
func isValidScheme(scheme string) bool {
validSchemes := map[string]bool{
"http": true,
"https": true,
"git": true,
"ssh": true,
"git::https": true,
}
return validSchemes[scheme]
}

// CustomGitHubDetector intercepts GitHub URLs and transforms them
// into something like git::https://<token>@github.com/... so we can
// do a git-based clone with a token.
type CustomGitHubDetector struct {

Check failure on line 655 in internal/exec/vendor_utils.go

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, linux)

CustomGitHubDetector redeclared in this block

Check failure on line 655 in internal/exec/vendor_utils.go

View workflow job for this annotation

GitHub Actions / Build (windows-latest, windows)

CustomGitHubDetector redeclared in this block

Check failure on line 655 in internal/exec/vendor_utils.go

View workflow job for this annotation

GitHub Actions / Build (macos-latest, macos)

CustomGitHubDetector redeclared in this block
AtmosConfig schema.AtmosConfiguration
}

// Detect implements the getter.Detector interface for go-getter v1.
func (d *CustomGitHubDetector) Detect(src, _ string) (string, bool, error) {

Check failure on line 660 in internal/exec/vendor_utils.go

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, linux)

method CustomGitHubDetector.Detect already declared at internal/exec/go_getter_utils.go:76:32

Check failure on line 660 in internal/exec/vendor_utils.go

View workflow job for this annotation

GitHub Actions / Build (windows-latest, windows)

method CustomGitHubDetector.Detect already declared at internal\exec\go_getter_utils.go:76:32

Check failure on line 660 in internal/exec/vendor_utils.go

View workflow job for this annotation

GitHub Actions / Build (macos-latest, macos)

method CustomGitHubDetector.Detect already declared at internal/exec/go_getter_utils.go:76:32
if len(src) == 0 {
return "", false, nil
}

if !strings.Contains(src, "://") {
src = "https://" + src
}

parsedURL, err := url.Parse(src)
if err != nil {
u.LogDebug(d.AtmosConfig, fmt.Sprintf("Failed to parse URL %q: %v\n", src, err))
return "", false, fmt.Errorf("failed to parse URL %q: %w", src, err)
}

if strings.ToLower(parsedURL.Host) != "github.com" {
u.LogDebug(d.AtmosConfig, fmt.Sprintf("Host is %q, not 'github.com', skipping token injection\n", parsedURL.Host))
return "", false, nil
}

parts := strings.SplitN(parsedURL.Path, "/", 4)
if len(parts) < 3 {
u.LogDebug(d.AtmosConfig, fmt.Sprintf("URL path %q doesn't look like /owner/repo\n", parsedURL.Path))
return "", false, fmt.Errorf("invalid GitHub URL %q", parsedURL.Path)
}

atmosGitHubToken := os.Getenv("ATMOS_GITHUB_TOKEN")
gitHubToken := os.Getenv("GITHUB_TOKEN")

var usedToken string
var tokenSource string

// 1. If ATMOS_GITHUB_TOKEN is set, always use that
if atmosGitHubToken != "" {
usedToken = atmosGitHubToken
tokenSource = "ATMOS_GITHUB_TOKEN"
u.LogDebug(d.AtmosConfig, "ATMOS_GITHUB_TOKEN is set\n")
} else {
// 2. Otherwise, only inject GITHUB_TOKEN if cfg.Settings.InjectGithubToken == true
if d.AtmosConfig.Settings.InjectGithubToken && gitHubToken != "" {
usedToken = gitHubToken
tokenSource = "GITHUB_TOKEN"
u.LogTrace(d.AtmosConfig, "InjectGithubToken=true and GITHUB_TOKEN is set, using it\n")
} else {
u.LogTrace(d.AtmosConfig, "No ATMOS_GITHUB_TOKEN or GITHUB_TOKEN found\n")
}
}

if usedToken != "" {
user := parsedURL.User.Username()
pass, _ := parsedURL.User.Password()
if user == "" && pass == "" {
u.LogDebug(d.AtmosConfig, fmt.Sprintf("Injecting token from %s for %s\n", tokenSource, src))
parsedURL.User = url.UserPassword("x-access-token", usedToken)
} else {
u.LogDebug(d.AtmosConfig, "Credentials found, skipping token injection\n")
}
}

finalURL := "git::" + parsedURL.String()

return finalURL, true, nil
}

// RegisterCustomDetectors prepends the custom detector so it runs before
// the built-in ones. Any code that calls go-getter should invoke this.
func RegisterCustomDetectors(atmosConfig schema.AtmosConfiguration) {

Check failure on line 726 in internal/exec/vendor_utils.go

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, linux)

RegisterCustomDetectors redeclared in this block

Check failure on line 726 in internal/exec/vendor_utils.go

View workflow job for this annotation

GitHub Actions / Build (windows-latest, windows)

RegisterCustomDetectors redeclared in this block

Check failure on line 726 in internal/exec/vendor_utils.go

View workflow job for this annotation

GitHub Actions / Build (macos-latest, macos)

RegisterCustomDetectors redeclared in this block
getter.Detectors = append(
[]getter.Detector{
&CustomGitHubDetector{AtmosConfig: atmosConfig},
},
getter.Detectors...,
)
}
Loading

0 comments on commit 063f955

Please sign in to comment.