Compare commits

...

51 Commits

Author SHA1 Message Date
Bo-Yi Wu 2f461525af chore: bump go directive to 1.25.10
- Update go.mod go directive from 1.25.9 to 1.25.10
2026-05-08 21:19:20 +08:00
Bo-Yi Wu 5f9d683257 ci: bump golangci-lint to v2.12
- Upgrade golangci-lint version from v2.11 to v2.12
2026-05-08 20:13:39 +08:00
Bo-Yi Wu 66afccb389 ci(actions): bump trivy-action to v0.36.0 and codecov-action to v6 2026-04-25 16:51:02 +08:00
Bo-Yi Wu 8c87ebd4ef docs(readme): add Trivy security scan badge 2026-04-16 23:23:44 +08:00
Bo-Yi Wu 156f3c6cb1 fix(deps): bump golang.org/x/crypto to v0.50.0 to fix CVE-2025-58181 and CVE-2025-47914 2026-04-16 23:18:55 +08:00
Bo-Yi Wu 8c8da8b643 fix(docker): bump alpine to 3.23 to clear HIGH CVEs 2026-04-16 23:15:42 +08:00
Bo-Yi Wu d7493e77f5 ci: add trivy workflow and gate docker push on image scan 2026-04-16 23:00:58 +08:00
Bo-Yi Wu 1917781d94 ci: enable check-latest in docker and goreleaser workflows 2026-04-16 22:42:42 +08:00
Bo-Yi Wu c08c2995d2 ci: enable check-latest for setup-go to fetch newest patch 2026-04-16 21:15:35 +08:00
Bo-Yi Wu 55f880d64f ci: pin golangci-lint to v2.11 2026-04-16 21:11:11 +08:00
Bo-Yi Wu 983705ffd7 ci: bump GitHub Actions and add Go 1.25/1.26 to test matrix 2026-04-16 21:03:21 +08:00
Bo-Yi Wu 523c4bb724 chore: bump go directive to 1.25.9 2026-04-16 20:57:50 +08:00
appleboy 2cbd8efffa test: update color conversion tests for new calculation logic
- Update expected output values in color conversion tests to reflect new color calculation logic

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-07-05 22:46:25 +08:00
Bo-Yi Wu f2b9ede051 refactor: refactor messaging and file upload with improved error handling (#66)
- Refactor message and file sending logic into separate handleMessages and handleFiles methods
- Stream file uploads via io.Copy rather than loading the entire content into memory
- Add centralized http.Client with timeout for all requests
- Enhance error handling throughout by returning more descriptive and wrapped errors
- Improve response validation for file and message uploads, checking HTTP status and parsing error details
- Update tests to cover plain text messages, embed messages, file uploads, color conversion, and combined features
- Add tests using assert.Error/assert.NoError and checking specific error messages
- Simplify and clarify configuration validation logic

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-07-05 21:02:30 +08:00
appleboy 1bdf20515c ci: update golangci-lint workflow to use latest action and linter
- Update golangci-lint GitHub Action from v7 to v8 and set linter version to v2.1

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-07-05 20:28:04 +08:00
appleboy 7678d611f9 chore: update and streamline dependency management
- Bump github.com/urfave/cli/v2 to v2.27.7
- Update indirect dependencies: github.com/Masterminds/semver/v3, github.com/Masterminds/sprig/v3, github.com/cpuguy83/go-md2man/v2, github.com/spf13/cast, golang.org/x/crypto, and golang.org/x/sys to newer versions
- Replace github.com/imdario/mergo with dario.cat/mergo as an indirect dependency

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-07-05 20:27:24 +08:00
Bo-Yi Wu 0e20c42ccd docs: update notification docs for Woodpecker 3.x status changes (#65)
* 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>

* Update DOCS.md

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

---------

Signed-off-by: appleboy <appleboy.tw@gmail.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-07-05 20:26:09 +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
appleboy 2173b97920 feat: filter out empty messages in configuration processing
- Add a check for empty messages in the configuration
- Replace the original message handling with a filtered list of non-empty messages
- Update the logic to process messages only if the filtered list is not empty

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 22:45:36 +08:00
appleboy d661b29efe feat: add debug mode for plugin configuration dumping
- Add a new dependency for godump in go.mod
- Import godump in main.go
- Introduce a debug flag in the CLI options
- Update the run function to include the debug flag
- Add logic to dump the plugin configuration if debug mode is enabled
- Extend the plugin struct to include a debug field

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 22:37:30 +08:00
appleboy 3e0f7cf5df fix: enhance error handling and reporting for API responses
- Replace direct reading of response body with error handling for reading
- Add JSON unmarshalling of the response body for better error reporting
- Improve error message format to include details from the JSON response

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 20:57:02 +08:00
appleboy 464bf4772f fix: improve error reporting for message sending failures
- Enhance error reporting by including the response body in the error message when message sending fails.
- Remove the previous error message that only included the status code.

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 17:42:58 +08:00
appleboy c84a5276cb ci: rename lint workflow to testing for clarity and consistency
- Rename the lint workflow file to testing.

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 17:16:18 +08:00
appleboy e344b3ec67 ci: add webhook environment variables to lint workflow
- Add environment variables for `WEBHOOK_ID` and `WEBHOOK_TOKEN` in the lint workflow.

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 17:16:02 +08:00
appleboy 8533df8e0b refactor: enhance file upload functionality with context and error handling
- Rename the function `newfileUploadRequest` to `fileUploadRequest`
- Add context parameter to the `fileUploadRequest` function
- Improve error handling by wrapping errors with descriptive messages
- Update the `Exec` method to pass context when calling `SendFile`
- Rename the `SendFile` method to accept context as a parameter

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 17:10:53 +08:00
appleboy 217a6b17eb docs: clarify usage descriptions for webhook and build parameters
- Update usage descriptions for various webhook parameters to provide clearer context.
- Improve clarity in usage statements for Discord webhook configurations.
- Enhance descriptions for build-related parameters to better explain their purpose.
- Revise usage text for GitHub Actions parameters to ensure consistency and clarity.

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 17:07:21 +08:00
appleboy a58131af2a feat: add support for Discord webhook URL configuration and validation
- Add a new command-line flag for the Discord webhook URL
- Update the configuration structure to include the webhook URL
- Implement validation for the webhook URL format
- Introduce a method to retrieve the webhook URL from the configuration
- Refactor the code to use the new method for generating the webhook URL in multiple places

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 17:03:50 +08:00
appleboy 3721fc313d feat: validate configuration fields in Exec method
- Remove the import of the errors package
- Add a validate method to the Config type to check for missing fields
- Update the Exec method to use the new validate method for configuration validation

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 16:56:57 +08:00
appleboy cea35a9ac9 fix: fix error handling for empty HTTP responses
- Change the condition to check for `http.StatusNoContent` instead of `http.StatusOK` before returning an error.

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 16:53:12 +08:00
appleboy e80db3da6a chore: update base image to Alpine 3.21
- Update the base image from alpine version 3.17 to 3.21

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 16:44:54 +08:00
appleboy 6c782afaae feat: add context support to Exec and SendMessage functions
- Update the `Exec` function to accept a context parameter.
- Modify the `SendMessage` function to also accept a context parameter.
- Add context import to the necessary files.
- Update test cases to pass a context when calling `Exec`.

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 16:43:06 +08:00
appleboy ffa230b880 docs: refine API documentation and improve grammatical consistency
- Correct grammatical errors in descriptions, changing "message" to "messages" and "Webhook" to "Webhooks."
- Update "API document information" to "API documentation."
- Change "Sending discord message" to "Send Discord messages."
- Clarify the list of supported OS types in the binaries section.
- Improve phrasing for building the binary and sending notifications.
- Capitalize "Binary," "Docker," and "Drone CI" for consistency.

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 16:38:35 +08:00
appleboy f2bd7836ef refactor: refactor HTTP request handling and improve linter settings
- Remove the `exportloopref` linter from the golangci configuration
- Add the `strconv` package import in `main.go`
- Replace the `fmt.Sprintf` for the year with `strconv.Itoa` to convert the year to a string
- Update the HTTP request method to use `http.MethodPost` instead of a string literal in `plugin.go`

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 16:36:43 +08:00
appleboy 4d1d86d8c2 docs: clean up documentation by removing unnecessary comments
- Remove a commented-out line from the documentation file

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 16:35:19 +08:00
appleboy 53d0f6ec67 chore: configure golangci-lint with multiple linters and settings
- Add a new configuration file for golangci-lint
- Set a timeout of 5 minutes for linting
- Enable multiple linters including asciicheck, errcheck, and gofmt
- Configure settings for the gosec linter with specific rule inclusions
- Add settings for the perfsprint linter to check various error handling practices

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 16:30:04 +08:00
appleboy 91c0d241df refactor: refactor GitHub event handling in Template function
- Refactor the handling of GitHub events in the Template function
- Replace the message construction with a switch statement for better clarity
- Simplify the logic for determining the branch in pull requests
- Update the case structure for handling different build events

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 16:29:54 +08:00
appleboy 223b0aa14f chore: upgrade Go version and dependencies in workflow settings
- Update Go version from 1.20 to 1.23.0
- Change Go versions in the workflow from 1.21, 1.22, 1.23 to 1.23, 1.24
- Upgrade Codecov action from version 4 to version 5
- Update indirect dependencies for golang.org/x/crypto and golang.org/x/sys to newer versions

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 16:22:17 +08:00
appleboy 5e71b59c72 chore: upgrade dependencies and refine CLI configuration
- Update `github.com/stretchr/testify` from version `1.9.0` to `1.10.0`
- Update `github.com/urfave/cli` to version `v2.27.6` and change import path to include `/v2`
- Update `github.com/cpuguy83/go-md2man/v2` from version `2.0.4` to `2.0.5`
- Add `github.com/xrash/smetrics` as a new indirect dependency
- Change `cli.Author` to use a pointer type
- Update environment variable fields in multiple `cli.StringFlag` definitions to use `EnvVars` instead of `EnvVar`

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-08 16:20:27 +08:00
appleboy 01518e5a92 style: refactor codebase for consistency and performance improvements
- Change single quotes to double quotes in the custom funding URL

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-10-10 02:22:19 +08:00
appleboy 7478381b56 ci: refactor and optimize backend API handling
- Update Docker login action to use version 3 instead of version 2

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-10-10 02:21:59 +08:00
appleboy c96089116d chore: simplify and clean up build and release processes
- Update `GOFMT` command to include `-s` and `-w` flags
- Remove redundant `DIST` and `DIST_DIRS` definitions
- Remove unused variables and dependencies
- Remove `.PHONY` targets and associated release tasks
- Simplify `clean` target by removing `$(DIST)` directory from the removal list

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-10-06 10:08:58 +08:00
appleboy e17a1e9920 ci: streamline build process for multi-architecture support
- Remove `build_linux_arm` target from Makefile
- Remove `make build_linux_arm` step from Docker workflow
- Update Docker workflow to build for `linux/amd64` and `linux/arm64` platforms only

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-10-06 09:46:49 +08:00
appleboy 51f0b338c5 ci: enhance CI pipeline for Go projects
- Rename job from `testing` to `test`
- Add matrix strategy to test on multiple Go versions (1.21, 1.22, 1.23)
- Set up Go environment variables `GO111MODULE` and `GOPROXY`
- Replace `actions/checkout@v4` with `actions/setup-go@v5` for setting up Go
- Add caching for Go build and module directories using `actions/cache@v4`
- Change test command from `make test` to `go test -v -covermode=atomic -coverprofile=coverage.out`
- Add flags to `codecov/codecov-action@v4` for matrix OS and Go version

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-10-04 21:06:18 +08:00
appleboy 2e8d61dcf2 chore: update dependencies to latest versions
- Update `github.com/huandu/xstrings` from v1.4.0 to v1.5.0
- Update `golang.org/x/crypto` from v0.22.0 to v0.24.0
- Update `golang.org/x/sys` from v0.19.0 to v0.21.0

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-06-28 22:03:48 +08:00
appleboy d80fc1adb6 chore: update CI workflows and dependencies
- Update `docker/build-push-action` to version 6
- Update `goreleaser/goreleaser-action` to version 6

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-06-28 21:55:35 +08:00
Bo-Yi Wu 1b92a095c1 ci: update GitHub Actions lint workflow configuration
- Update the golangci-lint-action version from `v5` to `v6` in the GitHub Actions lint workflow

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-05-16 16:14:33 +08:00
qwerty287 8a872ab32f fix: icon URL (#60) 2024-05-16 16:10:54 +08:00
19 changed files with 879 additions and 572 deletions
+1 -1
View File
@@ -10,4 +10,4 @@ liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: ['https://www.paypal.me/appleboy46']
custom: ["https://www.paypal.me/appleboy46"]
+3 -3
View File
@@ -38,11 +38,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -51,4 +51,4 @@ jobs:
# queries: ./path/to/local/query, your-org/your-repo/queries@main
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v4
+42 -11
View File
@@ -10,38 +10,43 @@ on:
branches:
- "master"
permissions:
contents: read
packages: write
security-events: write
jobs:
build-docker:
runs-on: ubuntu-latest
steps:
- name: Setup go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: "^1"
check-latest: true
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Build binary
run: |
make build_linux_amd64
make build_linux_arm
make build_linux_arm64
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
@@ -49,7 +54,7 @@ jobs:
- name: Docker meta
id: docker-meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: |
${{ github.repository }}
@@ -60,11 +65,37 @@ jobs:
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
- name: Build and push
uses: docker/build-push-action@v5
- name: Build image for scanning
uses: docker/build-push-action@v7
with:
context: .
platforms: linux/amd64,linux/arm,linux/arm64
file: docker/Dockerfile
platforms: linux/amd64
push: false
load: true
tags: drone-discord:scan
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@v0.36.0
with:
image-ref: "drone-discord:scan"
format: "sarif"
output: "trivy-image-results.sarif"
severity: "CRITICAL,HIGH"
exit-code: '1'
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: "trivy-image-results.sarif"
category: "trivy-docker-image"
- name: Build and push
uses: docker/build-push-action@v7
with:
context: .
platforms: linux/amd64,linux/arm64
file: docker/Dockerfile
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.docker-meta.outputs.tags }}
+4 -3
View File
@@ -13,16 +13,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: "^1"
check-latest: true
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v5
uses: goreleaser/goreleaser-action@v7
with:
# either 'goreleaser' (default) or 'goreleaser-pro'
distribution: goreleaser
-44
View File
@@ -1,44 +0,0 @@
name: Lint and Testing
on:
push:
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Setup go
uses: actions/setup-go@v5
with:
go-version: "^1"
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup golangci-lint
uses: golangci/golangci-lint-action@v5
with:
version: latest
args: --verbose
- uses: hadolint/hadolint-action@v3.1.0
name: hadolint for Dockerfile
with:
dockerfile: docker/Dockerfile
testing:
runs-on: ubuntu-latest
container: golang:1.22-alpine
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: setup sshd server
run: |
apk add git make curl perl bash build-base zlib-dev ucl-dev
- name: testing
run: |
make test
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
+72
View File
@@ -0,0 +1,72 @@
name: Lint and Testing
on:
push:
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Setup go
uses: actions/setup-go@v6
with:
go-version: "^1"
check-latest: true
- name: Checkout repository
uses: actions/checkout@v6
- name: Setup golangci-lint
uses: golangci/golangci-lint-action@v9
with:
version: v2.12
args: --verbose
- uses: hadolint/hadolint-action@v3.3.0
name: hadolint for Dockerfile
with:
dockerfile: docker/Dockerfile
test:
strategy:
matrix:
os: [ubuntu-latest]
go: [1.25, 1.26]
include:
- os: ubuntu-latest
go-build: ~/.cache/go-build
name: ${{ matrix.os }} @ Go ${{ matrix.go }}
runs-on: ${{ matrix.os }}
env:
GO111MODULE: on
GOPROXY: https://proxy.golang.org
steps:
- name: Set up Go ${{ matrix.go }}
uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go }}
check-latest: true
- name: Checkout Code
uses: actions/checkout@v6
with:
ref: ${{ github.ref }}
- uses: actions/cache@v5
with:
path: |
${{ matrix.go-build }}
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run Tests
env:
WEBHOOK_ID: ${{ secrets.WEBHOOK_ID }}
WEBHOOK_TOKEN: ${{ secrets.WEBHOOK_TOKEN }}
run: |
go test -v -covermode=atomic -coverprofile=coverage.out
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v6
with:
flags: ${{ matrix.os }},go-${{ matrix.go }}
+84
View File
@@ -0,0 +1,84 @@
name: Trivy Security Scan
on:
push:
branches:
- master
pull_request:
branches:
- master
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
permissions:
contents: read
security-events: write
jobs:
trivy-repo-scan:
name: Trivy Repository Scan
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Run Trivy vulnerability scanner (repo)
uses: aquasecurity/trivy-action@v0.36.0
with:
scan-type: "fs"
scan-ref: "."
format: "sarif"
output: "trivy-repo-results.sarif"
severity: "CRITICAL,HIGH"
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: "trivy-repo-results.sarif"
trivy-image-scan:
name: Trivy Image Scan
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Setup go
uses: actions/setup-go@v6
with:
go-version-file: go.mod
check-latest: true
- name: Build binary
run: |
make build_linux_amd64
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build Docker image for scanning
uses: docker/build-push-action@v7
with:
context: .
file: docker/Dockerfile
platforms: linux/amd64
push: false
load: true
tags: drone-discord:scan
- name: Run Trivy vulnerability scanner (image)
uses: aquasecurity/trivy-action@v0.36.0
with:
image-ref: "drone-discord:scan"
format: "sarif"
output: "trivy-image-results.sarif"
severity: "CRITICAL,HIGH"
- name: Upload Trivy image scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: "trivy-image-results.sarif"
category: "trivy-image"
+54
View File
@@ -0,0 +1,54 @@
version: "2"
linters:
enable:
- asciicheck
- durationcheck
- errorlint
- gosec
- misspell
- nakedret
- nilerr
- nolintlint
- perfsprint
- revive
- usestdlibvars
- wastedassign
settings:
gosec:
includes:
- G102
- G106
- G108
- G109
- G111
- G112
- G201
- G203
perfsprint:
int-conversion: true
err-error: true
errorf: true
sprintf1: true
strconcat: true
exclusions:
generated: lax
presets:
- 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:
- glob: ./**.xz
name_template: "Drone Discord {{.Version}}"
changelog:
use: github
groups:
+29 -1
View File
@@ -7,7 +7,7 @@ author: appleboy
tags: [ notifications, chat ]
repo: appleboy/drone-discord
logo: discord.svg
icon: https://raw.githubusercontent.com/appleboy/drone-discord/main/images/discord-mark-blue.svg
icon: https://raw.githubusercontent.com/appleboy/drone-discord/master/images/discord-mark-blue.svg
image: appleboy/drone-discord
containerImage: appleboy/drone-discord
containerImageUrl: https://hub.docker.com/r/appleboy/drone-discord
@@ -197,3 +197,31 @@ urlencode
since
: 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.
+3 -62
View File
@@ -1,19 +1,8 @@
DIST := dist
EXECUTABLE := drone-discord
GOFMT ?= gofumpt -l
DIST := dist
DIST_DIRS := $(DIST)/binaries $(DIST)/release
GOFMT ?= gofumpt -l -w
GO ?= go
SHASUM ?= shasum -a 256
GOFILES := $(shell find . -name "*.go" -type f)
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
XGO_VERSION := go-1.19.x
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11
LINUX_ARCHS ?= linux/amd64,linux/arm64
DARWIN_ARCHS ?= darwin-10.12/amd64,darwin-10.12/arm64
WINDOWS_ARCHS ?= windows/*
ifneq ($(shell uname), Darwin)
EXTLDFLAGS = -extldflags "-static" $(null)
@@ -53,7 +42,7 @@ all: build
fmt:
@hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install mvdan.cc/gofumpt; \
$(GO) install mvdan.cc/gofumpt@latest; \
fi
$(GOFMT) -w $(GOFILES)
@@ -89,57 +78,9 @@ build_linux_amd64:
build_linux_arm64:
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $(GO) build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/arm64/$(DEPLOY_IMAGE)
build_linux_arm:
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 $(GO) build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/arm/$(DEPLOY_IMAGE)
.PHONY: deps-backend
deps-backend:
$(GO) mod download
$(GO) install $(GXZ_PAGAGE)
$(GO) install $(XGO_PACKAGE)
.PHONY: release
release: release-linux release-darwin release-windows release-copy release-compress release-check
$(DIST_DIRS):
mkdir -p $(DIST_DIRS)
.PHONY: release-windows
release-windows: | $(DIST_DIRS)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(WINDOWS_ARCHS)' -out $(EXECUTABLE)-$(VERSION) .
ifeq ($(CI),true)
cp -r /build/* $(DIST)/binaries/
endif
.PHONY: release-linux
release-linux: | $(DIST_DIRS)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out $(EXECUTABLE)-$(VERSION) .
ifeq ($(CI),true)
cp -r /build/* $(DIST)/binaries/
endif
.PHONY: release-darwin
release-darwin: | $(DIST_DIRS)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets '$(DARWIN_ARCHS)' -out $(EXECUTABLE)-$(VERSION) .
ifeq ($(CI),true)
cp -r /build/* $(DIST)/binaries/
endif
.PHONY: release-copy
release-copy: | $(DIST_DIRS)
cd $(DIST); for file in `find . -type f -name "*"`; do cp $${file} ./release/; done;
.PHONY: release-check
release-check: | $(DIST_DIRS)
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "checksumming $${file}" && $(SHASUM) `echo $${file} | sed 's/^..//'` > $${file}.sha256; done;
.PHONY: release-compress
release-compress: | $(DIST_DIRS)
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && $(GO) run $(GXZ_PAGAGE) -k -9 $${file}; done;
clean:
$(GO) clean -x -i ./...
rm -rf coverage.txt $(EXECUTABLE) $(DIST)
rm -rf coverage.txt $(EXECUTABLE)
version:
@echo $(VERSION)
+20 -19
View File
@@ -2,37 +2,38 @@
![logo](images/discord-logo.png)
[Drone](https://www.drone.io/) / [Woodpecker](https://woodpecker-ci.org/) plugin for sending message to Discord channel using Webhook.
[Drone](https://www.drone.io/) / [Woodpecker](https://woodpecker-ci.org/) plugin for sending messages to Discord channels using Webhooks.
[![GoDoc](https://godoc.org/github.com/appleboy/drone-discord?status.svg)](https://godoc.org/github.com/appleboy/drone-discord)
[![Trivy Security Scan](https://github.com/appleboy/drone-discord/actions/workflows/trivy.yml/badge.svg?branch=master)](https://github.com/appleboy/drone-discord/actions/workflows/trivy.yml)
[![codecov](https://codecov.io/gh/appleboy/drone-discord/branch/master/graph/badge.svg)](https://codecov.io/gh/appleboy/drone-discord)
[![Go Report Card](https://goreportcard.com/badge/github.com/appleboy/drone-discord)](https://goreportcard.com/report/github.com/appleboy/drone-discord)
[![Docker Pulls](https://img.shields.io/docker/pulls/appleboy/drone-discord.svg)](https://hub.docker.com/r/appleboy/drone-discord/)
Webhooks are a low-effort way to post messages to channels in Discord. They do not require a bot user or authentication to use. See more [api document information](https://discordapp.com/developers/docs/resources/webhook). For the usage information and a listing of the available options please take a look at [the docs](http://plugins.drone.io/appleboy/drone-discord/).
Webhooks are a low-effort way to post messages to channels in Discord. They do not require a bot user or authentication to use. See more [API documentation](https://discordapp.com/developers/docs/resources/webhook). For usage information and a list of available options, please refer to [the documentation](http://plugins.drone.io/appleboy/drone-discord/).
Sending discord message using a binary, docker or [Drone CI](http://docs.drone.io/).
Send Discord messages using a binary, Docker, or [Drone CI](http://docs.drone.io/).
## Features
* [x] Send Multiple Messages
* [x] Send Multiple Files
- [x] Send Multiple Messages
- [x] Send Multiple Files
## Build or Download a binary
The pre-compiled binaries can be downloaded from [release page](https://github.com/appleboy/drone-discord/releases). Support the following OS type.
The pre-compiled binaries can be downloaded from the [release page](https://github.com/appleboy/drone-discord/releases). The following OS types are supported:
* Windows amd64/386
* Linux arm/amd64/386
* Darwin amd64/386
- Windows amd64/386
- Linux arm/amd64/386
- Darwin amd64/386
With `Go` installed
With `Go` installed:
```sh
go get -u -v github.com/appleboy/drone-discord
```
or build the binary with the following command:
Or build the binary with the following command:
```sh
export GOOS=linux
@@ -47,9 +48,9 @@ go build -v -a -tags netgo -o release/linux/amd64/drone-discord
## Usage
There are three ways to send notification.
There are three ways to send notifications:
### Usage from binary
### Usage from Binary
```bash
drone-discord \
@@ -58,7 +59,7 @@ drone-discord \
--message "Test Message"
```
### Usage from docker
### Usage from Docker
```bash
docker run --rm \
@@ -72,7 +73,7 @@ docker run --rm \
appleboy/drone-discord
```
### Usage from drone ci
### Usage from Drone CI
#### Send Notification
@@ -104,9 +105,9 @@ docker run --rm \
appleboy/drone-discord
```
## Declarative environment config usage
## Declarative Environment Config Usage
You can get more [information](DOCS.md) about how to use this plugin in drone.
You can get more [information](DOCS.md) about how to use this plugin in Drone.
```yml
- name: msg status
@@ -118,11 +119,11 @@ You can get more [information](DOCS.md) about how to use this plugin in drone.
from_secret: discord_token
message: "{{#success build.status}}✅{{else}}❌{{/success}} Repository `[{{repo.name}}/{{commit.branch}}]` triggered by event `[{{uppercase build.event}}]` for build.\n - Commit [[{{commit.sha}}]({{commit.link}})]\n - Author `[{{commit.author}} / {{commit.email}}]`\n - Message: {{commit.message}} - Drone build [[#{{build.number}}]({{build.link}})] reported `[{{uppercase build.status}}]` at `[{{datetime build.finished \"2006.01.02 15:04\" \"\"}}]`\n"
when:
status: [ success, failure, changed ]
status: [success, failure, changed]
```
```yml
- name: multi line msg status
- name: multi line msg status
...
message: >
Line one
+7 -8
View File
@@ -2,19 +2,18 @@
//
// Details about the drone-discord project are found in github page:
//
// https://github.com/appleboy/drone-discord
// https://github.com/appleboy/drone-discord
//
// The pre-compiled binaries can be downloaded from release page.
//
// Send Notification
//
// drone-discord \
// --webhook-id xxxx \
// --webhook-token xxxx \
// --username value \
// --avatar-url value \
// --message "Test Message"
// drone-discord \
// --webhook-id xxxx \
// --webhook-token xxxx \
// --username value \
// --avatar-url value \
// --message "Test Message"
//
// For more details, see the documentation and example.
//
package main
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.17
FROM alpine:3.23
ARG TARGETOS
ARG TARGETARCH
+13 -11
View File
@@ -1,23 +1,24 @@
module github.com/appleboy/drone-discord
go 1.20
go 1.25.10
require (
github.com/appleboy/drone-template-lib v1.3.0
github.com/joho/godotenv v1.5.1
github.com/stretchr/testify v1.9.0
github.com/urfave/cli v1.22.15
github.com/stretchr/testify v1.10.0
github.com/urfave/cli/v2 v2.27.7
github.com/yassinebenaid/godump v0.11.1
)
require (
dario.cat/mergo v1.0.2 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/Masterminds/semver/v3 v3.4.0 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/mailgun/raymond/v2 v2.0.48 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
@@ -25,8 +26,9 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/cast v1.6.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/sys v0.19.0 // indirect
github.com/spf13/cast v1.9.2 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
golang.org/x/crypto v0.50.0 // indirect
golang.org/x/sys v0.43.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
+30 -67
View File
@@ -1,107 +1,70 @@
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
github.com/appleboy/drone-template-lib v1.3.0 h1:aX36/1za3v8JsEyBeMY1Bp/VNRtZa8qPYkfkjBszW+A=
github.com/appleboy/drone-template-lib v1.3.0/go.mod h1:edlmXkFMKYAVypff8r2oN7aFlHfOZE5sLyPEnRHONeA=
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw=
github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE=
github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/urfave/cli v1.22.15 h1:nuqt+pdC/KqswQKhETJjo7pvn/k4xMUxgW6liI7XpnM=
github.com/urfave/cli v1.22.15/go.mod h1:wSan1hmo5zeyLGBjRJbzRTNk8gwoYa2B9n4q9dmRIc0=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU=
github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
github.com/yassinebenaid/godump v0.11.1 h1:SPujx/XaYqGDfmNh7JI3dOyCUVrG0bG2duhO3Eh2EhI=
github.com/yassinebenaid/godump v0.11.1/go.mod h1:dc/0w8wmg6kVIvNGAzbKH1Oa54dXQx8SNKh4dPRyW44=
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+178 -162
View File
@@ -1,13 +1,14 @@
package main
import (
"fmt"
"log"
"os"
"strconv"
"time"
"github.com/joho/godotenv"
"github.com/urfave/cli"
"github.com/urfave/cli/v2"
"github.com/yassinebenaid/godump"
)
// Version set at compile-time
@@ -23,12 +24,11 @@ func main() {
_ = godotenv.Overload("/run/drone/env")
}
year := fmt.Sprintf("%v", time.Now().Year())
app := cli.NewApp()
app.Name = "Drone Discord"
app.Usage = "Sending message to Discord channel using Webhook"
app.Copyright = "Copyright (c) " + year + " Bo-Yi Wu"
app.Authors = []cli.Author{
app.Copyright = "Copyright (c) " + strconv.Itoa(time.Now().Year()) + " Bo-Yi Wu"
app.Authors = []*cli.Author{
{
Name: "Bo-Yi Wu",
Email: "appleboy.tw@gmail.com",
@@ -37,199 +37,209 @@ func main() {
app.Action = run
app.Version = Version
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "webhook-id",
Usage: "discord webhook id",
EnvVar: "PLUGIN_WEBHOOK_ID,WEBHOOK_ID,DISCORD_WEBHOOK_ID,INPUT_WEBHOOK_ID",
&cli.StringFlag{
Name: "webhook-url",
Usage: "The Discord webhook URL to send messages to.",
EnvVars: []string{"PLUGIN_WEBHOOK_URL", "WEBHOOK_URL", "DISCORD_WEBHOOK_URL", "INPUT_WEBHOOK_URL"},
},
cli.StringFlag{
Name: "webhook-token",
Usage: "discord webhook token",
EnvVar: "PLUGIN_WEBHOOK_TOKEN,WEBHOOK_TOKEN,DISCORD_WEBHOOK_TOKEN,INPUT_WEBHOOK_TOKEN",
&cli.StringFlag{
Name: "webhook-id",
Usage: "The Discord webhook ID.",
EnvVars: []string{"PLUGIN_WEBHOOK_ID", "WEBHOOK_ID", "DISCORD_WEBHOOK_ID", "INPUT_WEBHOOK_ID"},
},
cli.StringSliceFlag{
Name: "message",
Usage: "the message contents (up to 2000 characters)",
EnvVar: "PLUGIN_MESSAGE,DISCORD_MESSAGE,MESSAGE,INPUT_MESSAGE",
&cli.StringFlag{
Name: "webhook-token",
Usage: "The Discord webhook token.",
EnvVars: []string{"PLUGIN_WEBHOOK_TOKEN", "WEBHOOK_TOKEN", "DISCORD_WEBHOOK_TOKEN", "INPUT_WEBHOOK_TOKEN"},
},
cli.StringSliceFlag{
Name: "file",
Usage: "the contents of the file being sent",
EnvVar: "PLUGIN_FILE,DISCORD_FILE,FILE,INPUT_FILE",
&cli.StringSliceFlag{
Name: "message",
Usage: "The message contents to send to the Discord channel (up to 2000 characters).",
EnvVars: []string{"PLUGIN_MESSAGE", "DISCORD_MESSAGE", "MESSAGE", "INPUT_MESSAGE"},
},
cli.StringFlag{
Name: "color",
Usage: "color code of the embed",
EnvVar: "PLUGIN_COLOR,COLOR,INPUT_COLOR",
&cli.StringSliceFlag{
Name: "file",
Usage: "The contents of the file being sent to the Discord channel.",
EnvVars: []string{"PLUGIN_FILE", "DISCORD_FILE", "FILE", "INPUT_FILE"},
},
cli.BoolFlag{
Name: "wait",
Usage: "waits for server confirmation of message send before response, and returns the created message body",
EnvVar: "PLUGIN_WAIT,WAIT,INPUT_WAIT",
&cli.StringFlag{
Name: "color",
Usage: "The color code of the embed message.",
EnvVars: []string{"PLUGIN_COLOR", "COLOR", "INPUT_COLOR"},
},
cli.BoolFlag{
Name: "tts",
Usage: "true if this is a TTS message",
EnvVar: "PLUGIN_TTS,TTS,INPUT_TTS",
&cli.BoolFlag{
Name: "wait",
Usage: "Wait for server confirmation of message send before response, and return the created message body.",
EnvVars: []string{"PLUGIN_WAIT", "WAIT", "INPUT_WAIT"},
},
cli.StringFlag{
Name: "username",
Usage: "override the default username of the webhook",
EnvVar: "PLUGIN_USERNAME,USERNAME,INPUT_USERNAME",
&cli.BoolFlag{
Name: "tts",
Usage: "Set to true if this is a Text-to-Speech (TTS) message.",
EnvVars: []string{"PLUGIN_TTS", "TTS", "INPUT_TTS"},
},
cli.StringFlag{
Name: "avatar-url",
Usage: "override the default avatar of the webhook",
EnvVar: "PLUGIN_AVATAR_URL,AVATAR_URL,INPUT_AVATAR_URL",
&cli.StringFlag{
Name: "username",
Usage: "Override the default username of the webhook.",
EnvVars: []string{"PLUGIN_USERNAME", "USERNAME", "INPUT_USERNAME"},
},
cli.BoolFlag{
Name: "drone",
Usage: "environment is drone",
EnvVar: "DRONE",
&cli.StringFlag{
Name: "avatar-url",
Usage: "Override the default avatar of the webhook.",
EnvVars: []string{"PLUGIN_AVATAR_URL", "AVATAR_URL", "INPUT_AVATAR_URL"},
},
cli.StringFlag{
Name: "ci.environment",
Usage: "ci environment name",
EnvVar: "CI",
&cli.BoolFlag{
Name: "drone",
Usage: "Indicate if the environment is Drone CI.",
EnvVars: []string{"DRONE"},
},
cli.StringFlag{
Name: "repo",
Usage: "repository owner and repository name",
EnvVar: "DRONE_REPO,CI_REPO,GITHUB_REPOSITORY",
&cli.StringFlag{
Name: "ci.environment",
Usage: "The name of the CI environment.",
EnvVars: []string{"CI"},
},
cli.StringFlag{
Name: "repo.namespace",
Usage: "repository namespace",
EnvVar: "DRONE_REPO_OWNER,DRONE_REPO_NAMESPACE,CI_REPO_OWNER,GITHUB_ACTOR",
&cli.StringFlag{
Name: "repo",
Usage: "The repository owner and repository name.",
EnvVars: []string{"DRONE_REPO", "CI_REPO", "GITHUB_REPOSITORY"},
},
cli.StringFlag{
Name: "repo.name",
Usage: "repository name",
EnvVar: "DRONE_REPO_NAME,CI_REPO_NAME",
&cli.StringFlag{
Name: "repo.namespace",
Usage: "The repository namespace.",
EnvVars: []string{"DRONE_REPO_OWNER", "DRONE_REPO_NAMESPACE", "CI_REPO_OWNER", "GITHUB_ACTOR"},
},
cli.StringFlag{
Name: "commit.sha",
Usage: "git commit sha",
EnvVar: "DRONE_COMMIT_SHA,CI_COMMIT_SHA,GITHUB_SHA",
&cli.StringFlag{
Name: "repo.name",
Usage: "The repository name.",
EnvVars: []string{"DRONE_REPO_NAME", "CI_REPO_NAME"},
},
cli.StringFlag{
Name: "commit.ref",
Usage: "git commit ref",
EnvVar: "DRONE_COMMIT_REF,CI_COMMIT_REF,GITHUB_REF",
&cli.StringFlag{
Name: "commit.sha",
Usage: "The Git commit SHA.",
EnvVars: []string{"DRONE_COMMIT_SHA", "CI_COMMIT_SHA", "GITHUB_SHA"},
},
cli.StringFlag{
Name: "commit.branch",
Value: "master",
Usage: "git commit branch",
EnvVar: "DRONE_COMMIT_BRANCH,CI_COMMIT_BRANCH",
&cli.StringFlag{
Name: "commit.ref",
Usage: "The Git commit reference.",
EnvVars: []string{"DRONE_COMMIT_REF", "CI_COMMIT_REF", "GITHUB_REF"},
},
cli.StringFlag{
Name: "commit.link",
Usage: "git commit link",
EnvVar: "DRONE_COMMIT_LINK,CI_PIPELINE_FORGE_URL",
&cli.StringFlag{
Name: "commit.branch",
Value: "master",
Usage: "The Git commit branch.",
EnvVars: []string{"DRONE_COMMIT_BRANCH", "CI_COMMIT_BRANCH"},
},
cli.StringFlag{
Name: "commit.author",
Usage: "git author name",
EnvVar: "DRONE_COMMIT_AUTHOR,CI_COMMIT_AUTHOR",
&cli.StringFlag{
Name: "commit.link",
Usage: "The link to the Git commit.",
EnvVars: []string{"DRONE_COMMIT_LINK", "CI_PIPELINE_FORGE_URL"},
},
cli.StringFlag{
Name: "commit.author.email",
Usage: "git author email",
EnvVar: "DRONE_COMMIT_AUTHOR_EMAIL,CI_COMMIT_AUTHOR_EMAIL",
&cli.StringFlag{
Name: "commit.author",
Usage: "The name of the Git commit author.",
EnvVars: []string{"DRONE_COMMIT_AUTHOR", "CI_COMMIT_AUTHOR"},
},
cli.StringFlag{
Name: "commit.author.avatar",
Usage: "git author avatar",
EnvVar: "DRONE_COMMIT_AUTHOR_AVATAR,CI_COMMIT_AUTHOR_AVATAR",
&cli.StringFlag{
Name: "commit.author.email",
Usage: "The email of the Git commit author.",
EnvVars: []string{"DRONE_COMMIT_AUTHOR_EMAIL", "CI_COMMIT_AUTHOR_EMAIL"},
},
cli.StringFlag{
Name: "commit.message",
Usage: "commit message",
EnvVar: "DRONE_COMMIT_MESSAGE,CI_COMMIT_MESSAGE",
&cli.StringFlag{
Name: "commit.author.avatar",
Usage: "The avatar URL of the Git commit author.",
EnvVars: []string{"DRONE_COMMIT_AUTHOR_AVATAR", "CI_COMMIT_AUTHOR_AVATAR"},
},
cli.StringFlag{
Name: "source.branch",
Value: "develop",
Usage: "git source branch",
EnvVar: "DRONE_SOURCE_BRANCH,CI_COMMIT_SOURCE_BRANCH",
&cli.StringFlag{
Name: "commit.message",
Usage: "The Git commit message.",
EnvVars: []string{"DRONE_COMMIT_MESSAGE", "CI_COMMIT_MESSAGE"},
},
cli.StringFlag{
Name: "build.event",
Value: "push",
Usage: "build event",
EnvVar: "DRONE_BUILD_EVENT,CI_PIPELINE_EVENT",
&cli.StringFlag{
Name: "source.branch",
Value: "develop",
Usage: "The Git source branch.",
EnvVars: []string{"DRONE_SOURCE_BRANCH", "CI_COMMIT_SOURCE_BRANCH"},
},
cli.IntFlag{
Name: "build.number",
Usage: "build number",
EnvVar: "DRONE_BUILD_NUMBER,CI_PIPELINE_NUMBER",
&cli.StringFlag{
Name: "build.event",
Value: "push",
Usage: "The build event type.",
EnvVars: []string{"DRONE_BUILD_EVENT", "CI_PIPELINE_EVENT"},
},
cli.StringFlag{
Name: "build.status",
Usage: "build status",
Value: "success",
EnvVar: "DRONE_BUILD_STATUS,CI_PIPELINE_STATUS",
&cli.IntFlag{
Name: "build.number",
Usage: "The build number.",
EnvVars: []string{"DRONE_BUILD_NUMBER", "CI_PIPELINE_NUMBER"},
},
cli.StringFlag{
Name: "build.link",
Usage: "build link",
EnvVar: "DRONE_BUILD_LINK,CI_PIPELINE_URL",
&cli.StringFlag{
Name: "build.status",
Usage: "The build status.",
Value: "success",
EnvVars: []string{"DRONE_BUILD_STATUS", "CI_PIPELINE_STATUS"},
},
cli.StringFlag{
Name: "build.tag",
Usage: "build tag",
EnvVar: "DRONE_TAG,CI_COMMIT_TAG",
&cli.StringFlag{
Name: "build.link",
Usage: "The link to the build.",
EnvVars: []string{"DRONE_BUILD_LINK", "CI_PIPELINE_URL"},
},
cli.StringFlag{
Name: "pull.request",
Usage: "pull request",
EnvVar: "DRONE_PULL_REQUEST,CI_COMMIT_PULL_REQUEST",
&cli.StringFlag{
Name: "build.tag",
Usage: "The build tag.",
EnvVars: []string{"DRONE_TAG", "CI_COMMIT_TAG"},
},
cli.Int64Flag{
Name: "build.started",
Usage: "build started",
EnvVar: "DRONE_BUILD_STARTED,CI_PIPELINE_STARTED",
&cli.StringFlag{
Name: "pull.request",
Usage: "The pull request number.",
EnvVars: []string{"DRONE_PULL_REQUEST", "CI_COMMIT_PULL_REQUEST"},
},
cli.Int64Flag{
Name: "build.finished",
Usage: "build finished",
EnvVar: "DRONE_BUILD_FINISHED,CI_PIPELINE_FINISHED",
&cli.Int64Flag{
Name: "build.started",
Usage: "The timestamp when the build started.",
EnvVars: []string{"DRONE_BUILD_STARTED", "CI_PIPELINE_STARTED"},
},
cli.BoolFlag{
Name: "github",
Usage: "Boolean value, indicates the runtime environment is GitHub Action.",
EnvVar: "PLUGIN_GITHUB,GITHUB",
&cli.Int64Flag{
Name: "build.finished",
Usage: "The timestamp when the build finished.",
EnvVars: []string{"DRONE_BUILD_FINISHED", "CI_PIPELINE_FINISHED"},
},
cli.StringFlag{
Name: "github.workflow",
Usage: "The name of the workflow.",
EnvVar: "GITHUB_WORKFLOW",
&cli.BoolFlag{
Name: "github",
Usage: "Indicate if the runtime environment is GitHub Actions.",
EnvVars: []string{"PLUGIN_GITHUB", "GITHUB"},
},
cli.StringFlag{
Name: "github.action",
Usage: "The name of the action.",
EnvVar: "GITHUB_ACTION",
&cli.StringFlag{
Name: "github.workflow",
Usage: "The name of the GitHub Actions workflow.",
EnvVars: []string{"GITHUB_WORKFLOW"},
},
cli.StringFlag{
Name: "github.event.name",
Usage: "The webhook name of the event that triggered the workflow.",
EnvVar: "GITHUB_EVENT_NAME",
&cli.StringFlag{
Name: "github.action",
Usage: "The name of the GitHub Actions action.",
EnvVars: []string{"GITHUB_ACTION"},
},
cli.StringFlag{
Name: "github.event.path",
Usage: "The path to a file that contains the payload of the event that triggered the workflow. Value: /github/workflow/event.json.",
EnvVar: "GITHUB_EVENT_PATH",
&cli.StringFlag{
Name: "github.event.name",
Usage: "The name of the GitHub event that triggered the workflow.",
EnvVars: []string{"GITHUB_EVENT_NAME"},
},
cli.StringFlag{
Name: "github.workspace",
Usage: "The GitHub workspace path. Value: /github/workspace.",
EnvVar: "GITHUB_WORKSPACE",
&cli.StringFlag{
Name: "github.event.path",
Usage: "The path to the file containing the payload of the event that triggered the workflow. Default: /github/workflow/event.json",
EnvVars: []string{"GITHUB_EVENT_PATH"},
},
cli.StringFlag{
Name: "deploy.to",
Usage: "Provides the target deployment environment for the running build. This value is only available to promotion and rollback pipelines.",
EnvVar: "DRONE_DEPLOY_TO,CI_PIPELINE_DEPLOY_TARGET",
&cli.StringFlag{
Name: "github.workspace",
Usage: "The GitHub workspace path. Default: /github/workspace",
EnvVars: []string{"GITHUB_WORKSPACE"},
},
&cli.StringFlag{
Name: "deploy.to",
Usage: "The target deployment environment for the running build. This value is only available to promotion and rollback pipelines.",
EnvVars: []string{"DRONE_DEPLOY_TO", "CI_PIPELINE_DEPLOY_TARGET"},
},
&cli.BoolFlag{
Name: "debug",
Usage: "Enable debug mode.",
EnvVars: []string{"PLUGIN_DEBUG", "INPUT_DEBUG", "DEBUG"},
},
}
@@ -277,6 +287,7 @@ func run(c *cli.Context) error {
DeployTo: c.String("deploy.to"),
},
Config: Config{
webhookURL: c.String("webhook-url"),
WebhookID: c.String("webhook-id"),
WebhookToken: c.String("webhook-token"),
Message: c.StringSlice("message"),
@@ -284,6 +295,7 @@ func run(c *cli.Context) error {
Color: c.String("color"),
Drone: c.Bool("drone") || c.String("ci.environment") == "woodpecker",
GitHub: c.Bool("github"),
Debug: c.Bool("debug"),
},
Payload: Payload{
Wait: c.Bool("wait"),
@@ -293,5 +305,9 @@ func run(c *cli.Context) error {
},
}
return plugin.Exec()
if plugin.Config.Debug {
_ = godump.Dump(plugin)
}
return plugin.Exec(c.Context)
}
+208 -107
View File
@@ -2,16 +2,18 @@ package main
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/url"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/appleboy/drone-template-lib/template"
)
@@ -71,6 +73,7 @@ type (
// Config for the plugin.
Config struct {
webhookURL string
WebhookID string
WebhookToken string
Color string
@@ -78,6 +81,7 @@ type (
File []string
Drone bool
GitHub bool
Debug bool
}
// EmbedFooterObject for Embed Footer Structure.
@@ -122,110 +126,182 @@ type (
// Plugin values.
Plugin struct {
GitHub GitHub
Repo Repo
Build Build
Source Source
Config Config
Payload Payload
Commit Commit
GitHub GitHub
Repo Repo
Build Build
Source Source
Config Config
Payload Payload
Commit Commit
httpClient *http.Client
}
)
func (c *Config) validate() error {
if c.webhookURL != "" {
if _, err := url.Parse(c.webhookURL); err != nil {
return fmt.Errorf("invalid webhook url: %w", err)
}
return nil
}
var missingFields []string
if c.WebhookID == "" {
missingFields = append(missingFields, "WebhookID")
}
if c.WebhookToken == "" {
missingFields = append(missingFields, "WebhookToken")
}
if len(missingFields) > 0 {
return fmt.Errorf("missing discord config: %s", strings.Join(missingFields, ", "))
}
return nil
}
// Get WebhookURL
func (c *Config) GetWebhookURL() string {
if c.webhookURL != "" {
return c.webhookURL
}
return fmt.Sprintf("https://discord.com/api/webhooks/%s/%s", c.WebhookID, c.WebhookToken)
}
func templateMessage(t string, plugin Plugin) (string, error) {
return template.RenderTrim(t, plugin)
}
// Creates a new file upload http request with optional extra params
// https://matt.aimonetti.net/posts/2013/07/01/golang-multipart-file-upload-example/
func newfileUploadRequest(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) {
// Clean and check path
path = filepath.Clean(path)
file, err := os.Open(path)
if err != nil {
return nil, err
return nil, fmt.Errorf("file %s not accessible: %w", path, err)
}
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
// Add file
part, err := writer.CreateFormFile(paramName, filepath.Base(path))
if err != nil {
return nil, err
}
_, err = io.Copy(part, file)
if err != nil {
return nil, err
}
for key, val := range params {
_ = writer.WriteField(key, val)
}
err = writer.Close()
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to create form file: %w", err)
}
req, err := http.NewRequest("POST", uri, body)
// Stream file content
if _, err = io.Copy(part, file); err != nil {
return nil, fmt.Errorf("failed to write file content: %w", err)
}
// Add extra params
for key, val := range params {
if err = writer.WriteField(key, val); err != nil {
return nil, fmt.Errorf("failed to write field %s: %w", key, err)
}
}
if err = writer.Close(); err != nil {
return nil, fmt.Errorf("failed to close multipart writer: %w", err)
}
// Create request
req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, body)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", writer.FormDataContentType())
return req, err
return req, nil
}
// Exec executes the plugin.
func (p *Plugin) Exec() error {
if p.Config.WebhookID == "" || p.Config.WebhookToken == "" {
return errors.New("missing discord config")
func (p *Plugin) Exec(ctx context.Context) error {
// init http client
p.httpClient = &http.Client{
Timeout: 15 * time.Second,
}
if err := p.Config.validate(); err != nil {
return fmt.Errorf("failed to validate config: %w", err)
}
if err := p.handleMessages(ctx); err != nil {
return err
}
if err := p.handleFiles(ctx); err != nil {
return err
}
return nil
}
// handleMessages sends all configured messages.
func (p *Plugin) handleMessages(ctx context.Context) error {
// 1. Handle empty message (default template)
if len(p.Config.Message) == 0 {
object := p.Template()
p.Payload.Embeds = []EmbedObject{object}
err := p.SendMessage()
if err != nil {
return err
if err := p.SendMessage(ctx); err != nil {
return fmt.Errorf("failed to send default message: %w", err)
}
return nil
}
if len(p.Config.Message) > 0 {
for _, m := range p.Config.Message {
txt, err := templateMessage(m, *p)
if err != nil {
return err
}
if len(p.Config.Color) != 0 {
object := p.DefaultTemplate(txt)
p.Payload.Embeds = append(p.Payload.Embeds, object)
} else {
p.Payload.Content = txt
err = p.SendMessage()
if err != nil {
return err
}
}
}
if len(p.Payload.Embeds) > 0 {
err := p.SendMessage()
if err != nil {
return err
}
}
}
for _, f := range p.Config.File {
if f == "" {
// 2. Handle custom messages
for _, m := range p.Config.Message {
if m == "" {
continue
}
err := p.SendFile(f)
txt, err := templateMessage(m, *p)
if err != nil {
return err
return fmt.Errorf("failed to render template: %w", err)
}
// With color, messages are grouped as embeds
if p.Config.Color != "" {
object := p.DefaultTemplate(txt)
p.Payload.Embeds = append(p.Payload.Embeds, object)
} else {
// Without color, send as plain text immediately
p.Payload.Content = txt
if err := p.SendMessage(ctx); err != nil {
return fmt.Errorf("failed to send plain text message: %w", err)
}
// Reset for next message
p.Clear()
}
}
// 3. Send grouped embeds if any
if len(p.Payload.Embeds) > 0 {
if err := p.SendMessage(ctx); err != nil {
return fmt.Errorf("failed to send embed messages: %w", err)
}
}
return nil
}
// handleFiles sends all configured files.
func (p *Plugin) handleFiles(ctx context.Context) error {
for _, f := range p.Config.File {
if f == "" {
continue
}
if err := p.SendFile(ctx, f); err != nil {
return fmt.Errorf("failed to send file %s: %w", f, err)
}
}
return nil
}
// SendFile upload file to discord
func (p *Plugin) SendFile(file string) error {
webhookURL := fmt.Sprintf("https://discord.com/api/webhooks/%s/%s", p.Config.WebhookID, p.Config.WebhookToken)
func (p *Plugin) SendFile(ctx context.Context, file string) error {
webhookURL := p.Config.GetWebhookURL()
extraParams := map[string]string{}
if p.Payload.Username != "" {
@@ -240,34 +316,69 @@ func (p *Plugin) SendFile(file string) error {
extraParams["tts"] = "true"
}
request, err := newfileUploadRequest(
request, err := fileUploadRequest(
ctx,
webhookURL,
extraParams,
"file",
file,
)
if err != nil {
return err
return fmt.Errorf("failed to create file upload request: %w", err)
}
client := &http.Client{}
_, err = client.Do(request)
resp, err := p.httpClient.Do(request)
if err != nil {
return err
return fmt.Errorf("failed to send file: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode >= http.StatusBadRequest {
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}
var jsonResponse map[string]interface{}
if err := json.Unmarshal(bodyBytes, &jsonResponse); err != nil {
return fmt.Errorf("failed to send file, status code: %d, body: %s", resp.StatusCode, string(bodyBytes))
}
return fmt.Errorf("failed to send file, status code: %d, error: %s, code: %v", resp.StatusCode, jsonResponse["message"], jsonResponse["code"])
}
return nil
}
// SendMessage to send discord message.
func (p *Plugin) SendMessage() error {
webhookURL := fmt.Sprintf("https://discordapp.com/api/webhooks/%s/%s", p.Config.WebhookID, p.Config.WebhookToken)
func (p *Plugin) SendMessage(ctx context.Context) error {
webhookURL := p.Config.GetWebhookURL()
b := new(bytes.Buffer)
if err := json.NewEncoder(b).Encode(p.Payload); err != nil {
return err
return fmt.Errorf("failed to encode payload: %w", err)
}
_, err := http.Post(webhookURL, "application/json; charset=utf-8", b)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, webhookURL, b)
if err != nil {
return err
return fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
resp, err := p.httpClient.Do(req)
if err != nil {
return fmt.Errorf("failed to send message: %w", err)
}
defer resp.Body.Close()
// 200 and 204 are both valid status codes for webhooks.
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}
var jsonResponse map[string]interface{}
if err := json.Unmarshal(bodyBytes, &jsonResponse); err != nil {
return fmt.Errorf("failed to unmarshal response body: %w", err)
}
return fmt.Errorf("failed to send message, status code: %d, error: %s, code: %v", resp.StatusCode, jsonResponse["message"], jsonResponse["code"])
}
return nil
@@ -283,37 +394,24 @@ func (p *Plugin) DefaultTemplate(title string) EmbedObject {
// Template is plugin default template for Drone CI or GitHub Action.
func (p *Plugin) Template() EmbedObject {
if p.Config.GitHub {
message := fmt.Sprintf("%s/%s triggered by %s (%s)",
var description string
switch {
case p.Config.GitHub:
description = fmt.Sprintf("%s/%s triggered by %s (%s)",
p.Repo.FullName,
p.GitHub.Workflow,
p.Repo.Namespace,
p.GitHub.EventName,
)
return EmbedObject{
Title: message,
Color: p.Color(),
Footer: EmbedFooterObject{
Text: DroneDesc,
IconURL: DroneIconURL,
},
}
}
description := ""
switch p.Build.Event {
case "push":
case p.Build.Event == "push":
description = fmt.Sprintf("%s pushed to %s", p.Commit.Author, p.Commit.Branch)
case "pull_request":
branch := ""
if p.Commit.Ref != "" {
branch = p.Commit.Ref
} else {
case p.Build.Event == "pull_request":
branch := p.Commit.Ref
if branch == "" {
branch = p.Commit.Branch
}
description = fmt.Sprintf("%s updated pull request %s", p.Commit.Author, branch)
case "tag":
case p.Build.Event == "tag":
description = fmt.Sprintf("%s pushed tag %s", p.Commit.Author, p.Commit.Branch)
}
@@ -342,22 +440,25 @@ func (p *Plugin) Clear() {
// Color code of the embed
func (p *Plugin) Color() int {
// Handle custom color
if p.Config.Color != "" {
p.Config.Color = strings.Replace(p.Config.Color, "#", "", -1)
if s, err := strconv.ParseInt(p.Config.Color, 16, 32); err == nil {
cleanColor := strings.TrimPrefix(p.Config.Color, "#")
if s, err := strconv.ParseInt(cleanColor, 16, 32); err == nil {
return int(s)
}
}
switch p.Build.Status {
case "success":
// green
return 0x1ac600
case "failure", "error", "killed":
// red
return 0xff3232
default:
// yellow
return 0xffd930
// Predefined status colors
statusColors := map[string]int{
"success": 0x1ac600, // green
"failure": 0xff3232, // red
"error": 0xff3232, // red
"killed": 0xff3232, // red
"default": 0xffd930, // yellow
}
if color, exists := statusColors[p.Build.Status]; exists {
return color
}
return statusColors["default"]
}
+128 -72
View File
@@ -1,6 +1,7 @@
package main
import (
"context"
"os"
"testing"
"time"
@@ -9,14 +10,48 @@ import (
)
func TestMissingConfig(t *testing.T) {
var plugin Plugin
plugin := Plugin{}
err := plugin.Exec()
err := plugin.Exec(context.Background())
assert.NotNil(t, err)
assert.Error(t, err)
assert.Contains(t, err.Error(), "missing discord config")
}
func TestTemplate(t *testing.T) {
func TestSendPlainTextMessage(t *testing.T) {
plugin := Plugin{
Config: Config{
WebhookID: os.Getenv("WEBHOOK_ID"),
WebhookToken: os.Getenv("WEBHOOK_TOKEN"),
Message: []string{"Hello, world!", "This is a test."},
},
Payload: Payload{
Username: "test-bot",
},
}
err := plugin.Exec(context.Background())
assert.NoError(t, err)
}
func TestSendEmbedMessage(t *testing.T) {
plugin := Plugin{
Config: Config{
WebhookID: os.Getenv("WEBHOOK_ID"),
WebhookToken: os.Getenv("WEBHOOK_TOKEN"),
Message: []string{"This is an embed message."},
Color: "#48f442",
},
Payload: Payload{
Username: "embed-bot",
},
}
err := plugin.Exec(context.Background())
assert.NoError(t, err)
}
func TestSendDefaultMessage(t *testing.T) {
plugin := Plugin{
Repo: Repo{
Name: "go-hello",
@@ -25,99 +60,120 @@ func TestTemplate(t *testing.T) {
Commit: Commit{
Author: "appleboy",
Branch: "master",
Message: "update by drone discord plugin. \r\n update by drone discord plugin.",
Message: "feat: new feature",
Avatar: "https://avatars0.githubusercontent.com/u/21979?v=3&s=100",
},
Build: Build{
Number: 101,
Status: "success",
Link: "https://github.com/appleboy/go-hello",
Event: "tag",
Event: "push",
},
Source: Source{
Branch: "feature/awesome-feature",
},
Config: Config{
WebhookID: os.Getenv("WEBHOOK_ID"),
WebhookToken: os.Getenv("WEBHOOK_TOKEN"),
Message: []string{"test one message from drone testing", "test two message from drone testing"},
File: []string{"./images/discord-logo.png"},
Drone: true,
},
Payload: Payload{
Username: "drone",
TTS: false,
Wait: false,
Username: "default-bot",
},
}
err := plugin.Exec()
assert.Nil(t, err)
plugin.Clear()
plugin.Config.Message = []string{"I am appleboy"}
plugin.Payload.TTS = true
plugin.Payload.Wait = true
err = plugin.Exec()
assert.Nil(t, err)
// send success embed message
plugin.Config.Message = []string{}
plugin.Payload.TTS = false
plugin.Payload.Wait = false
plugin.Clear()
err = plugin.Exec()
assert.Nil(t, err)
// send success embed message
plugin.Build.Status = "failure"
plugin.Commit.Message = "send failure embed message"
plugin.Clear()
err = plugin.Exec()
assert.Nil(t, err)
time.Sleep(1 * time.Second)
// send default embed message
plugin.Build.Status = "test"
plugin.Commit.Message = "send default embed message"
plugin.Clear()
err = plugin.Exec()
assert.Nil(t, err)
// change color for embed message
plugin.Config.Color = "#4842f4"
plugin.Commit.Message = "Change embed color to #4842f4"
plugin.Clear()
err = plugin.Exec()
assert.Nil(t, err)
err := plugin.Exec(context.Background())
assert.NoError(t, err)
}
func TestDefaultTemplate(t *testing.T) {
func TestSendFile(t *testing.T) {
// Create a dummy file for testing
dummyFile, err := os.Create("test_file.txt")
assert.NoError(t, err)
_, err = dummyFile.WriteString("This is a test file.")
assert.NoError(t, err)
dummyFile.Close()
defer os.Remove("test_file.txt")
plugin := Plugin{
Config: Config{
WebhookID: os.Getenv("WEBHOOK_ID"),
WebhookToken: os.Getenv("WEBHOOK_TOKEN"),
Message: []string{"default message 1", "default message 2"},
Color: "#48f442",
File: []string{"test_file.txt"},
},
Payload: Payload{
Username: "drone-ci",
TTS: false,
Wait: false,
Username: "file-bot",
},
}
time.Sleep(1 * time.Second)
plugin.Clear()
err := plugin.Exec()
assert.Nil(t, err)
plugin.Config.Color = "#f4be41"
time.Sleep(1 * time.Second)
plugin.Clear()
err = plugin.Exec()
assert.Nil(t, err)
err = plugin.Exec(context.Background())
assert.NoError(t, err)
}
func TestColorConversion(t *testing.T) {
tests := []struct {
name string
colorHex string
expectedInt int
buildStatus string
expectedFall int
}{
{"valid hex", "#ffaa00", 16755200, "success", 1752220},
{"invalid hex", "not-a-hex", 16724530, "failure", 16724530},
{"status success", "", 0, "success", 1754624},
{"status failure", "", 0, "failure", 16724530},
{"status killed", "", 0, "killed", 16724530},
{"status default", "", 0, "running", 16767280},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := Plugin{
Config: Config{Color: tt.colorHex},
Build: Build{Status: tt.buildStatus},
}
if tt.colorHex != "" {
assert.Equal(t, tt.expectedInt, p.Color())
} else {
assert.Equal(t, tt.expectedFall, p.Color())
}
})
}
}
func TestExecWithAllFeatures(t *testing.T) {
time.Sleep(1 * time.Second)
// Create a dummy file for testing
dummyFile, err := os.Create("test_all.txt")
assert.NoError(t, err)
_, err = dummyFile.WriteString("This is a test file for a combined test.")
assert.NoError(t, err)
dummyFile.Close()
defer os.Remove("test_all.txt")
plugin := Plugin{
Repo: Repo{
Name: "go-hello",
Namespace: "appleboy",
},
Commit: Commit{
Author: "appleboy",
Message: "Combined test with multiple features",
},
Build: Build{
Status: "success",
Link: "http://example.com",
},
Config: Config{
WebhookID: os.Getenv("WEBHOOK_ID"),
WebhookToken: os.Getenv("WEBHOOK_TOKEN"),
Message: []string{"First line of embed.", "Second line."},
File: []string{"test_all.txt"},
Color: "#32a852",
Drone: true,
},
Payload: Payload{
Username: "super-bot",
},
}
err = plugin.Exec(context.Background())
assert.NoError(t, err)
}