Skip to content

Commit

Permalink
output to github actions
Browse files Browse the repository at this point in the history
  • Loading branch information
jsbroks committed Nov 20, 2024
1 parent 63b4d0b commit 2df1c38
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 7 deletions.
4 changes: 0 additions & 4 deletions actions/get-resource/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@ runs:
echo "$line"
done
# Print GITHUB_OUTPUT contents for debugging
echo "Contents of GITHUB_OUTPUT:"
cat "$GITHUB_OUTPUT"
# Exit if no required outputs specified
if [ -z "${{ inputs.required_outputs }}" ]; then
echo "No required outputs specified."
Expand Down
17 changes: 14 additions & 3 deletions cmd/ctrlc/root/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package api

import (
"fmt"
"os"

"github.com/ctrlplanedev/cli/cmd/ctrlc/root/api/create"
"github.com/ctrlplanedev/cli/cmd/ctrlc/root/api/delete"
Expand All @@ -19,11 +20,21 @@ func NewAPICmd() *cobra.Command {
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
apiURL := viper.GetString("url")
if apiURL == "" {
return fmt.Errorf("API URL is required. Set via --url flag or in config")
fmt.Fprintln(cmd.ErrOrStderr(), "API URL is required. Set via --url flag or in config")
os.Exit(1)
}
apiKey := viper.GetString("api-key")
if apiKey == "" {
return fmt.Errorf("API key is required. Set via --api-key flag or in config")
fmt.Fprintln(cmd.ErrOrStderr(), "API key is required. Set via --api-key flag or in config")
os.Exit(1)
}

templateFlag, _ := cmd.Flags().GetString("template")
formatFlag, _ := cmd.Flags().GetString("format")

if templateFlag != "" && formatFlag != "json" {
fmt.Fprintln(cmd.ErrOrStderr(), "--template and --format flags cannot be used together")
os.Exit(1)
}
return nil
},
Expand All @@ -32,7 +43,7 @@ func NewAPICmd() *cobra.Command {
},
}
cmd.PersistentFlags().String("template", "", "Template for output format. Accepts Go template format (e.g. --template='{{.status.phase}}')")
cmd.PersistentFlags().String("format", "json", "Output format. Accepts 'json' or 'yaml'")
cmd.PersistentFlags().String("format", "json", "Output format. Accepts 'json', 'yaml', or 'github-action'")

cmd.AddCommand(get.NewGetCmd())
cmd.AddCommand(create.NewCreateCmd())
Expand Down
117 changes: 117 additions & 0 deletions internal/cliutil/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
"text/template"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -45,6 +47,8 @@ func HandleOutput(cmd *cobra.Command, resp *http.Response) error {
if err != nil {
return fmt.Errorf("failed to marshal to YAML: %w", err)
}
case "github-action":
return handleGitHubActionOutput(result)
default:
output, err = json.MarshalIndent(result, "", " ")
if err != nil {
Expand All @@ -55,3 +59,116 @@ func HandleOutput(cmd *cobra.Command, resp *http.Response) error {
fmt.Fprintln(cmd.OutOrStdout(), string(output))
return nil
}

func handleGitHubActionOutput(result map[string]interface{}) error {
writer, err := NewGitHubOutputWriter()
if err != nil {
return fmt.Errorf("failed to create GitHubOutputWriter: %w", err)
}
defer writer.Close()

output, err := json.Marshal(result)
if err != nil {
return fmt.Errorf("failed to marshal to JSON: %w", err)
}

writer.Write("json", string(output))
var data map[string]interface{}
if err := json.Unmarshal(output, &data); err != nil {
return fmt.Errorf("failed to unmarshal JSON: %w", err)
}

var flatten func(prefix string, v interface{}) error
flatten = func(prefix string, v interface{}) error {
switch val := v.(type) {
case map[string]interface{}:
for k, v := range val {
newPrefix := strings.ReplaceAll(k, "/", "_")
if prefix != "" {
newPrefix = prefix + "_" + newPrefix
}
if err := flatten(newPrefix, v); err != nil {
return err
}
}
case []interface{}:
for i, v := range val {
newPrefix := fmt.Sprintf("%s_%d", prefix, i)
if err := flatten(newPrefix, v); err != nil {
return err
}
}
default:
if val == nil {
return nil
}

writer.Write(prefix, fmt.Sprintf("%v", val))
}
return nil
}

if err := flatten("", data); err != nil {
return fmt.Errorf("failed to flatten output: %w", err)
}

return nil
}

// GitHubOutputWriter is a helper for writing to the GITHUB_OUTPUT file.
type GitHubOutputWriter struct {
file *os.File
}

// NewGitHubOutputWriter creates and initializes a new GitHubOutputWriter. It
// opens the GITHUB_OUTPUT file for appending.
func NewGitHubOutputWriter() (*GitHubOutputWriter, error) {
// Get the GITHUB_OUTPUT environment variable
githubOutput := os.Getenv("GITHUB_OUTPUT")
if githubOutput == "" {
return nil, fmt.Errorf("GITHUB_OUTPUT environment variable is not set")
}

// Open the file in append mode
file, err := os.OpenFile(githubOutput, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return nil, fmt.Errorf("error opening GITHUB_OUTPUT file: %w", err)
}

return &GitHubOutputWriter{file: file}, nil
}

// Write writes a key-value pair to the GITHUB_OUTPUT file.
func (w *GitHubOutputWriter) Write(key, value string) error {
if w.file == nil {
return fmt.Errorf("GitHubOutputWriter is not initialized")
}

// Format and write the output
output := fmt.Sprintf("%s=%s\n", key, value)
if _, err := w.file.WriteString(output); err != nil {
return fmt.Errorf("error writing to GITHUB_OUTPUT file: %w", err)
}

return nil
}

// Close closes the GITHUB_OUTPUT file.
func (w *GitHubOutputWriter) Close() error {
if w.file == nil {
return nil
}
err := w.file.Close()
w.file = nil
return err
}

// GetEnv fetches the value of an environment variable or returns a default
// value.
func GetEnv(key string, defaultValue string) string {
value := os.Getenv(key)
if value == "" {
return defaultValue
}
return value
}

0 comments on commit 2df1c38

Please sign in to comment.