6 Commits

Author SHA1 Message Date
Johannes Zottele 140300a5da Update of README.md 2024-04-24 15:57:18 +02:00
Johannes Zottele 850a48c535 Fix out of range on invalid path 2024-04-24 15:39:50 +02:00
Johannes Zottele 3bd882eccc Remove title parameter 2024-04-18 14:24:04 +02:00
Johannes Zottele 6dde9c117a Update README.md 2024-04-18 12:25:38 +02:00
Johannes Zottele 260a6f55da Write README.md 2024-04-18 12:20:33 +02:00
Johannes Zottele ea789ba05f Add support for message-text and delete-identifier
The delete-identifier allows to delete all exiting comments of this identifier in the PR. So the identifier does only exist once.
2024-04-18 11:30:56 +02:00
5 changed files with 207 additions and 48 deletions
-8
View File
@@ -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
+69 -1
View File
@@ -1 +1,69 @@
# drone-gitea-messenger
# drone-gitea-message
[![Docker Pulls](https://img.shields.io/docker/pulls/jozott/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
```
+17 -15
View File
@@ -1,10 +1,10 @@
package main
import (
"github.com/sirupsen/logrus"
"os"
"github.com/joho/godotenv"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
@@ -24,10 +24,15 @@ func main() {
Usage: "api key to access gitea api",
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{
Name: "message-file",
Usage: "file with content for message",
EnvVar: "PLUGIN_FILE,GITEA_MESSAGE_FILE",
EnvVar: "PLUGIN_MESSAGE_FILE,GITEA_MESSAGE_FILE",
},
cli.StringFlag{
Name: "base-url",
@@ -35,15 +40,11 @@ func main() {
EnvVar: "PLUGIN_BASE_URL,GITEA_MESSAGE_BASE_URL",
},
cli.StringFlag{
Name: "title",
Value: "",
Usage: "string for the title shown in the gitea pr comment",
EnvVar: "PLUGIN_TITLE,GITEA_MESSAGE_TITLE",
},
cli.StringFlag{
Name: "repo.ns",
Usage: "repository namespace",
EnvVar: "DRONE_REPO_NAMESPACE",
Name: "delete-identifier",
Value: "",
Usage: "string that is used as identifier for deletion upon a new message. " +
"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.owner",
@@ -94,10 +95,11 @@ func run(c *cli.Context) error {
Event: c.String("build.event"),
},
Config: Config{
APIKey: c.String("api-key"),
MessageFile: c.String("message-file"),
BaseURl: c.String("base-url"),
Title: c.String("title"),
APIKey: c.String("api-key"),
MessageText: c.String("message-text"),
MessageFile: c.String("message-file"),
BaseURl: c.String("base-url"),
DeleteIdentifier: c.String("delete-identifier"),
},
}
+69 -7
View File
@@ -2,20 +2,28 @@ package main
import (
"code.gitea.io/sdk/gitea"
"fmt"
log "github.com/sirupsen/logrus"
"strings"
)
type messageClient struct {
Client *gitea.Client
Owner string
Repo string
Index int64
Title string
Message string
Client *gitea.Client
Owner string
Repo string
Index int64
Message string
DeleteIdentifier string
}
func (mc *messageClient) sendMessage() (*gitea.Comment, *gitea.Response, error) {
var body = mc.Message
if mc.DeleteIdentifier != "" {
body = mc._getDeleteIdentifierMd() + "\n" + body
}
opt := gitea.CreateIssueCommentOption{
Body: mc.Message,
Body: body,
}
return mc.Client.CreateIssueComment(
@@ -25,3 +33,57 @@ func (mc *messageClient) sendMessage() (*gitea.Comment, *gitea.Response, error)
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 + "\" -->"
}
+52 -17
View File
@@ -3,6 +3,7 @@ package main
import (
"code.gitea.io/sdk/gitea"
"fmt"
"github.com/sirupsen/logrus"
"net/http"
"os"
"path/filepath"
@@ -21,10 +22,11 @@ type (
Event string
}
Config struct {
APIKey string
MessageFile string
BaseURl string
Title string
APIKey string
MessageText string
MessageFile string
BaseURl string
DeleteIdentifier string
}
Plugin struct {
Repo Repo
@@ -56,29 +58,62 @@ func (p Plugin) Exec() error {
return fmt.Errorf("pull request number is not set")
}
glob, err := filepath.Glob(p.Config.MessageFile)
if err != nil {
return fmt.Errorf("failed to glob %s. %s", p.Config.MessageFile, err)
var content []byte
if p.Config.MessageText == "" {
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])
if err != nil {
return fmt.Errorf("failed to read the file %s. %s", glob[0], err)
}
logrus.WithFields(logrus.Fields{
"repo.baseurl": p.Config.BaseURl,
"repo.owner": p.Repo.Owner,
"repo.name": p.Repo.Name,
"pr.index": p.Pr.Index,
}).Info("Start message commenting")
httpClient := &http.Client{}
client, err := gitea.NewClient(p.Config.BaseURl, gitea.SetToken(p.Config.APIKey), gitea.SetHTTPClient(httpClient))
mc := messageClient{
Client: client,
Owner: p.Repo.Owner,
Repo: p.Repo.Name,
Index: p.Pr.Index,
Title: p.Config.Title,
Message: string(content),
Client: client,
Owner: p.Repo.Owner,
Repo: p.Repo.Name,
Index: p.Pr.Index,
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()
if err == nil {
logrus.Info("Done.")
}
return err
}