Skip to content

Commit de4cace

Browse files
committed
refactor workflor to trigger tests
1 parent 575bd6a commit de4cace

File tree

3 files changed

+778
-486
lines changed

3 files changed

+778
-486
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: 'Checkout JFrog Repository'
2+
description: 'Checkout a JFrog repository with conditional logic based on whether repo/ref are provided'
3+
4+
inputs:
5+
repository:
6+
description: 'Repository to checkout (e.g., jfrog/jfrog-cli). If empty, step is skipped.'
7+
required: false
8+
default: ''
9+
ref:
10+
description: 'Branch/tag/SHA to checkout'
11+
required: false
12+
default: 'master'
13+
path:
14+
description: 'Relative path to checkout to'
15+
required: true
16+
default-repository:
17+
description: 'Default repository to use if repository input is empty but checkout is still needed'
18+
required: false
19+
default: ''
20+
default-ref:
21+
description: 'Default ref to use with default-repository'
22+
required: false
23+
default: 'master'
24+
25+
runs:
26+
using: 'composite'
27+
steps:
28+
# Checkout from specified repository if provided
29+
- name: Checkout from specified repo
30+
if: inputs.repository != ''
31+
uses: actions/checkout@v5
32+
with:
33+
repository: ${{ inputs.repository }}
34+
ref: ${{ inputs.ref }}
35+
path: ${{ inputs.path }}
36+
37+
# Checkout from default repository if no specific repo but default is provided
38+
- name: Checkout from default repo
39+
if: inputs.repository == '' && inputs.default-repository != ''
40+
uses: actions/checkout@v5
41+
with:
42+
repository: ${{ inputs.default-repository }}
43+
ref: ${{ inputs.default-ref }}
44+
path: ${{ inputs.path }}

.github/tools/detect-deps/main.go

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
// Package main provides a tool to detect and resolve JFrog module dependencies
2+
// by parsing go.mod using `go mod edit -json` and checking for branch availability
3+
// in forked repositories.
4+
package main
5+
6+
import (
7+
"encoding/json"
8+
"fmt"
9+
"os"
10+
"os/exec"
11+
"strings"
12+
)
13+
14+
// GoMod represents the JSON structure from `go mod edit -json`
15+
type GoMod struct {
16+
Module Module `json:"Module"`
17+
Go string `json:"Go"`
18+
Require []Require `json:"Require"`
19+
Replace []Replace `json:"Replace"`
20+
}
21+
22+
// Module represents the module path
23+
type Module struct {
24+
Path string `json:"Path"`
25+
}
26+
27+
// Require represents a required module
28+
type Require struct {
29+
Path string `json:"Path"`
30+
Version string `json:"Version"`
31+
Indirect bool `json:"Indirect"`
32+
}
33+
34+
// Replace represents a replace directive
35+
type Replace struct {
36+
Old ModuleVersion `json:"Old"`
37+
New ModuleVersion `json:"New"`
38+
}
39+
40+
// ModuleVersion represents a module with optional version
41+
type ModuleVersion struct {
42+
Path string `json:"Path"`
43+
Version string `json:"Version,omitempty"`
44+
}
45+
46+
// DependencyInfo holds information about a detected dependency
47+
type DependencyInfo struct {
48+
Name string // Short name like "build-info-go"
49+
ModulePath string // Full module path like "github.com/jfrog/build-info-go"
50+
Repo string // Repository like "jfrog/build-info-go"
51+
Ref string // Branch or tag reference
52+
}
53+
54+
// jfrogDependencies maps short names to their module paths
55+
var jfrogDependencies = map[string]string{
56+
"build-info-go": "github.com/jfrog/build-info-go",
57+
"jfrog-client-go": "github.com/jfrog/jfrog-client-go",
58+
"jfrog-cli-core": "github.com/jfrog/jfrog-cli-core/v2",
59+
}
60+
61+
func main() {
62+
// Get current branch from environment
63+
currentBranch := os.Getenv("CURRENT_BRANCH")
64+
if currentBranch == "" {
65+
currentBranch = "main"
66+
}
67+
68+
// Parse go.mod
69+
goMod, err := parseGoMod()
70+
if err != nil {
71+
fmt.Fprintf(os.Stderr, "Error parsing go.mod: %v\n", err)
72+
os.Exit(1)
73+
}
74+
75+
// Build a map of replace directives
76+
replaces := make(map[string]Replace)
77+
for _, r := range goMod.Replace {
78+
replaces[r.Old.Path] = r
79+
}
80+
81+
// Open GITHUB_OUTPUT file for writing outputs
82+
outputFile := os.Getenv("GITHUB_OUTPUT")
83+
var output *os.File
84+
if outputFile != "" {
85+
var err error
86+
output, err = os.OpenFile(outputFile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
87+
if err != nil {
88+
fmt.Fprintf(os.Stderr, "Error opening GITHUB_OUTPUT: %v\n", err)
89+
os.Exit(1)
90+
}
91+
defer output.Close()
92+
}
93+
94+
fmt.Println("============================================")
95+
fmt.Println("Detecting JFrog dependencies...")
96+
fmt.Println("============================================")
97+
fmt.Printf("Current branch: %s\n\n", currentBranch)
98+
99+
// Process each dependency
100+
for name, modulePath := range jfrogDependencies {
101+
info := detectDependency(name, modulePath, replaces, currentBranch)
102+
writeOutput(output, name, info)
103+
}
104+
}
105+
106+
// parseGoMod runs `go mod edit -json` and parses the output
107+
func parseGoMod() (*GoMod, error) {
108+
cmd := exec.Command("go", "mod", "edit", "-json")
109+
out, err := cmd.Output()
110+
if err != nil {
111+
return nil, fmt.Errorf("failed to run go mod edit -json: %w", err)
112+
}
113+
114+
var goMod GoMod
115+
if err := json.Unmarshal(out, &goMod); err != nil {
116+
return nil, fmt.Errorf("failed to parse go.mod JSON: %w", err)
117+
}
118+
119+
return &goMod, nil
120+
}
121+
122+
// detectDependency determines the repository and ref for a dependency
123+
func detectDependency(name, modulePath string, replaces map[string]Replace, currentBranch string) *DependencyInfo {
124+
// Check if there's a replace directive for this module
125+
if replace, ok := replaces[modulePath]; ok {
126+
// Parse the replace target
127+
newPath := replace.New.Path
128+
if strings.HasPrefix(newPath, "github.com/") {
129+
// Extract repo and version/ref
130+
parts := strings.TrimPrefix(newPath, "github.com/")
131+
repo := parts
132+
ref := replace.New.Version
133+
134+
// Handle version format like "v1.2.3-0.20240101-abc123"
135+
// The ref might be a pseudo-version containing a commit hash
136+
if ref != "" {
137+
fmt.Printf("Found replace directive: %s => %s @ %s\n", name, repo, ref)
138+
return &DependencyInfo{
139+
Name: name,
140+
ModulePath: modulePath,
141+
Repo: repo,
142+
Ref: ref,
143+
}
144+
}
145+
}
146+
}
147+
148+
// No replace directive found, check if current branch exists in the dependency repo
149+
repo := fmt.Sprintf("jfrog/%s", name)
150+
if name == "jfrog-cli-core" {
151+
repo = "jfrog/jfrog-cli-core"
152+
}
153+
154+
// Check if the current branch exists in the repo
155+
if branchExists(repo, currentBranch) {
156+
fmt.Printf("Branch '%s' exists in %s, using it\n", currentBranch, repo)
157+
return &DependencyInfo{
158+
Name: name,
159+
ModulePath: modulePath,
160+
Repo: repo,
161+
Ref: currentBranch,
162+
}
163+
}
164+
165+
// Fall back to master
166+
fmt.Printf("No matching branch for %s, will use default (master)\n", name)
167+
return nil
168+
}
169+
170+
// branchExists checks if a branch exists in a GitHub repository
171+
func branchExists(repo, branch string) bool {
172+
if branch == "" || branch == "main" || branch == "master" {
173+
return false // Don't try to match main/master, use defaults
174+
}
175+
176+
url := fmt.Sprintf("https://github.com/%s.git", repo)
177+
cmd := exec.Command("git", "ls-remote", "--heads", url, branch)
178+
out, err := cmd.Output()
179+
if err != nil {
180+
return false
181+
}
182+
183+
// If output contains the branch name, it exists
184+
return strings.Contains(string(out), fmt.Sprintf("refs/heads/%s", branch))
185+
}
186+
187+
// writeOutput writes the dependency info to GITHUB_OUTPUT
188+
func writeOutput(output *os.File, name string, info *DependencyInfo) {
189+
// Convert name to output key format (e.g., "build-info-go" -> "build_info_go")
190+
keyName := strings.ReplaceAll(name, "-", "_")
191+
192+
var repo, ref string
193+
if info != nil {
194+
repo = info.Repo
195+
ref = info.Ref
196+
}
197+
198+
// Write to GITHUB_OUTPUT if available
199+
if output != nil {
200+
fmt.Fprintf(output, "%s_repo=%s\n", keyName, repo)
201+
fmt.Fprintf(output, "%s_ref=%s\n", keyName, ref)
202+
}
203+
204+
// Also print for visibility
205+
if info != nil {
206+
fmt.Printf(" %s_repo=%s\n", keyName, repo)
207+
fmt.Printf(" %s_ref=%s\n", keyName, ref)
208+
} else {
209+
fmt.Printf(" %s: using default\n", keyName)
210+
}
211+
}

0 commit comments

Comments
 (0)