Skip to content

Commit

Permalink
Merge pull request #152 from catatsuy/feature_use_new_api_for_uploadi…
Browse files Browse the repository at this point in the history
…ng_file

use new api for uploading file
  • Loading branch information
catatsuy authored Apr 27, 2024
2 parents 023803b + 5702f4e commit cf17b0b
Show file tree
Hide file tree
Showing 11 changed files with 370 additions and 275 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Change Log

## [v0.5.0] -

### Breaking Changes

- **API Deprecation**: As per [Slack's latest API update](https://api.slack.com/changelog/2024-04-a-better-way-to-upload-files-is-here-to-stay), `files.upload` is now deprecated. We have updated our tool to use the new APIs, `files.getUploadURLExternal` and `files.completeUploadExternal`.
- **Channel Specification**: It is no longer possible to specify a `channel` for file uploads. You must now use `channel-id`.
- **Filetype Option Update**: The `-filetype` option has been modified. Please use `-snippet-type` instead for specifying the type of file when uploading to a snippet.

### Changed

* update Go version
* update dependent libraries
* update README

## [v0.4.14] - 2023-09-30

### Changed
Expand Down
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,14 @@ The Slack API allows you to specify the filetype of a file when posting it as a
config file name
-channel string
specify channel (unavailable for new Incoming Webhooks)
-channel-id string
specify channel id (for uploading a file)
-debug
debug mode (for developers)
-filename string
specify a file name (for uploading to snippet)
-filetype string
specify a filetype (for uploading to snippet)
[compatible] specify a filetype for uploading to snippet. This option is maintained for compatibility. Please use -snippet-type instead.
-icon-emoji string
specify icon emoji (unavailable for new Incoming Webhooks)
-interval duration
Expand All @@ -68,6 +72,8 @@ The Slack API allows you to specify the filetype of a file when posting it as a
slack url (Incoming Webhooks URL)
-snippet
switch to snippet uploading mode
-snippet-type string
specify a snippet_type (for uploading to snippet)
-token string
token (for uploading to snippet)
-username string
Expand All @@ -92,6 +98,7 @@ The toml file contains the following information.
url = "https://hooks.slack.com/services/**"
token = "xoxp-xxxxx"
channel = "#general"
channel_id = "C12345678"
username = "tester"
icon_emoji = ":rocket:"
interval = "1s"
Expand All @@ -103,13 +110,12 @@ Note:
* You can use the following options to customize your message when posting to Slack as text: `channel`, `username`, `icon_emoji`, and `interval`.
* Due to a recent change in the specification for Incoming Webhooks, it is currently not possible to override the `channel`, `username`, and `icon_emoji` options when posting to Slack. For more information, please refer to [this resource](https://api.slack.com/messaging/webhooks#advanced_message_formatting)
* You can create an Incoming Webhooks URL at https://slack.com/services/new/incoming-webhook
* To post a file as a snippet to Slack, you will need to provide both a `token` and a `channel`.
* To post a file as a snippet to Slack, you will need to provide both a `token` and a `channel_id`.
* The `username` and `icon_emoji` options will be ignored when posting a file as a snippet to Slack.
* For instructions on how to create a token, please see the next section.

Tips:

* If you want to use a different default channel for snippets, you can specify it using the `snippet_channel` option.
* You cannot specify a channel because the slack api support only the `channel_id`.
* If you don't specify `channel_id`, the file will be private. So, if you need to post a file public, you must specify `channel_id`.
* The Slack API can cause delays, so posting might take longer.

### How to create a token

Expand Down Expand Up @@ -149,7 +155,7 @@ Some settings for the Slack API can be provided using environment variables.
NOTIFY_SLACK_WEBHOOK_URL
NOTIFY_SLACK_TOKEN
NOTIFY_SLACK_CHANNEL
NOTIFY_SLACK_SNIPPET_CHANNEL
NOTIFY_SLACK_CHANNEL_ID
NOTIFY_SLACK_USERNAME
NOTIFY_SLACK_ICON_EMOJI
NOTIFY_SLACK_INTERVAL
Expand Down
35 changes: 12 additions & 23 deletions internal/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,17 @@ func (c *CLI) Run(args []string) int {
flags := flag.NewFlagSet("notify_slack", flag.ContinueOnError)
flags.SetOutput(c.errStream)

flags.StringVar(&c.conf.PrimaryChannel, "channel", "", "specify channel (unavailable for new Incoming Webhooks)")
flags.StringVar(&c.conf.Channel, "channel", "", "specify channel (unavailable for new Incoming Webhooks)")
flags.StringVar(&c.conf.ChannelID, "channel-id", "", "specify channel id (for uploading a file)")
flags.StringVar(&c.conf.SlackURL, "slack-url", "", "slack url (Incoming Webhooks URL)")
flags.StringVar(&c.conf.Token, "token", "", "token (for uploading to snippet)")
flags.StringVar(&c.conf.Username, "username", "", "specify username (unavailable for new Incoming Webhooks)")
flags.StringVar(&c.conf.IconEmoji, "icon-emoji", "", "specify icon emoji (unavailable for new Incoming Webhooks)")
flags.DurationVar(&c.conf.Duration, "interval", time.Second, "interval")
flags.StringVar(&tomlFile, "c", "", "config file name")
flags.StringVar(&uploadFilename, "filename", "", "specify a file name (for uploading to snippet)")
flags.StringVar(&filetype, "filetype", "", "specify a filetype (for uploading to snippet)")
flags.StringVar(&filetype, "filetype", "", "[compatible] specify a filetype for uploading to snippet. This option is maintained for compatibility. Please use -snippet-type instead.")
flags.StringVar(&filetype, "snippet-type", "", "specify a snippet_type (for uploading to snippet)")

flags.BoolVar(&snippetMode, "snippet", false, "switch to snippet uploading mode")

Expand Down Expand Up @@ -178,10 +180,7 @@ func (c *CLI) Run(args []string) int {
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
defer stop()

channel := c.conf.PrimaryChannel
if channel == "" {
channel = c.conf.Channel
}
channel := c.conf.Channel

param := &slack.PostTextParam{
Channel: channel,
Expand Down Expand Up @@ -216,18 +215,8 @@ func (c *CLI) Run(args []string) int {
return ExitCodeOK
}

func (c *CLI) uploadSnippet(ctx context.Context, filename, uploadFilename, filetype string) error {
channel := c.conf.PrimaryChannel
if channel == "" {
channel = c.conf.SnippetChannel
}
if channel == "" {
channel = c.conf.Channel
}

if channel == "" {
return fmt.Errorf("must specify channel for uploading to snippet")
}
func (c *CLI) uploadSnippet(ctx context.Context, filename, uploadFilename, snippetType string) error {
channelID := c.conf.ChannelID

var reader io.ReadCloser
if filename == "" {
Expand All @@ -254,12 +243,12 @@ func (c *CLI) uploadSnippet(ctx context.Context, filename, uploadFilename, filet
}

param := &slack.PostFileParam{
Channel: channel,
Filename: uploadFilename,
Content: string(content),
Filetype: filetype,
ChannelID: channelID,
Filename: uploadFilename,
SnippetType: snippetType,
}
err = c.sClient.PostFile(ctx, param)

err = c.sClient.PostFile(ctx, param, content)
if err != nil {
return err
}
Expand Down
111 changes: 22 additions & 89 deletions internal/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ import (

"github.com/catatsuy/notify_slack/internal/config"
"github.com/catatsuy/notify_slack/internal/slack"
"github.com/google/go-cmp/cmp"
)

type fakeSlackClient struct {
slack.Slack

FakePostFile func(ctx context.Context, param *slack.PostFileParam) error
FakePostFile func(ctx context.Context, param *slack.PostFileParam, content []byte) error
}

func (c *fakeSlackClient) PostFile(ctx context.Context, param *slack.PostFileParam) error {
return c.FakePostFile(ctx, param)
func (c *fakeSlackClient) PostFile(ctx context.Context, param *slack.PostFileParam, content []byte) error {
return c.FakePostFile(ctx, param, content)
}

func (c *fakeSlackClient) PostText(ctx context.Context, param *slack.PostTextParam) error {
Expand Down Expand Up @@ -48,33 +49,23 @@ func TestUploadSnippet(t *testing.T) {
conf: config.NewConfig(),
}

err := cl.uploadSnippet(context.Background(), "", "", "")
want := "must specify channel"
if err == nil || !strings.Contains(err.Error(), want) {
t.Errorf("error = %v; want %q", err, want)
}

cl.conf.Channel = "normal_channel"
err = cl.uploadSnippet(context.Background(), "testdata/nofile.txt", "", "")
want = "no such file or directory"
cl.conf.ChannelID = "C12345678"
err := cl.uploadSnippet(context.Background(), "testdata/nofile.txt", "", "")
want := "no such file or directory"
if err == nil || !strings.Contains(err.Error(), want) {
t.Errorf("error = %v; want %q", err, want)
}

cl.sClient = &fakeSlackClient{
FakePostFile: func(ctx context.Context, param *slack.PostFileParam) error {
if param.Channel != cl.conf.Channel {
t.Errorf("expected %s; got %s", cl.conf.Channel, param.Channel)
}

FakePostFile: func(ctx context.Context, param *slack.PostFileParam, content []byte) error {
expectedFilename := "testdata/upload.txt"
if param.Filename != expectedFilename {
t.Errorf("expected %s; got %s", expectedFilename, param.Filename)
}

expectedContent := "upload_test\n"
if param.Content != expectedContent {
t.Errorf("expected %q; got %q", expectedContent, param.Content)
if diff := cmp.Diff(expectedContent, string(content)); diff != "" {
t.Errorf("unexpected diff: (-want +got):\n%s", diff)
}

return nil
Expand All @@ -87,19 +78,15 @@ func TestUploadSnippet(t *testing.T) {
}

cl.sClient = &fakeSlackClient{
FakePostFile: func(ctx context.Context, param *slack.PostFileParam) error {
if param.Channel != cl.conf.Channel {
t.Errorf("expected %s; got %s", cl.conf.Channel, param.Channel)
}

FakePostFile: func(ctx context.Context, param *slack.PostFileParam, content []byte) error {
expectedFilename := "overwrite.txt"
if param.Filename != expectedFilename {
t.Errorf("expected %s; got %s", expectedFilename, param.Filename)
}

expectedContent := "upload_test\n"
if param.Content != expectedContent {
t.Errorf("expected %q; got %q", expectedContent, param.Content)
if diff := cmp.Diff(expectedContent, string(content)); diff != "" {
t.Errorf("unexpected diff: (-want +got):\n%s", diff)
}

return nil
Expand All @@ -112,85 +99,31 @@ func TestUploadSnippet(t *testing.T) {
}

cl.sClient = &fakeSlackClient{
FakePostFile: func(ctx context.Context, param *slack.PostFileParam) error {
if param.Channel != cl.conf.Channel {
t.Errorf("expected %s; got %s", cl.conf.Channel, param.Channel)
FakePostFile: func(ctx context.Context, param *slack.PostFileParam, content []byte) error {
if param.ChannelID != cl.conf.ChannelID {
t.Errorf("expected %s; got %s", cl.conf.ChannelID, param.ChannelID)
}

expectedFilename := "overwrite.txt"
if param.Filename != expectedFilename {
t.Errorf("expected %s; got %s", expectedFilename, param.Filename)
}

expectedContent := "upload_test\n"
if param.Content != expectedContent {
t.Errorf("expected %q; got %q", expectedContent, param.Content)
}

expectedFiletype := "diff"
if param.Filetype != expectedFiletype {
t.Errorf("expected %s; got %s", expectedFiletype, param.Filetype)
}

return nil
},
}

err = cl.uploadSnippet(context.Background(), "testdata/upload.txt", "overwrite.txt", "diff")
if err != nil {
t.Errorf("expected nil; got %v", err)
}

cl.conf.SnippetChannel = "snippet_channel"

cl.sClient = &fakeSlackClient{
FakePostFile: func(ctx context.Context, param *slack.PostFileParam) error {
if param.Channel != cl.conf.SnippetChannel {
t.Errorf("expected %s; got %s", cl.conf.SnippetChannel, param.Channel)
}

expectedFilename := "testdata/upload.txt"
if param.Filename != expectedFilename {
t.Errorf("expected %s; got %s", expectedFilename, param.Filename)
}

expectedContent := "upload_test\n"
if param.Content != expectedContent {
t.Errorf("expected %q; got %q", expectedContent, param.Content)
}

return nil
},
}

err = cl.uploadSnippet(context.Background(), "testdata/upload.txt", "", "")
if err != nil {
t.Errorf("expected nil; got %v", err)
}

cl.conf.PrimaryChannel = "primary_channel"

cl.sClient = &fakeSlackClient{
FakePostFile: func(ctx context.Context, param *slack.PostFileParam) error {
if param.Channel != cl.conf.PrimaryChannel {
t.Errorf("expected %s; got %s", cl.conf.PrimaryChannel, param.Channel)
}

expectedFilename := "testdata/upload.txt"
if param.Filename != expectedFilename {
t.Errorf("expected %s; got %s", expectedFilename, param.Filename)
expectedSnippetType := "diff"
if param.SnippetType != expectedSnippetType {
t.Errorf("expected %s; got %s", expectedSnippetType, param.SnippetType)
}

expectedContent := "upload_test\n"
if param.Content != expectedContent {
t.Errorf("expected %q; got %q", expectedContent, param.Content)
if diff := cmp.Diff(expectedContent, string(content)); diff != "" {
t.Errorf("unexpected diff: (-want +got):\n%s", diff)
}

return nil
},
}

err = cl.uploadSnippet(context.Background(), "testdata/upload.txt", "", "")
err = cl.uploadSnippet(context.Background(), "testdata/upload.txt", "overwrite.txt", "diff")
if err != nil {
t.Errorf("expected nil; got %v", err)
}
Expand Down
24 changes: 17 additions & 7 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ var (
type Config struct {
SlackURL string
Token string
PrimaryChannel string
Channel string
SnippetChannel string
ChannelID string
Username string
IconEmoji string
Duration time.Duration
Expand All @@ -42,7 +42,13 @@ func (c *Config) LoadEnv() error {
}

if c.SnippetChannel == "" {
c.SnippetChannel = os.Getenv("NOTIFY_SLACK_SNIPPET_CHANNEL")
if os.Getenv("NOTIFY_SLACK_SNIPPET_CHANNEL") != "" {
return fmt.Errorf("the NOTIFY_SLACK_SNIPPET_CHANNEL option is deprecated")
}
}

if c.ChannelID == "" {
c.ChannelID = os.Getenv("NOTIFY_SLACK_CHANNEL_ID")
}

if c.Username == "" {
Expand Down Expand Up @@ -70,6 +76,7 @@ type slackConfig struct {
Token string
Channel string
SnippetChannel string `toml:"snippet_channel"`
ChannelID string `toml:"channel_id"`
Username string
IconEmoji string `toml:"icon_emoji"`
Interval string
Expand Down Expand Up @@ -109,16 +116,19 @@ func (c *Config) LoadTOML(filename string) error {
c.Channel = slackConfig.Channel
}
}
if c.SnippetChannel == "" {
if slackConfig.SnippetChannel != "" {
c.SnippetChannel = slackConfig.SnippetChannel
}
}
if c.Username == "" {
if slackConfig.Username != "" {
c.Username = slackConfig.Username
}
}
if slackConfig.SnippetChannel != "" {
return fmt.Errorf("the snippet_channel option is deprecated")
}
if c.ChannelID == "" {
if slackConfig.ChannelID != "" {
c.ChannelID = slackConfig.ChannelID
}
}
if c.IconEmoji == "" {
if slackConfig.IconEmoji != "" {
c.IconEmoji = slackConfig.IconEmoji
Expand Down
Loading

0 comments on commit cf17b0b

Please sign in to comment.