Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Listener430 committed Dec 20, 2024
1 parent fb72316 commit 5185fc0
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 49 deletions.
16 changes: 10 additions & 6 deletions internal/exec/vendor_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package exec

import (
"fmt"
"net/url"
"os"
"path/filepath"
"sort"
Expand Down Expand Up @@ -372,7 +373,7 @@ func ExecuteAtmosVendorInternal(

// Handle GitHub source
if isGitHubSource {
u.LogInfo(atmosConfig, fmt.Sprintf("Fetching GitHub source: %s", uri))
u.LogDebug(atmosConfig, fmt.Sprintf("Fetching GitHub source: %s", uri))
fileContents, err := u.DownloadFileFromGitHub(uri)
if err != nil {
return fmt.Errorf("failed to download GitHub file: %w", err)
Expand Down Expand Up @@ -534,17 +535,20 @@ func determineSourceType(uri *string, vendorConfigFilePath string) (bool, bool,
sourceIsLocalFile := false
isGitHubSource := false

// If not OCI, we proceed with checks
if !useOciScheme {
if strings.Contains(*uri, "github.com") {
// Check if the URL is a GitHub source
isGitHubSource = true
} else {
// Handle local file system sources
parsedURL, err := url.Parse(*uri)
if err != nil || parsedURL.Scheme == "" || parsedURL.Host == "" {
// Not a valid URL or no host: consider local filesystem
if absPath, err := u.JoinAbsolutePathWithPath(vendorConfigFilePath, *uri); err == nil {
uri = &absPath
useLocalFileSystem = true
sourceIsLocalFile = u.FileExists(*uri)
}
} else {
if parsedURL.Host == "github.com" && parsedURL.Scheme == "https" {
isGitHubSource = true
}
}
}

Expand Down
21 changes: 9 additions & 12 deletions pkg/utils/file_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,24 +245,21 @@ func GetFileNameFromURL(rawURL string) (string, error) {

// ParseGitHubURL parses a GitHub URL and returns the owner, repo, file path and branch
func ParseGitHubURL(rawURL string) (owner, repo, filePath, branch string, err error) {
parsedURL, err := url.Parse(rawURL)
u, err := url.Parse(rawURL)
if err != nil {
return "", "", "", "", fmt.Errorf("invalid URL: %w", err)
}

if !strings.Contains(parsedURL.Host, "github.com") {
return "", "", "", "", fmt.Errorf("URL is not a GitHub URL")
}

pathParts := strings.Split(strings.Trim(parsedURL.Path, "/"), "/")
if len(pathParts) < 4 || pathParts[2] != "blob" {
return "", "", "", "", fmt.Errorf("URL format not supported. Expected: /owner/repo/blob/branch/filepath")
// Expected format: https://github.com/owner/repo/blob/branch/path/to/file
parts := strings.Split(u.Path, "/")
if len(parts) < 5 || (parts[3] != "blob" && parts[3] != "raw") {
return "", "", "", "", fmt.Errorf("invalid GitHub URL format")
}

owner = pathParts[0]
repo = pathParts[1]
branch = pathParts[3]
filePath = strings.Join(pathParts[4:], "/")
owner = parts[1]
repo = parts[2]
branch = parts[4]
filePath = strings.Join(parts[5:], "/")

return owner, repo, filePath, branch, nil
}
77 changes: 46 additions & 31 deletions pkg/utils/github_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,68 +2,83 @@ package utils

import (
"context"
"encoding/base64"
"fmt"
"io"
"net/http"
"os"
"time"

"github.com/google/go-github/v59/github"
"golang.org/x/oauth2"
)

// GetLatestGitHubRepoRelease returns the latest release tag for a GitHub repository
func GetLatestGitHubRepoRelease(owner string, repo string) (string, error) {
opt := &github.ListOptions{Page: 1, PerPage: 1}
client := github.NewClient(nil)
// newGitHubClient creates a new GitHub client. If a token is provided, it returns an authenticated client;
// otherwise, it returns an unauthenticated client.
func newGitHubClient(ctx context.Context) *github.Client {
githubToken := os.Getenv("GITHUB_TOKEN")
if githubToken == "" {
return github.NewClient(nil)
}

ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
// Token found, create an authenticated client
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: githubToken},
)
tc := oauth2.NewClient(ctx, ts)

return github.NewClient(tc)
}

// GetLatestGitHubRepoRelease returns the latest release tag for a GitHub repository.
func GetLatestGitHubRepoRelease(owner string, repo string) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

client := newGitHubClient(ctx)
opt := &github.ListOptions{Page: 1, PerPage: 1}

releases, _, err := client.Repositories.ListReleases(ctx, owner, repo, opt)
if err != nil {
return "", err
return "", fmt.Errorf("failed to list releases: %w", err)
}

if len(releases) > 0 {
latestRelease := releases[0]
latestReleaseTag := *latestRelease.TagName
return latestReleaseTag, nil
if len(releases) > 0 && releases[0].TagName != nil {
return *releases[0].TagName, nil
}

return "", nil
}

// ParseGitHubURL parses a GitHub URL and returns the owner, repo, file path and branch
// DownloadFileFromGitHub downloads a file from a GitHub repository using the GitHub API.
func DownloadFileFromGitHub(rawURL string) ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

owner, repo, filePath, branch, err := ParseGitHubURL(rawURL)
if err != nil {
return nil, fmt.Errorf("failed to parse GitHub URL: %w", err)
}

githubToken := os.Getenv("GITHUB_TOKEN")
if githubToken == "" {
return nil, fmt.Errorf("GITHUB_TOKEN is not set")
}
client := newGitHubClient(ctx)

apiURL := fmt.Sprintf("https://api.github.com/repos/%s/%s/contents/%s?ref=%s", owner, repo, filePath, branch)
req, err := http.NewRequest("GET", apiURL, nil)
// Get the file content
opt := &github.RepositoryContentGetOptions{Ref: branch}
fileContent, _, _, err := client.Repositories.GetContents(ctx, owner, repo, filePath, opt)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
return nil, fmt.Errorf("failed to get file content from GitHub: %w", err)
}
if fileContent == nil {
return nil, fmt.Errorf("no content returned for the requested file")
}

req.Header.Set("Authorization", "Bearer "+githubToken)
req.Header.Set("Accept", "application/vnd.github.v3.raw")

client := &http.Client{}
resp, err := client.Do(req)
// Decode the base64 encoded content
content, err := fileContent.GetContent()
if err != nil {
return nil, fmt.Errorf("failed to perform request: %w", err)
return nil, fmt.Errorf("failed to get file content: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to download file: %s", resp.Status)
data, err := base64.StdEncoding.DecodeString(content)
if err != nil {
return nil, fmt.Errorf("failed to decode file content: %w", err)
}

return io.ReadAll(resp.Body)
return data, nil
}

0 comments on commit 5185fc0

Please sign in to comment.