Skip to content

Commit 8f81390

Browse files
committed
feat: add a more comprehensive GitHub Action development example
1 parent df8e285 commit 8f81390

File tree

6 files changed

+196
-18
lines changed

6 files changed

+196
-18
lines changed

.github/configs/setup-my-action.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
input_text = "Hello, World!"
2+
find_word = "Hello"
3+
replace_word = "Hi"
4+
number_list = [1.0, 2.0, 3.0, 4.0, 5.0]
5+
input_file = "input.txt"
6+
output_file = "output.txt"
7+
append_text = "This text will be appended."
8+
api_url = "https://api.example.com/data"

.github/workflows/ci.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@ jobs:
1313
steps:
1414
- uses: actions/checkout@v4
1515

16-
- name: Set My Action
16+
- name: Run Comprehensive Action
17+
id: my_action
1718
uses: ./
18-
with:
19-
my_input: 'GitHub'
19+
20+
- name: Check Outputs
21+
run: |
22+
echo "processed_text: ${{ steps.my_action.outputs.processed_text }}"
23+
echo "word_count: ${{ steps.my_action.outputs.word_count }}"
24+
echo "sum: ${{ steps.my_action.outputs.sum }}"
25+
echo "average: ${{ steps.my_action.outputs.average }}"
26+
echo "response_field: ${{ steps.my_action.outputs.response_field }}"

action.yml

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
1-
name: 'Setup My Action'
2-
description: 'A GitHub Action built using Go'
1+
name: 'Comprehensive GitHub Action by Golang with TOML Config'
2+
description: 'A GitHub Action that handles text, lists, files, and API requests using Go, configured via TOML'
3+
author: 'Mystic'
4+
branding:
5+
icon: 'check-square' # Choose an icon
6+
color: 'blue' # Choose a color
37
runs:
48
using: 'docker'
59
image: 'Dockerfile'
10+
611
inputs:
7-
my_input:
8-
description: 'An input for the Go program'
9-
required: true
10-
default: 'World'
12+
config_path:
13+
description: 'Path to the TOML configuration file'
14+
required: false
15+
default: '.github/configs/setup-my-action.toml'
16+
1117
outputs:
12-
my_output:
13-
description: 'Output of the Go program'
18+
processed_text:
19+
description: 'The processed text after find and replace'
20+
word_count:
21+
description: 'The total number of words in the text'
22+
sum:
23+
description: 'The sum of the numbers'
24+
average:
25+
description: 'The average of the numbers'
26+
response_field:
27+
description: 'A specific field from the API response'

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
module github.com/pplmx/setup-my-action
22

33
go 1.23
4+
5+
require github.com/BurntSushi/toml v1.4.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
2+
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=

main.go

Lines changed: 152 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,163 @@
11
package main
22

33
import (
4+
"context"
5+
"encoding/json"
46
"fmt"
7+
"io"
8+
"log"
9+
"net/http"
510
"os"
11+
"strconv"
12+
"strings"
13+
"time"
14+
15+
"github.com/BurntSushi/toml"
16+
)
17+
18+
type Config struct {
19+
InputText string `toml:"input_text"`
20+
FindWord string `toml:"find_word"`
21+
ReplaceWord string `toml:"replace_word"`
22+
NumberList []float64 `toml:"number_list"`
23+
InputFile string `toml:"input_file"`
24+
OutputFile string `toml:"output_file"`
25+
AppendText string `toml:"append_text"`
26+
ApiURL string `toml:"api_url"`
27+
}
28+
29+
const (
30+
defaultConfigPath = ".github/configs/setup-my-action.toml"
31+
httpTimeout = 10 * time.Second
32+
contextTimeout = 15 * time.Second
633
)
734

35+
func loadConfig(path string) (*Config, error) {
36+
if path == "" {
37+
path = defaultConfigPath
38+
}
39+
40+
var config Config
41+
if _, err := toml.DecodeFile(path, &config); err != nil {
42+
return nil, fmt.Errorf("failed to decode TOML file: %w", err)
43+
}
44+
45+
// Validate config
46+
if err := validateConfig(&config); err != nil {
47+
return nil, fmt.Errorf("invalid configuration: %w", err)
48+
}
49+
50+
return &config, nil
51+
}
52+
53+
func validateConfig(config *Config) error {
54+
if config.InputText == "" {
55+
return fmt.Errorf("input_text is required")
56+
}
57+
if config.InputFile == "" || config.OutputFile == "" {
58+
return fmt.Errorf("input_file and output_file are required")
59+
}
60+
if config.ApiURL == "" {
61+
return fmt.Errorf("api_url is required")
62+
}
63+
return nil
64+
}
65+
66+
func processText(inputText, findWord, replaceWord string) (string, int) {
67+
processedText := strings.ReplaceAll(inputText, findWord, replaceWord)
68+
wordCount := len(strings.Fields(inputText))
69+
return processedText, wordCount
70+
}
71+
72+
func calculateSumAndAverage(numbers []float64) (float64, float64) {
73+
sum := 0.0
74+
for _, num := range numbers {
75+
sum += num
76+
}
77+
average := sum / float64(len(numbers))
78+
return sum, average
79+
}
80+
81+
func readAndAppendToFile(inputFile, outputFile, appendText string) error {
82+
content, err := os.ReadFile(inputFile)
83+
if err != nil {
84+
return fmt.Errorf("failed to read input file: %w", err)
85+
}
86+
87+
modifiedContent := string(content) + "\n" + appendText
88+
89+
return os.WriteFile(outputFile, []byte(modifiedContent), 0644)
90+
}
91+
92+
func callAPIAndExtractField(ctx context.Context, apiURL string) (string, error) {
93+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, apiURL, nil)
94+
if err != nil {
95+
return "", fmt.Errorf("failed to create request: %w", err)
96+
}
97+
98+
client := &http.Client{Timeout: httpTimeout}
99+
resp, err := client.Do(req)
100+
if err != nil {
101+
return "", fmt.Errorf("failed to make API request: %w", err)
102+
}
103+
defer func(Body io.ReadCloser) {
104+
err := Body.Close()
105+
if err != nil {
106+
log.Printf("Failed to close response body: %v", err)
107+
}
108+
}(resp.Body)
109+
110+
body, err := io.ReadAll(resp.Body)
111+
if err != nil {
112+
return "", fmt.Errorf("failed to read API response: %w", err)
113+
}
114+
115+
var result map[string]interface{}
116+
if err := json.Unmarshal(body, &result); err != nil {
117+
return "", fmt.Errorf("failed to parse JSON response: %w", err)
118+
}
119+
120+
dataField, ok := result["data"].(string)
121+
if !ok {
122+
return "", fmt.Errorf("field 'data' not found in API response or is not a string")
123+
}
124+
125+
return dataField, nil
126+
}
127+
128+
func setOutput(name, value string) {
129+
fmt.Printf("::set-output name=%s::%s\n", name, value)
130+
}
131+
8132
func main() {
9-
// 从环境变量中读取 GitHub Action 的输入
10-
input := os.Getenv("INPUT_MY_INPUT")
11-
if input == "" {
12-
fmt.Println("No input provided")
13-
return
133+
configPath := os.Getenv("INPUT_CONFIG_PATH")
134+
config, err := loadConfig(configPath)
135+
if err != nil {
136+
log.Fatalf("Failed to load configuration: %v", err)
14137
}
15138

16-
// 打印输出以便在 GitHub Action 日志中查看
17-
fmt.Printf("Hello, %s!\n", input)
139+
// 1. 文本处理
140+
processedText, wordCount := processText(config.InputText, config.FindWord, config.ReplaceWord)
141+
setOutput("processed_text", processedText)
142+
setOutput("word_count", strconv.Itoa(wordCount))
143+
144+
// 2. 列表处理
145+
sum, average := calculateSumAndAverage(config.NumberList)
146+
setOutput("sum", strconv.FormatFloat(sum, 'f', -1, 64))
147+
setOutput("average", strconv.FormatFloat(average, 'f', -1, 64))
148+
149+
// 3. 文件处理
150+
if err := readAndAppendToFile(config.InputFile, config.OutputFile, config.AppendText); err != nil {
151+
log.Fatalf("File processing error: %v", err)
152+
}
153+
154+
// 4. API 请求处理
155+
ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
156+
defer cancel()
157+
158+
responseField, err := callAPIAndExtractField(ctx, config.ApiURL)
159+
if err != nil {
160+
log.Fatalf("API request error: %v", err)
161+
}
162+
setOutput("response_field", responseField)
18163
}

0 commit comments

Comments
 (0)