Compare commits

...

7 Commits

Author SHA1 Message Date
Bo-Yi Wu bce2f5f991 Update DOCS.md
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-07-05 20:25:02 +08:00
appleboy 30fbdbe54d docs: update notification docs for Woodpecker 3.x status changes
- Add documentation note explaining that in Woodpecker 3.x, build.status is always "success", which affects message templates
- Recommend using the when.status condition to separate success and failure notifications, with example YAML provided
- Clarify that this issue results from upstream Woodpecker CI changes and is not fixable in the plugin

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-07-05 20:22:59 +08:00
appleboy 9f96bb575e build: update Go formatting and GitHub actions configuration
- Remove `DIST` variable definition
- Update the `GOFMT` definition by removing the `-s` flag
- Install `gofumpt` latest version instead of an unspecified version

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-04-12 09:37:03 +08:00
appleboy 1b1fb67645 build: improve release management and Discord integration
- Add name_template to release section for Drone Discord version representation

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-04-12 09:35:09 +08:00
appleboy b2b10008a5 refactor: refactor file handling for improved readability and performance
- Clean path and check accessibility before reading file
- Replace file reading with `os.ReadFile` for simpler code
- Remove deferred file closing as file is read into `content`
- Write file content directly to multipart form
- Add comments for clearer code sections

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-04-11 23:40:58 +08:00
appleboy b291372e68 refactor: refactor and streamline status color handling
- Handle custom color by trimming the prefix '#'
- Refactor predefined status colors into a map
- Simplify status color handling code

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-04-11 23:38:09 +08:00
appleboy 691536f46b ci: revise golangci-lint configuration and update versioning
- Update golangci-lint-action used version from `v6` to `v7`
- Set specific golangci-lint version to `v2.0` instead of latest
- Remove `run` section with timeout setting in `.golangci.yaml`
- Eliminate multiple linters (`errcheck`, `gci`, `gofmt`, `goimports`) from `.golangci.yaml`
- Change `linters-settings` to `settings` in `.golangci.yaml`
- Add `int-conversion: true` to `perfsprint` settings
- Add new exclusion settings for generated code, preset rules, and specific paths under `exclusions` in `.golangci.yaml`
- Incorporate formatter settings with enabled formatters and exclusions for certain paths in `.golangci.yaml`

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-04-11 23:35:39 +08:00
6 changed files with 111 additions and 52 deletions
+2 -2
View File
@@ -15,9 +15,9 @@ jobs:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup golangci-lint - name: Setup golangci-lint
uses: golangci/golangci-lint-action@v6 uses: golangci/golangci-lint-action@v7
with: with:
version: latest version: v2.0
args: --verbose args: --verbose
- uses: hadolint/hadolint-action@v3.1.0 - uses: hadolint/hadolint-action@v3.1.0
+40 -27
View File
@@ -1,14 +1,9 @@
run: version: "2"
timeout: 5m
linters: linters:
enable: enable:
- asciicheck - asciicheck
- durationcheck - durationcheck
- errcheck
- errorlint - errorlint
- gci
- gofmt
- goimports
- gosec - gosec
- misspell - misspell
- nakedret - nakedret
@@ -18,24 +13,42 @@ linters:
- revive - revive
- usestdlibvars - usestdlibvars
- wastedassign - wastedassign
settings:
linters-settings: gosec:
gosec: includes:
# To select a subset of rules to run. - G102
# Available rules: https://github.com/securego/gosec#available-rules - G106
# Default: [] - means include all rules - G108
includes: - G109
- G102 - G111
- G106 - G112
- G108 - G201
- G109 - G203
- G111 perfsprint:
- G112 int-conversion: true
- G201 err-error: true
- G203 errorf: true
perfsprint: sprintf1: true
err-error: true strconcat: true
errorf: true exclusions:
int-conversion: true generated: lax
sprintf1: true presets:
strconcat: true - comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gci
- gofmt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
+2
View File
@@ -98,6 +98,8 @@ release:
extra_files: extra_files:
- glob: ./**.xz - glob: ./**.xz
name_template: "Drone Discord {{.Version}}"
changelog: changelog:
use: github use: github
groups: groups:
+28
View File
@@ -197,3 +197,31 @@ urlencode
since since
: returns a duration string between now and the given timestamp. Example `{{since build.started}}` : returns a duration string between now and the given timestamp. Example `{{since build.started}}`
## Note for Woodpecker 3.x Users
Starting with Woodpecker 3.x, the `build.status` variable is always set to `success`, which means message templates cannot correctly distinguish between success and failure. It is recommended to use the `when.status` condition to split notifications for success and failure, as shown below:
```yaml
- name: discord success notification
when:
status: [ success ]
image: appleboy/drone-discord
settings:
webhook_id: xxxxxxxxxx
webhook_token: xxxxxxxxxx
message: >
build {{build.number}} succeeded. Good job.
- name: discord failure notification
when:
status: [ failure ]
image: appleboy/drone-discord
settings:
webhook_id: xxxxxxxxxx
webhook_token: xxxxxxxxxx
message: >
build {{build.number}} failed. Fix me please.
```
This is due to a change in Woodpecker CI behavior and cannot be fixed on the plugin side. Please use the above workaround for correct notifications.
+2 -3
View File
@@ -1,6 +1,5 @@
DIST := dist
EXECUTABLE := drone-discord EXECUTABLE := drone-discord
GOFMT ?= gofumpt -l -s -w GOFMT ?= gofumpt -l -w
GO ?= go GO ?= go
GOFILES := $(shell find . -name "*.go" -type f) GOFILES := $(shell find . -name "*.go" -type f)
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" ) HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
@@ -43,7 +42,7 @@ all: build
fmt: fmt:
@hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ @hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install mvdan.cc/gofumpt; \ $(GO) install mvdan.cc/gofumpt@latest; \
fi fi
$(GOFMT) -w $(GOFILES) $(GOFMT) -w $(GOFILES)
+37 -20
View File
@@ -176,35 +176,49 @@ func templateMessage(t string, plugin Plugin) (string, error) {
// Creates a new file upload http request with optional extra params // Creates a new file upload http request with optional extra params
// https://matt.aimonetti.net/posts/2013/07/01/golang-multipart-file-upload-example/ // https://matt.aimonetti.net/posts/2013/07/01/golang-multipart-file-upload-example/
func fileUploadRequest(ctx context.Context, uri string, params map[string]string, paramName, path string) (*http.Request, error) { func fileUploadRequest(ctx context.Context, uri string, params map[string]string, paramName, path string) (*http.Request, error) {
file, err := os.Open(path) // Clean and check path
if err != nil { path = filepath.Clean(path)
return nil, fmt.Errorf("failed to open file: %w", err) if _, err := os.Stat(path); err != nil {
return nil, fmt.Errorf("file %s not accessible: %w", path, err)
} }
defer file.Close()
// Read file content
content, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("failed to read file %s: %w", path, err)
}
// Create multipart form
body := &bytes.Buffer{} body := &bytes.Buffer{}
writer := multipart.NewWriter(body) writer := multipart.NewWriter(body)
// Add file
part, err := writer.CreateFormFile(paramName, filepath.Base(path)) part, err := writer.CreateFormFile(paramName, filepath.Base(path))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create form file: %w", err) return nil, fmt.Errorf("failed to create form file: %w", err)
} }
if _, err = io.Copy(part, file); err != nil { if _, err = part.Write(content); err != nil {
return nil, fmt.Errorf("failed to copy file content: %w", err) return nil, fmt.Errorf("failed to write file content: %w", err)
} }
// Add extra params
for key, val := range params { for key, val := range params {
if err = writer.WriteField(key, val); err != nil { if err = writer.WriteField(key, val); err != nil {
return nil, fmt.Errorf("failed to write field %s: %w", key, err) return nil, fmt.Errorf("failed to write field %s: %w", key, err)
} }
} }
if err = writer.Close(); err != nil { if err = writer.Close(); err != nil {
return nil, fmt.Errorf("failed to close writer: %w", err) return nil, fmt.Errorf("failed to close multipart writer: %w", err)
} }
// Create request
req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, body) req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, body)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create new request: %w", err) return nil, fmt.Errorf("failed to create request: %w", err)
} }
req.Header.Set("Content-Type", writer.FormDataContentType()) req.Header.Set("Content-Type", writer.FormDataContentType())
return req, nil return req, nil
} }
@@ -402,22 +416,25 @@ func (p *Plugin) Clear() {
// Color code of the embed // Color code of the embed
func (p *Plugin) Color() int { func (p *Plugin) Color() int {
// Handle custom color
if p.Config.Color != "" { if p.Config.Color != "" {
p.Config.Color = strings.Replace(p.Config.Color, "#", "", -1) cleanColor := strings.TrimPrefix(p.Config.Color, "#")
if s, err := strconv.ParseInt(p.Config.Color, 16, 32); err == nil { if s, err := strconv.ParseInt(cleanColor, 16, 32); err == nil {
return int(s) return int(s)
} }
} }
switch p.Build.Status { // Predefined status colors
case "success": statusColors := map[string]int{
// green "success": 0x1ac600, // green
return 0x1ac600 "failure": 0xff3232, // red
case "failure", "error", "killed": "error": 0xff3232, // red
// red "killed": 0xff3232, // red
return 0xff3232 "default": 0xffd930, // yellow
default:
// yellow
return 0xffd930
} }
if color, exists := statusColors[p.Build.Status]; exists {
return color
}
return statusColors["default"]
} }