Compare commits

...

121 Commits

Author SHA1 Message Date
appleboy bb2dd5543b ci: improve release process and test robustness
- Add .xz files to the checksum in .goreleaser.yaml

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2023-05-06 08:15:56 +08:00
appleboy 8b963288b3 chore: improve API usage and test robustness across OSs
- Update github.com/urfave/cli/v2 from v2.25.1 to v2.25.3
- Update golang.org/x/sys from v0.7.0 to v0.8.0 (indirect)

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2023-05-06 08:01:03 +08:00
Bo-Yi Wu bd2ddc2b6c chore: improve recordings, API, tests, and actions
- Add "strconv" import to main.go
- Update app.Copyright to use the current year dynamically

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-05-05 08:14:24 +08:00
Bo-Yi Wu d098811ced build: improve build process and release packaging
- Add a post-build hook to compress artifacts using xz
- Include extra .xz files in the release package

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-05-05 08:13:24 +08:00
Bo-Yi.Wu de6f344960 refactor: update Plugin Class Exec Method with Version Print Statement
- Add print of current version to Exec method of Plugin class

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-16 13:36:35 +08:00
Bo-Yi Wu cf87fecefa feat: improve file handling with OS-specific functions and tests (#178)
- Add functions for removing and creating files/directories based on the operating system
- Add unit tests for the functions
2023-04-16 12:15:02 +08:00
Bo-Yi Wu 665c665298 refactor: remove unnecessary quotes in plugin build process (#177)
- Modify `rmcmd` and `mkdircmd` to remove unneeded quotes
- Update `buildUnTarArgs` in `plugin.go` to use target without quotes
- Add `Exec` function to `plugin.go` with `strings.Replace` call
- Update tests in `plugin_test.go` to use target without quotes

ref: https://github.com/appleboy/scp-action/issues/112
2023-04-16 12:05:23 +08:00
Bo-Yi Wu c663c07449 feat: refactor plugin struct and add hostPort function with tests (#176)
- Change the `go` keyword to `gofmt` in line 259
- Add a new function `hostPort` to the `Plugin` struct
- Modify the `hostPort` function to set the port if it is specified in the host string
- Add 2 tests for `hostPort` function to `plugin_test.go`

ref https://github.com/appleboy/scp-action/issues/98
2023-04-16 11:29:15 +08:00
Bo-Yi.Wu 30279a3e8d refactor: refactor command line flags in main function
- Remove the `t` alias from the `main` function&#39;s flags.

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-15 07:16:23 +08:00
Bo-Yi.Wu b9cdc20c14 chore(config): align with drone-ssh
Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-15 07:02:58 +08:00
Bo-Yi.Wu cb8f851d7b refactor: refactor command execution configuration
- Remove 12 lines of code related to proxy configuration
- Remove 5 lines of code related to cipher configuration
- Add 18 lines of code related to proxy configuration
- Add a command timeout flag with a default value of 10 minutes

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-15 06:29:32 +08:00
Bo-Yi Wu fb4058bc55 chore(main): remove unused variable (#175) 2023-04-15 01:49:26 +08:00
Bo-Yi.Wu ec6021f1f1 chore: update dependencies to latest versions
- Update `com` to v0.1.7
- Update `easyssh-proxy` to v1.3.10
- Update `color` to v1.15.0
- Update `godotenv` to v1.5.1
- Update `testify` to v1.8.2
- Update `cli/v2` to v2.25.1
- Update `crypto` to v0.8.0
- Update `sshkeys` to v1.2.0
- Update `go-md2man/v2` to v2.0.2
- Update `go-spew` to v1.1.1
- Update `go-colorable` to v0.1.13
- Update `go-isatty` to v0.0.18
- Update `sys` to v0.7.0
- Update `yaml.v3` to v3.0.1

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-15 01:23:33 +08:00
Bo-Yi Wu 41313253fa fix: improve support for folder names with spaces (#174)
- Add a test for a target folder with spaces in the name
- Fix a bug in the `buildUnTarArgs` function that caused it to fail when receiving a target with spaces
- Remove unused code in the `TestRemoveDestFile` function

ref https://github.com/appleboy/scp-action/issues/85
2023-04-11 12:54:53 +08:00
Bo-Yi.Wu de5e936a05 chore: update Go version and dependencies
- Upgrade Go version from `1.20` to `1.18`
- Update dependencies:
  - `github.com/appleboy/com` from `v0.1.7` to `v0.1.6`
  - `github.com/appleboy/easyssh-proxy` from `v1.3.10` to `v1.3.9`
  - `github.com/fatih/color` from `v1.15.0` to `v1.9.0`
  - `github.com/joho/godotenv` from `v1.5.1` to `v1.4.0`
  - `github.com/stretchr/testify` from `v1.8.2` to `v1.7.0`
  - `github.com/urfave/cli/v2` from `v2.25.1` to `v2.8.1`
  - `golang.org/x/crypto` from `v0.8.0` to `v0.0.0-20220525230936-793ad666bf5e`
  - `github.com/ScaleFT/sshkeys` from `v1.2.0` to `v0.0.0-20200327173127-6142f742bca5`
  - `github.com/cpuguy83/go-md2man/v2` from `v2.0.2

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-10 21:42:31 +08:00
Bo-Yi.Wu 46df30d9ba refactor: refactor system type checks in SSH commands
- Remove `uname` check for system type from `removeAllDestFile` function.
- Add `ver` check for SSH command in `Exec` function.
- Remove `uname` check for system type from `Exec` function.

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-10 21:00:36 +08:00
Bo-Yi.Wu 87ebe720f5 feat: improve server logging with OS type detection
- Add a log message with the remote server OS type

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-10 20:53:18 +08:00
Bo-Yi Wu 55f04f07eb chore: update easyssh-proxy version in go.mod file
- Update the version of `github.com/appleboy/easyssh-proxy` from `v1.3.9` to `v1.3.10` in `go.mod` file.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-04-10 15:12:01 +08:00
Bo-Yi.Wu 0745e13d39 test: refactor plugin_test.go file and optimize code
- Remove the `TestSetPasswordAndKey` function from `plugin_test.go`

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-09 17:06:03 +08:00
Bo-Yi.Wu f1301199ca fix: refactor error handling and panic statements
- Remove error message for setting password and key at the same time
- Replace `errMissingHost` error check with a panic statement

ref: https://github.com/appleboy/scp-action/issues/86

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-09 17:03:48 +08:00
Bo-Yi Wu 6fd87e0460 refactor: add dereference flag (#169)
- Add a `--dereference` flag to use with tar

fix https://github.com/appleboy/drone-scp/issues/112
2023-04-09 15:49:32 +08:00
Bo-Yi.Wu cf09357b85 build: refactor buildArgs function argument
- Change argument from `-xf` to `-zxf` in `buildArgs` function

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-09 13:39:39 +08:00
Bo-Yi Wu 9bfb71b9ef build: compress build artifacts using gzip (#168)
- Change the compression format from `tar` to `tar.gz`
- Replace the flag `-cf` with `-zcf` in the `buildArgs` function

fix https://github.com/appleboy/drone-scp/issues/123
2023-04-09 12:38:12 +08:00
Bo-Yi.Wu 9d8fc691c1 refactor: refactor testing functions for consistency
- Replace `trimPath` with `trimValues` in `TestTrimElement` function

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-09 12:14:31 +08:00
Bo-Yi Wu 244d28d58a test: check ignore list function working or not. (#167)
Modify the assert function call to use trimValues instead of trimPath
2023-04-09 12:12:53 +08:00
Bo-Yi.Wu 42d07ba823 test: refactor test function names for clarity
- Change function name from `trimPath` to `trimValues` in `TestTrimElement` test

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-09 09:51:08 +08:00
Bo-Yi.Wu dd5f3b500f refactor: refactor configuration file handling
- Remove the `trimPath` function
- Change `trimPath(p.Config.Source)` to `trimValues(p.Config.Source)`

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-09 09:50:39 +08:00
Bo-Yi.Wu 95b01590dc refactor: refactor host configuration handling
- Replace the iteration over `p.Config.Host` with `trimValues(p.Config.Host)`
- Replace `len(p.Config.Host)` with `len(hosts)`
- Replace iteration over `p.Config.Host` with `for _, host := range hosts`
- Add `trimValues` function to trim spaces and empty values of a string slice

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-09 09:13:21 +08:00
Bo-Yi.Wu c42b26f044 build: update build process for cross-platform compatibility
- Update the container to `golang:1.20-alpine`
- Add a new file `.goreleaser.yaml`
- Modify `.goreleaser.yaml` to include additional builds and flags for cross-compiling and building the binary
- Add a new checksum file to the release archives

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-09 08:16:45 +08:00
Bo-Yi Wu 244b0a9e58 refactor: handling functions for cross-platform compatibility (#166)
- Change the `rmcmd` and `mkdircmd` functions to accept an OS parameter
- Remove `command_windows.go` file
- Modify `removeDestFile` and `Exec` functions to use the OS parameter
- Add OS detection logic to `removeAllDestFile` and `Exec` functions
- Modify `TestRemoveDestFile` function to use the OS parameter

fix https://github.com/appleboy/drone-scp/pull/119
2023-04-09 08:14:05 +08:00
Bo-Yi.Wu 8b578d1df8 chore: refactor Dockerfile for improved security
- Remove `.hadolint.yaml` from the project
- Add open container labels to the Dockerfile

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-09 06:52:54 +08:00
Bo-Yi.Wu ea5c04f515 ci: update setup-go action version in workflows
- Update `setup-go` action to version 4 in 3 workflows

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-09 06:50:46 +08:00
Bo-Yi Wu f4da147fda chore: upgrade dependencies in go.mod file
- Delete `.github/workflows/binary.yml` file.
- Upgrade `github.com/appleboy/com` from `v0.1.6` to `v0.1.7` in `go.mod`.
- Upgrade `github.com/fatih/color` from `v1.14.1` to `v1.15.0` in `go.mod`.
- Upgrade `github.com/urfave/cli/v2` from `v2.24.4` to `v2.25.1` in `go.mod`.
- Upgrade `golang.org/x/crypto` from `v0.6.0` to `v0.8.0` in `go.mod`.
- Upgrade `github.com/mattn/go-isatty` from `v0.0.17` to `v0.0.18` in `go.mod`.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-04-08 11:18:30 +08:00
dependabot[bot] 54bc4f9c50 chore(deps): bump github.com/stretchr/testify from 1.8.1 to 1.8.2 (#157)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-03 23:20:52 +08:00
Bo-Yi Wu 2f24f092e0 chore(docker): update plugin name 2023-02-27 13:58:56 +08:00
Bo-Yi Wu c66c78f88f fix: lint error 2023-02-27 13:24:12 +08:00
Bo-Yi Wu 9723eea384 chore(CI): build docker image with multiple platform 2023-02-27 11:56:42 +08:00
dependabot[bot] 14ec2704bd chore(deps): bump github.com/urfave/cli/v2 from 2.24.3 to 2.24.4 (#156)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-23 13:15:47 +08:00
dependabot[bot] a1482e89a3 chore(deps): bump docker/build-push-action from 3 to 4 (#154)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-12 14:26:12 +08:00
Bo-Yi.Wu 9bf9ed00a4 chore(deps): upgrade go module
Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-02-12 09:36:06 +08:00
Bo-Yi Wu 6bc14e020b chore(deps): upgrade go package 2023-02-03 17:22:02 +08:00
Bo-Yi Wu c309cf901d chore(command): support windows (#153) 2023-02-03 17:12:57 +08:00
Bo-Yi Wu 4c5df18366 chore(deps): upgrade action package 2023-02-02 13:43:54 +08:00
Bo-Yi Wu 5ec7c1ddf8 chore(deps): upgrade go package 2023-02-02 13:42:33 +08:00
Bo-Yi Wu 1c9314ed83 chore(CI): latest tag for linux and amd64 2023-01-03 10:33:55 +08:00
Bo-Yi.Wu 5672c1219f chore(CI): add strategy in docker build
Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-01-01 15:16:45 +08:00
Bo-Yi.Wu 9d29c82de6 docs: add new badge
Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2022-12-29 21:31:02 +08:00
Bo-Yi.Wu 1f8d333b42 chore(CI): add hadolint config
Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2022-12-29 21:28:29 +08:00
Bo-Yi.Wu 50338d5bb1 chore(deps): update
Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2022-12-29 21:16:31 +08:00
teutates 6d8c114979 feat(tar): add unlink-first flag (#141) 2022-12-29 21:15:21 +08:00
Bo-Yi.Wu c5c8b4021f chore(cli): add alias
Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2022-12-29 21:13:47 +08:00
Bo-Yi.Wu 4a81a55a53 chore(lint): fix warning.
Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2022-12-29 21:10:16 +08:00
Bo-Yi.Wu 9aef844da2 chore(CI): remove drone config
Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2022-12-29 21:08:06 +08:00
Bo-Yi.Wu 6a4996cd63 chore(CI): update makefile
Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2022-12-29 21:05:12 +08:00
Bo-Yi Wu 5053fc6aee chore(CI): migrate to GitHub Actions 2022-12-29 16:08:32 +08:00
Bo-Yi Wu 55cde9a13c fix: missing installed version 2022-06-15 21:51:42 +08:00
Bo-Yi Wu 7a31e10541 chore(go1.18): build tag 2022-06-15 15:29:09 +08:00
Bo-Yi Wu 8f4c7fa15b fix(ssh): OpenSSH 8.8+ RSA keys incompatibility (#136) 2022-06-15 15:28:13 +08:00
Bo-Yi Wu 8ed049422b chore(binary): unsupported GOOS/GOARCH pair darwin/386
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2021-10-23 18:43:22 +08:00
Bo-Yi Wu 731b24356e chore(lint): check removeAllDestFile
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2021-10-23 18:30:17 +08:00
Bo-Yi Wu 2d05265e3d chore(deploy): disbale testing
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2021-10-23 18:28:09 +08:00
Bo-Yi Wu 6ddf21aca4 chore(action): wrong variable name
see https://github.com/appleboy/scp-action/issues/30

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2021-10-23 18:23:13 +08:00
Bo-Yi Wu 8c5cba51c2 chore(go): upgrade go module
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2021-10-23 18:17:23 +08:00
Bo-Yi Wu 1b33947d29 chore: upgrade to go.16
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2021-06-18 08:52:35 +08:00
Bo-Yi Wu 35f7b2f6af chore: upgrade to go1.15
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-09-25 22:13:34 +08:00
Bo-Yi Wu f0867af189 chore: remove auto load .env file
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-06-15 15:55:32 +08:00
Bo-Yi Wu 4457897da5 chore: Support UseInsecureCipher (#115) 2020-05-24 14:17:43 +08:00
Bo-Yi Wu 6d6124e8d8 docs: add fingerprint 2020-05-21 23:13:26 +08:00
Bo-Yi Wu f4fff01bdb chore: missing Ciphers in removeAllDestFile 2020-05-21 23:09:53 +08:00
Bo-Yi Wu ac8ff855ae chore: update ssh server 2020-05-21 23:09:10 +08:00
Bo-Yi Wu 2ff51f00ff chore: support Fingerprint (#114) 2020-05-21 23:08:17 +08:00
Bo-Yi Wu b0f9b5b277 remove load env file from urfave/cli
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-05-05 09:36:22 +08:00
Bo-Yi Wu 457861ab2a chore(ssh): support Ciphers
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-05-04 10:27:02 +08:00
techknowlogick 1996e5d780 Add option to use file for host info (#113) 2020-04-29 14:22:30 +08:00
Bo-Yi Wu c75daae1f3 upgrade go version
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-04-16 15:29:15 +08:00
Bo-Yi Wu 72e6ea15b6 upgrade easyssh-proxy
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-04-16 15:28:58 +08:00
Bo-Yi Wu bad565d475 update success message format.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-02-27 09:53:36 +08:00
Bo-Yi Wu 8216bd8fb8 update to go 1.14
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-02-27 09:51:12 +08:00
Daniel Bingham 3d36432240 Fix typo in EnvVars for ssh-passphrase (#109) 2020-02-27 08:58:49 +08:00
Bo-Yi Wu 2fcaffcac8 docs: update passphrase variable
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-02-07 13:27:23 +08:00
Bo-Yi Wu c1e3242f53 update module
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-02-07 13:24:23 +08:00
Bo-Yi Wu 8e4a3f5e0c chore(makefile): remove GOPACKAGE variable 2020-02-01 00:41:34 +08:00
Bo-Yi Wu fe231a1c43 docs: add passphrase 2020-01-20 22:37:45 +08:00
Bo-Yi Wu 177625c6e7 chore: support passphrase (#107)
* chore: support passphrase
2020-01-20 22:34:16 +08:00
Bo-Yi Wu bb6466e8d9 chore: upgrade easyssh-proxy to v1.3.0 2020-01-19 23:40:00 +08:00
Bo-Yi Wu e5eae442c3 chore: update urfave/cli to v2 2020-01-19 23:38:47 +08:00
Bo-Yi Wu b73ec894ab chore: update default timeout to 10 minutes 2019-11-30 23:08:26 +08:00
Bo-Yi Wu 05eba8f809 docs(install): Add export GO111MODULE=on 2019-11-12 10:34:51 +08:00
Bo-Yi Wu a2493062f7 upgrade go module
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-11-12 10:11:21 +08:00
Bo-Yi Wu b2b346a0ca update example
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-11-04 14:11:57 +08:00
Bo-Yi Wu 9d8f5ac419 update
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-11-04 13:43:54 +08:00
Bo-Yi Wu 5d93e7b8ab docs: update diff format 2019-10-18 22:40:46 +08:00
Bo-Yi Wu bf812f8e29 update docs
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-10-14 23:34:52 +08:00
Bo-Yi Wu 8814cfe72c docs: update drone 2019-10-14 23:33:18 +08:00
Bo-Yi Wu 954e0069e6 docs: update readme 2019-10-10 01:25:32 +08:00
Bo-Yi Wu 03524ed8bd docs: update to drone 1.0 format. 2019-09-29 02:01:24 +08:00
Bo-Yi Wu 531df19c8c docs: update drone docs. 2019-09-28 21:36:07 +08:00
Bo-Yi Wu df8214b645 chore: remove microbadge url 2019-09-28 17:33:25 +08:00
Bo-Yi Wu c85ca1ffd2 feat(tar): add Overwrite flag (#102)
* feat(tar): add Overwrite flag

* chore: remove

* chore: output

* chore: output
2019-09-28 16:59:01 +08:00
Ivo Nunes 933b45bc15 Add variable to set temporary tar upload path (#100) 2019-09-28 16:36:05 +08:00
Bo-Yi Wu 15344d67ae fix strip-components
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-09-28 16:30:07 +08:00
Bo-Yi Wu cf9e6f260d chore: debug command 2019-09-28 14:52:31 +08:00
Bo-Yi Wu cfa325a8c4 refactor: Add args command 2019-09-28 14:40:28 +08:00
Bo-Yi Wu c8dbddab25 chore: support -arch= 2019-09-28 14:14:15 +08:00
Bo-Yi Wu 1b27d28b27 chore: upgrade package 2019-09-28 12:52:08 +08:00
Bo-Yi Wu 8a0b0f3c0c chore(GitHub): support actions parameter. 2019-09-28 10:30:15 +08:00
Bo-Yi Wu ec489106f9 chore: upgrade to go1.13 2019-09-28 10:04:29 +08:00
Bo-Yi Wu 9ed20ee32d docs: fix markdown lint 2019-09-28 09:59:58 +08:00
Bo-Yi Wu 2aee5a3df1 docs: update 2019-08-03 23:51:16 +08:00
Bo-Yi Wu bc633e27cf docs: fix markdown lint 2019-08-03 18:55:27 +08:00
Bo-Yi Wu 9dad691d4f docs: update example 2019-08-03 18:55:02 +08:00
Bo-Yi Wu 66579b6dae chore: add proxy variable 2019-05-11 19:51:39 +08:00
Bo-Yi Wu 06609f35cf add key variable
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-05-11 16:50:50 +08:00
Bo-Yi Wu c9771cce78 chore: add variable 2019-05-11 16:49:20 +08:00
Bo-Yi Wu 6088f7da5a chore: update build tag 2019-05-11 16:34:36 +08:00
Bo-Yi Wu 6de8f74170 docs: add ignore list example. 2019-05-11 14:34:40 +08:00
Bo-Yi Wu bb63d55f89 Update README.md 2019-05-09 14:08:52 +08:00
Bo-Yi Wu da44b071c4 chore: switch finished to struct{} for zero allocate (#96) 2019-03-30 07:26:53 +08:00
Bo-Yi Wu a7eddc4b11 docs: fix setting
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-11 17:22:33 +08:00
Bo-Yi Wu 813faf56be chore: remove build number 2019-03-10 23:43:06 +08:00
Bo-Yi Wu 4117d2ca30 fix: trigger build fail if error (#94)
fix #93
2019-03-10 23:41:21 +08:00
33 changed files with 1645 additions and 1396 deletions
-16
View File
@@ -1,16 +0,0 @@
local pipeline = import 'pipeline.libsonnet';
local name = 'drone-scp';
[
pipeline.test,
pipeline.build(name, 'linux', 'amd64'),
pipeline.build(name, 'linux', 'arm64'),
pipeline.build(name, 'linux', 'arm'),
pipeline.release,
pipeline.notifications(depends_on=[
'linux-amd64',
'linux-arm64',
'linux-arm',
'release-binary',
]),
]
-388
View File
@@ -1,388 +0,0 @@
---
kind: pipeline
name: testing
platform:
os: linux
arch: amd64
steps:
- name: vet
pull: always
image: golang:1.12
commands:
- make vet
environment:
GO111MODULE: on
volumes:
- name: gopath
path: /go
- name: lint
pull: always
image: golang:1.12
commands:
- make lint
environment:
GO111MODULE: on
volumes:
- name: gopath
path: /go
- name: misspell
pull: always
image: golang:1.12
commands:
- make misspell-check
environment:
GO111MODULE: on
volumes:
- name: gopath
path: /go
- name: test
pull: always
image: golang:1.12-alpine
commands:
- apk add git make curl perl bash build-base zlib-dev ucl-dev
- make ssh-server
- make test
- make coverage
environment:
GO111MODULE: on
volumes:
- name: gopath
path: /go
- name: codecov
pull: always
image: robertstettner/drone-codecov
settings:
token:
from_secret: codecov_token
volumes:
- name: gopath
temp: {}
---
kind: pipeline
name: linux-amd64
platform:
os: linux
arch: amd64
steps:
- name: build-push
pull: always
image: golang:1.12
commands:
- "go build -v -ldflags '-X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/amd64/drone-scp"
environment:
CGO_ENABLED: 0
GO111MODULE: on
when:
event:
exclude:
- tag
- name: build-tag
pull: always
image: golang:1.12
commands:
- "go build -v -ldflags '-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/amd64/drone-scp"
environment:
CGO_ENABLED: 0
GO111MODULE: on
when:
event:
- tag
- name: executable
pull: always
image: golang:1.12
commands:
- ./release/linux/amd64/drone-scp --help
- name: dryrun
pull: always
image: plugins/docker:linux-amd64
settings:
cache_from: appleboy/drone-scp
dockerfile: docker/Dockerfile.linux.amd64
dry_run: true
repo: appleboy/drone-scp
tags: linux-amd64
when:
event:
- pull_request
- name: publish
pull: always
image: plugins/docker:linux-amd64
settings:
auto_tag: true
auto_tag_suffix: linux-amd64
cache_from: appleboy/drone-scp
daemon_off: false
dockerfile: docker/Dockerfile.linux.amd64
password:
from_secret: docker_password
repo: appleboy/drone-scp
username:
from_secret: docker_username
when:
event:
exclude:
- pull_request
trigger:
ref:
- refs/heads/master
- "refs/pull/**"
- "refs/tags/**"
depends_on:
- testing
---
kind: pipeline
name: linux-arm64
platform:
os: linux
arch: arm64
steps:
- name: build-push
pull: always
image: golang:1.12
commands:
- "go build -v -ldflags '-X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/arm64/drone-scp"
environment:
CGO_ENABLED: 0
GO111MODULE: on
when:
event:
exclude:
- tag
- name: build-tag
pull: always
image: golang:1.12
commands:
- "go build -v -ldflags '-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/arm64/drone-scp"
environment:
CGO_ENABLED: 0
GO111MODULE: on
when:
event:
- tag
- name: executable
pull: always
image: golang:1.12
commands:
- ./release/linux/arm64/drone-scp --help
- name: dryrun
pull: always
image: plugins/docker:linux-arm64
settings:
cache_from: appleboy/drone-scp
dockerfile: docker/Dockerfile.linux.arm64
dry_run: true
repo: appleboy/drone-scp
tags: linux-arm64
when:
event:
- pull_request
- name: publish
pull: always
image: plugins/docker:linux-arm64
settings:
auto_tag: true
auto_tag_suffix: linux-arm64
cache_from: appleboy/drone-scp
daemon_off: false
dockerfile: docker/Dockerfile.linux.arm64
password:
from_secret: docker_password
repo: appleboy/drone-scp
username:
from_secret: docker_username
when:
event:
exclude:
- pull_request
trigger:
ref:
- refs/heads/master
- "refs/pull/**"
- "refs/tags/**"
depends_on:
- testing
---
kind: pipeline
name: linux-arm
platform:
os: linux
arch: arm
steps:
- name: build-push
pull: always
image: golang:1.12
commands:
- "go build -v -ldflags '-X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/arm/drone-scp"
environment:
CGO_ENABLED: 0
GO111MODULE: on
when:
event:
exclude:
- tag
- name: build-tag
pull: always
image: golang:1.12
commands:
- "go build -v -ldflags '-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/arm/drone-scp"
environment:
CGO_ENABLED: 0
GO111MODULE: on
when:
event:
- tag
- name: executable
pull: always
image: golang:1.12
commands:
- ./release/linux/arm/drone-scp --help
- name: dryrun
pull: always
image: plugins/docker:linux-arm
settings:
cache_from: appleboy/drone-scp
dockerfile: docker/Dockerfile.linux.arm
dry_run: true
repo: appleboy/drone-scp
tags: linux-arm
when:
event:
- pull_request
- name: publish
pull: always
image: plugins/docker:linux-arm
settings:
auto_tag: true
auto_tag_suffix: linux-arm
cache_from: appleboy/drone-scp
daemon_off: false
dockerfile: docker/Dockerfile.linux.arm
password:
from_secret: docker_password
repo: appleboy/drone-scp
username:
from_secret: docker_username
when:
event:
exclude:
- pull_request
trigger:
ref:
- refs/heads/master
- "refs/pull/**"
- "refs/tags/**"
depends_on:
- testing
---
kind: pipeline
name: release-binary
platform:
os: linux
arch: amd64
steps:
- name: build-all-binary
pull: always
image: golang:1.12
commands:
- make release
environment:
GO111MODULE: on
when:
event:
- tag
- name: deploy-all-binary
pull: always
image: plugins/github-release
settings:
api_key:
from_secret: github_release_api_key
files:
- "dist/release/*"
when:
event:
- tag
trigger:
ref:
- "refs/tags/**"
depends_on:
- testing
---
kind: pipeline
name: notifications
platform:
os: linux
arch: amd64
steps:
- name: manifest
pull: always
image: plugins/manifest
settings:
ignore_missing: true
password:
from_secret: docker_password
spec: docker/manifest.tmpl
username:
from_secret: docker_username
- name: microbadger
pull: always
image: plugins/webhook:1
settings:
url:
from_secret: microbadger_url
trigger:
ref:
- refs/heads/master
- "refs/tags/**"
depends_on:
- linux-amd64
- linux-arm64
- linux-arm
- release-binary
...
-42
View File
@@ -1,42 +0,0 @@
# unifying the coding style for different editors and IDEs => editorconfig.org
; indicate this is the root of the project
root = true
###########################################################
; common
###########################################################
[*]
charset = utf-8
end_of_line = LF
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
###########################################################
; make
###########################################################
[Makefile]
indent_style = tab
[makefile]
indent_style = tab
###########################################################
; markdown
###########################################################
[*.md]
trim_trailing_whitespace = false
###########################################################
; golang
###########################################################
[*.go]
indent_style = tab
+13
View File
@@ -0,0 +1,13 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: ['https://www.paypal.me/appleboy46']
+10
View File
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
- package-ecosystem: gomod
directory: /
schedule:
interval: weekly
+54
View File
@@ -0,0 +1,54 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '41 23 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'go' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
+77
View File
@@ -0,0 +1,77 @@
name: Docker Image
on:
push:
branches:
- master
tags:
- 'v*'
pull_request:
branches:
- 'master'
jobs:
build-docker:
runs-on: ubuntu-latest
steps:
- name: Setup go
uses: actions/setup-go@v4
with:
go-version: '^1'
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Build binary
run : |
make build_linux_amd64
make build_linux_arm
make build_linux_arm64
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
-
name: Docker meta
id: docker-meta
uses: docker/metadata-action@v4
with:
images: |
${{ github.repository }}
ghcr.io/${{ github.repository }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
-
name: Build and push
uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64,linux/arm,linux/arm64
file: docker/Dockerfile
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.docker-meta.outputs.tags }}
labels: ${{ steps.docker-meta.outputs.labels }}
+35
View File
@@ -0,0 +1,35 @@
name: Goreleaser
on:
push:
tags:
- '*'
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
-
name: Setup go
uses: actions/setup-go@v4
with:
go-version: '^1'
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v4
with:
# either 'goreleaser' (default) or 'goreleaser-pro'
distribution: goreleaser
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+45
View File
@@ -0,0 +1,45 @@
name: Lint and Testing
on:
push:
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Setup go
uses: actions/setup-go@v4
with:
go-version: '^1'
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
args: --verbose
- uses: hadolint/hadolint-action@v3.1.0
name: hadolint for Dockerfile
with:
dockerfile: docker/Dockerfile
testing:
runs-on: ubuntu-latest
container: golang:1.20-alpine
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: setup sshd server
run: |
apk add git make curl perl bash build-base zlib-dev ucl-dev
make ssh-server
- name: testing
run: |
make test
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
+99
View File
@@ -0,0 +1,99 @@
before:
hooks:
- go mod tidy
builds:
- env:
- CGO_ENABLED=0
goos:
- darwin
- linux
- windows
- freebsd
goarch:
- amd64
- arm
- arm64
goarm:
- "5"
- "6"
- "7"
ignore:
- goos: darwin
goarch: arm
- goos: darwin
goarch: ppc64le
- goos: darwin
goarch: s390x
- goos: windows
goarch: ppc64le
- goos: windows
goarch: s390x
- goos: windows
goarch: arm
goarm: "5"
- goos: windows
goarch: arm
goarm: "6"
- goos: windows
goarch: arm
goarm: "7"
- goos: windows
goarch: arm64
- goos: freebsd
goarch: ppc64le
- goos: freebsd
goarch: s390x
- goos: freebsd
goarch: arm
goarm: "5"
- goos: freebsd
goarch: arm
goarm: "6"
- goos: freebsd
goarch: arm
goarm: "7"
- goos: freebsd
goarch: arm64
flags:
- -trimpath
ldflags:
- -s -w
- -X main.Version={{.Version}}
binary: >-
{{ .ProjectName }}-
{{- if .IsSnapshot }}{{ .Branch }}-
{{- else }}{{- .Version }}-{{ end }}
{{- .Os }}-
{{- if eq .Arch "amd64" }}amd64
{{- else if eq .Arch "amd64_v1" }}amd64
{{- else if eq .Arch "386" }}386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}-{{ .Arm }}{{ end }}
no_unique_dist_dir: true
hooks:
post:
- cmd: xz -k -9 {{ .Path }}
dir: ./dist/
archives:
- format: binary
name_template: "{{ .Binary }}"
allow_different_binary_count: true
checksum:
name_template: 'checksums.txt'
extra_files:
- glob: ./**.xz
snapshot:
name_template: "{{ incpatch .Version }}"
release:
# You can add extra pre-existing files to the release.
# The filename on the release will be the last part of the path (base).
# If another file with the same name exists, the last one found will be used.
#
# Templates: allowed
extra_files:
- glob: ./**.xz
-25
View File
@@ -1,25 +0,0 @@
ignoreGeneratedHeader = false
severity = "warning"
confidence = 0.8
errorCode = 1
warningCode = 1
[rule.blank-imports]
[rule.context-as-argument]
[rule.context-keys-type]
[rule.dot-imports]
[rule.error-return]
[rule.error-strings]
[rule.error-naming]
[rule.exported]
[rule.if-return]
[rule.increment-decrement]
[rule.var-naming]
[rule.var-declaration]
[rule.package-comments]
[rule.range]
[rule.receiver-naming]
[rule.time-naming]
[rule.unexported-return]
[rule.indent-error-flow]
[rule.errorf]
+88 -46
View File
@@ -11,35 +11,21 @@ image: appleboy/drone-scp
The SCP plugin copy files and artifacts to target host machine via SSH. The below pipeline configuration demonstrates simple usage:
```yaml
pipeline:
scp:
image: appleboy/drone-scp
settings:
host: example.com
target: /home/deploy/web
source: release.tar.gz
```
Example configuration with custom username, password and port:
```diff
pipeline:
scp:
image: appleboy/drone-scp
settings:
host: example.com
+ username: appleboy
+ password: 12345678
+ port: 4430
target: /home/deploy/web
source: release.tar.gz
- name: scp files
image: appleboy/drone-scp
settings:
host: example.com
username: foo
password: bar
port: 22
target: /var/www/deploy/${DRONE_REPO_OWNER}/${DRONE_REPO_NAME}
source: release.tar.gz
```
Example configuration with multiple source and target folder:
```diff
pipeline:
scp:
- name: scp files
image: appleboy/drone-scp
settings:
host: example.com
@@ -54,8 +40,7 @@ pipeline:
Example configuration with multiple host:
```diff
pipeline:
scp:
- name: scp files
image: appleboy/drone-scp
settings:
- host: example.com
@@ -69,8 +54,7 @@ pipeline:
Example configuration with wildcard pattern of source list:
```diff
pipeline:
scp:
- name: scp files
image: appleboy/drone-scp
settings:
host:
@@ -86,9 +70,8 @@ pipeline:
Remove target folder before copy files and artifacts to target:
```diff
scp:
- name: scp files
image: appleboy/drone-scp
host: example.com
settings:
target: /home/deploy/web
source: release.tar.gz
@@ -98,7 +81,7 @@ Remove target folder before copy files and artifacts to target:
Example for remove the specified number of leading path elements:
```diff
scp:
- name: scp files
image: appleboy/drone-scp
settings:
host: example.com
@@ -110,8 +93,7 @@ Example for remove the specified number of leading path elements:
Example configuration using SSHProxyCommand:
```diff
pipeline:
scp:
- name: scp files
image: appleboy/drone-scp
settings:
host:
@@ -129,8 +111,7 @@ pipeline:
Example configuration using password from secrets:
```diff
pipeline:
scp:
- name: scp files
image: appleboy/drone-scp
settings:
host:
@@ -140,7 +121,7 @@ pipeline:
port: 22
- password: 1234
+ password:
from_secret: ssh_password
+ from_secret: ssh_password
target: /home/deploy/web
source:
- release/*.tar.gz
@@ -149,24 +130,64 @@ pipeline:
Example configuration using command timeout:
```diff
pipeline:
scp:
- name: scp files
image: appleboy/drone-scp
settings:
host:
- example1.com
- example2.com
user: ubuntu
password:
from_secret: ssh_password
port: 22
- command_timeout: 120
+ command_timeout: 2m
target: /home/deploy/web
source:
- release/*.tar.gz
```
Example configuration for ignore list:
```diff
- name: scp files
image: appleboy/drone-scp
settings:
host:
- example1.com
- example2.com
user: ubuntu
port: 22
- command_timeout: 120
+ command_timeout: 2m
password:
from_secret: ssh_password
port: 22
command_timeout: 2m
target: /home/deploy/web
source:
- release/*.tar.gz
+ - !release/README.md
- release/*
```
# Parameter Reference
Example configuration for passphrase which protecting a private key:
```diff
- name: scp files
image: appleboy/drone-scp
settings:
host:
- example1.com
- example2.com
user: ubuntu
+ key:
+ from_secret: ssh_key
+ passphrase: 1234
port: 22
command_timeout: 2m
target: /home/deploy/web
source:
- release/*
```
## Parameter Reference
host
: target hostname or IP
@@ -183,6 +204,12 @@ password
key
: plain text of user private key
passphrase
: The purpose of the passphrase is usually to encrypt the private key.
fingerprint
: fingerprint SHA256 of the host public key, default is to skip verification
target
: folder path of target host
@@ -193,14 +220,23 @@ rm
: remove target folder before copy files and artifacts
timeout
: timeout is the maximum amount of time for the TCP connection to establish
: Timeout is the maximum amount of time for the ssh connection to establish, default is 30 seconds.
command_timeout
: timeout is the maximum amount of time for execute command
: Command timeout is the maximum amount of time for the execute commands, default is 10 minutes.
strip_components
: remove the specified number of leading path elements
tar_tmp_path
: temporary path for tar file on the dest host
tar_exec
: alternative `tar` executable to on the dest host
overwrite
: use `--overwrite` flag with tar
proxy_host
: proxy hostname or IP
@@ -219,7 +255,13 @@ proxy_key
proxy_key_path
: key path of proxy private key
# Template Reference
proxy_passphrase
: The purpose of the passphrase is usually to encrypt the private key.
proxy_fingerprint
: fingerprint SHA256 of the host public key, default is to skip verification
## Template Reference
repo.owner
: repository owner
+97 -71
View File
@@ -1,17 +1,19 @@
DIST := dist
EXECUTABLE := drone-scp
GOFMT ?= gofmt "-s"
GOFMT ?= gofumpt -l
DIST := dist
DIST_DIRS := $(DIST)/binaries $(DIST)/release
GO ?= go
SHASUM ?= shasum -a 256
GOFILES := $(shell find . -name "*.go" -type f)
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
XGO_VERSION := go-1.19.x
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11
# for dockerhub
DEPLOY_ACCOUNT := appleboy
DEPLOY_IMAGE := $(EXECUTABLE)
TARGETS ?= linux darwin windows
PACKAGES ?= $(shell $(GO) list ./...)
SOURCES ?= $(shell find . -name "*.go" -type f)
TAGS ?=
LDFLAGS ?= -X 'main.Version=$(VERSION)'
LINUX_ARCHS ?= linux/amd64,linux/arm64
DARWIN_ARCHS ?= darwin-10.12/amd64,darwin-10.12/arm64
WINDOWS_ARCHS ?= windows/*
ifneq ($(shell uname), Darwin)
EXTLDFLAGS = -extldflags "-static" $(null)
@@ -19,77 +21,68 @@ else
EXTLDFLAGS =
endif
ifeq ($(HAS_GO), GO)
GOPATH ?= $(shell $(GO) env GOPATH)
export PATH := $(GOPATH)/bin:$(PATH)
CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766
CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS)
endif
ifeq ($(OS), Windows_NT)
GOFLAGS := -v -buildmode=exe
EXECUTABLE ?= $(EXECUTABLE).exe
else ifeq ($(OS), Windows)
GOFLAGS := -v -buildmode=exe
EXECUTABLE ?= $(EXECUTABLE).exe
else
GOFLAGS := -v
EXECUTABLE ?= $(EXECUTABLE)
endif
ifneq ($(DRONE_TAG),)
VERSION ?= $(DRONE_TAG)
else
VERSION ?= $(shell git describe --tags --always || git rev-parse --short HEAD)
endif
TAGS ?=
LDFLAGS ?= -X 'main.Version=$(VERSION)'
all: build
fmt:
$(GOFMT) -w $(SOURCES)
@hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install mvdan.cc/gofumpt; \
fi
$(GOFMT) -w $(GOFILES)
vet:
$(GO) vet $(PACKAGES)
lint:
@hash revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/mgechev/revive; \
fi
revive -config .revive.toml ./... || exit 1
.PHONY: misspell-check
misspell-check:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/client9/misspell/cmd/misspell; \
fi
misspell -error $(SOURCES)
.PHONY: misspell
misspell:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/client9/misspell/cmd/misspell; \
fi
misspell -w $(SOURCES)
$(GO) vet ./...
.PHONY: fmt-check
fmt-check:
@diff=$$($(GOFMT) -d $(SOURCES)); \
@hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install mvdan.cc/gofumpt; \
fi
@diff=$$($(GOFMT) -d $(GOFILES)); \
if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \
echo "$${diff}"; \
exit 1; \
fi;
test: fmt-check
@$(GO) test -v -cover -coverprofile coverage.txt $(PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
test:
@$(GO) test -v -cover -coverprofile coverage.txt ./... && echo "\n==>\033[32m Ok\033[m\n" || exit 1
install: $(SOURCES)
install: $(GOFILES)
$(GO) install -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)'
build: $(EXECUTABLE)
$(EXECUTABLE): $(SOURCES)
$(EXECUTABLE): $(GOFILES)
$(GO) build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o $@
release: release-dirs release-build release-copy release-check
release-dirs:
mkdir -p $(DIST)/binaries $(DIST)/release
release-build:
@which gox > /dev/null; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/mitchellh/gox; \
fi
gox -os="$(TARGETS)" -tags="$(TAGS)" -ldflags="-s -w $(LDFLAGS)" -output="$(DIST)/binaries/$(EXECUTABLE)-$(VERSION)-{{.OS}}-{{.Arch}}"
release-copy:
$(foreach file,$(wildcard $(DIST)/binaries/$(EXECUTABLE)-*),cp $(file) $(DIST)/release/$(notdir $(file));)
release-check:
cd $(DIST)/release; $(foreach file,$(wildcard $(DIST)/release/$(EXECUTABLE)-*),sha256sum $(notdir $(file)) > $(notdir $(file)).sha256;)
build_linux_amd64:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GO) build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/amd64/$(DEPLOY_IMAGE)
@@ -102,36 +95,69 @@ build_linux_arm64:
build_linux_arm:
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 $(GO) build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/arm/$(DEPLOY_IMAGE)
docker_image:
docker build -t $(DEPLOY_ACCOUNT)/$(DEPLOY_IMAGE) .
docker: docker_image
docker_deploy:
ifeq ($(tag),)
@echo "Usage: make $@ tag=<tag>"
@exit 1
endif
# deploy image
docker tag $(DEPLOY_ACCOUNT)/$(DEPLOY_IMAGE):latest $(DEPLOY_ACCOUNT)/$(DEPLOY_IMAGE):$(tag)
docker push $(DEPLOY_ACCOUNT)/$(DEPLOY_IMAGE):$(tag)
ssh-server:
adduser -h /home/drone-scp -s /bin/bash -D -S drone-scp
adduser -h /home/drone-scp -s /bin/sh -D -S drone-scp
echo drone-scp:1234 | chpasswd
mkdir -p /home/drone-scp/.ssh
chmod 700 /home/drone-scp/.ssh
cp tests/.ssh/id_rsa.pub /home/drone-scp/.ssh/authorized_keys
cat tests/.ssh/id_rsa.pub >> /home/drone-scp/.ssh/authorized_keys
cat tests/.ssh/test.pub >> /home/drone-scp/.ssh/authorized_keys
chmod 600 /home/drone-scp/.ssh/authorized_keys
chown -R drone-scp /home/drone-scp/.ssh
# install ssh and start server
apk add --update openssh openrc
rm -rf /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_dsa_key
sed -i 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/g' /etc/ssh/sshd_config
sed -i 's/AllowTcpForwarding no/AllowTcpForwarding yes/g' /etc/ssh/sshd_config
./tests/entrypoint.sh /usr/sbin/sshd -D &
coverage:
sed -i '/main.go/d' coverage.txt
.PHONY: deps-backend
deps-backend:
$(GO) mod download
$(GO) install $(GXZ_PAGAGE)
$(GO) install $(XGO_PACKAGE)
.PHONY: release
release: release-linux release-darwin release-windows release-copy release-compress release-check
$(DIST_DIRS):
mkdir -p $(DIST_DIRS)
.PHONY: release-windows
release-windows: | $(DIST_DIRS)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(WINDOWS_ARCHS)' -out $(EXECUTABLE)-$(VERSION) .
ifeq ($(CI),true)
cp -r /build/* $(DIST)/binaries/
endif
.PHONY: release-linux
release-linux: | $(DIST_DIRS)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out $(EXECUTABLE)-$(VERSION) .
ifeq ($(CI),true)
cp -r /build/* $(DIST)/binaries/
endif
.PHONY: release-darwin
release-darwin: | $(DIST_DIRS)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets '$(DARWIN_ARCHS)' -out $(EXECUTABLE)-$(VERSION) .
ifeq ($(CI),true)
cp -r /build/* $(DIST)/binaries/
endif
.PHONY: release-copy
release-copy: | $(DIST_DIRS)
cd $(DIST); for file in `find . -type f -name "*"`; do cp $${file} ./release/; done;
.PHONY: release-check
release-check: | $(DIST_DIRS)
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "checksumming $${file}" && $(SHASUM) `echo $${file} | sed 's/^..//'` > $${file}.sha256; done;
.PHONY: release-compress
release-compress: | $(DIST_DIRS)
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && $(GO) run $(GXZ_PAGAGE) -k -9 $${file}; done;
clean:
$(GO) clean -x -i ./...
rm -rf coverage.txt $(EXECUTABLE) $(DIST)
+41 -54
View File
@@ -1,11 +1,10 @@
# drone-scp
[![GoDoc](https://godoc.org/github.com/appleboy/drone-scp?status.svg)](https://godoc.org/github.com/appleboy/drone-scp)
[![Build Status](https://cloud.drone.io/api/badges/appleboy/drone-scp/status.svg)](https://cloud.drone.io/appleboy/drone-scp)
[![codecov](https://codecov.io/gh/appleboy/drone-scp/branch/master/graph/badge.svg)](https://codecov.io/gh/appleboy/drone-scp)
[![Go Report Card](https://goreportcard.com/badge/github.com/appleboy/drone-scp)](https://goreportcard.com/report/github.com/appleboy/drone-scp)
[![Docker Pulls](https://img.shields.io/docker/pulls/appleboy/drone-scp.svg)](https://hub.docker.com/r/appleboy/drone-scp/)
[![](https://images.microbadger.com/badges/image/appleboy/drone-scp.svg)](https://microbadger.com/images/appleboy/drone-scp "Get your own image badge on microbadger.com")
[![GoDoc](https://godoc.org/github.com/appleboy/drone-scp?status.svg)](https://godoc.org/github.com/appleboy/drone-scp)
[![Lint and Testing](https://github.com/appleboy/drone-scp/actions/workflows/lint.yml/badge.svg)](https://github.com/appleboy/drone-scp/actions/workflows/lint.yml)
[![codecov](https://codecov.io/gh/appleboy/drone-scp/branch/master/graph/badge.svg)](https://codecov.io/gh/appleboy/drone-scp)
[![Go Report Card](https://goreportcard.com/badge/github.com/appleboy/drone-scp)](https://goreportcard.com/report/github.com/appleboy/drone-scp)
[![Docker Pulls](https://img.shields.io/docker/pulls/appleboy/drone-scp.svg)](https://hub.docker.com/r/appleboy/drone-scp/)
Copy files and artifacts via SSH using a binary, docker or [Drone CI](http://docs.drone.io/).
@@ -18,17 +17,17 @@ Copy files and artifacts via SSH using a binary, docker or [Drone CI](http://doc
* [x] Support load ssh key from absolute path or raw body.
* [x] Support SSH ProxyCommand.
```
+--------+ +----------+ +-----------+
| Laptop | <--> | Jumphost | <--> | FooServer |
+--------+ +----------+ +-----------+
```sh
+--------+ +----------+ +-----------+
| Laptop | <--> | Jumphost | <--> | FooServer |
+--------+ +----------+ +-----------+
OR
OR
+--------+ +----------+ +-----------+
| Laptop | <--> | Firewall | <--> | FooServer |
+--------+ +----------+ +-----------+
192.168.1.5 121.1.2.3 10.10.29.68
+--------+ +----------+ +-----------+
| Laptop | <--> | Firewall | <--> | FooServer |
+--------+ +----------+ +-----------+
192.168.1.5 121.1.2.3 10.10.29.68
```
## Breaking changes
@@ -36,18 +35,18 @@ Copy files and artifacts via SSH using a binary, docker or [Drone CI](http://doc
`v1.5.0`: change command timeout flag to `Duration`. See the following setting:
```diff
pipeline:
scp:
- name: scp files
image: appleboy/drone-scp
settings:
host:
- example1.com
- example2.com
user: ubuntu
username: ubuntu
password:
from_secret: ssh_password
port: 22
- command_timeout: 120
+ command_timeout: 2m
from_secret: ssh_password
target: /home/deploy/web
source:
- release/*.tar.gz
@@ -63,37 +62,30 @@ The pre-compiled binaries can be downloaded from [release page](https://github.c
With `Go` installed
```sh
export GO111MODULE=on
go get -u -v github.com/appleboy/drone-scp
```
$ go get -u -v github.com/appleboy/drone-scp
```
or build the binary with the following command:
```
$ export GOOS=linux
$ export GOARCH=amd64
$ export CGO_ENABLED=0
$ export GO111MODULE=on
```sh
export GOOS=linux
export GOARCH=amd64
export CGO_ENABLED=0
export GO111MODULE=on
$ go test -cover ./...
go test -cover ./...
$ go build -v -a -tags netgo -o release/linux/amd64/drone-scp .
go build -v -a -tags netgo -o release/linux/amd64/drone-scp .
```
## Docker
Build the docker image with the following commands:
```
$ make docker
```
Please note incorrectly building the image for the correct x64 linux and with
CGO disabled will result in an error when running the Docker image:
```
docker: Error response from daemon: Container command
'/bin/drone-scp' not found or does not exist..
```sh
make docker
```
## Usage
@@ -104,7 +96,6 @@ There are three ways to send notification.
* [usage from docker](#usage-from-docker)
* [usage from drone ci](#usage-from-drone-ci)
<a name="usage-from-binary"></a>
### Usage from binary
#### Using public key
@@ -139,8 +130,8 @@ eval `ssh-agent -s`
Import your local public key `~/.ssh/id_rsa`
```bash
$ ssh-add
```sh
ssh-add
```
You don't need to add `--password` or `--key-path` arguments.
@@ -167,10 +158,9 @@ drone-scp --host example1.com \
+ --source your_local_folder_path_2
```
<a name="usage-from-docker"></a>
### Usage from docker
#### Using public key
Using public key
```bash
docker run --rm \
@@ -185,7 +175,7 @@ docker run --rm \
appleboy/drone-scp
```
#### Using password
Using password
```diff
docker run --rm \
@@ -200,9 +190,7 @@ docker run --rm \
appleboy/drone-scp
```
#### Using ssh-agent
Start your local ssh agent:
Using ssh-agent, start your local ssh agent:
```bash
eval `ssh-agent -s`
@@ -210,11 +198,11 @@ eval `ssh-agent -s`
Import your local public key `~/.ssh/id_rsa`
```bash
$ ssh-add
```sh
ssh-add
```
You don't need to add `SCP_PASSWORD` or `SCP_KEY_PATH ` arguments.
You don't need to add `SCP_PASSWORD` or `SCP_KEY_PATH` arguments.
```bash
docker run --rm \
@@ -228,7 +216,7 @@ docker run --rm \
appleboy/drone-scp
```
#### Send multiple source or target folder and hosts
Send multiple source or target folder and hosts
```bash
docker run --rm \
@@ -243,7 +231,6 @@ docker run --rm \
appleboy/drone-scp
```
<a name="usage-from-drone-ci"></a>
### Usage from drone ci
Execute from the working directory:
@@ -269,6 +256,6 @@ You can get more [information](http://plugins.drone.io/appleboy/drone-scp/) abou
Test the package with the following command:
```
$ make test
```sh
make test
```
+29
View File
@@ -0,0 +1,29 @@
package main
// This function returns the appropriate command for removing a file/directory based on the operating system.
func rmcmd(os, target string) string {
switch os {
case "windows":
// On Windows, use DEL command to delete files and folders recursively
return "DEL /F /S " + target
case "unix":
// On Unix-based systems, use rm command to delete files and folders recursively
return "rm -rf " + target
}
// Return an empty string if the operating system is not recognized
return ""
}
// This function returns the appropriate command for creating a directory based on the operating system.
func mkdircmd(os, target string) string {
switch os {
case "windows":
// On Windows, use mkdir command to create directory and check if it exists
return "if not exist " + target + " mkdir " + target
case "unix":
// On Unix-based systems, use mkdir command with -p option to create directories recursively
return "mkdir -p " + target
}
// Return an empty string if the operating system is not recognized
return ""
}
+42
View File
@@ -0,0 +1,42 @@
package main
import "testing"
// Unit tests for rmcmd and mkdircmd
func TestCommands(t *testing.T) {
// Test rmcmd on Windows
os1 := "windows"
target1 := "C:\\path\\to\\file"
expected1 := "DEL /F /S " + target1
actual1 := rmcmd(os1, target1)
if actual1 != expected1 {
t.Errorf("rmcmd(%s, %s) = %s; expected %s", os1, target1, actual1, expected1)
}
// Test rmcmd on Unix-based system
os2 := "unix"
target2 := "/path/to/folder"
expected2 := "rm -rf " + target2
actual2 := rmcmd(os2, target2)
if actual2 != expected2 {
t.Errorf("rmcmd(%s, %s) = %s; expected %s", os2, target2, actual2, expected2)
}
// Test mkdircmd on Windows
os3 := "windows"
target3 := "C:\\path\\to\\folder"
expected3 := "if not exist " + target3 + " mkdir " + target3
actual3 := mkdircmd(os3, target3)
if actual3 != expected3 {
t.Errorf("mkdircmd(%s, %s) = %s; expected %s", os3, target3, actual3, expected3)
}
// Test mkdircmd on Unix-based system
os4 := "unix"
target4 := "/path/to/folder"
expected4 := "mkdir -p " + target4
actual4 := mkdircmd(os4, target4)
if actual4 != expected4 {
t.Errorf("mkdircmd(%s, %s) = %s; expected %s", os4, target4, actual4, expected4)
}
}
+20
View File
@@ -0,0 +1,20 @@
FROM alpine:3.17
ARG TARGETOS
ARG TARGETARCH
LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>" \
org.label-schema.name="SCP Plugin" \
org.label-schema.vendor="Bo-Yi Wu" \
org.label-schema.schema-version="1.0"
LABEL org.opencontainers.image.source=https://github.com/appleboy/drone-scp
LABEL org.opencontainers.image.description="Copy files and artifacts via SSH"
LABEL org.opencontainers.image.licenses=MIT
RUN apk add --no-cache ca-certificates=20220614-r4 && \
rm -rf /var/cache/apk/*
COPY release/${TARGETOS}/${TARGETARCH}/drone-scp /bin/
ENTRYPOINT ["/bin/drone-scp"]
-12
View File
@@ -1,12 +0,0 @@
FROM plugins/base:linux-amd64
LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>" \
org.label-schema.name="Drone SCP" \
org.label-schema.vendor="Bo-Yi Wu" \
org.label-schema.schema-version="1.0"
RUN apk add --no-cache ca-certificates && \
rm -rf /var/cache/apk/*
COPY release/linux/amd64/drone-scp /bin/
ENTRYPOINT ["/bin/drone-scp"]
-12
View File
@@ -1,12 +0,0 @@
FROM plugins/base:linux-arm
LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>" \
org.label-schema.name="Drone SCP" \
org.label-schema.vendor="Bo-Yi Wu" \
org.label-schema.schema-version="1.0"
RUN apk add --no-cache ca-certificates && \
rm -rf /var/cache/apk/*
COPY release/linux/arm/drone-scp /bin/
ENTRYPOINT ["/bin/drone-scp"]
-12
View File
@@ -1,12 +0,0 @@
FROM plugins/base:linux-arm64
LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>" \
org.label-schema.name="Drone SCP" \
org.label-schema.vendor="Bo-Yi Wu" \
org.label-schema.schema-version="1.0"
RUN apk add --no-cache ca-certificates && \
rm -rf /var/cache/apk/*
COPY release/linux/arm64/drone-scp /bin/
ENTRYPOINT ["/bin/drone-scp"]
-10
View File
@@ -1,10 +0,0 @@
FROM microsoft/nanoserver:10.0.14393.1884
LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>" \
org.label-schema.name="Drone SCP" \
org.label-schema.vendor="Bo-Yi Wu" \
org.label-schema.schema-version="1.0"
COPY drone-scp.exe /drone-scp.exe
ENTRYPOINT [ "\\drone-scp.exe" ]
-25
View File
@@ -1,25 +0,0 @@
image: appleboy/drone-scp:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
{{#if build.tags}}
tags:
{{#each build.tags}}
- {{this}}
{{/each}}
{{/if}}
manifests:
-
image: appleboy/drone-scp:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
platform:
architecture: amd64
os: linux
-
image: appleboy/drone-scp:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
platform:
architecture: arm64
os: linux
variant: v8
-
image: appleboy/drone-scp:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm
platform:
architecture: arm
os: linux
variant: v7
+22 -9
View File
@@ -1,14 +1,27 @@
module github.com/appleboy/drone-scp
go 1.12
go 1.18
require (
github.com/appleboy/com v0.0.1
github.com/appleboy/easyssh-proxy v1.2.0
github.com/fatih/color v1.7.0
github.com/joho/godotenv v1.3.0
github.com/mattn/go-colorable v0.1.1 // indirect
github.com/mattn/go-isatty v0.0.6 // indirect
github.com/stretchr/testify v1.3.0
github.com/urfave/cli v1.20.0
github.com/appleboy/com v0.1.7
github.com/appleboy/easyssh-proxy v1.3.10
github.com/fatih/color v1.15.0
github.com/joho/godotenv v1.5.1
github.com/stretchr/testify v1.8.2
github.com/urfave/cli/v2 v2.25.3
golang.org/x/crypto v0.8.0
)
require (
github.com/ScaleFT/sshkeys v1.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/sys v0.8.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
+53 -21
View File
@@ -1,26 +1,58 @@
github.com/appleboy/com v0.0.1 h1:SeP6J/YlZGWRwH7jdPYXXWA+qJy4GoQfcQFPda0ERYU=
github.com/appleboy/com v0.0.1/go.mod h1:rtwjPnHClMOJw4K5oW3ASx9BCPCJ1SDbFbzJjY4Ebqw=
github.com/appleboy/easyssh-proxy v1.2.0 h1:KvaUGC18WkBFet+N1oofQy03jkC5HaKFn2XGxFxCTtg=
github.com/appleboy/easyssh-proxy v1.2.0/go.mod h1:vHskChUNhxwW4dXMe2MNE/k+UBCkBagrQDm70UWZrS0=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/ScaleFT/sshkeys v1.2.0 h1:5BRp6rTVIhJzXT3VcUQrKgXR8zWA3sOsNeuyW15WUA8=
github.com/ScaleFT/sshkeys v1.2.0/go.mod h1:gxOHeajFfvGQh/fxlC8oOKBe23xnnJTif00IFFbiT+o=
github.com/appleboy/com v0.1.7 h1:4lYTFNoMAAXGGIC8lDxVg/NY+1aXbYqfAWN05cZhd0M=
github.com/appleboy/com v0.1.7/go.mod h1:JUK+oH0SXCLRH57pDMJx6VWVsm8CPdajalmRSWwamBE=
github.com/appleboy/easyssh-proxy v1.3.10 h1:iriF68tlrYoxgWhS7t7Wyr0FA+hJlOem5tMfm+RDlx4=
github.com/appleboy/easyssh-proxy v1.3.10/go.mod h1:T81pu/Cxx/zf/7YXhFCFiucBa4xeQ81ci5b0PFnMRJc=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.6 h1:SrwhHcpV4nWrMGdNcC2kXpMfcBVYGDuTArqyhocJgvA=
github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a h1:saTgr5tMLFnmy/yg3qDTft4rE5DY2uJ/cCxCe3q0XTU=
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a/go.mod h1:Bw9BbhOJVNR+t0jCqx2GC6zv0TGBsShs56Y3gfSCvl0=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25 h1:jsG6UpNLt9iAsb0S2AGW28DveNzzgmbXR+ENoPjUeIU=
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/urfave/cli/v2 v2.25.3 h1:VJkt6wvEBOoSjPFQvOkv6iWIrsJyCrKGtCtxXWwmGeY=
github.com/urfave/cli/v2 v2.25.3/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+193 -186
View File
@@ -3,27 +3,31 @@ package main
import (
"log"
"os"
"strconv"
"time"
"github.com/appleboy/easyssh-proxy"
"github.com/joho/godotenv"
_ "github.com/joho/godotenv/autoload"
"github.com/urfave/cli"
"github.com/urfave/cli/v2"
)
// Version set at compile-time
var (
Version string
BuildNum string
Version string
)
func main() {
// Load env-file if it exists first
if filename, found := os.LookupEnv("PLUGIN_ENV_FILE"); found {
_ = godotenv.Load(filename)
}
app := cli.NewApp()
app.Name = "Drone SCP"
app.Usage = "Copy files and artifacts via SSH."
app.Copyright = "Copyright (c) 2017 Bo-Yi Wu"
app.Authors = []cli.Author{
app.Copyright = "Copyright (c) " + strconv.Itoa(time.Now().Year()) + " Bo-Yi Wu"
app.Version = Version
app.Authors = []*cli.Author{
{
Name: "Bo-Yi Wu",
Email: "appleboy.tw@gmail.com",
@@ -32,172 +36,186 @@ func main() {
app.Action = run
app.Version = Version
app.Flags = []cli.Flag{
cli.StringSliceFlag{
Name: "host, H",
Usage: "Server host",
EnvVar: "PLUGIN_HOST,SCP_HOST,SSH_HOST",
&cli.StringSliceFlag{
Name: "host",
Aliases: []string{"H"},
Usage: "connect to host",
EnvVars: []string{"PLUGIN_HOST", "SSH_HOST", "INPUT_HOST"},
FilePath: ".host",
},
cli.StringFlag{
Name: "port, P",
Value: "22",
Usage: "Server port, default to 22",
EnvVar: "PLUGIN_PORT,SCP_PORT,SSH_PORT",
&cli.IntFlag{
Name: "port",
Aliases: []string{"p"},
Usage: "connect to port",
EnvVars: []string{"PLUGIN_PORT", "SSH_PORT", "INPUT_PORT"},
Value: 22,
},
cli.StringFlag{
Name: "username, u",
Usage: "Server username",
EnvVar: "PLUGIN_USERNAME,PLUGIN_USER,SCP_USERNAME,SSH_USERNAME",
&cli.StringFlag{
Name: "username",
Aliases: []string{"user", "u"},
Usage: "connect as user",
EnvVars: []string{"PLUGIN_USERNAME", "PLUGIN_USER", "SSH_USERNAME", "INPUT_USERNAME"},
Value: "root",
},
cli.StringFlag{
Name: "password, p",
Usage: "Password for password-based authentication",
EnvVar: "PLUGIN_PASSWORD,SCP_PASSWORD,SSH_PASSWORD",
&cli.StringFlag{
Name: "password",
Aliases: []string{"P"},
Usage: "user password",
EnvVars: []string{"PLUGIN_PASSWORD", "SSH_PASSWORD", "INPUT_PASSWORD"},
},
cli.DurationFlag{
Name: "timeout",
Usage: "connection timeout",
EnvVar: "PLUGIN_TIMEOUT,SCP_TIMEOUT",
&cli.DurationFlag{
Name: "timeout",
Usage: "connection timeout",
EnvVars: []string{"PLUGIN_TIMEOUT", "SSH_TIMEOUT", "INPUT_TIMEOUT"},
Value: 30 * time.Second,
},
cli.DurationFlag{
Name: "command.timeout,T",
Usage: "command timeout",
EnvVar: "PLUGIN_COMMAND_TIMEOUT,SSH_COMMAND_TIMEOUT",
Value: 60 * time.Second,
&cli.StringFlag{
Name: "ssh-key",
Usage: "private ssh key",
EnvVars: []string{"PLUGIN_SSH_KEY", "PLUGIN_KEY", "SSH_KEY", "INPUT_KEY"},
},
cli.StringFlag{
Name: "key, k",
Usage: "ssh private key",
EnvVar: "PLUGIN_KEY,SCP_KEY,SSH_KEY",
&cli.StringFlag{
Name: "ssh-passphrase",
Usage: "The purpose of the passphrase is usually to encrypt the private key.",
EnvVars: []string{"PLUGIN_SSH_PASSPHRASE", "PLUGIN_PASSPHRASE", "SSH_PASSPHRASE", "INPUT_PASSPHRASE"},
},
cli.StringFlag{
Name: "key-path, i",
Usage: "ssh private key path",
EnvVar: "PLUGIN_KEY_PATH,SCP_KEY_PATH,SSH_KEY_PATH",
&cli.StringFlag{
Name: "key-path",
Aliases: []string{"i"},
Usage: "ssh private key path",
EnvVars: []string{"PLUGIN_KEY_PATH", "SSH_KEY_PATH", "INPUT_KEY_PATH"},
},
cli.StringSliceFlag{
Name: "target, t",
Usage: "Target path on the server",
EnvVar: "PLUGIN_TARGET,SCP_TARGET",
&cli.StringSliceFlag{
Name: "ciphers",
Usage: "The allowed cipher algorithms. If unspecified then a sensible",
EnvVars: []string{"PLUGIN_CIPHERS", "SSH_CIPHERS", "INPUT_CIPHERS"},
},
cli.StringSliceFlag{
Name: "source, s",
Usage: "scp file list",
EnvVar: "PLUGIN_SOURCE,SCP_SOURCE",
&cli.BoolFlag{
Name: "useInsecureCipher",
Usage: "include more ciphers with use_insecure_cipher",
EnvVars: []string{"PLUGIN_USE_INSECURE_CIPHER", "SSH_USE_INSECURE_CIPHER", "INPUT_USE_INSECURE_CIPHER"},
},
cli.BoolFlag{
Name: "rm, r",
Usage: "remove target folder before upload data",
EnvVar: "PLUGIN_RM,SCP_RM",
&cli.StringFlag{
Name: "fingerprint",
Usage: "fingerprint SHA256 of the host public key, default is to skip verification",
EnvVars: []string{"PLUGIN_FINGERPRINT", "SSH_FINGERPRINT", "INPUT_FINGERPRINT"},
},
cli.StringFlag{
Name: "repo.owner",
Usage: "repository owner",
EnvVar: "DRONE_REPO_OWNER",
&cli.DurationFlag{
Name: "command.timeout",
Usage: "command timeout",
EnvVars: []string{"PLUGIN_COMMAND_TIMEOUT", "SSH_COMMAND_TIMEOUT", "INPUT_COMMAND_TIMEOUT"},
Value: 10 * time.Minute,
},
cli.StringFlag{
Name: "repo.name",
Usage: "repository name",
EnvVar: "DRONE_REPO_NAME",
&cli.StringSliceFlag{
Name: "target",
Aliases: []string{"t"},
Usage: "Target path on the server",
EnvVars: []string{"PLUGIN_TARGET", "SSH_TARGET", "INPUT_TARGET"},
},
cli.StringFlag{
Name: "commit.sha",
Usage: "git commit sha",
EnvVar: "DRONE_COMMIT_SHA",
&cli.StringSliceFlag{
Name: "source",
Aliases: []string{"s"},
Usage: "scp file list",
EnvVars: []string{"PLUGIN_SOURCE", "SCP_SOURCE", "INPUT_SOURCE"},
},
cli.StringFlag{
Name: "commit.branch",
Value: "master",
Usage: "git commit branch",
EnvVar: "DRONE_COMMIT_BRANCH",
&cli.BoolFlag{
Name: "rm",
Aliases: []string{"r"},
Usage: "remove target folder before upload data",
EnvVars: []string{"PLUGIN_RM", "SCP_RM", "INPUT_RM"},
},
cli.StringFlag{
Name: "commit.author",
Usage: "git author name",
EnvVar: "DRONE_COMMIT_AUTHOR",
&cli.StringFlag{
Name: "proxy.host",
Usage: "connect to host of proxy",
EnvVars: []string{"PLUGIN_PROXY_HOST", "PROXY_SSH_HOST", "INPUT_PROXY_HOST"},
},
cli.StringFlag{
Name: "commit.message",
Usage: "commit message",
EnvVar: "DRONE_COMMIT_MESSAGE",
&cli.StringFlag{
Name: "proxy.port",
Usage: "connect to port of proxy",
EnvVars: []string{"PLUGIN_PROXY_PORT", "PROXY_SSH_PORT", "INPUT_PROXY_PORT"},
Value: "22",
},
cli.StringFlag{
Name: "build.event",
Value: "push",
Usage: "build event",
EnvVar: "DRONE_BUILD_EVENT",
&cli.StringFlag{
Name: "proxy.username",
Usage: "connect as user of proxy",
EnvVars: []string{"PLUGIN_PROXY_USERNAME", "PLUGIN_PROXY_USER", "PROXY_SSH_USERNAME", "INPUT_PROXY_USERNAME"},
Value: "root",
},
cli.IntFlag{
Name: "build.number",
Usage: "build number",
EnvVar: "DRONE_BUILD_NUMBER",
&cli.StringFlag{
Name: "proxy.password",
Usage: "user password of proxy",
EnvVars: []string{"PLUGIN_PROXY_PASSWORD", "PROXY_SSH_PASSWORD", "INPUT_PROXY_PASSWORD"},
},
cli.StringFlag{
Name: "build.status",
Usage: "build status",
Value: "success",
EnvVar: "DRONE_BUILD_STATUS",
&cli.StringFlag{
Name: "proxy.ssh-key",
Usage: "private ssh key of proxy",
EnvVars: []string{"PLUGIN_PROXY_SSH_KEY", "PLUGIN_PROXY_KEY", "PROXY_SSH_KEY", "INPUT_PROXY_KEY"},
},
cli.StringFlag{
Name: "build.link",
Usage: "build link",
EnvVar: "DRONE_BUILD_LINK",
&cli.StringFlag{
Name: "proxy.ssh-passphrase",
Usage: "The purpose of the passphrase is usually to encrypt the private key.",
EnvVars: []string{"PLUGIN_PROXY_SSH_PASSPHRASE", "PLUGIN_PROXY_PASSPHRASE", "PROXY_SSH_PASSPHRASE", "INPUT_PROXY_PASSPHRASE"},
},
cli.StringFlag{
Name: "env-file",
Usage: "source env file",
&cli.StringFlag{
Name: "proxy.key-path",
Usage: "ssh private key path of proxy",
EnvVars: []string{"PLUGIN_PROXY_KEY_PATH", "PROXY_SSH_KEY_PATH", "INPUT_PROXY_KEY_PATH"},
},
cli.StringFlag{
Name: "proxy.ssh-key",
Usage: "private ssh key of proxy",
EnvVar: "PLUGIN_PROXY_SSH_KEY,PLUGIN_PROXY_KEY,PROXY_SSH_KEY",
&cli.DurationFlag{
Name: "proxy.timeout",
Usage: "proxy connection timeout",
EnvVars: []string{"PLUGIN_PROXY_TIMEOUT", "PROXY_SSH_TIMEOUT", "INPUT_PROXY_TIMEOUT"},
},
cli.StringFlag{
Name: "proxy.key-path",
Usage: "ssh private key path of proxy",
EnvVar: "PLUGIN_PROXY_KEY_PATH,PROXY_SSH_KEY_PATH",
&cli.StringSliceFlag{
Name: "proxy.ciphers",
Usage: "The allowed cipher algorithms. If unspecified then a sensible",
EnvVars: []string{"PLUGIN_PROXY_CIPHERS", "PROXY_SSH_CIPHERS", "INPUT_PROXY_CIPHERS"},
},
cli.StringFlag{
Name: "proxy.username",
Usage: "connect as user of proxy",
EnvVar: "PLUGIN_PROXY_USERNAME,PLUGIN_PROXY_USER,PROXY_SSH_USERNAME",
Value: "root",
&cli.BoolFlag{
Name: "proxy.useInsecureCipher",
Usage: "include more ciphers with use_insecure_cipher",
EnvVars: []string{"PLUGIN_PROXY_USE_INSECURE_CIPHER", "PROXY_SSH_USE_INSECURE_CIPHER", "INPUT_PROXY_USE_INSECURE_CIPHER"},
},
cli.StringFlag{
Name: "proxy.password",
Usage: "user password of proxy",
EnvVar: "PLUGIN_PROXY_PASSWORD,PROXY_SSH_PASSWORD",
&cli.StringFlag{
Name: "proxy.fingerprint",
Usage: "fingerprint SHA256 of the host public key, default is to skip verification",
EnvVars: []string{"PLUGIN_PROXY_FINGERPRINT", "PROXY_SSH_FINGERPRINT", "PROXY_FINGERPRINT", "INPUT_PROXY_FINGERPRINT"},
},
cli.StringFlag{
Name: "proxy.host",
Usage: "connect to host of proxy",
EnvVar: "PLUGIN_PROXY_HOST,PROXY_SSH_HOST",
&cli.IntFlag{
Name: "strip.components",
Usage: "Remove the specified number of leading path elements.",
EnvVars: []string{"PLUGIN_STRIP_COMPONENTS", "TAR_STRIP_COMPONENTS", "INPUT_STRIP_COMPONENTS"},
},
cli.StringFlag{
Name: "proxy.port",
Usage: "connect to port of proxy",
EnvVar: "PLUGIN_PROXY_PORT,PROXY_SSH_PORT",
Value: "22",
&cli.StringFlag{
Name: "tar.exec",
Usage: "Alternative `tar` executable to on the dest host",
EnvVars: []string{"PLUGIN_TAR_EXEC", "SSH_TAR_EXEC", "INPUT_TAR_EXEC"},
Value: "tar",
},
cli.DurationFlag{
Name: "proxy.timeout",
Usage: "proxy connection timeout",
EnvVar: "PLUGIN_PROXY_TIMEOUT,PROXY_SSH_TIMEOUT",
&cli.StringFlag{
Name: "tar.tmp-path",
Usage: "Temporary path for tar file on the dest host",
EnvVars: []string{"PLUGIN_TAR_TMP_PATH", "SSH_TAR_TMP_PATH", "INPUT_TAR_TMP_PATH"},
},
cli.IntFlag{
Name: "strip.components",
Usage: "Remove the specified number of leading path elements.",
EnvVar: "PLUGIN_STRIP_COMPONENTS,TAR_STRIP_COMPONENTS",
&cli.BoolFlag{
Name: "debug",
Usage: "remove target folder before upload data",
EnvVars: []string{"PLUGIN_DEBUG", "INPUT_DEBUG"},
},
cli.StringFlag{
Name: "tar.exec",
Usage: "Alternative `tar` executable to on the dest host",
EnvVar: "PLUGIN_TAR_EXEC,SCP_TAR_EXEC",
Value: "tar",
&cli.BoolFlag{
Name: "overwrite",
Usage: "use --overwrite flag with tar",
EnvVars: []string{"PLUGIN_OVERWRITE", "INPUT_OVERWRITE"},
},
cli.BoolFlag{
Name: "debug",
Usage: "remove target folder before upload data",
EnvVar: "PLUGIN_DEBUG,DEBUG",
&cli.BoolFlag{
Name: "unlink.first",
Usage: "use --unlink-first flag with tar",
EnvVars: []string{"PLUGIN_UNLINK_FIRST", "INPUT_UNLINK_FIRST"},
},
&cli.BoolFlag{
Name: "tar.dereference",
Usage: "use --dereference flag with tar",
EnvVars: []string{"PLUGIN_TAR_DEREFERENCE", "INPUT_TAR_DEREFERENCE"},
},
}
@@ -233,60 +251,49 @@ VERSION:
REPOSITORY:
Github: https://github.com/appleboy/drone-scp
`
app.Version = Version
if BuildNum != "" {
app.Version = app.Version + "+" + BuildNum
}
if err := app.Run(os.Args); err != nil {
log.Println(err)
log.Fatal(err)
}
}
func run(c *cli.Context) error {
if c.String("env-file") != "" {
_ = godotenv.Load(c.String("env-file"))
}
plugin := Plugin{
Repo: Repo{
Owner: c.String("repo.owner"),
Name: c.String("repo.name"),
},
Build: Build{
Number: c.Int("build.number"),
Event: c.String("build.event"),
Status: c.String("build.status"),
Commit: c.String("commit.sha"),
Branch: c.String("commit.branch"),
Author: c.String("commit.author"),
Message: c.String("commit.message"),
Link: c.String("build.link"),
},
Config: Config{
Host: c.StringSlice("host"),
Port: c.String("port"),
Username: c.String("username"),
Password: c.String("password"),
Timeout: c.Duration("timeout"),
CommandTimeout: c.Duration("command.timeout"),
Key: c.String("key"),
KeyPath: c.String("key-path"),
Target: c.StringSlice("target"),
Source: c.StringSlice("source"),
Remove: c.Bool("rm"),
Debug: c.Bool("debug"),
StripComponents: c.Int("strip.components"),
TarExec: c.String("tar.exec"),
Host: c.StringSlice("host"),
Port: c.String("port"),
Username: c.String("username"),
Password: c.String("password"),
Passphrase: c.String("ssh-passphrase"),
Fingerprint: c.String("fingerprint"),
Timeout: c.Duration("timeout"),
CommandTimeout: c.Duration("command.timeout"),
Key: c.String("ssh-key"),
KeyPath: c.String("key-path"),
Target: c.StringSlice("target"),
Source: c.StringSlice("source"),
Remove: c.Bool("rm"),
Debug: c.Bool("debug"),
StripComponents: c.Int("strip.components"),
TarExec: c.String("tar.exec"),
TarTmpPath: c.String("tar.tmp-path"),
Overwrite: c.Bool("overwrite"),
UnlinkFirst: c.Bool("unlink.first"),
Ciphers: c.StringSlice("ciphers"),
UseInsecureCipher: c.Bool("useInsecureCipher"),
TarDereference: c.Bool("tar.dereference"),
Proxy: easyssh.DefaultConfig{
Key: c.String("proxy.ssh-key"),
KeyPath: c.String("proxy.key-path"),
User: c.String("proxy.username"),
Password: c.String("proxy.password"),
Server: c.String("proxy.host"),
Port: c.String("proxy.port"),
Timeout: c.Duration("proxy.timeout"),
Key: c.String("proxy.ssh-key"),
Passphrase: c.String("proxy.ssh-passphrase"),
Fingerprint: c.String("proxy.fingerprint"),
KeyPath: c.String("proxy.key-path"),
User: c.String("proxy.username"),
Password: c.String("proxy.password"),
Server: c.String("proxy.host"),
Port: c.String("proxy.port"),
Timeout: c.Duration("proxy.timeout"),
Ciphers: c.StringSlice("proxy.ciphers"),
UseInsecureCipher: c.Bool("proxy.useInsecureCipher"),
},
},
}
+2 -1
View File
@@ -1,4 +1,5 @@
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
//go:build !windows
// +build !windows
package main
+1
View File
@@ -1,3 +1,4 @@
//go:build windows
// +build windows
package main
+3 -1
View File
@@ -1,6 +1,8 @@
package main
import "testing"
import (
"testing"
)
func TestGetRealPath(t *testing.T) {
type args struct {
-281
View File
@@ -1,281 +0,0 @@
{
test:: {
kind: 'pipeline',
name: 'testing',
platform: {
os: 'linux',
arch: 'amd64',
},
steps: [
{
name: 'vet',
image: 'golang:1.12',
pull: 'always',
environment: {
GO111MODULE: 'on',
},
commands: [
'make vet',
],
volumes: [
{
name: 'gopath',
path: '/go',
},
],
},
{
name: 'lint',
image: 'golang:1.12',
pull: 'always',
environment: {
GO111MODULE: 'on',
},
commands: [
'make lint',
],
volumes: [
{
name: 'gopath',
path: '/go',
},
],
},
{
name: 'misspell',
image: 'golang:1.12',
pull: 'always',
environment: {
GO111MODULE: 'on',
},
commands: [
'make misspell-check',
],
volumes: [
{
name: 'gopath',
path: '/go',
},
],
},
{
name: 'test',
image: 'golang:1.12-alpine',
pull: 'always',
environment: {
GO111MODULE: 'on',
},
commands: [
'apk add git make curl perl bash build-base zlib-dev ucl-dev',
'make ssh-server',
'make test',
'make coverage',
],
volumes: [
{
name: 'gopath',
path: '/go',
},
],
},
{
name: 'codecov',
image: 'robertstettner/drone-codecov',
pull: 'always',
settings: {
token: { 'from_secret': 'codecov_token' },
},
},
],
volumes: [
{
name: 'gopath',
temp: {},
},
],
},
build(name, os='linux', arch='amd64'):: {
kind: 'pipeline',
name: os + '-' + arch,
platform: {
os: os,
arch: arch,
},
steps: [
{
name: 'build-push',
image: 'golang:1.12',
pull: 'always',
environment: {
CGO_ENABLED: '0',
GO111MODULE: 'on',
},
commands: [
'go build -v -ldflags \'-X main.build=${DRONE_BUILD_NUMBER}\' -a -o release/' + os + '/' + arch + '/' + name,
],
when: {
event: {
exclude: [ 'tag' ],
},
},
},
{
name: 'build-tag',
image: 'golang:1.12',
pull: 'always',
environment: {
CGO_ENABLED: '0',
GO111MODULE: 'on',
},
commands: [
'go build -v -ldflags \'-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}\' -a -o release/' + os + '/' + arch + '/' + name,
],
when: {
event: [ 'tag' ],
},
},
{
name: 'executable',
image: 'golang:1.12',
pull: 'always',
commands: [
'./release/' + os + '/' + arch + '/' + name + ' --help',
],
},
{
name: 'dryrun',
image: 'plugins/docker:' + os + '-' + arch,
pull: 'always',
settings: {
daemon_off: false,
dry_run: true,
tags: os + '-' + arch,
dockerfile: 'docker/Dockerfile.' + os + '.' + arch,
repo: 'appleboy/' + name,
cache_from: 'appleboy/' + name,
},
when: {
event: [ 'pull_request' ],
},
},
{
name: 'publish',
image: 'plugins/docker:' + os + '-' + arch,
pull: 'always',
settings: {
daemon_off: 'false',
auto_tag: true,
auto_tag_suffix: os + '-' + arch,
dockerfile: 'docker/Dockerfile.' + os + '.' + arch,
repo: 'appleboy/' + name,
cache_from: 'appleboy/' + name,
username: { 'from_secret': 'docker_username' },
password: { 'from_secret': 'docker_password' },
},
when: {
event: {
exclude: [ 'pull_request' ],
},
},
},
],
depends_on: [
'testing',
],
trigger: {
ref: [
'refs/heads/master',
'refs/pull/**',
'refs/tags/**',
],
},
},
release:: {
kind: 'pipeline',
name: 'release-binary',
platform: {
os: 'linux',
arch: 'amd64',
},
steps: [
{
name: 'build-all-binary',
image: 'golang:1.12',
pull: 'always',
environment: {
GO111MODULE: 'on',
},
commands: [
'make release'
],
when: {
event: [ 'tag' ],
},
},
{
name: 'deploy-all-binary',
image: 'plugins/github-release',
pull: 'always',
settings: {
files: [ 'dist/release/*' ],
api_key: { 'from_secret': 'github_release_api_key' },
},
when: {
event: [ 'tag' ],
},
},
],
depends_on: [
'testing',
],
trigger: {
ref: [
'refs/tags/**',
],
},
},
notifications(os='linux', arch='amd64', depends_on=[]):: {
kind: 'pipeline',
name: 'notifications',
platform: {
os: os,
arch: arch,
},
steps: [
{
name: 'manifest',
image: 'plugins/manifest',
pull: 'always',
settings: {
username: { from_secret: 'docker_username' },
password: { from_secret: 'docker_password' },
spec: 'docker/manifest.tmpl',
ignore_missing: true,
},
},
{
name: 'microbadger',
image: 'plugins/webhook:1',
pull: 'always',
settings: {
url: { 'from_secret': 'microbadger_url' },
},
},
],
depends_on: depends_on,
trigger: {
ref: [
'refs/heads/master',
'refs/tags/**',
],
},
},
signature(key):: {
kind: 'signature',
hmac: key,
}
}
+213 -141
View File
@@ -3,10 +3,10 @@ package main
import (
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
@@ -19,52 +19,39 @@ import (
var (
errMissingHost = errors.New("Error: missing server host")
errMissingPasswordOrKey = errors.New("Error: can't connect without a private SSH key or password")
errSetPasswordandKey = errors.New("can't set password and key at the same time")
errMissingSourceOrTarget = errors.New("missing source or target config")
)
type (
// Repo information.
Repo struct {
Owner string
Name string
}
// Build information.
Build struct {
Event string
Number int
Commit string
Message string
Branch string
Author string
Status string
Link string
}
// Config for the plugin.
Config struct {
Host []string
Port string
Username string
Password string
Key string
KeyPath string
Timeout time.Duration
CommandTimeout time.Duration
Target []string
Source []string
Remove bool
StripComponents int
TarExec string
Proxy easyssh.DefaultConfig
Debug bool
Host []string
Port string
Username string
Password string
Key string
Passphrase string
Fingerprint string
KeyPath string
Timeout time.Duration
CommandTimeout time.Duration
Target []string
Source []string
Remove bool
StripComponents int
TarExec string
TarTmpPath string
Proxy easyssh.DefaultConfig
Debug bool
Overwrite bool
UnlinkFirst bool
Ciphers []string
UseInsecureCipher bool
TarDereference bool
}
// Plugin values.
Plugin struct {
Repo Repo
Build Build
Config Config
DestFile string
}
@@ -79,27 +66,12 @@ func (e copyError) Error() string {
return fmt.Sprintf("error copy file to dest: %s, error message: %s\n", e.host, e.message)
}
func trimPath(keys []string) []string {
var newKeys []string
for _, value := range keys {
value = strings.Trim(value, " ")
if len(value) == 0 {
continue
}
newKeys = append(newKeys, value)
}
return newKeys
}
func globList(paths []string) fileList {
var list fileList
for _, pattern := range paths {
ignore := false
pattern = strings.Trim(pattern, " ")
pattern = strings.TrimSpace(pattern)
if string(pattern[0]) == "!" {
pattern = pattern[1:]
ignore = true
@@ -120,21 +92,6 @@ func globList(paths []string) fileList {
return list
}
func buildArgs(tar string, files fileList) []string {
args := []string{}
if len(files.Ignore) > 0 {
for _, v := range files.Ignore {
args = append(args, "--exclude")
args = append(args, v)
}
}
args = append(args, "-cf")
args = append(args, getRealPath(tar))
args = append(args, files.Source...)
return args
}
func (p Plugin) log(host string, message ...interface{}) {
if count := len(p.Config.Host); count == 1 {
fmt.Printf("%s", fmt.Sprintln(message...))
@@ -143,10 +100,9 @@ func (p Plugin) log(host string, message ...interface{}) {
}
}
func (p *Plugin) removeDestFile(ssh *easyssh.MakeConfig) error {
func (p *Plugin) removeDestFile(os string, ssh *easyssh.MakeConfig) error {
p.log(ssh.Server, "remove file", p.DestFile)
_, errStr, _, err := ssh.Run(fmt.Sprintf("rm -rf %s", p.DestFile), p.Config.CommandTimeout)
_, errStr, _, err := ssh.Run(rmcmd(os, p.DestFile), p.Config.CommandTimeout)
if err != nil {
return err
}
@@ -159,28 +115,42 @@ func (p *Plugin) removeDestFile(ssh *easyssh.MakeConfig) error {
}
func (p *Plugin) removeAllDestFile() error {
for _, host := range p.Config.Host {
for _, host := range trimValues(p.Config.Host) {
ssh := &easyssh.MakeConfig{
Server: host,
User: p.Config.Username,
Password: p.Config.Password,
Port: p.Config.Port,
Key: p.Config.Key,
KeyPath: p.Config.KeyPath,
Timeout: p.Config.Timeout,
Server: host,
User: p.Config.Username,
Password: p.Config.Password,
Port: p.Config.Port,
Key: p.Config.Key,
KeyPath: p.Config.KeyPath,
Passphrase: p.Config.Passphrase,
Timeout: p.Config.Timeout,
Ciphers: p.Config.Ciphers,
Fingerprint: p.Config.Fingerprint,
UseInsecureCipher: p.Config.UseInsecureCipher,
Proxy: easyssh.DefaultConfig{
Server: p.Config.Proxy.Server,
User: p.Config.Proxy.User,
Password: p.Config.Proxy.Password,
Port: p.Config.Proxy.Port,
Key: p.Config.Proxy.Key,
KeyPath: p.Config.Proxy.KeyPath,
Timeout: p.Config.Proxy.Timeout,
Server: p.Config.Proxy.Server,
User: p.Config.Proxy.User,
Password: p.Config.Proxy.Password,
Port: p.Config.Proxy.Port,
Key: p.Config.Proxy.Key,
KeyPath: p.Config.Proxy.KeyPath,
Passphrase: p.Config.Proxy.Passphrase,
Timeout: p.Config.Proxy.Timeout,
Ciphers: p.Config.Proxy.Ciphers,
Fingerprint: p.Config.Proxy.Fingerprint,
UseInsecureCipher: p.Config.Proxy.UseInsecureCipher,
},
}
_, _, _, err := ssh.Run("ver", p.Config.CommandTimeout)
systemType := "unix"
if err == nil {
systemType = "windows"
}
// remove tar file
err := p.removeDestFile(ssh)
err = p.removeDestFile(systemType, ssh)
if err != nil {
return err
}
@@ -194,37 +164,83 @@ type fileList struct {
Source []string
}
func (p *Plugin) buildTarArgs(src string) []string {
files := globList(trimValues(p.Config.Source))
args := []string{}
if len(files.Ignore) > 0 {
for _, v := range files.Ignore {
args = append(args, "--exclude")
args = append(args, v)
}
}
if p.Config.TarDereference {
args = append(args, "--dereference")
}
args = append(args, "-zcf")
args = append(args, getRealPath(src))
args = append(args, files.Source...)
return args
}
func (p *Plugin) buildUnTarArgs(target string) []string {
args := []string{}
args = append(args,
p.Config.TarExec,
"-zxf",
p.DestFile,
)
if p.Config.StripComponents > 0 {
args = append(args, "--strip-components")
args = append(args, strconv.Itoa(p.Config.StripComponents))
}
if p.Config.Overwrite {
args = append(args, "--overwrite")
}
if p.Config.UnlinkFirst {
args = append(args, "--unlink-first")
}
args = append(args,
"-C",
target,
)
return args
}
// Exec executes the plugin.
func (p *Plugin) Exec() error {
if len(p.Config.Host) == 0 {
return errMissingHost
}
if len(p.Config.Key) == 0 && len(p.Config.Password) == 0 && len(p.Config.KeyPath) == 0 {
return errMissingPasswordOrKey
}
if len(p.Config.Key) != 0 && len(p.Config.Password) != 0 {
return errSetPasswordandKey
}
if len(p.Config.Source) == 0 || len(p.Config.Target) == 0 {
return errMissingSourceOrTarget
}
files := globList(trimPath(p.Config.Source))
p.DestFile = fmt.Sprintf("%s.tar", random.String(10))
hosts := trimValues(p.Config.Host)
if len(hosts) == 0 {
return errMissingHost
}
p.DestFile = fmt.Sprintf("%s.tar.gz", random.String(10))
// create a temporary file for the archive
dir, err := ioutil.TempDir("", "")
if err != nil {
return err
}
tar := filepath.Join(dir, p.DestFile)
dir := os.TempDir()
src := filepath.Join(dir, p.DestFile)
// show current version
fmt.Println("drone-scp version: " + Version)
// run archive command
fmt.Println("tar all files into " + tar)
args := buildArgs(tar, files)
fmt.Println("tar all files into " + src)
args := p.buildTarArgs(src)
cmd := exec.Command(p.Config.TarExec, args...)
if p.Config.Debug {
fmt.Println("$", strings.Join(cmd.Args, " "))
@@ -237,55 +253,73 @@ func (p *Plugin) Exec() error {
wg := sync.WaitGroup{}
wg.Add(len(p.Config.Host))
errChannel := make(chan error, 1)
finished := make(chan bool, 1)
for _, host := range p.Config.Host {
go func(host string) {
errChannel := make(chan error)
finished := make(chan struct{})
for _, host := range hosts {
go func(h string) {
defer wg.Done()
host, port := p.hostPort(h)
// Create MakeConfig instance with remote username, server address and path to private key.
ssh := &easyssh.MakeConfig{
Server: host,
User: p.Config.Username,
Password: p.Config.Password,
Port: p.Config.Port,
Key: p.Config.Key,
KeyPath: p.Config.KeyPath,
Timeout: p.Config.Timeout,
Server: host,
User: p.Config.Username,
Password: p.Config.Password,
Port: port,
Key: p.Config.Key,
KeyPath: p.Config.KeyPath,
Passphrase: p.Config.Passphrase,
Timeout: p.Config.Timeout,
Ciphers: p.Config.Ciphers,
Fingerprint: p.Config.Fingerprint,
UseInsecureCipher: p.Config.UseInsecureCipher,
Proxy: easyssh.DefaultConfig{
Server: p.Config.Proxy.Server,
User: p.Config.Proxy.User,
Password: p.Config.Proxy.Password,
Port: p.Config.Proxy.Port,
Key: p.Config.Proxy.Key,
KeyPath: p.Config.Proxy.KeyPath,
Timeout: p.Config.Proxy.Timeout,
Server: p.Config.Proxy.Server,
User: p.Config.Proxy.User,
Password: p.Config.Proxy.Password,
Port: p.Config.Proxy.Port,
Key: p.Config.Proxy.Key,
KeyPath: p.Config.Proxy.KeyPath,
Passphrase: p.Config.Proxy.Passphrase,
Timeout: p.Config.Proxy.Timeout,
Ciphers: p.Config.Proxy.Ciphers,
Fingerprint: p.Config.Proxy.Fingerprint,
UseInsecureCipher: p.Config.Proxy.UseInsecureCipher,
},
}
systemType := "unix"
_, _, _, err := ssh.Run("ver", p.Config.CommandTimeout)
if err == nil {
systemType = "windows"
}
// upload file to the tmp path
p.DestFile = fmt.Sprintf("%s%s", p.Config.TarTmpPath, p.DestFile)
p.log(host, "remote server os type is "+systemType)
// Call Scp method with file you want to upload to remote server.
p.log(host, "scp file to server.")
err := ssh.Scp(tar, p.DestFile)
err = ssh.Scp(src, p.DestFile)
if err != nil {
errChannel <- copyError{host, err.Error()}
return
}
for _, target := range p.Config.Target {
// remove target before upload data
target = strings.Replace(target, " ", "\\ ", -1)
// remove target folder before upload data
if p.Config.Remove {
p.log(host, "Remove target folder:", target)
_, _, _, err := ssh.Run(fmt.Sprintf("rm -rf %s", target), p.Config.CommandTimeout)
_, _, _, err := ssh.Run(rmcmd(systemType, target), p.Config.CommandTimeout)
if err != nil {
errChannel <- err
return
}
}
// mkdir path
p.log(host, "create folder", target)
_, errStr, _, err := ssh.Run(fmt.Sprintf("mkdir -p %s", target), p.Config.CommandTimeout)
_, errStr, _, err := ssh.Run(mkdircmd(systemType, target), p.Config.CommandTimeout)
if err != nil {
errChannel <- err
return
@@ -298,10 +332,18 @@ func (p *Plugin) Exec() error {
// untar file
p.log(host, "untar file", p.DestFile)
if p.Config.StripComponents > 0 {
_, _, _, err = ssh.Run(fmt.Sprintf("%s -xf %s --strip-components=%d -C %s", p.Config.TarExec, p.DestFile, p.Config.StripComponents, target), p.Config.CommandTimeout)
} else {
_, _, _, err = ssh.Run(fmt.Sprintf("%s -xf %s -C %s", p.Config.TarExec, p.DestFile, target), p.Config.CommandTimeout)
commamd := strings.Join(p.buildUnTarArgs(target), " ")
if p.Config.Debug {
fmt.Println("$", commamd)
}
outStr, errStr, _, err := ssh.Run(commamd, p.Config.CommandTimeout)
if outStr != "" {
p.log(host, "output: ", outStr)
}
if errStr != "" {
p.log(host, "error: ", errStr)
}
if err != nil {
@@ -311,14 +353,11 @@ func (p *Plugin) Exec() error {
}
// remove tar file
err = p.removeDestFile(ssh)
err = p.removeDestFile(systemType, ssh)
if err != nil {
errChannel <- err
return
}
wg.Done()
}(host)
}
@@ -335,15 +374,48 @@ func (p *Plugin) Exec() error {
c.Println("drone-scp error: ", err)
if _, ok := err.(copyError); !ok {
fmt.Println("drone-scp rollback: remove all target tmp file")
p.removeAllDestFile()
if err := p.removeAllDestFile(); err != nil {
return err
}
}
return err
}
}
fmt.Println("================================================")
fmt.Println("Successfully executed transfer data to all host.")
fmt.Println("================================================")
fmt.Println("===================================================")
fmt.Println("Successfully executed transfer data to all host")
fmt.Println("===================================================")
return nil
}
// This function takes a Plugin struct and a host string and returns the host and port as separate strings.
func (p Plugin) hostPort(host string) (string, string) {
// Split the host string by colon (":") to get the host and port
hosts := strings.Split(host, ":")
// Get the default port from the Plugin's Config field
port := p.Config.Port
// If the host string contains a port (i.e. it has more than one element after splitting), set the port to that value
if len(hosts) > 1 {
host = hosts[0]
port = hosts[1]
}
// Return the host and port as separate strings
return host, port
}
func trimValues(keys []string) []string {
var newKeys []string
for _, value := range keys {
value = strings.TrimSpace(value)
if len(value) == 0 {
continue
}
newKeys = append(newKeys, value)
}
return newKeys
}
+457 -43
View File
@@ -1,15 +1,18 @@
package main
import (
"log"
"os"
"os/exec"
"os/user"
"path/filepath"
"reflect"
"testing"
"time"
"github.com/appleboy/easyssh-proxy"
"github.com/stretchr/testify/assert"
"golang.org/x/crypto/ssh"
)
func TestMissingAllConfig(t *testing.T) {
@@ -48,35 +51,18 @@ func TestMissingSourceConfig(t *testing.T) {
assert.NotNil(t, err)
}
func TestSetPasswordAndKey(t *testing.T) {
plugin := Plugin{
Config: Config{
Host: []string{"example.com"},
Username: "ubuntu",
Port: "443",
Password: "1234",
Key: "test",
},
}
err := plugin.Exec()
assert.NotNil(t, err)
assert.Equal(t, errSetPasswordandKey, err)
}
func TestTrimElement(t *testing.T) {
var input, result []string
input = []string{"1", " ", "3"}
result = []string{"1", "3"}
assert.Equal(t, result, trimPath(input))
assert.Equal(t, result, trimValues(input))
input = []string{"1", "2"}
result = []string{"1", "2"}
assert.Equal(t, result, trimPath(input))
assert.Equal(t, result, trimValues(input))
}
func TestSCPFileFromPublicKey(t *testing.T) {
@@ -129,6 +115,129 @@ func TestSCPFileFromPublicKey(t *testing.T) {
}
}
func TestSCPFileFromPublicKeyWithPassphrase(t *testing.T) {
if os.Getenv("SSH_AUTH_SOCK") != "" {
if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil {
t.Fatalf("exec: %v", err)
}
}
u, err := user.Lookup("drone-scp")
if err != nil {
t.Fatalf("Lookup: %v", err)
}
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: "22",
KeyPath: "tests/.ssh/test",
Passphrase: "1234",
Source: []string{"tests/a.txt", "tests/b.txt"},
Target: []string{filepath.Join(u.HomeDir, "/test2")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
},
}
err = plugin.Exec()
assert.Nil(t, err)
// check file exist
if _, err := os.Stat(filepath.Join(u.HomeDir, "/test2/tests/a.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
if _, err := os.Stat(filepath.Join(u.HomeDir, "/test2/tests/b.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
}
func TestWrongFingerprint(t *testing.T) {
u, err := user.Lookup("drone-scp")
if err != nil {
t.Fatalf("Lookup: %v", err)
}
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: "22",
KeyPath: "./tests/.ssh/id_rsa",
Source: []string{"tests/a.txt", "tests/b.txt"},
Target: []string{filepath.Join(u.HomeDir, "/test2")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
Fingerprint: "wrong",
},
}
err = plugin.Exec()
log.Println(err)
assert.NotNil(t, err)
}
func getHostPublicKeyFile(keypath string) (ssh.PublicKey, error) {
var pubkey ssh.PublicKey
var err error
buf, err := os.ReadFile(keypath)
if err != nil {
return nil, err
}
pubkey, _, _, _, err = ssh.ParseAuthorizedKey(buf)
if err != nil {
return nil, err
}
return pubkey, nil
}
func TestSCPFileFromPublicKeyWithFingerprint(t *testing.T) {
if os.Getenv("SSH_AUTH_SOCK") != "" {
if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil {
t.Fatalf("exec: %v", err)
}
}
u, err := user.Lookup("drone-scp")
if err != nil {
t.Fatalf("Lookup: %v", err)
}
hostKey, err := getHostPublicKeyFile("/etc/ssh/ssh_host_rsa_key.pub")
assert.NoError(t, err)
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: "22",
KeyPath: "./tests/.ssh/id_rsa",
Fingerprint: ssh.FingerprintSHA256(hostKey),
Source: []string{"tests/a.txt", "tests/b.txt"},
Target: []string{filepath.Join(u.HomeDir, "/test2")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
},
}
err = plugin.Exec()
assert.Nil(t, err)
// check file exist
if _, err := os.Stat(filepath.Join(u.HomeDir, "/test2/tests/a.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
if _, err := os.Stat(filepath.Join(u.HomeDir, "/test2/tests/b.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
}
func TestSCPWildcardFileList(t *testing.T) {
if os.Getenv("SSH_AUTH_SOCK") != "" {
if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil {
@@ -244,6 +353,40 @@ func TestStripComponentsFlag(t *testing.T) {
}
}
func TestUseInsecureCipherFlag(t *testing.T) {
u, err := user.Lookup("drone-scp")
if err != nil {
t.Fatalf("Lookup: %v", err)
}
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: "22",
KeyPath: "tests/.ssh/id_rsa",
Source: []string{"tests/global/*"},
StripComponents: 2,
Target: []string{filepath.Join(u.HomeDir, "123")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
UseInsecureCipher: true,
},
}
err = plugin.Exec()
assert.Nil(t, err)
// check file exist
if _, err := os.Stat(filepath.Join(u.HomeDir, "123/c.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
if _, err := os.Stat(filepath.Join(u.HomeDir, "123/d.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
}
func TestIgnoreList(t *testing.T) {
if os.Getenv("SSH_AUTH_SOCK") != "" {
if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil {
@@ -267,6 +410,7 @@ func TestIgnoreList(t *testing.T) {
Target: []string{filepath.Join(u.HomeDir, "ignore")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
Debug: true,
},
}
@@ -274,12 +418,12 @@ func TestIgnoreList(t *testing.T) {
assert.Nil(t, err)
// check file exist
if _, err := os.Stat(filepath.Join(u.HomeDir, "ignore/c.txt")); err == nil {
if _, err := os.Stat(filepath.Join(u.HomeDir, "ignore/c.txt")); !os.IsNotExist(err) {
t.Fatal("c.txt file exist")
}
// check file exist
if _, err := os.Stat(filepath.Join(u.HomeDir, "ignore/e.txt")); err == nil {
if _, err := os.Stat(filepath.Join(u.HomeDir, "ignore/e.txt")); !os.IsNotExist(err) {
t.Fatal("c.txt file exist")
}
@@ -387,7 +531,7 @@ func TestGlobList(t *testing.T) {
assert.Equal(t, expects, globList(paterns).Source)
paterns = []string{"tests/*.txt", "tests/.ssh/*", "abc*"}
expects = []string{"tests/a.txt", "tests/b.txt", "tests/.ssh/id_rsa", "tests/.ssh/id_rsa.pub"}
expects = []string{"tests/a.txt", "tests/b.txt", "tests/.ssh/id_rsa", "tests/.ssh/id_rsa.pub", "tests/.ssh/test", "tests/.ssh/test.pub"}
assert.Equal(t, expects, globList(paterns).Source)
paterns = []string{"tests/?.txt"}
@@ -411,25 +555,6 @@ func TestGlobList(t *testing.T) {
assert.Equal(t, expectIgnores, result.Ignore)
}
func TestBuildArgs(t *testing.T) {
list := fileList{
Source: []string{"tests/a.txt", "tests/b.txt", "tests/c.txt"},
Ignore: []string{"tests/a.txt", "tests/b.txt"},
}
result := buildArgs("test.tar.gz", list)
expects := []string{"--exclude", "tests/a.txt", "--exclude", "tests/b.txt", "-cf", "test.tar.gz", "tests/a.txt", "tests/b.txt", "tests/c.txt"}
assert.Equal(t, expects, result)
list = fileList{
Source: []string{"tests/a.txt", "tests/b.txt"},
}
result = buildArgs("test.tar.gz", list)
expects = []string{"-cf", "test.tar.gz", "tests/a.txt", "tests/b.txt"}
assert.Equal(t, expects, result)
}
func TestRemoveDestFile(t *testing.T) {
ssh := &easyssh.MakeConfig{
Server: "localhost",
@@ -446,13 +571,302 @@ func TestRemoveDestFile(t *testing.T) {
DestFile: "/etc/resolv.conf",
}
_, _, _, err := ssh.Run("ver", plugin.Config.CommandTimeout)
systemType := "unix"
if err == nil {
systemType = "windows"
}
// ssh io timeout
err := plugin.removeDestFile(ssh)
err = plugin.removeDestFile(systemType, ssh)
assert.Error(t, err)
ssh.Timeout = 0
// permission denied
err = plugin.removeDestFile(ssh)
err = plugin.removeDestFile(systemType, ssh)
assert.Error(t, err)
}
func TestPlugin_buildUnTarArgs(t *testing.T) {
type fields struct {
Config Config
DestFile string
}
type args struct {
target string
}
tests := []struct {
name string
fields fields
args args
want []string
}{
{
name: "default command",
fields: fields{
Config: Config{
Overwrite: false,
UnlinkFirst: false,
TarExec: "tar",
},
DestFile: "foo.tar.gz",
},
args: args{
target: "foo",
},
want: []string{"tar", "-zxf", "foo.tar.gz", "-C", "foo"},
},
{
name: "strip components",
fields: fields{
Config: Config{
Overwrite: false,
UnlinkFirst: false,
TarExec: "tar",
StripComponents: 2,
},
DestFile: "foo.tar.gz",
},
args: args{
target: "foo",
},
want: []string{"tar", "-zxf", "foo.tar.gz", "--strip-components", "2", "-C", "foo"},
},
{
name: "overwrite",
fields: fields{
Config: Config{
TarExec: "tar",
StripComponents: 2,
Overwrite: true,
UnlinkFirst: false,
},
DestFile: "foo.tar.gz",
},
args: args{
target: "foo",
},
want: []string{"tar", "-zxf", "foo.tar.gz", "--strip-components", "2", "--overwrite", "-C", "foo"},
},
{
name: "unlink first",
fields: fields{
Config: Config{
TarExec: "tar",
StripComponents: 2,
Overwrite: true,
UnlinkFirst: true,
},
DestFile: "foo.tar.gz",
},
args: args{
target: "foo",
},
want: []string{"tar", "-zxf", "foo.tar.gz", "--strip-components", "2", "--overwrite", "--unlink-first", "-C", "foo"},
},
{
name: "output folder path with space",
fields: fields{
Config: Config{
TarExec: "tar",
StripComponents: 2,
Overwrite: true,
UnlinkFirst: true,
},
DestFile: "foo.tar.gz",
},
args: args{
target: "foo\\ bar",
},
want: []string{"tar", "-zxf", "foo.tar.gz", "--strip-components", "2", "--overwrite", "--unlink-first", "-C", "foo\\ bar"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := &Plugin{
Config: tt.fields.Config,
DestFile: tt.fields.DestFile,
}
if got := p.buildUnTarArgs(tt.args.target); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Plugin.buildArgs() = %v, want %v", got, tt.want)
}
})
}
}
func TestPlugin_buildTarArgs(t *testing.T) {
type fields struct {
Config Config
}
type args struct {
src string
}
tests := []struct {
name string
fields fields
args args
want []string
}{
{
name: "default command",
fields: fields{
Config: Config{
TarExec: "tar",
},
},
args: args{
src: "foo.tar.gz",
},
want: []string{"-zcf", "foo.tar.gz"},
},
{
name: "ignore list",
fields: fields{
Config: Config{
TarExec: "tar",
Source: []string{
"tests/*.txt",
"!tests/a.txt",
},
},
},
args: args{
src: "foo.tar.gz",
},
want: []string{"--exclude", "tests/a.txt", "-zcf", "foo.tar.gz", "tests/a.txt", "tests/b.txt"},
},
{
name: "dereference flag",
fields: fields{
Config: Config{
TarExec: "tar",
TarDereference: true,
Source: []string{
"tests/*.txt",
"!tests/a.txt",
},
},
},
args: args{
src: "foo.tar.gz",
},
want: []string{"--exclude", "tests/a.txt", "--dereference", "-zcf", "foo.tar.gz", "tests/a.txt", "tests/b.txt"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := &Plugin{
Config: tt.fields.Config,
}
if got := p.buildTarArgs(tt.args.src); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Plugin.buildTarArgs() = %v, want %v", got, tt.want)
}
})
}
}
func TestTargetFolderWithSpaces(t *testing.T) {
if os.Getenv("SSH_AUTH_SOCK") != "" {
if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil {
t.Fatalf("exec: %v", err)
}
}
u, err := user.Lookup("drone-scp")
if err != nil {
t.Fatalf("Lookup: %v", err)
}
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: "22",
KeyPath: "tests/.ssh/id_rsa",
Source: []string{"tests/global/*"},
StripComponents: 2,
Target: []string{filepath.Join(u.HomeDir, "123 456 789")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
},
}
err = plugin.Exec()
assert.Nil(t, err)
// check file exist
if _, err := os.Stat(filepath.Join(u.HomeDir, "123 456 789", "c.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
if _, err := os.Stat(filepath.Join(u.HomeDir, "123 456 789", "d.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
}
func TestHostPortString(t *testing.T) {
if os.Getenv("SSH_AUTH_SOCK") != "" {
if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil {
t.Fatalf("exec: %v", err)
}
}
u, err := user.Lookup("drone-scp")
if err != nil {
t.Fatalf("Lookup: %v", err)
}
plugin := Plugin{
Config: Config{
Host: []string{"localhost:22", "localhost:22"},
Username: "drone-scp",
Port: "8080",
KeyPath: "tests/.ssh/id_rsa",
Source: []string{"tests/global/*"},
StripComponents: 2,
Target: []string{filepath.Join(u.HomeDir, "1234")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
},
}
err = plugin.Exec()
assert.Nil(t, err)
// check file exist
if _, err := os.Stat(filepath.Join(u.HomeDir, "1234", "c.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
if _, err := os.Stat(filepath.Join(u.HomeDir, "1234", "d.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
}
// Unit test for hostPort
func TestHostPort(t *testing.T) {
p := Plugin{
Config: Config{
Port: "8080",
},
}
// Test case 1: host string with port
host1 := "example.com:1234"
expectedHost1 := "example.com"
expectedPort1 := "1234"
actualHost1, actualPort1 := p.hostPort(host1)
if actualHost1 != expectedHost1 || actualPort1 != expectedPort1 {
t.Errorf("hostPort(%s) = (%s, %s); expected (%s, %s)", host1, actualHost1, actualPort1, expectedHost1, expectedPort1)
}
// Test case 2: host string without port
host2 := "example.com"
expectedHost2 := "example.com"
expectedPort2 := "8080" // default port
actualHost2, actualPort2 := p.hostPort(host2)
if actualHost2 != expectedHost2 || actualPort2 != expectedPort2 {
t.Errorf("hostPort(%s) = (%s, %s); expected (%s, %s)", host2, actualHost2, actualPort2, expectedHost2, expectedPort2)
}
}
+50
View File
@@ -0,0 +1,50 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAZka7A7i
FscMeJBPyPteclAAAAEAAAAAEAAAIXAAAAB3NzaC1yc2EAAAADAQABAAACAQDz6aZ1jY2o
nnuj2YNHJ/HhfvIu0B973v/+pFFOavnTUOhEEKEy3TASu+s9CkHrYZAtRc+QYIkNZI31mh
HBhotdeP/7GoO2UirkFtrzyQKPNJxEcv0RBoG9ssN8jex0PyK6DHIYYFnIWadVBEEOh/H+
rK7j7u2/big3oTzYBuFrCwmYFcz5na99MzFeAUhazF44gVBma+zO+1quGeqF51UDIg1SMG
vX8I7LNEqrKEBaIUQJKFQcxlOWlRLQsjJCymrOujsXsRrXHAQWcnxDcNevv2ZMOUl0ybvv
9yH0BiGbRBd1Hy8/QPILbAQaqu0oQE7fubN8Q8lqb3Jg0loID4x/5GPhSY8WAXpuLcXTOr
b93SnCw1JsAgJDNqpuuRFy3BSZ7wBOr1jfeIoo7xk14OHiUjJ0uXDL9cLMkcw6ElWz81mr
D2VCkXUz+qFyjJ+G7aGWRtctZoOzKln4yfNfUmwW8/8ra3QnmrMZ2xW2Ylw3ZhO+tLi7jI
NHYFb54bAdLVPUU1ctIuJns2qkWnjJCxxMiynIqCif20/OU1n8CTJuOWiURmRdmvKOH4PE
3JxC2Qnk/3tV3Cf8hp1CH5VjBZ9AjGj5MDMHXyu34VY2WvYo5QyzfS3ySPoT8kCO0G0xpv
jwCMHOK+G2RP4kqb/KKZguiKdgintBXuskTlJmD7kcMQAAB1CnEMQGwAKZbd3F1DJqwfPf
KWjoUJKbTRiav6h5pQr65JaqDe/7YE2ZHYo5917AC2vPLwPxAnoHFMsbObd5mWcmpATg/0
K/qkN5Z4Ml5U3bwr51wfSPh1MiAP21Aickt09BDstIJzNNwwgcY31O3k/d6VBjqyM6Ezop
66LI4s/IIni1BI+cALyEfzE4Qu16GfzIeM+JVxildP4VImhvNBESmmbBL8rNmSzlQ+FTuF
JVmowUbcon1O0CppM1MRVPeG805XDwjxHXKwOp5O7MdTz7H8JeORoe8D6+4rNfJE0eQGY7
Nm4+Wa97HzAFbT9IS433rxoGx9Qps3LAySFONso2JWSOEfo8rxnqO04DrfVHQhY3DkkwQt
FsDnMtkthJa+ZzUYc75fnS0DBPGuF9DZUCqrev5oAUHP6C4Vc4b33JJQD4FZJ+ehk3Xsci
cwJQsmgLyc5Jdh543Dm7kZoM9ku7HDNrB4H/1p45Vo6aBZMAY50x+fTdBeTgCzzhzzTbf+
0IF8W3yW3/BYD+S2Byo3JKp6NH0Q8cgPJrGTl6GltGfpVuc6kLjMZ5zvxRbyWaqtIygM46
W1izbA+9jwbHhitCtOk42e/ff6iEB1MVC13LqPty3gPNR8Pv0rDUDjJS4KiVwXqUY+bMr0
C8l/hx93euHjLUJ49Ru6uy/2fBlHZEj6GmEAJhu/i6t2c1Rq0HBLis9X356oQT+YZnIai2
ym0MknPxjeYBAItOV3zhRd1cYnk7CDcl1XALcnh0tqP712x24IJ+Ytqg7nvB2NZV8T469I
8Fp254Nr89HOMAXaZD0UcIPm7D2rfWV+YJFI3ZcJ/8DM99H3tpXe2j4oHMdmAbBd++09sx
KBRdFLcvnBfd1lqwxpA7hbxzrxi/yehYCqzh5KQGaf2UXej6TPiVzBWVYbp34cMZtsT6mF
K8SS3l5TXoNK2DNEk30o8K3q+vngQpfC9GZ/id4B7LS/3ybellxemZHXQoU4PxDkLKt7jd
AAsd5WO13dv3n/qgyu8iBRiFU+W66NX0RJGkp+lZMnta0YzukafM2n6GDn/r/Cx/y21PAi
ah8i41ByI1QLI4m1r+bRHdUxAarS/XJw4tTSFiZu3zddMYrlzeG9O3VUX9zBvBtfQbSmeJ
omml0zlr/qD7TMsORiujy7XIn7sMW+Ls/NA8TvX8oRnACjXe/MYNEZ8WDu2rkZuY/Dfc+o
NyYWO7kZ3kcejQZ1NusJSA7MG0FFGYSIaC9T9CWqYd5IcRSJW4dZnCt9z8CIJ6TSUFqMb/
H1Y5Rmi0IIX+8qbGGXVBDIBk5y9xtS43+nz1nsdXwDmkTiXN9+ZX+GDsLxCWoHGryrWDbk
EuOAlqpvxFKzEkNsx+AC5wae6i/hBeiEce9bm4nZp+hFv1ic1Z9WS8B37YOFgJ4utGeOjB
6hnywUUJ3aH0LnCQNB3UzeFR7BmEaxmYD/phJodmjA5SD3CWpeizdXfrUjtqXGhYlr2jzq
vBAeeYEO4uaHIGxg8GqoqtaseqVcIdtouHxrVAxxXkjShV2ji7oJ/AtrLZNlkKYxMk0TpX
fFiKqL/uKfS78FfvVOhOkHZTD6ZeMgmdL/uOghEAtrf08ChyRvdp7QLjA802aio9eUVIQm
lHb1ltPEbIZNuvQ5kTIwk2eM6EAkOh0MBMoAYOxOpIb00XHNRDGJYuLewByjMQa8EoT6VM
NoiFIzJU9lLAXE6yz6JswctpTpLHK9Aq5vY7ObaOvrmpCQqsXfOuVUo2nR/FyEes97zuXG
E4aKaHK4IAW4UY/oGYk7pU/yRpudhiNRMXzmcQXfVmBEHuvDrh2chg8lDYn++07F7RWqkI
nfMAOWR8UEl4xp4zJtThDjRxNW6QLl8E1ADjndA9wVaKNSzv2i1TLXKBr5luFqY9MSJ2rm
yBR5EwairH/Qn9TUxaDD+0p6J+E9iz1l8UPTJa/cjtwiySljahY/6tHHnr9YQVnox92yfU
UXpfINGjYrpqh6EFwmyRw9fryIMvMhgZYo6ZoCRBCK2GfGAB0VTzJy2FGs4GecZK5ptXKu
sOX8BgGX/Q/nAJ7PWf9hgYlX2YyjmLjQZDMWECp05VFx9znEETNKlwF1FX5/E/37ISyz4d
I1LVSKOEccJX7jCR32LzvRW1UBX47Z+q3LVE4sa0QAV/JoISq6Qn6zAsVIV0yEPmVbd/xx
aX2uBUGHhmd99YJDh81xJIoYEMRzoGVfp0JjfYcDUc+2I6JdrOMF9/KmMA5wsZl4OKiu/F
cTRGjUkgw/cF2EFRGWknee2esYRB7tOr4y56qZ4gxqw8q9rYXhyB42jbdTvt5xcCm/ynid
sn4InokRRoIiMIPL5Ur7FZQHOP+915MWUBsrTJtkCWQuqJheYUi3mCzh/7NadAKplRpaKb
rS/DJIOOkjnGni/sDxJzPq7STDBVy4WStwQl6NI5hq+/c+JvN9GI4Vu/kz0z8qUcdShLaH
l4njcaMpg4tpQMHtCBOicGyV0=
-----END OPENSSH PRIVATE KEY-----
+1
View File
@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDz6aZ1jY2onnuj2YNHJ/HhfvIu0B973v/+pFFOavnTUOhEEKEy3TASu+s9CkHrYZAtRc+QYIkNZI31mhHBhotdeP/7GoO2UirkFtrzyQKPNJxEcv0RBoG9ssN8jex0PyK6DHIYYFnIWadVBEEOh/H+rK7j7u2/big3oTzYBuFrCwmYFcz5na99MzFeAUhazF44gVBma+zO+1quGeqF51UDIg1SMGvX8I7LNEqrKEBaIUQJKFQcxlOWlRLQsjJCymrOujsXsRrXHAQWcnxDcNevv2ZMOUl0ybvv9yH0BiGbRBd1Hy8/QPILbAQaqu0oQE7fubN8Q8lqb3Jg0loID4x/5GPhSY8WAXpuLcXTOrb93SnCw1JsAgJDNqpuuRFy3BSZ7wBOr1jfeIoo7xk14OHiUjJ0uXDL9cLMkcw6ElWz81mrD2VCkXUz+qFyjJ+G7aGWRtctZoOzKln4yfNfUmwW8/8ra3QnmrMZ2xW2Ylw3ZhO+tLi7jINHYFb54bAdLVPUU1ctIuJns2qkWnjJCxxMiynIqCif20/OU1n8CTJuOWiURmRdmvKOH4PE3JxC2Qnk/3tV3Cf8hp1CH5VjBZ9AjGj5MDMHXyu34VY2WvYo5QyzfS3ySPoT8kCO0G0xpvjwCMHOK+G2RP4kqb/KKZguiKdgintBXuskTlJmD7kcMQ== deploy@easyssh