Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions pkg/cli/add_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ type AddWorkflowsResult struct {
// NewAddCommand creates the add command
func NewAddCommand(validateEngine func(string) error) *cobra.Command {
cmd := &cobra.Command{
Use: "add <workflow>...",
Short: "Add agentic workflows from repositories to .github/workflows",
Use: "add <workflow>...",
Aliases: []string{"add-wizard"},
Short: "Add agentic workflows from repositories to .github/workflows",
Long: `Add one or more workflows from repositories to .github/workflows.
By default, this command runs in interactive mode, which guides you through:
Expand Down
106 changes: 6 additions & 100 deletions pkg/cli/add_interactive_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,15 @@ import (

"github.com/charmbracelet/huh"
"github.com/github/gh-aw/pkg/console"
"github.com/github/gh-aw/pkg/workflow"
)

// checkGHAuthStatus verifies the user is logged in to GitHub CLI
func (c *AddInteractiveConfig) checkGHAuthStatus() error {
addInteractiveLog.Print("Checking GitHub CLI authentication status")

output, err := workflow.RunGHCombined("Checking GitHub authentication...", "auth", "status")

if err != nil {
fmt.Fprintln(os.Stderr, console.FormatErrorMessage("You are not logged in to GitHub CLI."))
fmt.Fprintln(os.Stderr, "")
fmt.Fprintln(os.Stderr, "Please run the following command to authenticate:")
fmt.Fprintln(os.Stderr, "")
fmt.Fprintln(os.Stderr, console.FormatCommandMessage(" gh auth login"))
fmt.Fprintln(os.Stderr, "")
return fmt.Errorf("not authenticated with GitHub CLI")
}

if c.Verbose {
fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("GitHub CLI authenticated"))
addInteractiveLog.Printf("gh auth status output: %s", string(output))
}

return nil
return checkGHAuthStatusShared(c.Verbose)
}

// checkGitRepository verifies we're in a git repo and gets org/repo info
// This version has special interactive handling to prompt user for repo if not found
func (c *AddInteractiveConfig) checkGitRepository() error {
addInteractiveLog.Print("Checking git repository status")

Expand All @@ -54,7 +35,7 @@ func (c *AddInteractiveConfig) checkGitRepository() error {
if err != nil {
addInteractiveLog.Printf("Could not determine repository automatically: %v", err)

// Ask the user for the repository
// Ask the user for the repository (interactive-only feature)
fmt.Fprintln(os.Stderr, console.FormatWarningMessage("Could not determine the repository automatically."))
fmt.Fprintln(os.Stderr, "")

Expand Down Expand Up @@ -89,92 +70,17 @@ func (c *AddInteractiveConfig) checkGitRepository() error {
addInteractiveLog.Printf("Target repository: %s", repoSlug)

// Check if repository is public or private
c.isPublicRepo = c.checkRepoVisibility()
c.isPublicRepo = checkRepoVisibilityShared(c.RepoOverride)

return nil
}

// checkRepoVisibility checks if the repository is public or private
func (c *AddInteractiveConfig) checkRepoVisibility() bool {
addInteractiveLog.Print("Checking repository visibility")

// Use gh api to check repository visibility
output, err := workflow.RunGH("Checking repository visibility...", "api", fmt.Sprintf("/repos/%s", c.RepoOverride), "--jq", ".visibility")
if err != nil {
addInteractiveLog.Printf("Could not check repository visibility: %v", err)
// Default to public if we can't determine
return true
}

visibility := strings.TrimSpace(string(output))
isPublic := visibility == "public"
addInteractiveLog.Printf("Repository visibility: %s (isPublic=%v)", visibility, isPublic)
return isPublic
}

// checkActionsEnabled verifies that GitHub Actions is enabled for the repository
func (c *AddInteractiveConfig) checkActionsEnabled() error {
addInteractiveLog.Print("Checking if GitHub Actions is enabled")

// Use gh api to check Actions permissions
output, err := workflow.RunGH("Checking GitHub Actions status...", "api", fmt.Sprintf("/repos/%s/actions/permissions", c.RepoOverride), "--jq", ".enabled")
if err != nil {
addInteractiveLog.Printf("Failed to check Actions status: %v", err)
// If we can't check, warn but continue - actual operations will fail if Actions is disabled
fmt.Fprintln(os.Stderr, console.FormatWarningMessage("Could not verify GitHub Actions status. Proceeding anyway..."))
return nil
}

enabled := strings.TrimSpace(string(output))
if enabled != "true" {
fmt.Fprintln(os.Stderr, console.FormatErrorMessage("GitHub Actions is disabled for this repository."))
fmt.Fprintln(os.Stderr, "")
fmt.Fprintln(os.Stderr, "To enable GitHub Actions:")
fmt.Fprintln(os.Stderr, " 1. Go to your repository on GitHub")
fmt.Fprintln(os.Stderr, " 2. Navigate to Settings → Actions → General")
fmt.Fprintln(os.Stderr, " 3. Under 'Actions permissions', select 'Allow all actions and reusable workflows'")
fmt.Fprintln(os.Stderr, " 4. Click 'Save'")
fmt.Fprintln(os.Stderr, "")
return fmt.Errorf("GitHub Actions is not enabled for this repository")
}

if c.Verbose {
fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("GitHub Actions is enabled"))
}

return nil
return checkActionsEnabledShared(c.RepoOverride, c.Verbose)
}

// checkUserPermissions verifies the user has write/admin access
func (c *AddInteractiveConfig) checkUserPermissions() error {
addInteractiveLog.Print("Checking user permissions")

parts := strings.Split(c.RepoOverride, "/")
if len(parts) != 2 {
return fmt.Errorf("invalid repository format: %s", c.RepoOverride)
}
owner, repo := parts[0], parts[1]

hasAccess, err := checkRepositoryAccess(owner, repo)
if err != nil {
addInteractiveLog.Printf("Failed to check repository access: %v", err)
// If we can't check, warn but continue - actual operations will fail if no access
fmt.Fprintln(os.Stderr, console.FormatWarningMessage("Could not verify repository permissions. Proceeding anyway..."))
return nil
}

if !hasAccess {
fmt.Fprintln(os.Stderr, console.FormatErrorMessage(fmt.Sprintf("You do not have write access to %s/%s.", owner, repo)))
fmt.Fprintln(os.Stderr, "")
fmt.Fprintln(os.Stderr, "You need to be a maintainer, admin, or have write permissions on this repository.")
fmt.Fprintln(os.Stderr, "Please contact the repository owner or request access.")
fmt.Fprintln(os.Stderr, "")
return fmt.Errorf("insufficient repository permissions")
}

if c.Verbose {
fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Repository permissions verified"))
}

return nil
return checkUserPermissionsShared(c.RepoOverride, c.Verbose)
}
11 changes: 6 additions & 5 deletions pkg/cli/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ func InitRepositoryInteractive(verbose bool, rootCmd CommandProvider) error {
return fmt.Errorf("interactive init cannot be used in automated tests or CI environments")
}

// Ensure we're in a git repository
if !isGitRepo() {
initLog.Print("Not in a git repository, initialization failed")
return fmt.Errorf("not in a git repository")
// Run shared precondition checks (same as `gh aw add`)
// This verifies: gh auth, git repo, Actions enabled, user permissions
preconditionResult, err := CheckInteractivePreconditions(verbose)
if err != nil {
return err
}
initLog.Print("Verified git repository")
initLog.Printf("Precondition checks passed, repo: %s, isPublic: %v", preconditionResult.RepoSlug, preconditionResult.IsPublicRepo)

fmt.Fprintln(os.Stderr, "")
fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Welcome to GitHub Agentic Workflows setup!"))
Expand Down
Loading
Loading