mirror of
https://github.com/Jozott00/drone-gitea-message.git
synced 2026-07-06 16:02:39 +08:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 140300a5da | |||
| 850a48c535 | |||
| 3bd882eccc | |||
| 6dde9c117a | |||
| 260a6f55da | |||
| ea789ba05f |
@@ -1,11 +1,3 @@
|
|||||||
# This workflow uses actions that are not certified by GitHub.
|
|
||||||
# They are provided by a third-party and are governed by
|
|
||||||
# separate terms of service, privacy policy, and support
|
|
||||||
# documentation.
|
|
||||||
|
|
||||||
# GitHub recommends pinning actions to a commit SHA.
|
|
||||||
# To get a newer version, you will need to update the SHA.
|
|
||||||
# You can also reference a tag or branch, but the action may change without warning.
|
|
||||||
|
|
||||||
name: Publish Docker image
|
name: Publish Docker image
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,69 @@
|
|||||||
# drone-gitea-messenger
|
# drone-gitea-message
|
||||||
|
[](https://hub.docker.com/r/jozott/drone-gitea-message)
|
||||||
|
|
||||||
|
Drone plugin to send message as comments to Gitea pull requests.
|
||||||
|
All releases are available on [Docker Hub](https://hub.docker.com/r/jozott/drone-gitea-message).
|
||||||
|
|
||||||
|
## Drone YAML Usage
|
||||||
|
|
||||||
|
The plugin support sending text as well as some file's content.
|
||||||
|
By setting the `delete_identifier`, all older comments with the same identifier will be
|
||||||
|
deleted before sending the message.
|
||||||
|
|
||||||
|
### Example of sending a text
|
||||||
|
```yaml
|
||||||
|
steps:
|
||||||
|
- name: send text to pr
|
||||||
|
image: jozott/drone-gitea-message:latest
|
||||||
|
settings:
|
||||||
|
api_key:
|
||||||
|
from_secret: gitea_token
|
||||||
|
base_url: http://gitea.example.com
|
||||||
|
message_text: "Hello world"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example of sending content of file
|
||||||
|
```yaml
|
||||||
|
steps:
|
||||||
|
- name: send file content to pr
|
||||||
|
image: jozott/drone-gitea-message:latest
|
||||||
|
settings:
|
||||||
|
api_key:
|
||||||
|
from_secret: gitea_token
|
||||||
|
base_url: http://gitea.example.com
|
||||||
|
message_file: path/to/hello_world.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example with `delete_identifier`
|
||||||
|
If the `delete_identifier` is set, the plugin will delete all existing PR comments
|
||||||
|
that contain the delete identifier. This is handy if sending status updates that make
|
||||||
|
older status updates obsolete.
|
||||||
|
```yaml
|
||||||
|
steps:
|
||||||
|
- name: send test report to pr
|
||||||
|
image: jozott/drone-gitea-message:latest
|
||||||
|
settings:
|
||||||
|
api_key:
|
||||||
|
from_secret: gitea_token
|
||||||
|
base_url: http://gitea.example.com
|
||||||
|
message_file: build/test/report.md
|
||||||
|
delete_identifier: test-report-delete-id
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build
|
||||||
|
To build the binary execute the following commands
|
||||||
|
```bash
|
||||||
|
export GOOS=linux
|
||||||
|
export GOARCH=amd64
|
||||||
|
export CGO_ENABLED=0
|
||||||
|
export GO111MODULE=on
|
||||||
|
|
||||||
|
go build -v -a -tags netgo -o release/linux/amd64/drone-gitea-message
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run
|
||||||
|
To get all available commands run
|
||||||
|
```
|
||||||
|
./drone-gitea-message --help
|
||||||
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,10 +24,15 @@ func main() {
|
|||||||
Usage: "api key to access gitea api",
|
Usage: "api key to access gitea api",
|
||||||
EnvVar: "PLUGIN_API_KEY,GITEA_MESSAGE_API_KEY,GITEA_TOKEN",
|
EnvVar: "PLUGIN_API_KEY,GITEA_MESSAGE_API_KEY,GITEA_TOKEN",
|
||||||
},
|
},
|
||||||
|
cli.StringSliceFlag{
|
||||||
|
Name: "message-text",
|
||||||
|
Usage: "text of message content. If this is set, message-file is going to be ignored.",
|
||||||
|
EnvVar: "PLUGIN_MESSAGE_TEXT,GITEA_MESSAGE_FILE",
|
||||||
|
},
|
||||||
cli.StringSliceFlag{
|
cli.StringSliceFlag{
|
||||||
Name: "message-file",
|
Name: "message-file",
|
||||||
Usage: "file with content for message",
|
Usage: "file with content for message",
|
||||||
EnvVar: "PLUGIN_FILE,GITEA_MESSAGE_FILE",
|
EnvVar: "PLUGIN_MESSAGE_FILE,GITEA_MESSAGE_FILE",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "base-url",
|
Name: "base-url",
|
||||||
@@ -35,15 +40,11 @@ func main() {
|
|||||||
EnvVar: "PLUGIN_BASE_URL,GITEA_MESSAGE_BASE_URL",
|
EnvVar: "PLUGIN_BASE_URL,GITEA_MESSAGE_BASE_URL",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "title",
|
Name: "delete-identifier",
|
||||||
Value: "",
|
Value: "",
|
||||||
Usage: "string for the title shown in the gitea pr comment",
|
Usage: "string that is used as identifier for deletion upon a new message. " +
|
||||||
EnvVar: "PLUGIN_TITLE,GITEA_MESSAGE_TITLE",
|
"So every previous comment in the PR that has this identifier will be deleted before the message is sent",
|
||||||
},
|
EnvVar: "PLUGIN_DELETE_IDENTIFIER",
|
||||||
cli.StringFlag{
|
|
||||||
Name: "repo.ns",
|
|
||||||
Usage: "repository namespace",
|
|
||||||
EnvVar: "DRONE_REPO_NAMESPACE",
|
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "repo.owner",
|
Name: "repo.owner",
|
||||||
@@ -94,10 +95,11 @@ func run(c *cli.Context) error {
|
|||||||
Event: c.String("build.event"),
|
Event: c.String("build.event"),
|
||||||
},
|
},
|
||||||
Config: Config{
|
Config: Config{
|
||||||
APIKey: c.String("api-key"),
|
APIKey: c.String("api-key"),
|
||||||
MessageFile: c.String("message-file"),
|
MessageText: c.String("message-text"),
|
||||||
BaseURl: c.String("base-url"),
|
MessageFile: c.String("message-file"),
|
||||||
Title: c.String("title"),
|
BaseURl: c.String("base-url"),
|
||||||
|
DeleteIdentifier: c.String("delete-identifier"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+69
-7
@@ -2,20 +2,28 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/sdk/gitea"
|
"code.gitea.io/sdk/gitea"
|
||||||
|
"fmt"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type messageClient struct {
|
type messageClient struct {
|
||||||
Client *gitea.Client
|
Client *gitea.Client
|
||||||
Owner string
|
Owner string
|
||||||
Repo string
|
Repo string
|
||||||
Index int64
|
Index int64
|
||||||
Title string
|
Message string
|
||||||
Message string
|
DeleteIdentifier string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mc *messageClient) sendMessage() (*gitea.Comment, *gitea.Response, error) {
|
func (mc *messageClient) sendMessage() (*gitea.Comment, *gitea.Response, error) {
|
||||||
|
var body = mc.Message
|
||||||
|
if mc.DeleteIdentifier != "" {
|
||||||
|
body = mc._getDeleteIdentifierMd() + "\n" + body
|
||||||
|
}
|
||||||
|
|
||||||
opt := gitea.CreateIssueCommentOption{
|
opt := gitea.CreateIssueCommentOption{
|
||||||
Body: mc.Message,
|
Body: body,
|
||||||
}
|
}
|
||||||
|
|
||||||
return mc.Client.CreateIssueComment(
|
return mc.Client.CreateIssueComment(
|
||||||
@@ -25,3 +33,57 @@ func (mc *messageClient) sendMessage() (*gitea.Comment, *gitea.Response, error)
|
|||||||
opt,
|
opt,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deletes all comments in the PR that include the DeleteIdentifier.
|
||||||
|
// If the DeleteIdentifier is "", the search will not be performed.
|
||||||
|
//
|
||||||
|
// Returns the number of deleted comments or an error.
|
||||||
|
func (mc *messageClient) deletePreviousMessages() (int, error) {
|
||||||
|
if mc.DeleteIdentifier == "" {
|
||||||
|
log.Info("No DeleteIdentifier specified... skipping comment deletion")
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
identifier := mc._getDeleteIdentifierMd()
|
||||||
|
log.WithField("deleteIdentifier", mc.DeleteIdentifier).Info("Start deletion of PR comments")
|
||||||
|
matchingComments, err := mc._searchCommentsForIdentifier(identifier)
|
||||||
|
log.Info("Found comments with identifier: ", len(matchingComments))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to search for comments. %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, comment := range matchingComments {
|
||||||
|
_, err := mc.Client.DeleteIssueComment(mc.Owner, mc.Repo, comment.ID)
|
||||||
|
if err != nil {
|
||||||
|
return i, fmt.Errorf("error deleting comment: %w", err)
|
||||||
|
}
|
||||||
|
log.WithField("id", comment.ID).Info("Deleted comment")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.WithField("numberOfComments", len(matchingComments)).Info("Deletion of old comment(s) completed")
|
||||||
|
return len(matchingComments), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// searchCommentsForIdentifier searches for comments containing a specific identifier within a pull request
|
||||||
|
func (mc *messageClient) _searchCommentsForIdentifier(identifier string) ([]*gitea.Comment, error) {
|
||||||
|
// Fetch all comments on the specified pull request
|
||||||
|
comments, _, err := mc.Client.ListIssueComments(mc.Owner, mc.Repo, mc.Index, gitea.ListIssueCommentOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error fetching comments: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter comments to find those that contain the identifier
|
||||||
|
var matchingComments []*gitea.Comment
|
||||||
|
for _, comment := range comments {
|
||||||
|
if strings.Contains(comment.Body, identifier) {
|
||||||
|
matchingComments = append(matchingComments, comment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchingComments, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *messageClient) _getDeleteIdentifierMd() string {
|
||||||
|
return "<!-- delete-identifier=\"" + mc.DeleteIdentifier + "\" -->"
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"code.gitea.io/sdk/gitea"
|
"code.gitea.io/sdk/gitea"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -21,10 +22,11 @@ type (
|
|||||||
Event string
|
Event string
|
||||||
}
|
}
|
||||||
Config struct {
|
Config struct {
|
||||||
APIKey string
|
APIKey string
|
||||||
MessageFile string
|
MessageText string
|
||||||
BaseURl string
|
MessageFile string
|
||||||
Title string
|
BaseURl string
|
||||||
|
DeleteIdentifier string
|
||||||
}
|
}
|
||||||
Plugin struct {
|
Plugin struct {
|
||||||
Repo Repo
|
Repo Repo
|
||||||
@@ -56,29 +58,62 @@ func (p Plugin) Exec() error {
|
|||||||
return fmt.Errorf("pull request number is not set")
|
return fmt.Errorf("pull request number is not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
glob, err := filepath.Glob(p.Config.MessageFile)
|
var content []byte
|
||||||
if err != nil {
|
if p.Config.MessageText == "" {
|
||||||
return fmt.Errorf("failed to glob %s. %s", p.Config.MessageFile, err)
|
if p.Config.MessageFile == "" {
|
||||||
|
return fmt.Errorf("you must provide either a message text or a message file")
|
||||||
|
}
|
||||||
|
|
||||||
|
glob, err := filepath.Glob(p.Config.MessageFile)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to glob %s. %s", p.Config.MessageFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(glob) == 0 {
|
||||||
|
return fmt.Errorf("no file found matching %s", p.Config.MessageFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err = os.ReadFile(glob[0])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read the file %s. %s", glob[0], err)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if p.Config.MessageFile != "" {
|
||||||
|
return fmt.Errorf("you must provide either a message text or a message file, not both")
|
||||||
|
}
|
||||||
|
content = []byte(p.Config.MessageText)
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := os.ReadFile(glob[0])
|
logrus.WithFields(logrus.Fields{
|
||||||
if err != nil {
|
"repo.baseurl": p.Config.BaseURl,
|
||||||
return fmt.Errorf("failed to read the file %s. %s", glob[0], err)
|
"repo.owner": p.Repo.Owner,
|
||||||
}
|
"repo.name": p.Repo.Name,
|
||||||
|
"pr.index": p.Pr.Index,
|
||||||
|
}).Info("Start message commenting")
|
||||||
|
|
||||||
httpClient := &http.Client{}
|
httpClient := &http.Client{}
|
||||||
client, err := gitea.NewClient(p.Config.BaseURl, gitea.SetToken(p.Config.APIKey), gitea.SetHTTPClient(httpClient))
|
client, err := gitea.NewClient(p.Config.BaseURl, gitea.SetToken(p.Config.APIKey), gitea.SetHTTPClient(httpClient))
|
||||||
|
|
||||||
mc := messageClient{
|
mc := messageClient{
|
||||||
Client: client,
|
Client: client,
|
||||||
Owner: p.Repo.Owner,
|
Owner: p.Repo.Owner,
|
||||||
Repo: p.Repo.Name,
|
Repo: p.Repo.Name,
|
||||||
Index: p.Pr.Index,
|
Index: p.Pr.Index,
|
||||||
Title: p.Config.Title,
|
Message: string(content),
|
||||||
Message: string(content),
|
DeleteIdentifier: p.Config.DeleteIdentifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = mc.deletePreviousMessages()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error deleting previous messages: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Info("Sending message as PR comment...")
|
||||||
_, _, err = mc.sendMessage()
|
_, _, err = mc.sendMessage()
|
||||||
|
if err == nil {
|
||||||
|
logrus.Info("Done.")
|
||||||
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user