├── .hadolint.yaml
├── tests
├── vars.json
├── audio.mp3
├── github.png
├── video.mp4
├── voice.ogg
├── github-logo.png
├── gophercolor.png
├── message.txt
├── message_template.txt
└── message_html.txt
├── images
├── logo.png
└── logo.svg
├── .github
├── dependabot.yml
├── FUNDING.yml
└── workflows
│ ├── goreleaser.yml
│ ├── lint.yml
│ ├── codeql.yml
│ └── docker.yml
├── .gitignore
├── docker
└── Dockerfile
├── .golangci.yml
├── LICENSE
├── go.mod
├── .goreleaser.yaml
├── README.md
├── Makefile
├── go.sum
├── DOCS.md
├── main.go
├── plugin.go
└── plugin_test.go
/.hadolint.yaml:
--------------------------------------------------------------------------------
1 | ignored:
2 | - DL3018
3 | - DL3008
4 |
--------------------------------------------------------------------------------
/tests/vars.json:
--------------------------------------------------------------------------------
1 | {"env":"testing","version":"1.2.0-SNAPSHOT"}
2 |
--------------------------------------------------------------------------------
/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appleboy/drone-telegram/HEAD/images/logo.png
--------------------------------------------------------------------------------
/tests/audio.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appleboy/drone-telegram/HEAD/tests/audio.mp3
--------------------------------------------------------------------------------
/tests/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appleboy/drone-telegram/HEAD/tests/github.png
--------------------------------------------------------------------------------
/tests/video.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appleboy/drone-telegram/HEAD/tests/video.mp4
--------------------------------------------------------------------------------
/tests/voice.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appleboy/drone-telegram/HEAD/tests/voice.ogg
--------------------------------------------------------------------------------
/tests/github-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appleboy/drone-telegram/HEAD/tests/github-logo.png
--------------------------------------------------------------------------------
/tests/gophercolor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appleboy/drone-telegram/HEAD/tests/gophercolor.png
--------------------------------------------------------------------------------
/tests/message.txt:
--------------------------------------------------------------------------------
1 | Sample message loaded from file.
2 |
3 | Commit msg: {{commit.message}}
4 |
5 | duration: {{duration build.started build.finished}}
6 |
--------------------------------------------------------------------------------
/tests/message_template.txt:
--------------------------------------------------------------------------------
1 | Sample message template loaded from file.
2 |
3 | *Environ:* {{tpl.env}}
4 | *Version:* {{tpl.version}}
5 |
6 | Commit msg: {{commit.message}}
7 |
8 | duration: {{duration build.started build.finished}}
9 |
--------------------------------------------------------------------------------
/tests/message_html.txt:
--------------------------------------------------------------------------------
1 | Test HTML Format from file
2 | Google .com 1
3 | Google .com 2
4 | Google .com 3
5 | Google .com 4
6 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: github-actions
4 | directory: /
5 | schedule:
6 | interval: weekly
7 | - package-ecosystem: gomod
8 | directory: /
9 | schedule:
10 | interval: weekly
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files, Static and Dynamic libs (Shared Objects)
2 | *.o
3 | *.a
4 | *.so
5 |
6 | # Folders
7 | _obj
8 | _test
9 |
10 | # Architecture specific extensions/prefixes
11 | *.[568vq]
12 | [568vq].out
13 |
14 | *.cgo1.go
15 | *.cgo2.c
16 | _cgo_defun.c
17 | _cgo_gotypes.go
18 | _cgo_export.*
19 |
20 | _testmain.go
21 |
22 | *.exe
23 | *.test
24 | *.prof
25 | drone-telegram
26 | coverage.txt
27 | .env
28 | release
29 | bin
30 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine:3.17
2 |
3 | ARG TARGETOS
4 | ARG TARGETARCH
5 |
6 | LABEL maintainer="Bo-Yi Wu " \
7 | org.label-schema.name="Telegram Plugin" \
8 | org.label-schema.vendor="Bo-Yi Wu" \
9 | org.label-schema.schema-version="1.0"
10 |
11 | LABEL org.opencontainers.image.source=https://github.com/appleboy/drone-telegram
12 | LABEL org.opencontainers.image.description="plugin for sending telegram notifications"
13 | LABEL org.opencontainers.image.licenses=MIT
14 |
15 | RUN apk add --no-cache ca-certificates && \
16 | rm -rf /var/cache/apk/*
17 |
18 | COPY release/${TARGETOS}/${TARGETARCH}/drone-telegram /bin/
19 |
20 | ENTRYPOINT ["/bin/drone-telegram"]
21 |
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
1 | linters:
2 | disable-all: true
3 | enable:
4 | - bodyclose
5 | - dogsled
6 | - errcheck
7 | - exportloopref
8 | - exhaustive
9 | - gochecknoinits
10 | - goconst
11 | - gocritic
12 | - gofmt
13 | - goimports
14 | - goprintffuncname
15 | - gosec
16 | - gosimple
17 | - govet
18 | - ineffassign
19 | - misspell
20 | - nakedret
21 | - noctx
22 | - nolintlint
23 | - staticcheck
24 | - stylecheck
25 | - typecheck
26 | - unconvert
27 | - unparam
28 | - unused
29 | - whitespace
30 | - gofumpt
31 |
32 | issues:
33 | exclude-rules:
34 | # Exclude `lll` issues for long lines with `go:generate`.
35 | - linters:
36 | - lll
37 | source: "^//go:generate "
38 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
13 | custom: ['https://www.paypal.me/appleboy46']
14 |
--------------------------------------------------------------------------------
/.github/workflows/goreleaser.yml:
--------------------------------------------------------------------------------
1 | name: Goreleaser
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 |
8 | permissions:
9 | contents: write
10 |
11 | jobs:
12 | goreleaser:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Checkout
16 | uses: actions/checkout@v4
17 | with:
18 | fetch-depth: 0
19 | - name: Setup go
20 | uses: actions/setup-go@v5
21 | with:
22 | go-version-file: go.mod
23 | check-latest: true
24 |
25 | - name: Run GoReleaser
26 | uses: goreleaser/goreleaser-action@v6
27 | with:
28 | # either 'goreleaser' (default) or 'goreleaser-pro'
29 | distribution: goreleaser
30 | version: latest
31 | args: release --clean
32 | env:
33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Bo-Yi Wu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/appleboy/drone-telegram
2 |
3 | go 1.22
4 |
5 | require (
6 | github.com/appleboy/drone-template-lib v1.3.0
7 | github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
8 | github.com/joho/godotenv v1.5.1
9 | github.com/stretchr/testify v1.9.0
10 | github.com/urfave/cli v1.22.15
11 | )
12 |
13 | require (
14 | dario.cat/mergo v1.0.1 // indirect
15 | github.com/Masterminds/goutils v1.1.1 // indirect
16 | github.com/Masterminds/semver/v3 v3.3.0 // indirect
17 | github.com/Masterminds/sprig/v3 v3.3.0 // indirect
18 | github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
19 | github.com/davecgh/go-spew v1.1.1 // indirect
20 | github.com/google/uuid v1.6.0 // indirect
21 | github.com/huandu/xstrings v1.5.0 // indirect
22 | github.com/mailgun/raymond/v2 v2.0.48 // indirect
23 | github.com/mitchellh/copystructure v1.2.0 // indirect
24 | github.com/mitchellh/reflectwalk v1.0.2 // indirect
25 | github.com/pmezard/go-difflib v1.0.0 // indirect
26 | github.com/russross/blackfriday/v2 v2.1.0 // indirect
27 | github.com/shopspring/decimal v1.4.0 // indirect
28 | github.com/sirupsen/logrus v1.9.3 // indirect
29 | github.com/spf13/cast v1.7.0 // indirect
30 | github.com/technoweenie/multipartstreamer v1.0.1 // indirect
31 | golang.org/x/crypto v0.27.0 // indirect
32 | golang.org/x/sys v0.25.0 // indirect
33 | gopkg.in/yaml.v3 v3.0.1 // indirect
34 | )
35 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: Lint and Testing
2 |
3 | on:
4 | push:
5 | pull_request:
6 |
7 | jobs:
8 | lint:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Checkout repository
12 | uses: actions/checkout@v4
13 |
14 | - name: Setup go
15 | uses: actions/setup-go@v5
16 | with:
17 | go-version-file: go.mod
18 | check-latest: true
19 |
20 | - name: Setup golangci-lint
21 | uses: golangci/golangci-lint-action@v6
22 | with:
23 | version: latest
24 | args: --verbose
25 |
26 | - uses: hadolint/hadolint-action@v3.1.0
27 | name: hadolint for Dockerfile
28 | with:
29 | dockerfile: docker/Dockerfile
30 |
31 | test:
32 | strategy:
33 | matrix:
34 | os: [ubuntu-latest]
35 | go: [1.22, 1.23]
36 | include:
37 | - os: ubuntu-latest
38 | go-build: ~/.cache/go-build
39 | name: ${{ matrix.os }} @ Go ${{ matrix.go }}
40 | runs-on: ${{ matrix.os }}
41 | env:
42 | GO111MODULE: on
43 | GOPROXY: https://proxy.golang.org
44 | steps:
45 | - name: Set up Go ${{ matrix.go }}
46 | uses: actions/setup-go@v5
47 | with:
48 | go-version: ${{ matrix.go }}
49 |
50 | - name: Checkout Code
51 | uses: actions/checkout@v4
52 | with:
53 | ref: ${{ github.ref }}
54 |
55 | - uses: actions/cache@v4
56 | with:
57 | path: |
58 | ${{ matrix.go-build }}
59 | ~/go/pkg/mod
60 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
61 | restore-keys: |
62 | ${{ runner.os }}-go-
63 | - name: Run Tests
64 | run: |
65 | make test
66 | - name: Upload coverage to Codecov
67 | uses: codecov/codecov-action@v4
68 | with:
69 | flags: ${{ matrix.os }},go-${{ matrix.go }}
70 |
--------------------------------------------------------------------------------
/.github/workflows/codeql.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [master]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [master]
20 | schedule:
21 | - cron: "41 23 * * 6"
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 | permissions:
28 | actions: read
29 | contents: read
30 | security-events: write
31 |
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | language: ["go"]
36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support
38 |
39 | steps:
40 | - name: Checkout repository
41 | uses: actions/checkout@v4
42 |
43 | # Initializes the CodeQL tools for scanning.
44 | - name: Initialize CodeQL
45 | uses: github/codeql-action/init@v3
46 | with:
47 | languages: ${{ matrix.language }}
48 | # If you wish to specify custom queries, you can do so here or in a config file.
49 | # By default, queries listed here will override any specified in a config file.
50 | # Prefix the list here with "+" to use these queries and those in the config file.
51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
52 |
53 | - name: Perform CodeQL Analysis
54 | uses: github/codeql-action/analyze@v3
55 |
--------------------------------------------------------------------------------
/.github/workflows/docker.yml:
--------------------------------------------------------------------------------
1 | name: Docker Image
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | tags:
8 | - "v*"
9 | pull_request:
10 | branches:
11 | - "master"
12 |
13 | jobs:
14 | build-docker:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - name: Setup go
18 | uses: actions/setup-go@v5
19 | with:
20 | go-version: "^1"
21 | - name: Checkout repository
22 | uses: actions/checkout@v4
23 | with:
24 | fetch-depth: 0
25 |
26 | - name: Build binary
27 | run: |
28 | make build_linux_amd64
29 | make build_linux_arm64
30 |
31 | - name: Set up QEMU
32 | uses: docker/setup-qemu-action@v3
33 |
34 | - name: Set up Docker Buildx
35 | uses: docker/setup-buildx-action@v3
36 |
37 | - name: Login to Docker Hub
38 | uses: docker/login-action@v3
39 | with:
40 | username: ${{ secrets.DOCKERHUB_USERNAME }}
41 | password: ${{ secrets.DOCKERHUB_TOKEN }}
42 |
43 | - name: Login to GitHub Container Registry
44 | uses: docker/login-action@v3
45 | with:
46 | registry: ghcr.io
47 | username: ${{ github.repository_owner }}
48 | password: ${{ secrets.GITHUB_TOKEN }}
49 |
50 | - name: Docker meta
51 | id: docker-meta
52 | uses: docker/metadata-action@v5
53 | with:
54 | images: |
55 | ${{ github.repository }}
56 | ghcr.io/${{ github.repository }}
57 | tags: |
58 | type=raw,value=latest,enable={{is_default_branch}}
59 | type=semver,pattern={{version}}
60 | type=semver,pattern={{major}}.{{minor}}
61 | type=semver,pattern={{major}}
62 |
63 | - name: Build and push
64 | uses: docker/build-push-action@v6
65 | with:
66 | context: .
67 | platforms: linux/amd64,linux/arm64
68 | file: docker/Dockerfile
69 | push: ${{ github.event_name != 'pull_request' }}
70 | tags: ${{ steps.docker-meta.outputs.tags }}
71 | labels: ${{ steps.docker-meta.outputs.labels }}
72 |
--------------------------------------------------------------------------------
/.goreleaser.yaml:
--------------------------------------------------------------------------------
1 | before:
2 | hooks:
3 | - go mod tidy
4 |
5 | builds:
6 | - env:
7 | - CGO_ENABLED=0
8 | goos:
9 | - darwin
10 | - linux
11 | - windows
12 | - freebsd
13 | goarch:
14 | - amd64
15 | - arm
16 | - arm64
17 | goarm:
18 | - "5"
19 | - "6"
20 | - "7"
21 | ignore:
22 | - goos: darwin
23 | goarch: arm
24 | - goos: darwin
25 | goarch: ppc64le
26 | - goos: darwin
27 | goarch: s390x
28 | - goos: windows
29 | goarch: ppc64le
30 | - goos: windows
31 | goarch: s390x
32 | - goos: windows
33 | goarch: arm
34 | goarm: "5"
35 | - goos: windows
36 | goarch: arm
37 | goarm: "6"
38 | - goos: windows
39 | goarch: arm
40 | goarm: "7"
41 | - goos: windows
42 | goarch: arm64
43 | - goos: freebsd
44 | goarch: ppc64le
45 | - goos: freebsd
46 | goarch: s390x
47 | - goos: freebsd
48 | goarch: arm
49 | goarm: "5"
50 | - goos: freebsd
51 | goarch: arm
52 | goarm: "6"
53 | - goos: freebsd
54 | goarch: arm
55 | goarm: "7"
56 | - goos: freebsd
57 | goarch: arm64
58 | flags:
59 | - -trimpath
60 | ldflags:
61 | - -s -w
62 | - -X main.Version={{.Version}}
63 | binary: >-
64 | {{ .ProjectName }}-
65 | {{- if .IsSnapshot }}{{ .Branch }}-
66 | {{- else }}{{- .Version }}-{{ end }}
67 | {{- .Os }}-
68 | {{- if eq .Arch "amd64" }}amd64
69 | {{- else if eq .Arch "amd64_v1" }}amd64
70 | {{- else if eq .Arch "386" }}386
71 | {{- else }}{{ .Arch }}{{ end }}
72 | {{- if .Arm }}-{{ .Arm }}{{ end }}
73 | no_unique_dist_dir: true
74 | hooks:
75 | post:
76 | - cmd: xz -k -9 {{ .Path }}
77 | dir: ./dist/
78 |
79 | archives:
80 | - format: binary
81 | name_template: "{{ .Binary }}"
82 | allow_different_binary_count: true
83 |
84 | checksum:
85 | name_template: "checksums.txt"
86 | extra_files:
87 | - glob: ./**.xz
88 |
89 | snapshot:
90 | name_template: "{{ incpatch .Version }}"
91 |
92 | release:
93 | # You can add extra pre-existing files to the release.
94 | # The filename on the release will be the last part of the path (base).
95 | # If another file with the same name exists, the last one found will be used.
96 | #
97 | # Templates: allowed
98 | extra_files:
99 | - glob: ./**.xz
100 |
101 | changelog:
102 | use: github
103 | groups:
104 | - title: Features
105 | regexp: "^.*feat[(\\w)]*:+.*$"
106 | order: 0
107 | - title: "Bug fixes"
108 | regexp: "^.*fix[(\\w)]*:+.*$"
109 | order: 1
110 | - title: "Enhancements"
111 | regexp: "^.*chore[(\\w)]*:+.*$"
112 | order: 2
113 | - title: "Refactor"
114 | regexp: "^.*refactor[(\\w)]*:+.*$"
115 | order: 3
116 | - title: "Build process updates"
117 | regexp: ^.*?(build|ci)(\(.+\))??!?:.+$
118 | order: 4
119 | - title: "Documentation updates"
120 | regexp: ^.*?docs?(\(.+\))??!?:.+$
121 | order: 4
122 | - title: Others
123 | order: 999
124 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # drone-telegram
2 |
3 | 
4 |
5 | [](https://godoc.org/github.com/appleboy/drone-telegram)
6 | [](https://codecov.io/gh/appleboy/drone-telegram)
7 | [](https://goreportcard.com/report/github.com/appleboy/drone-telegram)
8 |
9 | [Drone](https://github.com/drone/drone) plugin for sending telegram notifications. For the usage
10 | information and a listing of the available options please take a look at [the docs](http://plugins.drone.io/appleboy/drone-telegram/).
11 |
12 | ## Feature
13 |
14 | * [x] Send with Text Message. (`markdown` or `html` format)
15 | * [x] Send with New Photo.
16 | * [x] Send with New Document.
17 | * [x] Send with New Audio.
18 | * [x] Send with New Voice.
19 | * [x] Send with New Location.
20 | * [x] Send with New Venue.
21 | * [x] Send with New Video.
22 | * [x] Send with New Sticker.
23 |
24 | ## Build or Download a binary
25 |
26 | The pre-compiled binaries can be downloaded from [release page](https://github.com/appleboy/drone-telegram/releases). Support the following OS type.
27 |
28 | * Windows amd64/386
29 | * Linux arm/amd64/386
30 | * Darwin amd64/386
31 |
32 | With `Go` installed
33 |
34 | ```sh
35 | go get -u -v github.com/appleboy/drone-telegram
36 | ```
37 |
38 | or build the binary with the following command:
39 |
40 | ```sh
41 | export GOOS=linux
42 | export GOARCH=amd64
43 | export CGO_ENABLED=0
44 | export GO111MODULE=on
45 |
46 | go test -cover ./...
47 |
48 | go build -v -a -tags netgo -o release/linux/amd64/drone-telegram .
49 | ```
50 |
51 | ## Testing
52 |
53 | Test the package with the following command:
54 |
55 | ```sh
56 | make test
57 | ```
58 |
59 | ## Usage
60 |
61 | Execute from the working directory:
62 |
63 | ```sh
64 | docker run --rm \
65 | -e PLUGIN_TOKEN=xxxxxxx \
66 | -e PLUGIN_TO=xxxxxxx \
67 | -e PLUGIN_MESSAGE=test \
68 | -e PLUGIN_MESSAGE_FILE=testmessage.md \
69 | -e PLUGIN_PHOTO=tests/github.png \
70 | -e PLUGIN_DOCUMENT=tests/gophercolor.png \
71 | -e PLUGIN_STICKER=tests/github-logo.png \
72 | -e PLUGIN_AUDIO=tests/audio.mp3 \
73 | -e PLUGIN_VOICE=tests/voice.ogg \
74 | -e PLUGIN_LOCATION="24.9163213 121.1424972" \
75 | -e PLUGIN_VENUE="24.9163213 121.1424972 title address" \
76 | -e PLUGIN_VIDEO=tests/video.mp4 \
77 | -e PLUGIN_DEBUG=true \
78 | -e PLUGIN_ONLY_MATCH_EMAIL=false \
79 | -e PLUGIN_FORMAT=markdown \
80 | -e DRONE_REPO_OWNER=appleboy \
81 | -e DRONE_REPO_NAME=go-hello \
82 | -e DRONE_COMMIT_SHA=e5e82b5eb3737205c25955dcc3dcacc839b7be52 \
83 | -e DRONE_COMMIT_BRANCH=master \
84 | -e DRONE_COMMIT_LINK=https://github.com/appleboy/go-hello/compare/master... \
85 | -e DRONE_COMMIT_AUTHOR=appleboy \
86 | -e DRONE_COMMIT_AUTHOR_EMAIL=appleboy@gmail.com \
87 | -e DRONE_BUILD_NUMBER=1 \
88 | -e DRONE_BUILD_STATUS=success \
89 | -e DRONE_BUILD_LINK=http://github.com/appleboy/go-hello \
90 | -e DRONE_TAG=1.0.0 \
91 | -e DRONE_JOB_STARTED=1477550550 \
92 | -e DRONE_JOB_FINISHED=1477550750 \
93 | -v $(pwd):$(pwd) \
94 | -w $(pwd) \
95 | appleboy/drone-telegram
96 | ```
97 |
98 | Load all environments from file.
99 |
100 | ```bash
101 | docker run --rm \
102 | -e PLUGIN_ENV_FILE=your_env_file_path \
103 | -v $(pwd):$(pwd) \
104 | -w $(pwd) \
105 | appleboy/drone-telegram
106 | ```
107 |
--------------------------------------------------------------------------------
/images/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | DIST := dist
2 | EXECUTABLE := drone-telegram
3 | GOFMT ?= gofumpt -l
4 | DIST := dist
5 | DIST_DIRS := $(DIST)/binaries $(DIST)/release
6 | GO ?= go
7 | SHASUM ?= shasum -a 256
8 | GOFILES := $(shell find . -name "*.go" -type f)
9 | HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
10 | XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
11 | XGO_VERSION := go-1.19.x
12 | GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11
13 |
14 | LINUX_ARCHS ?= linux/amd64,linux/arm64
15 | DARWIN_ARCHS ?= darwin-10.12/amd64,darwin-10.12/arm64
16 | WINDOWS_ARCHS ?= windows/*
17 |
18 | ifneq ($(shell uname), Darwin)
19 | EXTLDFLAGS = -extldflags "-static" $(null)
20 | else
21 | EXTLDFLAGS =
22 | endif
23 |
24 | ifeq ($(HAS_GO), GO)
25 | GOPATH ?= $(shell $(GO) env GOPATH)
26 | export PATH := $(GOPATH)/bin:$(PATH)
27 |
28 | CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766
29 | CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS)
30 | endif
31 |
32 | ifeq ($(OS), Windows_NT)
33 | GOFLAGS := -v -buildmode=exe
34 | EXECUTABLE ?= $(EXECUTABLE).exe
35 | else ifeq ($(OS), Windows)
36 | GOFLAGS := -v -buildmode=exe
37 | EXECUTABLE ?= $(EXECUTABLE).exe
38 | else
39 | GOFLAGS := -v
40 | EXECUTABLE ?= $(EXECUTABLE)
41 | endif
42 |
43 | ifneq ($(DRONE_TAG),)
44 | VERSION ?= $(DRONE_TAG)
45 | else
46 | VERSION ?= $(shell git describe --tags --always || git rev-parse --short HEAD)
47 | endif
48 |
49 | TAGS ?=
50 | LDFLAGS ?= -X 'main.Version=$(VERSION)'
51 |
52 | all: build
53 |
54 | fmt:
55 | @hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
56 | $(GO) install mvdan.cc/gofumpt; \
57 | fi
58 | $(GOFMT) -w $(GOFILES)
59 |
60 | vet:
61 | $(GO) vet ./...
62 |
63 | .PHONY: fmt-check
64 | fmt-check:
65 | @hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
66 | $(GO) install mvdan.cc/gofumpt; \
67 | fi
68 | @diff=$$($(GOFMT) -d $(GOFILES)); \
69 | if [ -n "$$diff" ]; then \
70 | echo "Please run 'make fmt' and commit the result:"; \
71 | echo "$${diff}"; \
72 | exit 1; \
73 | fi;
74 |
75 | test:
76 | @$(GO) test -v -cover -coverprofile coverage.txt ./... && echo "\n==>\033[32m Ok\033[m\n" || exit 1
77 |
78 | install: $(GOFILES)
79 | $(GO) install -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)'
80 |
81 | build: $(EXECUTABLE)
82 |
83 | $(EXECUTABLE): $(GOFILES)
84 | $(GO) build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o bin/$@
85 |
86 | build_linux_amd64:
87 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GO) build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/amd64/$(DEPLOY_IMAGE)
88 |
89 | build_linux_i386:
90 | CGO_ENABLED=0 GOOS=linux GOARCH=386 $(GO) build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/i386/$(DEPLOY_IMAGE)
91 |
92 | build_linux_arm64:
93 | CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $(GO) build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/arm64/$(DEPLOY_IMAGE)
94 |
95 | build_linux_arm:
96 | 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)
97 |
98 | ssh-server:
99 | adduser -h /home/drone-scp -s /bin/sh -D -S drone-scp
100 | echo drone-scp:1234 | chpasswd
101 | mkdir -p /home/drone-scp/.ssh
102 | chmod 700 /home/drone-scp/.ssh
103 | cat tests/.ssh/id_rsa.pub >> /home/drone-scp/.ssh/authorized_keys
104 | cat tests/.ssh/test.pub >> /home/drone-scp/.ssh/authorized_keys
105 | chmod 600 /home/drone-scp/.ssh/authorized_keys
106 | chown -R drone-scp /home/drone-scp/.ssh
107 | apk add --update openssh openrc
108 | rm -rf /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_dsa_key
109 | sed -i 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/g' /etc/ssh/sshd_config
110 | sed -i 's/AllowTcpForwarding no/AllowTcpForwarding yes/g' /etc/ssh/sshd_config
111 | ./tests/entrypoint.sh /usr/sbin/sshd -D &
112 |
113 | coverage:
114 | sed -i '/main.go/d' coverage.txt
115 |
116 | .PHONY: deps-backend
117 | deps-backend:
118 | $(GO) mod download
119 | $(GO) install $(GXZ_PAGAGE)
120 | $(GO) install $(XGO_PACKAGE)
121 |
122 | .PHONY: release
123 | release: release-linux release-darwin release-windows release-copy release-compress release-check
124 |
125 | $(DIST_DIRS):
126 | mkdir -p $(DIST_DIRS)
127 |
128 | .PHONY: release-windows
129 | release-windows: | $(DIST_DIRS)
130 | 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) .
131 | ifeq ($(CI),true)
132 | cp -r /build/* $(DIST)/binaries/
133 | endif
134 |
135 | .PHONY: release-linux
136 | release-linux: | $(DIST_DIRS)
137 | 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) .
138 | ifeq ($(CI),true)
139 | cp -r /build/* $(DIST)/binaries/
140 | endif
141 |
142 | .PHONY: release-darwin
143 | release-darwin: | $(DIST_DIRS)
144 | 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) .
145 | ifeq ($(CI),true)
146 | cp -r /build/* $(DIST)/binaries/
147 | endif
148 |
149 | .PHONY: release-copy
150 | release-copy: | $(DIST_DIRS)
151 | cd $(DIST); for file in `find . -type f -name "*"`; do cp $${file} ./release/; done;
152 |
153 | .PHONY: release-check
154 | release-check: | $(DIST_DIRS)
155 | cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "checksumming $${file}" && $(SHASUM) `echo $${file} | sed 's/^..//'` > $${file}.sha256; done;
156 |
157 | .PHONY: release-compress
158 | release-compress: | $(DIST_DIRS)
159 | cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && $(GO) run $(GXZ_PAGAGE) -k -9 $${file}; done;
160 |
161 | clean:
162 | $(GO) clean -x -i ./...
163 | rm -rf coverage.txt $(EXECUTABLE) $(DIST)
164 |
165 | version:
166 | @echo $(VERSION)
167 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
2 | dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
3 | github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
4 | github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
5 | github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
6 | github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
7 | github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
8 | github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
9 | github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
10 | github.com/appleboy/drone-template-lib v1.3.0 h1:aX36/1za3v8JsEyBeMY1Bp/VNRtZa8qPYkfkjBszW+A=
11 | github.com/appleboy/drone-template-lib v1.3.0/go.mod h1:edlmXkFMKYAVypff8r2oN7aFlHfOZE5sLyPEnRHONeA=
12 | github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
13 | github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
14 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
15 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
16 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
17 | github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
18 | github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
19 | github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU=
20 | github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
21 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
22 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
23 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
24 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
25 | github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
26 | github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
27 | github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
28 | github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
29 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
30 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
31 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
32 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
33 | github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw=
34 | github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18=
35 | github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
36 | github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
37 | github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
38 | github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
39 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
40 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
41 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
42 | github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
43 | github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
44 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
45 | github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
46 | github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
47 | github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
48 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
49 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
50 | github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
51 | github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
52 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
53 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
54 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
55 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
56 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
57 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
58 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
59 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
60 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
61 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
62 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
63 | github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
64 | github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
65 | github.com/urfave/cli v1.22.15 h1:nuqt+pdC/KqswQKhETJjo7pvn/k4xMUxgW6liI7XpnM=
66 | github.com/urfave/cli v1.22.15/go.mod h1:wSan1hmo5zeyLGBjRJbzRTNk8gwoYa2B9n4q9dmRIc0=
67 | golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
68 | golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
69 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
70 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
71 | golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
72 | golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
73 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
74 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
75 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
76 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
77 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
78 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
79 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
80 |
--------------------------------------------------------------------------------
/DOCS.md:
--------------------------------------------------------------------------------
1 | ---
2 | date: 2019-10-19T00:00:00+00:00
3 | author: appleboy
4 | containerImage: docker.io/appleboy/drone-telegram
5 | containerImageUrl: https://hub.docker.com/r/appleboy/drone-telegram
6 | description: Plugin for sending Telegram notifications
7 | icon: https://raw.githubusercontent.com/appleboy/drone-telegram/refs/heads/master/images/logo.svg
8 | image: appleboy/drone-telegram
9 | logo: telegram.svg
10 | name: Telegram
11 | repo: appleboy/drone-telegram
12 | tags: [ notifications, chat ]
13 | title: Telegram
14 | url: https://github.com/appleboy/drone-telegram
15 | ---
16 |
17 | The Telegram plugin posts build status messages to your account. The below pipeline configuration demonstrates simple usage:
18 |
19 | ```yaml
20 | - name: send telegram notification
21 | image: appleboy/drone-telegram
22 | settings:
23 | token: xxxxxxxxxx
24 | to: telegram_user_id
25 | ```
26 |
27 | Example configuration with photo message:
28 |
29 | ```diff
30 | - name: send telegram notification
31 | image: appleboy/drone-telegram
32 | settings:
33 | token: xxxxxxxxxx
34 | to: telegram_user_id
35 | + photo:
36 | + - tests/1.png
37 | + - tests/2.png
38 | ```
39 |
40 | Example configuration with document message:
41 |
42 | ```diff
43 | - name: send telegram notification
44 | image: appleboy/drone-telegram
45 | settings:
46 | token: xxxxxxxxxx
47 | to: telegram_user_id
48 | + document:
49 | + - tests/1.pdf
50 | + - tests/2.pdf
51 | ```
52 |
53 | Example configuration with sticker message:
54 |
55 | ```diff
56 | - name: send telegram notification
57 | image: appleboy/drone-telegram
58 | settings:
59 | token: xxxxxxxxxx
60 | to: telegram_user_id
61 | + sticker:
62 | + - tests/3.png
63 | + - tests/4.png
64 | ```
65 |
66 | Example configuration with audio message:
67 |
68 | ```diff
69 | - name: send telegram notification
70 | image: appleboy/drone-telegram
71 | settings:
72 | token: xxxxxxxxxx
73 | to: telegram_user_id
74 | + audio:
75 | + - tests/audio1.mp3
76 | + - tests/audio2.mp3
77 | ```
78 |
79 | Example configuration with voice message:
80 |
81 | ```diff
82 | - name: send telegram notification
83 | image: appleboy/drone-telegram
84 | settings:
85 | token: xxxxxxxxxx
86 | to: telegram_user_id
87 | + voice:
88 | + - tests/voice1.ogg
89 | + - tests/voice2.ogg
90 | ```
91 |
92 | Example configuration with location message:
93 |
94 | ```diff
95 | - name: send telegram notification
96 | image: appleboy/drone-telegram
97 | settings:
98 | token: xxxxxxxxxx
99 | to: telegram_user_id
100 | + location:
101 | + - 24.9163213,121.1424972
102 | + - 24.9263213,121.1224972
103 | ```
104 |
105 | Example configuration with venue message:
106 |
107 | ```diff
108 | - name: send telegram notification
109 | image: appleboy/drone-telegram
110 | settings:
111 | token: xxxxxxxxxx
112 | to: telegram_user_id
113 | + venue:
114 | + - 24.9163213,121.1424972,title,address
115 | + - 24.3163213,121.1824972,title,address
116 | ```
117 |
118 | Example configuration with video message:
119 |
120 | ```diff
121 | - name: send telegram notification
122 | image: appleboy/drone-telegram
123 | settings:
124 | token: xxxxxxxxxx
125 | to: telegram_user_id
126 | + video:
127 | + - tests/video1.mp4
128 | + - tests/video2.mp4
129 | ```
130 |
131 | Example configuration with message format (`Markdown` or `HTML`), default as `Markdown`:
132 |
133 | ```diff
134 | - name: send telegram notification
135 | image: appleboy/drone-telegram
136 | settings:
137 | token: xxxxxxxxxx
138 | to: telegram_user_id
139 | + format: Markdown
140 | ```
141 |
142 | Example configuration with a custom message template:
143 |
144 | ```diff
145 | - name: send telegram notification
146 | image: appleboy/drone-telegram
147 | settings:
148 | token: xxxxxxxxxx
149 | to: telegram_user_id
150 | + message: >
151 | + {{#success build.status}}
152 | + build {{build.number}} succeeded. Good job.
153 | + {{else}}
154 | + build {{build.number}} failed. Fix me please.
155 | + {{/success}}
156 | ```
157 |
158 | Example configuration with a custom message template loaded from file:
159 |
160 | ```diff
161 | - name: send telegram notification
162 | image: appleboy/drone-telegram
163 | settings:
164 | token: xxxxxxxxxx
165 | to: telegram_user_id
166 | + message_file: message_file.tpl
167 | ```
168 |
169 | Example configuration with a generic message template loaded from file, with additional extra vars:
170 |
171 | ```diff
172 | - name: send telegram notification
173 | image: appleboy/drone-telegram
174 | settings:
175 | token: xxxxxxxxxx
176 | to: telegram_user_id
177 | + message_file: message_file.tpl
178 | + template_vars:
179 | + env: testing
180 | + app: MyApp
181 | ```
182 |
183 | Where `message_file.tpl` is:
184 |
185 | ```bash
186 | Build finished for *{{tpl.app}}* - *{{tpl.env}}*
187 |
188 | {{#success build.status}}
189 | build {{build.number}} succeeded. Good job.
190 | {{else}}
191 | build {{build.number}} failed. Fix me please.
192 | {{/success}}
193 | ```
194 |
195 | Example configuration with a custom message template, with extra vars loaded from file (e.g. from previous build steps):
196 |
197 | ```diff
198 | - name: send telegram notification
199 | image: appleboy/drone-telegram
200 | settings:
201 | token: xxxxxxxxxx
202 | to: telegram_user_id
203 | + template_vars_file: build_report.json
204 | + message: >
205 | + {{#success build.status}}
206 | + build {{build.number}} succeeded, artefact version = {{tpl.artefact_version}}.
207 | + {{else}}
208 | + build {{build.number}} failed. Fix me please.
209 | + {{/success}}
210 | ```
211 |
212 | Where `build_report.json` is:
213 |
214 | ```
215 | {
216 | ...
217 | "artefact_version": "0.2.3452"
218 | ...
219 | }
220 | ```
221 |
222 | Example configuration with a custom socks5 URL:
223 |
224 | ```diff
225 | - name: send telegram notification
226 | image: appleboy/drone-telegram
227 | settings:
228 | token: xxxxxxxxxx
229 | to: telegram_user_id
230 | message: send message using custom socks5 URL
231 | + socks5: socks5://67.204.21.1:64312
232 | ```
233 |
234 | Disables link previews for links in this message
235 |
236 | ```diff
237 | - name: send telegram notification
238 | image: appleboy/drone-telegram
239 | settings:
240 | token: xxxxxxxxxx
241 | to: telegram_user_id
242 | message: send message without a link preview
243 | + disable_web_page_preview: true
244 | ```
245 |
246 | Disables notifications for this message
247 |
248 | ```diff
249 | - name: send telegram notification
250 | image: appleboy/drone-telegram
251 | settings:
252 | token: xxxxxxxxxx
253 | to: telegram_user_id
254 | message: send message message silently
255 | + disable_notification: true
256 | ```
257 |
258 | ## Parameter Reference
259 |
260 | token
261 | : telegram token from [telegram developer center](https://core.telegram.org/bots/api)
262 |
263 | to
264 | : telegram user id (can be requested from the @userinfobot inside Telegram)
265 |
266 | message
267 | : overwrite the default message template
268 |
269 | message_file
270 | : overwrite the default message template with the contents of the specified file
271 |
272 | template_vars
273 | : define additional template vars. Example: `var1: hello` can be used within the template as `tpl.var1`
274 |
275 | template_vars_file
276 | : load additional template vars from json file. Example: given file content `{"var1":"hello"}`, variable can be used within the template as `tpl.var1`
277 |
278 | photo
279 | : local file path
280 |
281 | document
282 | : local file path
283 |
284 | sticker
285 | : local file path
286 |
287 | audio
288 | : local file path
289 |
290 | voice
291 | : local file path
292 |
293 | location
294 | : local file path
295 |
296 | video
297 | : local file path
298 |
299 | venue
300 | : local file path
301 |
302 | format
303 | : `markdown` or `html` format
304 |
305 | ## Template Reference
306 |
307 | repo.owner
308 | : repository owner
309 |
310 | repo.name
311 | : repository name
312 |
313 | commit.sha
314 | : git sha for current commit
315 |
316 | commit.branch
317 | : git branch for current commit
318 |
319 | commit.link
320 | : git commit link in remote
321 |
322 | commit.author
323 | : git author for current commit
324 |
325 | commit.email
326 | : git author email for current commit
327 |
328 | commit.message
329 | : git current commit message
330 |
331 | build.status
332 | : build status type enumeration, either `success` or `failure`
333 |
334 | build.event
335 | : build event type enumeration, one of `push`, `pull_request`, `tag`, `deployment`
336 |
337 | build.number
338 | : build number
339 |
340 | build.tag
341 | : git tag for current commit
342 |
343 | build.link
344 | : link the the build results in drone
345 |
346 | build.started
347 | : unix timestamp for build started
348 |
349 | build.finished
350 | : unix timestamp for build finished
351 |
352 | ## Template Function Reference
353 |
354 | uppercasefirst
355 | : converts the first letter of a string to uppercase
356 |
357 | uppercase
358 | : converts a string to uppercase
359 |
360 | lowercase
361 | : converts a string to lowercase. Example `{{lowercase build.author}}`
362 |
363 | datetime
364 | : converts a unix timestamp to a date time string. Example `{{datetime build.started}}`
365 |
366 | success
367 | : returns true if the build is successful
368 |
369 | failure
370 | : returns true if the build is failed
371 |
372 | truncate
373 | : returns a truncated string to n characters. Example `{{truncate build.sha 8}}`
374 |
375 | urlencode
376 | : returns a url encoded string
377 |
378 | since
379 | : returns a duration string between now and the given timestamp. Example `{{since build.started}}`
380 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "os"
6 |
7 | "github.com/joho/godotenv"
8 | "github.com/urfave/cli"
9 | )
10 |
11 | // Version set at compile-time
12 | var (
13 | Version string
14 | )
15 |
16 | func main() {
17 | // Load env-file if it exists first
18 | if filename, found := os.LookupEnv("PLUGIN_ENV_FILE"); found {
19 | _ = godotenv.Load(filename)
20 | }
21 |
22 | if _, err := os.Stat("/run/drone/env"); err == nil {
23 | _ = godotenv.Overload("/run/drone/env")
24 | }
25 |
26 | app := cli.NewApp()
27 | app.Name = "telegram plugin"
28 | app.Usage = "telegram plugin"
29 | app.Action = run
30 | app.Version = Version
31 | app.Flags = []cli.Flag{
32 | cli.StringFlag{
33 | Name: "token",
34 | Usage: "telegram token",
35 | EnvVar: "PLUGIN_TOKEN,TELEGRAM_TOKEN,INPUT_TOKEN",
36 | },
37 | cli.StringSliceFlag{
38 | Name: "to",
39 | Usage: "telegram user",
40 | EnvVar: "PLUGIN_TO,TELEGRAM_TO,INPUT_TO",
41 | },
42 | cli.StringFlag{
43 | Name: "message",
44 | Usage: "send telegram message",
45 | EnvVar: "PLUGIN_MESSAGE,TELEGRAM_MESSAGE,INPUT_MESSAGE",
46 | },
47 | cli.StringFlag{
48 | Name: "message.file",
49 | Usage: "send telegram message from file",
50 | EnvVar: "PLUGIN_MESSAGE_FILE,TELEGRAM_MESSAGE_FILE,INPUT_MESSAGE_FILE",
51 | },
52 | cli.StringFlag{
53 | Name: "template.vars",
54 | Usage: "additional template vars to be used in message, as JSON string",
55 | EnvVar: "PLUGIN_TEMPLATE_VARS,TELEGRAM_TEMPLATE_VARS,INPUT_TEMPLATE_VARS",
56 | },
57 | cli.StringFlag{
58 | Name: "template.vars.file",
59 | Usage: "load additional template vars to be used in message, from json file",
60 | EnvVar: "PLUGIN_TEMPLATE_VARS_FILE,TELEGRAM_TEMPLATE_VARS_FILE",
61 | },
62 | cli.StringSliceFlag{
63 | Name: "photo",
64 | Usage: "send photo message",
65 | EnvVar: "PLUGIN_PHOTO,PHOTO,INPUT_PHOTO",
66 | },
67 | cli.StringSliceFlag{
68 | Name: "document",
69 | Usage: "send document message",
70 | EnvVar: "PLUGIN_DOCUMENT,DOCUMENT,INPUT_DOCUMENT",
71 | },
72 | cli.StringSliceFlag{
73 | Name: "sticker",
74 | Usage: "send sticker message",
75 | EnvVar: "PLUGIN_STICKER,STICKER,INPUT_STICKER",
76 | },
77 | cli.StringSliceFlag{
78 | Name: "audio",
79 | Usage: "send audio message",
80 | EnvVar: "PLUGIN_AUDIO,AUDIO,INPUT_AUDIO",
81 | },
82 | cli.StringSliceFlag{
83 | Name: "voice",
84 | Usage: "send voice message",
85 | EnvVar: "PLUGIN_VOICE,VOICE,INPUT_VOICE",
86 | },
87 | cli.StringSliceFlag{
88 | Name: "location",
89 | Usage: "send location message",
90 | EnvVar: "PLUGIN_LOCATION,LOCATION,INPUT_LOCATION",
91 | },
92 | cli.StringSliceFlag{
93 | Name: "venue",
94 | Usage: "send venue message",
95 | EnvVar: "PLUGIN_VENUE,VENUE,INPUT_VENUE",
96 | },
97 | cli.StringSliceFlag{
98 | Name: "video",
99 | Usage: "send video message",
100 | EnvVar: "PLUGIN_VIDEO,VIDEO,INPUT_VIDEO",
101 | },
102 | cli.BoolFlag{
103 | Name: "debug",
104 | Usage: "enable debug message",
105 | EnvVar: "PLUGIN_DEBUG,DEBUG,INPUT_DEBUG",
106 | },
107 | cli.BoolFlag{
108 | Name: "match.email",
109 | Usage: "send message when only match email",
110 | EnvVar: "PLUGIN_ONLY_MATCH_EMAIL,INPUT_ONLY_MATCH_EMAIL",
111 | },
112 | cli.BoolFlag{
113 | Name: "disable.webpage.preview",
114 | Usage: "disables link previews for links in this message",
115 | EnvVar: "PLUGIN_DISABLE_WEB_PAGE_PREVIEW,INPUT_DISABLE_WEB_PAGE_PREVIEW",
116 | },
117 | cli.BoolFlag{
118 | Name: "disable.notification",
119 | Usage: "sends the message silently. users will receive a notification with no sound.",
120 | EnvVar: "PLUGIN_DISABLE_NOTIFICATION,INPUT_DISABLE_NOTIFICATION",
121 | },
122 | cli.StringFlag{
123 | Name: "format",
124 | Value: formatMarkdown,
125 | Usage: "telegram message format (Markdown or HTML)",
126 | EnvVar: "PLUGIN_FORMAT,FORMAT,INPUT_FORMAT",
127 | },
128 | cli.StringFlag{
129 | Name: "repo",
130 | Usage: "repository owner and repository name",
131 | EnvVar: "DRONE_REPO,GITHUB_REPOSITORY",
132 | },
133 | cli.StringFlag{
134 | Name: "repo.namespace",
135 | Usage: "repository namespace",
136 | EnvVar: "DRONE_REPO_OWNER,DRONE_REPO_NAMESPACE,GITHUB_ACTOR",
137 | },
138 | cli.StringFlag{
139 | Name: "repo.name",
140 | Usage: "repository name",
141 | EnvVar: "DRONE_REPO_NAME",
142 | },
143 | cli.StringFlag{
144 | Name: "commit.sha",
145 | Usage: "git commit sha",
146 | EnvVar: "DRONE_COMMIT_SHA,GITHUB_SHA",
147 | },
148 | cli.StringFlag{
149 | Name: "commit.ref",
150 | Usage: "git commit ref",
151 | EnvVar: "DRONE_COMMIT_REF,GITHUB_REF",
152 | },
153 | cli.StringFlag{
154 | Name: "commit.branch",
155 | Value: "master",
156 | Usage: "git commit branch",
157 | EnvVar: "DRONE_COMMIT_BRANCH",
158 | },
159 | cli.StringFlag{
160 | Name: "commit.link",
161 | Usage: "git commit link",
162 | EnvVar: "DRONE_COMMIT_LINK",
163 | },
164 | cli.StringFlag{
165 | Name: "commit.author",
166 | Usage: "git author name",
167 | EnvVar: "DRONE_COMMIT_AUTHOR",
168 | },
169 | cli.StringFlag{
170 | Name: "commit.author.email",
171 | Usage: "git author email",
172 | EnvVar: "DRONE_COMMIT_AUTHOR_EMAIL",
173 | },
174 | cli.StringFlag{
175 | Name: "commit.author.avatar",
176 | Usage: "git author avatar",
177 | EnvVar: "DRONE_COMMIT_AUTHOR_AVATAR",
178 | },
179 | cli.StringFlag{
180 | Name: "commit.message",
181 | Usage: "commit message",
182 | EnvVar: "DRONE_COMMIT_MESSAGE",
183 | },
184 | cli.StringFlag{
185 | Name: "build.event",
186 | Value: "push",
187 | Usage: "build event",
188 | EnvVar: "DRONE_BUILD_EVENT",
189 | },
190 | cli.IntFlag{
191 | Name: "build.number",
192 | Usage: "build number",
193 | EnvVar: "DRONE_BUILD_NUMBER",
194 | },
195 | cli.StringFlag{
196 | Name: "build.status",
197 | Usage: "build status",
198 | Value: "success",
199 | EnvVar: "DRONE_BUILD_STATUS",
200 | },
201 | cli.StringFlag{
202 | Name: "build.link",
203 | Usage: "build link",
204 | EnvVar: "DRONE_BUILD_LINK",
205 | },
206 | cli.StringFlag{
207 | Name: "build.tag",
208 | Usage: "build tag",
209 | EnvVar: "DRONE_TAG",
210 | },
211 | cli.StringFlag{
212 | Name: "pull.request",
213 | Usage: "pull request",
214 | EnvVar: "DRONE_PULL_REQUEST",
215 | },
216 | cli.Int64Flag{
217 | Name: "build.started",
218 | Usage: "build started",
219 | EnvVar: "DRONE_STAGE_STARTED",
220 | },
221 | cli.Int64Flag{
222 | Name: "build.finished",
223 | Usage: "build finished",
224 | EnvVar: "DRONE_BUILD_FINISHED",
225 | },
226 | cli.BoolFlag{
227 | Name: "github",
228 | Usage: "Boolean value, indicates the runtime environment is GitHub Action.",
229 | EnvVar: "PLUGIN_GITHUB,GITHUB",
230 | },
231 | cli.StringFlag{
232 | Name: "github.workflow",
233 | Usage: "The name of the workflow.",
234 | EnvVar: "GITHUB_WORKFLOW",
235 | },
236 | cli.StringFlag{
237 | Name: "github.action",
238 | Usage: "The name of the action.",
239 | EnvVar: "GITHUB_ACTION",
240 | },
241 | cli.StringFlag{
242 | Name: "github.event.name",
243 | Usage: "The webhook name of the event that triggered the workflow.",
244 | EnvVar: "GITHUB_EVENT_NAME",
245 | },
246 | cli.StringFlag{
247 | Name: "github.event.path",
248 | Usage: "The path to a file that contains the payload of the event that triggered the workflow. Value: /github/workflow/event.json.",
249 | EnvVar: "GITHUB_EVENT_PATH",
250 | },
251 | cli.StringFlag{
252 | Name: "github.workspace",
253 | Usage: "The GitHub workspace path. Value: /github/workspace.",
254 | EnvVar: "GITHUB_WORKSPACE",
255 | },
256 | cli.StringFlag{
257 | Name: "deploy.to",
258 | Usage: "Provides the target deployment environment for the running build. This value is only available to promotion and rollback pipelines.",
259 | EnvVar: "DRONE_DEPLOY_TO",
260 | },
261 | cli.StringFlag{
262 | Name: "socks5",
263 | Usage: "Socks5 proxy URL",
264 | EnvVar: "PLUGIN_SOCKS5,SOCKS5,INPUT_SOCKS5",
265 | },
266 | }
267 |
268 | if err := app.Run(os.Args); err != nil {
269 | log.Fatal(err)
270 | }
271 | }
272 |
273 | func run(c *cli.Context) error {
274 | plugin := Plugin{
275 | GitHub: GitHub{
276 | Workflow: c.String("github.workflow"),
277 | Workspace: c.String("github.workspace"),
278 | Action: c.String("github.action"),
279 | EventName: c.String("github.event.name"),
280 | EventPath: c.String("github.event.path"),
281 | },
282 | Repo: Repo{
283 | FullName: c.String("repo"),
284 | Namespace: c.String("repo.namespace"),
285 | Name: c.String("repo.name"),
286 | },
287 | Commit: Commit{
288 | Sha: c.String("commit.sha"),
289 | Ref: c.String("commit.ref"),
290 | Branch: c.String("commit.branch"),
291 | Link: c.String("commit.link"),
292 | Author: c.String("commit.author"),
293 | Email: c.String("commit.author.email"),
294 | Avatar: c.String("commit.author.avatar"),
295 | Message: c.String("commit.message"),
296 | },
297 | Build: Build{
298 | Tag: c.String("build.tag"),
299 | Number: c.Int("build.number"),
300 | Event: c.String("build.event"),
301 | Status: c.String("build.status"),
302 | Link: c.String("build.link"),
303 | Started: c.Int64("build.started"),
304 | Finished: c.Int64("build.finished"),
305 | PR: c.String("pull.request"),
306 | DeployTo: c.String("deploy.to"),
307 | },
308 | Config: Config{
309 | Token: c.String("token"),
310 | Debug: c.Bool("debug"),
311 | MatchEmail: c.Bool("match.email"),
312 | To: c.StringSlice("to"),
313 | Message: c.String("message"),
314 | MessageFile: c.String("message.file"),
315 | TemplateVars: c.String("template.vars"),
316 | TemplateVarsFile: c.String("template.vars.file"),
317 | Photo: c.StringSlice("photo"),
318 | Document: c.StringSlice("document"),
319 | Sticker: c.StringSlice("sticker"),
320 | Audio: c.StringSlice("audio"),
321 | Voice: c.StringSlice("voice"),
322 | Location: c.StringSlice("location"),
323 | Video: c.StringSlice("video"),
324 | Venue: c.StringSlice("venue"),
325 | Format: c.String("format"),
326 | GitHub: c.Bool("github"),
327 | Socks5: c.String("socks5"),
328 |
329 | DisableWebPagePreview: c.Bool("disable.webpage.preview"),
330 | DisableNotification: c.Bool("disable.notification"),
331 | },
332 | }
333 |
334 | return plugin.Exec()
335 | }
336 |
--------------------------------------------------------------------------------
/plugin.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bufio"
5 | "encoding/json"
6 | "errors"
7 | "fmt"
8 | "html"
9 | "io"
10 | "log"
11 | "net/http"
12 | "net/url"
13 | "os"
14 | "path/filepath"
15 | "strconv"
16 | "strings"
17 |
18 | "github.com/appleboy/drone-template-lib/template"
19 | tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
20 | )
21 |
22 | const (
23 | formatMarkdown = "Markdown"
24 | formatHTML = "HTML"
25 | )
26 |
27 | type (
28 | // GitHub information.
29 | GitHub struct {
30 | Workflow string
31 | Workspace string
32 | Action string
33 | EventName string
34 | EventPath string
35 | }
36 |
37 | // Repo information.
38 | Repo struct {
39 | FullName string
40 | Namespace string
41 | Name string
42 | }
43 |
44 | // Commit information.
45 | Commit struct {
46 | Sha string
47 | Ref string
48 | Branch string
49 | Link string
50 | Author string
51 | Avatar string
52 | Email string
53 | Message string
54 | }
55 |
56 | // Build information.
57 | Build struct {
58 | Tag string
59 | Event string
60 | Number int
61 | Status string
62 | Link string
63 | Started int64
64 | Finished int64
65 | PR string
66 | DeployTo string
67 | }
68 |
69 | // Config for the plugin.
70 | Config struct {
71 | Token string
72 | Debug bool
73 | MatchEmail bool
74 | To []string
75 | Message string
76 | MessageFile string
77 | TemplateVarsFile string
78 | TemplateVars string
79 | Photo []string
80 | Document []string
81 | Sticker []string
82 | Audio []string
83 | Voice []string
84 | Location []string
85 | Video []string
86 | Venue []string
87 | Format string
88 | GitHub bool
89 | Socks5 string
90 |
91 | DisableWebPagePreview bool
92 | DisableNotification bool
93 | }
94 |
95 | // Plugin values.
96 | Plugin struct {
97 | GitHub GitHub
98 | Repo Repo
99 | Commit Commit
100 | Build Build
101 | Config Config
102 | Tpl map[string]string
103 | }
104 |
105 | // Location format
106 | Location struct {
107 | Title string
108 | Address string
109 | Latitude float64
110 | Longitude float64
111 | }
112 | )
113 |
114 | var icons = map[string]string{
115 | "failure": "❌",
116 | "cancelled": "❕",
117 | "success": "✅",
118 | }
119 |
120 | func trimElement(keys []string) []string {
121 | var newKeys []string
122 |
123 | for _, value := range keys {
124 | value = strings.Trim(value, " ")
125 | if len(value) == 0 {
126 | continue
127 | }
128 | newKeys = append(newKeys, value)
129 | }
130 |
131 | return newKeys
132 | }
133 |
134 | func escapeMarkdown(keys []string) []string {
135 | var newKeys []string
136 |
137 | for _, value := range keys {
138 | value = escapeMarkdownOne(value)
139 | if len(value) == 0 {
140 | continue
141 | }
142 | newKeys = append(newKeys, value)
143 | }
144 |
145 | return newKeys
146 | }
147 |
148 | func escapeMarkdownOne(str string) string {
149 | str = strings.ReplaceAll(str, `\_`, `_`)
150 | str = strings.ReplaceAll(str, `_`, `\_`)
151 |
152 | return str
153 | }
154 |
155 | func globList(keys []string) []string {
156 | var newKeys []string
157 |
158 | for _, pattern := range keys {
159 | pattern = strings.Trim(pattern, " ")
160 | matches, err := filepath.Glob(pattern)
161 | if err != nil {
162 | fmt.Printf("Glob error for %q: %s\n", pattern, err)
163 | continue
164 | }
165 | newKeys = append(newKeys, matches...)
166 | }
167 |
168 | return newKeys
169 | }
170 |
171 | func convertLocation(value string) (Location, bool) {
172 | var latitude, longitude float64
173 | var title, address string
174 | var err error
175 | values := trimElement(strings.Split(value, " "))
176 |
177 | if len(values) < 2 {
178 | return Location{}, true
179 | }
180 |
181 | if len(values) > 2 {
182 | title = values[2]
183 | }
184 |
185 | if len(values) > 3 {
186 | title = values[2]
187 | address = values[3]
188 | }
189 |
190 | latitude, err = strconv.ParseFloat(values[0], 64)
191 | if err != nil {
192 | log.Println(err.Error())
193 | return Location{}, true
194 | }
195 |
196 | longitude, err = strconv.ParseFloat(values[1], 64)
197 | if err != nil {
198 | log.Println(err.Error())
199 | return Location{}, true
200 | }
201 |
202 | return Location{
203 | Title: title,
204 | Address: address,
205 | Latitude: latitude,
206 | Longitude: longitude,
207 | }, false
208 | }
209 |
210 | func loadTextFromFile(filename string) ([]string, error) {
211 | f, err := os.Open(filename)
212 | if err != nil {
213 | return nil, err
214 | }
215 | defer f.Close()
216 | r := bufio.NewReader(f)
217 | content, err := io.ReadAll(r)
218 | if err != nil {
219 | return nil, err
220 | }
221 | return []string{string(content)}, nil
222 | }
223 |
224 | func parseTo(to []string, authorEmail string, matchEmail bool) []int64 {
225 | var emails []int64
226 | var ids []int64
227 | attachEmail := true
228 |
229 | for _, value := range trimElement(to) {
230 | idArray := trimElement(strings.Split(value, ":"))
231 |
232 | // check id
233 | id, err := strconv.ParseInt(idArray[0], 10, 64)
234 | if err != nil {
235 | continue
236 | }
237 |
238 | // check match author email
239 | if len(idArray) > 1 {
240 | if email := idArray[1]; email != authorEmail {
241 | continue
242 | }
243 |
244 | emails = append(emails, id)
245 | attachEmail = false
246 | continue
247 | }
248 |
249 | ids = append(ids, id)
250 | }
251 |
252 | if matchEmail && !attachEmail {
253 | return emails
254 | }
255 |
256 | ids = append(ids, emails...)
257 |
258 | return ids
259 | }
260 |
261 | func templateMessage(t string, plugin Plugin) (string, error) {
262 | return template.RenderTrim(t, plugin)
263 | }
264 |
265 | // Exec executes the plugin.
266 | func (p Plugin) Exec() (err error) {
267 | if len(p.Config.Token) == 0 || len(p.Config.To) == 0 {
268 | return errors.New("missing telegram token or user list")
269 | }
270 |
271 | var message []string
272 | switch {
273 | case len(p.Config.MessageFile) > 0:
274 | message, err = loadTextFromFile(p.Config.MessageFile)
275 | if err != nil {
276 | return fmt.Errorf("error loading message file '%s': %v", p.Config.MessageFile, err)
277 | }
278 | case len(p.Config.Message) > 0:
279 | message = []string{p.Config.Message}
280 | default:
281 | p.Config.Format = formatMarkdown
282 | message = p.Message()
283 | }
284 |
285 | if p.Config.TemplateVars != "" {
286 | p.Tpl = make(map[string]string)
287 | if err = json.Unmarshal([]byte(p.Config.TemplateVars), &p.Tpl); err != nil {
288 | return fmt.Errorf("unable to unmarshall template vars from JSON string '%s': %v", p.Config.TemplateVars, err)
289 | }
290 | }
291 |
292 | if p.Config.TemplateVarsFile != "" {
293 | content, err := os.ReadFile(p.Config.TemplateVarsFile)
294 | if err != nil {
295 | return fmt.Errorf("unable to read file with template vars '%s': %v", p.Config.TemplateVarsFile, err)
296 | }
297 | vars := make(map[string]string)
298 | if err = json.Unmarshal(content, &vars); err != nil {
299 | return fmt.Errorf("unable to unmarshall template vars from JSON file '%s': %v", p.Config.TemplateVarsFile, err)
300 | }
301 | // Merging templates variables from file to the variables form plugin settings (variables from file takes precedence)
302 | if p.Tpl == nil {
303 | p.Tpl = vars
304 | } else {
305 | for k, v := range vars {
306 | p.Tpl[k] = v
307 | }
308 | }
309 | }
310 |
311 | var proxyURL *url.URL
312 | if proxyURL, err = url.Parse(p.Config.Socks5); err != nil {
313 | return fmt.Errorf("unable to unmarshall socks5 proxy url from string '%s': %v", p.Config.Socks5, err)
314 | }
315 |
316 | var bot *tgbotapi.BotAPI
317 | if len(p.Config.Socks5) > 0 {
318 | proxyClient := &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)}}
319 | bot, err = tgbotapi.NewBotAPIWithClient(p.Config.Token, proxyClient)
320 | } else {
321 | bot, err = tgbotapi.NewBotAPI(p.Config.Token)
322 | }
323 |
324 | if err != nil {
325 | return err
326 | }
327 |
328 | bot.Debug = p.Config.Debug
329 |
330 | ids := parseTo(p.Config.To, p.Commit.Email, p.Config.MatchEmail)
331 | photos := globList(trimElement(p.Config.Photo))
332 | documents := globList(trimElement(p.Config.Document))
333 | stickers := globList(trimElement(p.Config.Sticker))
334 | audios := globList(trimElement(p.Config.Audio))
335 | voices := globList(trimElement(p.Config.Voice))
336 | videos := globList(trimElement(p.Config.Video))
337 | locations := trimElement(p.Config.Location)
338 | venues := trimElement(p.Config.Venue)
339 |
340 | message = trimElement(message)
341 |
342 | if p.Config.Format == formatMarkdown {
343 | message = escapeMarkdown(message)
344 |
345 | p.Commit.Message = escapeMarkdownOne(p.Commit.Message)
346 | p.Commit.Branch = escapeMarkdownOne(p.Commit.Branch)
347 | p.Commit.Link = escapeMarkdownOne(p.Commit.Link)
348 | p.Commit.Author = escapeMarkdownOne(p.Commit.Author)
349 | p.Commit.Email = escapeMarkdownOne(p.Commit.Email)
350 |
351 | p.Build.Tag = escapeMarkdownOne(p.Build.Tag)
352 | p.Build.Link = escapeMarkdownOne(p.Build.Link)
353 | p.Build.PR = escapeMarkdownOne(p.Build.PR)
354 |
355 | p.Repo.Namespace = escapeMarkdownOne(p.Repo.Namespace)
356 | p.Repo.Name = escapeMarkdownOne(p.Repo.Name)
357 | }
358 |
359 | // send message.
360 | for _, user := range ids {
361 | for _, value := range message {
362 | txt, err := templateMessage(value, p)
363 | if err != nil {
364 | return err
365 | }
366 |
367 | txt = html.UnescapeString(txt)
368 |
369 | msg := tgbotapi.NewMessage(user, txt)
370 | msg.ParseMode = p.Config.Format
371 | msg.DisableWebPagePreview = p.Config.DisableWebPagePreview
372 | msg.DisableNotification = p.Config.DisableNotification
373 | if err := p.Send(bot, msg); err != nil {
374 | return err
375 | }
376 | }
377 |
378 | for _, value := range photos {
379 | msg := tgbotapi.NewPhotoUpload(user, value)
380 | if err := p.Send(bot, msg); err != nil {
381 | return err
382 | }
383 | }
384 |
385 | for _, value := range documents {
386 | msg := tgbotapi.NewDocumentUpload(user, value)
387 | if err := p.Send(bot, msg); err != nil {
388 | return err
389 | }
390 | }
391 |
392 | for _, value := range stickers {
393 | msg := tgbotapi.NewStickerUpload(user, value)
394 | if err := p.Send(bot, msg); err != nil {
395 | return err
396 | }
397 | }
398 |
399 | for _, value := range audios {
400 | msg := tgbotapi.NewAudioUpload(user, value)
401 | msg.Title = "Audio Message."
402 | if err := p.Send(bot, msg); err != nil {
403 | return err
404 | }
405 | }
406 |
407 | for _, value := range voices {
408 | msg := tgbotapi.NewVoiceUpload(user, value)
409 | if err := p.Send(bot, msg); err != nil {
410 | return err
411 | }
412 | }
413 |
414 | for _, value := range videos {
415 | msg := tgbotapi.NewVideoUpload(user, value)
416 | msg.Caption = "Video Message"
417 | if err := p.Send(bot, msg); err != nil {
418 | return err
419 | }
420 | }
421 |
422 | for _, value := range locations {
423 | location, empty := convertLocation(value)
424 |
425 | if empty {
426 | continue
427 | }
428 |
429 | msg := tgbotapi.NewLocation(user, location.Latitude, location.Longitude)
430 | if err := p.Send(bot, msg); err != nil {
431 | return err
432 | }
433 | }
434 |
435 | for _, value := range venues {
436 | location, empty := convertLocation(value)
437 |
438 | if empty {
439 | continue
440 | }
441 |
442 | msg := tgbotapi.NewVenue(user, location.Title, location.Address, location.Latitude, location.Longitude)
443 | if err := p.Send(bot, msg); err != nil {
444 | return err
445 | }
446 | }
447 | }
448 |
449 | return nil
450 | }
451 |
452 | // Send bot message.
453 | func (p Plugin) Send(bot *tgbotapi.BotAPI, msg tgbotapi.Chattable) error {
454 | message, err := bot.Send(msg)
455 |
456 | if p.Config.Debug {
457 | log.Println("=====================")
458 | log.Printf("Response Message: %#v\n", message)
459 | log.Println("=====================")
460 | }
461 |
462 | if err == nil {
463 | return nil
464 | }
465 |
466 | return errors.New(strings.ReplaceAll(err.Error(), p.Config.Token, ""))
467 | }
468 |
469 | // Message is plugin default message.
470 | func (p Plugin) Message() []string {
471 | icon := icons[strings.ToLower(p.Build.Status)]
472 |
473 | if p.Config.GitHub {
474 | return []string{fmt.Sprintf("%s/%s triggered by %s (%s)",
475 | p.Repo.FullName,
476 | p.GitHub.Workflow,
477 | p.Repo.Namespace,
478 | p.GitHub.EventName,
479 | )}
480 | }
481 |
482 | // ✅ Build #106 of drone-telegram succeeded.
483 | //
484 | // 📝 Commit by appleboy on master:
485 | // chore: update default template
486 | //
487 | // 🌐 https://cloud.drone.io/appleboy/drone-telegram/106
488 | return []string{fmt.Sprintf("%s Build #%d of `%s` %s.\n\n📝 Commit by %s on `%s`:\n``` %s ```\n\n🌐 %s",
489 | icon,
490 | p.Build.Number,
491 | p.Repo.FullName,
492 | p.Build.Status,
493 | p.Commit.Author,
494 | p.Commit.Branch,
495 | p.Commit.Message,
496 | p.Build.Link,
497 | )}
498 | }
499 |
--------------------------------------------------------------------------------
/plugin_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "os"
5 | "testing"
6 | "time"
7 |
8 | "github.com/appleboy/drone-template-lib/template"
9 | "github.com/stretchr/testify/assert"
10 | )
11 |
12 | func TestMissingDefaultConfig(t *testing.T) {
13 | var plugin Plugin
14 |
15 | err := plugin.Exec()
16 |
17 | assert.NotNil(t, err)
18 | }
19 |
20 | func TestMissingUserConfig(t *testing.T) {
21 | plugin := Plugin{
22 | Config: Config{
23 | Token: "123456789",
24 | },
25 | }
26 |
27 | err := plugin.Exec()
28 |
29 | assert.NotNil(t, err)
30 | }
31 |
32 | func TestDefaultMessageFormat(t *testing.T) {
33 | plugin := Plugin{
34 | Repo: Repo{
35 | FullName: "appleboy/go-hello",
36 | Name: "go-hello",
37 | Namespace: "appleboy",
38 | },
39 | Commit: Commit{
40 | Sha: "e7c4f0a63ceeb42a39ac7806f7b51f3f0d204fd2",
41 | Author: "Bo-Yi Wu",
42 | Branch: "master",
43 | Message: "update travis",
44 | },
45 | Build: Build{
46 | Number: 101,
47 | Status: "success",
48 | Link: "https://github.com/appleboy/go-hello",
49 | },
50 | }
51 |
52 | message := plugin.Message()
53 |
54 | assert.Equal(t, []string{"✅ Build #101 of `appleboy/go-hello` success.\n\n📝 Commit by Bo-Yi Wu on `master`:\n``` update travis ```\n\n🌐 https://github.com/appleboy/go-hello"}, message)
55 | }
56 |
57 | func TestDefaultMessageFormatFromGitHub(t *testing.T) {
58 | plugin := Plugin{
59 | Config: Config{
60 | GitHub: true,
61 | },
62 | Repo: Repo{
63 | FullName: "appleboy/go-hello",
64 | Name: "go-hello",
65 | Namespace: "appleboy",
66 | },
67 | GitHub: GitHub{
68 | Workflow: "test-workflow",
69 | Action: "send notification",
70 | EventName: "push",
71 | },
72 | }
73 |
74 | message := plugin.Message()
75 |
76 | assert.Equal(t, []string{"appleboy/go-hello/test-workflow triggered by appleboy (push)"}, message)
77 | }
78 |
79 | func TestSendMessage(t *testing.T) {
80 | plugin := Plugin{
81 | Repo: Repo{
82 | Name: "go-hello",
83 | Namespace: "appleboy",
84 | },
85 | Commit: Commit{
86 | Sha: "e7c4f0a63ceeb42a39ac7806f7b51f3f0d204fd2",
87 | Author: "Bo-Yi Wu",
88 | Branch: "master",
89 | Message: "update travis by drone plugin",
90 | Email: "test@gmail.com",
91 | },
92 | Build: Build{
93 | Tag: "1.0.0",
94 | Number: 101,
95 | Status: "success",
96 | Link: "https://github.com/appleboy/go-hello",
97 | },
98 |
99 | Config: Config{
100 | Token: os.Getenv("TELEGRAM_TOKEN"),
101 | To: []string{os.Getenv("TELEGRAM_TO"), os.Getenv("TELEGRAM_TO") + ":appleboy@gmail.com", "中文ID", "1234567890"},
102 | Message: "Test Telegram Chat Bot From Travis or Local, commit message: 『{{ build.message }}』",
103 | Photo: []string{"tests/github.png", "1234", " "},
104 | Document: []string{"tests/gophercolor.png", "1234", " "},
105 | Sticker: []string{"tests/github-logo.png", "tests/github.png", "1234", " "},
106 | Audio: []string{"tests/audio.mp3", "1234", " "},
107 | Voice: []string{"tests/voice.ogg", "1234", " "},
108 | Location: []string{"24.9163213 121.1424972", "1", " "},
109 | Venue: []string{"35.661777 139.704051 竹北體育館 新竹縣竹北市", "24.9163213 121.1424972", "1", " "},
110 | Video: []string{"tests/video.mp4", "1234", " "},
111 | Debug: false,
112 | },
113 | }
114 |
115 | err := plugin.Exec()
116 | assert.NotNil(t, err)
117 |
118 | plugin.Config.Format = formatMarkdown
119 | plugin.Config.Message = "Test escape under_score"
120 | err = plugin.Exec()
121 | assert.NotNil(t, err)
122 |
123 | // disable message
124 | plugin.Config.Message = ""
125 | err = plugin.Exec()
126 | assert.NotNil(t, err)
127 | }
128 |
129 | func TestDisableWebPagePreviewMessage(t *testing.T) {
130 | plugin := Plugin{
131 | Config: Config{
132 | Token: os.Getenv("TELEGRAM_TOKEN"),
133 | To: []string{os.Getenv("TELEGRAM_TO")},
134 | DisableWebPagePreview: true,
135 | Debug: false,
136 | },
137 | }
138 |
139 | plugin.Config.Message = "DisableWebPagePreview https://www.google.com.tw"
140 | err := plugin.Exec()
141 | assert.Nil(t, err)
142 |
143 | // disable message
144 | plugin.Config.DisableWebPagePreview = false
145 | plugin.Config.Message = "EnableWebPagePreview https://www.google.com.tw"
146 | err = plugin.Exec()
147 | assert.Nil(t, err)
148 | }
149 |
150 | func TestDisableNotificationMessage(t *testing.T) {
151 | plugin := Plugin{
152 | Config: Config{
153 | Token: os.Getenv("TELEGRAM_TOKEN"),
154 | To: []string{os.Getenv("TELEGRAM_TO")},
155 | DisableNotification: true,
156 | Debug: false,
157 | },
158 | }
159 |
160 | plugin.Config.Message = "DisableNotification https://www.google.com.tw"
161 | err := plugin.Exec()
162 | assert.Nil(t, err)
163 |
164 | // disable message
165 | plugin.Config.DisableNotification = false
166 | plugin.Config.Message = "EnableNotification https://www.google.com.tw"
167 | err = plugin.Exec()
168 | assert.Nil(t, err)
169 | }
170 |
171 | func TestBotError(t *testing.T) {
172 | plugin := Plugin{
173 | Repo: Repo{
174 | Name: "go-hello",
175 | Namespace: "appleboy",
176 | },
177 | Commit: Commit{
178 | Sha: "e7c4f0a63ceeb42a39ac7806f7b51f3f0d204fd2",
179 | Author: "Bo-Yi Wu",
180 | Branch: "master",
181 | Message: "update travis by drone plugin",
182 | },
183 | Build: Build{
184 | Number: 101,
185 | Status: "success",
186 | Link: "https://github.com/appleboy/go-hello",
187 | },
188 |
189 | Config: Config{
190 | Token: "appleboy",
191 | To: []string{os.Getenv("TELEGRAM_TO"), "中文ID", "1234567890"},
192 | Message: "Test Telegram Chat Bot From Travis or Local",
193 | },
194 | }
195 |
196 | err := plugin.Exec()
197 | assert.NotNil(t, err)
198 | }
199 |
200 | func TestTrimElement(t *testing.T) {
201 | var input, result []string
202 |
203 | input = []string{"1", " ", "3"}
204 | result = []string{"1", "3"}
205 |
206 | assert.Equal(t, result, trimElement(input))
207 |
208 | input = []string{"1", "2"}
209 | result = []string{"1", "2"}
210 |
211 | assert.Equal(t, result, trimElement(input))
212 | }
213 |
214 | func TestEscapeMarkdown(t *testing.T) {
215 | provider := [][][]string{
216 | {
217 | {"user", "repo"},
218 | {"user", "repo"},
219 | },
220 | {
221 | {"user_name", "repo_name"},
222 | {`user\_name`, `repo\_name`},
223 | },
224 | {
225 | {"user_name_long", "user_name_long"},
226 | {`user\_name\_long`, `user\_name\_long`},
227 | },
228 | {
229 | {`user\_name\_long`, `repo\_name\_long`},
230 | {`user\_name\_long`, `repo\_name\_long`},
231 | },
232 | {
233 | {`user\_name\_long`, `repo\_name\_long`, ""},
234 | {`user\_name\_long`, `repo\_name\_long`},
235 | },
236 | }
237 |
238 | for _, testCase := range provider {
239 | assert.Equal(t, testCase[1], escapeMarkdown(testCase[0]))
240 | }
241 | }
242 |
243 | func TestEscapeMarkdownOne(t *testing.T) {
244 | provider := [][]string{
245 | {"user", "user"},
246 | {"user_name", `user\_name`},
247 | {"user_name_long", `user\_name\_long`},
248 | {`user\_name\_escaped`, `user\_name\_escaped`},
249 | }
250 |
251 | for _, testCase := range provider {
252 | assert.Equal(t, testCase[1], escapeMarkdownOne(testCase[0]))
253 | }
254 | }
255 |
256 | func TestParseTo(t *testing.T) {
257 | input := []string{"0", "1:1@gmail.com", "2:2@gmail.com", "3:3@gmail.com", "4", "5"}
258 |
259 | ids := parseTo(input, "1@gmail.com", false)
260 | assert.Equal(t, []int64{0, 4, 5, 1}, ids)
261 |
262 | ids = parseTo(input, "1@gmail.com", true)
263 | assert.Equal(t, []int64{1}, ids)
264 |
265 | ids = parseTo(input, "a@gmail.com", false)
266 | assert.Equal(t, []int64{0, 4, 5}, ids)
267 |
268 | ids = parseTo(input, "a@gmail.com", true)
269 | assert.Equal(t, []int64{0, 4, 5}, ids)
270 |
271 | // test empty ids
272 | ids = parseTo([]string{"", " ", " "}, "a@gmail.com", true)
273 | assert.Equal(t, 0, len(ids))
274 | }
275 |
276 | func TestGlobList(t *testing.T) {
277 | var input []string
278 | var result []string
279 |
280 | input = []string{"tests/gophercolor.png", "測試", "3"}
281 | result = []string{"tests/gophercolor.png"}
282 | assert.Equal(t, result, globList(input))
283 |
284 | input = []string{"tests/*.mp3"}
285 | result = []string{"tests/audio.mp3"}
286 | assert.Equal(t, result, globList(input))
287 | }
288 |
289 | func TestConvertLocation(t *testing.T) {
290 | var input string
291 | var result Location
292 | var empty bool
293 |
294 | input = "1"
295 | result, empty = convertLocation(input)
296 |
297 | assert.Equal(t, true, empty)
298 | assert.Equal(t, Location{}, result)
299 |
300 | // strconv.ParseInt: parsing "測試": invalid syntax
301 | input = "測試 139.704051"
302 | result, empty = convertLocation(input)
303 |
304 | assert.Equal(t, true, empty)
305 | assert.Equal(t, Location{}, result)
306 |
307 | // strconv.ParseInt: parsing "測試": invalid syntax
308 | input = "35.661777 測試"
309 | result, empty = convertLocation(input)
310 |
311 | assert.Equal(t, true, empty)
312 | assert.Equal(t, Location{}, result)
313 |
314 | input = "35.661777 139.704051"
315 | result, empty = convertLocation(input)
316 |
317 | assert.Equal(t, false, empty)
318 | assert.Equal(t, Location{
319 | Latitude: float64(35.661777),
320 | Longitude: float64(139.704051),
321 | }, result)
322 |
323 | input = "35.661777 139.704051 title"
324 | result, empty = convertLocation(input)
325 |
326 | assert.Equal(t, false, empty)
327 | assert.Equal(t, Location{
328 | Title: "title",
329 | Address: "",
330 | Latitude: float64(35.661777),
331 | Longitude: float64(139.704051),
332 | }, result)
333 |
334 | input = "35.661777 139.704051 title address"
335 | result, empty = convertLocation(input)
336 |
337 | assert.Equal(t, false, empty)
338 | assert.Equal(t, Location{
339 | Title: "title",
340 | Address: "address",
341 | Latitude: float64(35.661777),
342 | Longitude: float64(139.704051),
343 | }, result)
344 | }
345 |
346 | func TestHTMLMessage(t *testing.T) {
347 | plugin := Plugin{
348 | Repo: Repo{
349 | Name: "go-hello",
350 | Namespace: "appleboy",
351 | },
352 | Commit: Commit{
353 | Sha: "e7c4f0a63ceeb42a39ac7806f7b51f3f0d204fd2",
354 | Author: "Bo-Yi Wu",
355 | Branch: "master",
356 | Message: "test",
357 | },
358 | Build: Build{
359 | Number: 101,
360 | Status: "success",
361 | Link: "https://github.com/appleboy/go-hello",
362 | },
363 |
364 | Config: Config{
365 | Token: os.Getenv("TELEGRAM_TOKEN"),
366 | To: []string{os.Getenv("TELEGRAM_TO")},
367 | Message: `
368 | Test HTML Format
369 | Google .com 1
370 | Google .com 2
371 | Google .com 3
372 | `,
373 | Format: formatHTML,
374 | },
375 | }
376 |
377 | assert.Nil(t, plugin.Exec())
378 |
379 | plugin.Config.MessageFile = "tests/message_html.txt"
380 | assert.Nil(t, plugin.Exec())
381 | }
382 |
383 | func TestMessageFile(t *testing.T) {
384 | plugin := Plugin{
385 | Repo: Repo{
386 | Name: "go-hello",
387 | Namespace: "appleboy",
388 | },
389 | Commit: Commit{
390 | Sha: "e7c4f0a63ceeb42a39ac7806f7b51f3f0d204fd2",
391 | Author: "Bo-Yi Wu",
392 | Branch: "master",
393 | Message: "Freakin' macOS isn't fully case-sensitive..",
394 | },
395 | Build: Build{
396 | Number: 101,
397 | Status: "success",
398 | Link: "https://github.com/appleboy/go-hello",
399 | Started: time.Now().Unix(),
400 | Finished: time.Now().Add(180 * time.Second).Unix(),
401 | },
402 |
403 | Config: Config{
404 | Token: os.Getenv("TELEGRAM_TOKEN"),
405 | To: []string{os.Getenv("TELEGRAM_TO")},
406 | MessageFile: "tests/message.txt",
407 | },
408 | }
409 |
410 | err := plugin.Exec()
411 | assert.Nil(t, err)
412 | }
413 |
414 | func TestTemplateVars(t *testing.T) {
415 | plugin := Plugin{
416 | Repo: Repo{
417 | Name: "go-hello",
418 | Namespace: "appleboy",
419 | },
420 | Commit: Commit{
421 | Sha: "e7c4f0a63ceeb42a39ac7806f7b51f3f0d204fd2",
422 | Author: "Bo-Yi Wu",
423 | Branch: "master",
424 | Message: "This is a test commit msg",
425 | },
426 | Build: Build{
427 | Number: 101,
428 | Status: "success",
429 | Link: "https://github.com/appleboy/go-hello",
430 | Started: time.Now().Unix(),
431 | Finished: time.Now().Add(180 * time.Second).Unix(),
432 | },
433 |
434 | Config: Config{
435 | Token: os.Getenv("TELEGRAM_TOKEN"),
436 | To: []string{os.Getenv("TELEGRAM_TO")},
437 | Format: formatMarkdown,
438 | MessageFile: "tests/message_template.txt",
439 | TemplateVars: `{"env":"testing","version":"1.2.0-SNAPSHOT"}`,
440 | },
441 | }
442 |
443 | err := plugin.Exec()
444 | assert.Nil(t, err)
445 | }
446 |
447 | func TestTemplateVarsFile(t *testing.T) {
448 | plugin := Plugin{
449 | Repo: Repo{
450 | Name: "go-hello",
451 | Namespace: "appleboy",
452 | },
453 | Commit: Commit{
454 | Sha: "e7c4f0a63ceeb42a39ac7806f7b51f3f0d204fd2",
455 | Author: "Bo-Yi Wu",
456 | Branch: "master",
457 | Message: "This is a test commit msg",
458 | },
459 | Build: Build{
460 | Number: 101,
461 | Status: "success",
462 | Link: "https://github.com/appleboy/go-hello",
463 | },
464 |
465 | Config: Config{
466 | Token: os.Getenv("TELEGRAM_TOKEN"),
467 | To: []string{os.Getenv("TELEGRAM_TO")},
468 | Format: formatMarkdown,
469 | MessageFile: "tests/message_template.txt",
470 | TemplateVarsFile: "tests/vars.json",
471 | },
472 | }
473 |
474 | err := plugin.Exec()
475 | assert.Nil(t, err)
476 | }
477 |
478 | func TestProxySendMessage(t *testing.T) {
479 | plugin := Plugin{
480 | Repo: Repo{
481 | Name: "go-hello",
482 | Namespace: "appleboy",
483 | },
484 | Commit: Commit{
485 | Sha: "e7c4f0a63ceeb42a39ac7806f7b51f3f0d204fd2",
486 | Author: "Bo-Yi Wu",
487 | Branch: "master",
488 | Message: "start use proxy",
489 | Email: "test@gmail.com",
490 | },
491 | Build: Build{
492 | Tag: "1.0.0",
493 | Number: 101,
494 | Status: "success",
495 | Link: "https://github.com/appleboy/go-hello",
496 | },
497 |
498 | Config: Config{
499 | Token: os.Getenv("TELEGRAM_TOKEN"),
500 | To: []string{os.Getenv("TELEGRAM_TO")},
501 | Message: "Send message from socks5 proxy URL.",
502 | Debug: false,
503 | Socks5: os.Getenv("SOCKS5"),
504 | },
505 | }
506 |
507 | err := plugin.Exec()
508 | assert.Nil(t, err)
509 | }
510 |
511 | func TestBuildTemplate(t *testing.T) {
512 | plugin := Plugin{
513 | Commit: Commit{
514 | Sha: "e7c4f0a63ceeb42a39ac7806f7b51f3f0d204fd2",
515 | Author: "Bo-Yi Wu",
516 | Branch: "master",
517 | Message: "This is a test commit msg",
518 | },
519 | Build: Build{
520 | Number: 101,
521 | Status: "success",
522 | Link: "https://github.com/appleboy/go-hello",
523 | Started: time.Now().Unix(),
524 | Finished: time.Now().Add(180 * time.Second).Unix(),
525 | },
526 | }
527 |
528 | _, err := template.RenderTrim(
529 | `
530 | Sample message loaded from file.
531 |
532 | Commit msg: {{uppercasefirst commit.message}}
533 |
534 | duration: {{duration build.started build.finished}}
535 | `, plugin)
536 | assert.Nil(t, err)
537 | }
538 |
--------------------------------------------------------------------------------