Skip to content

Commit 2df1c38

Browse files
committed
output to github actions
1 parent 63b4d0b commit 2df1c38

File tree

3 files changed

+131
-7
lines changed

3 files changed

+131
-7
lines changed

actions/get-resource/action.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,6 @@ runs:
4949
echo "$line"
5050
done
5151
52-
# Print GITHUB_OUTPUT contents for debugging
53-
echo "Contents of GITHUB_OUTPUT:"
54-
cat "$GITHUB_OUTPUT"
55-
5652
# Exit if no required outputs specified
5753
if [ -z "${{ inputs.required_outputs }}" ]; then
5854
echo "No required outputs specified."

cmd/ctrlc/root/api/api.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package api
22

33
import (
44
"fmt"
5+
"os"
56

67
"github.com/ctrlplanedev/cli/cmd/ctrlc/root/api/create"
78
"github.com/ctrlplanedev/cli/cmd/ctrlc/root/api/delete"
@@ -19,11 +20,21 @@ func NewAPICmd() *cobra.Command {
1920
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
2021
apiURL := viper.GetString("url")
2122
if apiURL == "" {
22-
return fmt.Errorf("API URL is required. Set via --url flag or in config")
23+
fmt.Fprintln(cmd.ErrOrStderr(), "API URL is required. Set via --url flag or in config")
24+
os.Exit(1)
2325
}
2426
apiKey := viper.GetString("api-key")
2527
if apiKey == "" {
26-
return fmt.Errorf("API key is required. Set via --api-key flag or in config")
28+
fmt.Fprintln(cmd.ErrOrStderr(), "API key is required. Set via --api-key flag or in config")
29+
os.Exit(1)
30+
}
31+
32+
templateFlag, _ := cmd.Flags().GetString("template")
33+
formatFlag, _ := cmd.Flags().GetString("format")
34+
35+
if templateFlag != "" && formatFlag != "json" {
36+
fmt.Fprintln(cmd.ErrOrStderr(), "--template and --format flags cannot be used together")
37+
os.Exit(1)
2738
}
2839
return nil
2940
},
@@ -32,7 +43,7 @@ func NewAPICmd() *cobra.Command {
3243
},
3344
}
3445
cmd.PersistentFlags().String("template", "", "Template for output format. Accepts Go template format (e.g. --template='{{.status.phase}}')")
35-
cmd.PersistentFlags().String("format", "json", "Output format. Accepts 'json' or 'yaml'")
46+
cmd.PersistentFlags().String("format", "json", "Output format. Accepts 'json', 'yaml', or 'github-action'")
3647

3748
cmd.AddCommand(get.NewGetCmd())
3849
cmd.AddCommand(create.NewCreateCmd())

internal/cliutil/output.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"encoding/json"
55
"fmt"
66
"net/http"
7+
"os"
8+
"strings"
79
"text/template"
810

911
"github.com/spf13/cobra"
@@ -45,6 +47,8 @@ func HandleOutput(cmd *cobra.Command, resp *http.Response) error {
4547
if err != nil {
4648
return fmt.Errorf("failed to marshal to YAML: %w", err)
4749
}
50+
case "github-action":
51+
return handleGitHubActionOutput(result)
4852
default:
4953
output, err = json.MarshalIndent(result, "", " ")
5054
if err != nil {
@@ -55,3 +59,116 @@ func HandleOutput(cmd *cobra.Command, resp *http.Response) error {
5559
fmt.Fprintln(cmd.OutOrStdout(), string(output))
5660
return nil
5761
}
62+
63+
func handleGitHubActionOutput(result map[string]interface{}) error {
64+
writer, err := NewGitHubOutputWriter()
65+
if err != nil {
66+
return fmt.Errorf("failed to create GitHubOutputWriter: %w", err)
67+
}
68+
defer writer.Close()
69+
70+
output, err := json.Marshal(result)
71+
if err != nil {
72+
return fmt.Errorf("failed to marshal to JSON: %w", err)
73+
}
74+
75+
writer.Write("json", string(output))
76+
var data map[string]interface{}
77+
if err := json.Unmarshal(output, &data); err != nil {
78+
return fmt.Errorf("failed to unmarshal JSON: %w", err)
79+
}
80+
81+
var flatten func(prefix string, v interface{}) error
82+
flatten = func(prefix string, v interface{}) error {
83+
switch val := v.(type) {
84+
case map[string]interface{}:
85+
for k, v := range val {
86+
newPrefix := strings.ReplaceAll(k, "/", "_")
87+
if prefix != "" {
88+
newPrefix = prefix + "_" + newPrefix
89+
}
90+
if err := flatten(newPrefix, v); err != nil {
91+
return err
92+
}
93+
}
94+
case []interface{}:
95+
for i, v := range val {
96+
newPrefix := fmt.Sprintf("%s_%d", prefix, i)
97+
if err := flatten(newPrefix, v); err != nil {
98+
return err
99+
}
100+
}
101+
default:
102+
if val == nil {
103+
return nil
104+
}
105+
106+
writer.Write(prefix, fmt.Sprintf("%v", val))
107+
}
108+
return nil
109+
}
110+
111+
if err := flatten("", data); err != nil {
112+
return fmt.Errorf("failed to flatten output: %w", err)
113+
}
114+
115+
return nil
116+
}
117+
118+
// GitHubOutputWriter is a helper for writing to the GITHUB_OUTPUT file.
119+
type GitHubOutputWriter struct {
120+
file *os.File
121+
}
122+
123+
// NewGitHubOutputWriter creates and initializes a new GitHubOutputWriter. It
124+
// opens the GITHUB_OUTPUT file for appending.
125+
func NewGitHubOutputWriter() (*GitHubOutputWriter, error) {
126+
// Get the GITHUB_OUTPUT environment variable
127+
githubOutput := os.Getenv("GITHUB_OUTPUT")
128+
if githubOutput == "" {
129+
return nil, fmt.Errorf("GITHUB_OUTPUT environment variable is not set")
130+
}
131+
132+
// Open the file in append mode
133+
file, err := os.OpenFile(githubOutput, os.O_APPEND|os.O_WRONLY, 0644)
134+
if err != nil {
135+
return nil, fmt.Errorf("error opening GITHUB_OUTPUT file: %w", err)
136+
}
137+
138+
return &GitHubOutputWriter{file: file}, nil
139+
}
140+
141+
// Write writes a key-value pair to the GITHUB_OUTPUT file.
142+
func (w *GitHubOutputWriter) Write(key, value string) error {
143+
if w.file == nil {
144+
return fmt.Errorf("GitHubOutputWriter is not initialized")
145+
}
146+
147+
// Format and write the output
148+
output := fmt.Sprintf("%s=%s\n", key, value)
149+
if _, err := w.file.WriteString(output); err != nil {
150+
return fmt.Errorf("error writing to GITHUB_OUTPUT file: %w", err)
151+
}
152+
153+
return nil
154+
}
155+
156+
// Close closes the GITHUB_OUTPUT file.
157+
func (w *GitHubOutputWriter) Close() error {
158+
if w.file == nil {
159+
return nil
160+
}
161+
err := w.file.Close()
162+
w.file = nil
163+
return err
164+
}
165+
166+
// GetEnv fetches the value of an environment variable or returns a default
167+
// value.
168+
func GetEnv(key string, defaultValue string) string {
169+
value := os.Getenv(key)
170+
if value == "" {
171+
return defaultValue
172+
}
173+
return value
174+
}

0 commit comments

Comments
 (0)