Compare commits

...

106 Commits

Author SHA1 Message Date
appleboy 2a9a5789cc ci(docker): improve CI workflow and API integration
- Downgrade docker/login-action from v4 to v3 in GitHub workflow

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-10-28 21:48:53 +08:00
appleboy 38fe651776 style(lint): improve error handling and testing robustness
- Fix formatting issue in error message by using a formatted string with `fmt.Errorf`

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-10-28 21:47:09 +08:00
appleboy 2679e1a33b build(goreleaser): refactor codebase for improved performance and maintainability
- Change goreleaser argument from `--rm-dist` to `--clean`

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-10-28 21:02:41 +08:00
appleboy 12827c56e5 refactor(makefile): simplify and clean up Makefile for streamlined builds
- Remove redundant `DIST` variable declaration
- Update `GOFMT` command to include `-s` and `-w` flags
- Remove `SHASUM` variable declaration
- Remove `XGO_PACKAGE` and `XGO_VERSION` variable declarations
- Remove `GXZ_PAGAGE` variable declaration
- Remove architecture-specific variables (`LINUX_ARCHS`, `DARWIN_ARCHS`, `WINDOWS_ARCHS`)
- Remove `.PHONY` targets and associated rules for `deps-backend`, `release`, `release-windows`, `release-linux`, `release-darwin`, `release-copy`, `release-check`, and `release-compress`
- Simplify the `Makefile` by removing complex release-related commands and dependencies

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-10-28 21:01:40 +08:00
appleboy 9f8137bea7 chore(deps): update dependencies to latest versions
- Update `github.com/appleboy/com` to v0.2.0
- Update `github.com/fatih/color` to v1.18.0
- Update `github.com/urfave/cli/v2` to v2.27.5
- Update `golang.org/x/crypto` to v0.28.0
- Update `github.com/cpuguy83/go-md2man/v2` to v2.0.5
- Update `golang.org/x/sys` to v0.26.0

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-10-28 20:48:54 +08:00
Bo-Yi Wu 2decbc4a77 feat: refactor protocol configuration handling in main and plugin
- Add protocol configuration to the `run` function in `main.go`
- Remove redundant protocol configuration from the `run` function in `main.go`
- Add proxy protocol configuration to the `run` function in `main.go`
- Add protocol configuration to the `removeAllDestFile` function in `plugin.go`
- Add proxy protocol configuration to the `removeAllDestFile` function in `plugin.go`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-07-19 07:50:09 +08:00
Bo-Yi Wu 7468610684 chore: standardize code style and enhance changelog configuration
- Change single quotes to double quotes for `name_template`
- Add changelog configuration with GitHub integration
- Define changelog groups for Features, Bug fixes, Enhancements, Refactor, Build process updates, Documentation updates, and Others

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-07-19 07:46:51 +08:00
Xiaotong Liu 79beba5443 fix(parameter): missing protocol argument (#193)
* fix host split

* rm .idea
2024-07-19 07:43:10 +08:00
Bo-Yi Wu 716cc7189b ci: downgrade GitHub workflow dependencies
- Downgrade docker/login-action from v4 to v3 in GitHub workflow

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-07-14 22:16:01 +08:00
Bo-Yi Wu 052d6e71bc feat: load environment variables from /run/drone/env file
- Add check for `/run/drone/env` file and load environment variables if it exists

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-07-14 22:10:19 +08:00
Bo-Yi Wu 13819778ab ci: update Go version and improve lint workflow
- Add repository checkout step to lint workflow
- Update Go version in lint workflow to use `go.mod` file and check latest version
- Change container image in lint workflow from `golang:1.21-alpine` to `golang:1.22-alpine`
- Update Go version in `go.mod` from `1.18` to `1.22`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-07-14 22:09:41 +08:00
Bo-Yi Wu e61e2409d3 ci: update Docker actions and remove ARM build step
- Remove `make build_linux_arm` step
- Update `docker/setup-qemu-action` to v3
- Update `docker/setup-buildx-action` to v3
- Update `docker/login-action` to v4
- Update `docker/metadata-action` to v5
- Update `docker/build-push-action` to v6
- Remove `linux/arm` platform from build platforms

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-07-14 22:08:26 +08:00
Bo-Yi Wu 0601816b74 chore: update Golang dependencies to latest versions
- Update `golang.org/x/crypto` from v0.23.0 to v0.25.0
- Update `golang.org/x/sys` from v0.20.0 to v0.22.0

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-07-11 22:28:41 +08:00
Bo-Yi Wu 13c4ec4609 ci: update GitHub Actions to latest versions
- Update `actions/checkout` to version `v4` in `codeql.yml`
- Update `github/codeql-action/init` to version `v3` in `codeql.yml`
- Update `github/codeql-action/analyze` to version `v3` in `codeql.yml`
- Update `actions/checkout` to version `v4` in `goreleaser.yml`
- Update `goreleaser/goreleaser-action` to version `v6` in `goreleaser.yml`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-07-11 22:27:50 +08:00
Bo-Yi Wu 87c72235a8 test: enhance SCP plugin with folder ignore and error handling (#192)
- Add `TestIgnoreFolder` function to test ignoring specific folders during SCP
- Initialize and terminate `ssh-agent` if `SSH_AUTH_SOCK` is set
- Lookup user `drone-scp` and handle potential errors
- Configure `Plugin` with specific settings for SCP operation
- Execute `plugin.Exec()` and assert no errors
- Verify that certain files do not exist in the target directory after SCP operation

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-06-01 12:33:11 +08:00
Bo-Yi Wu fe4a745be0 feat: enhance plugin networking capabilities support IPV6 (#191)
* feat: enhance plugin networking capabilities

- Enable SSH server to listen on all interfaces by uncommenting relevant lines in `sshd_config`
- Add new `protocol` and `proxy.protocol` flags to `main.go` with usage information and default values
- Change the `Port` field type from `string` to `int` in `plugin.go` and `plugin_test.go`
- Refactor variable name from `host` to `h` and add `port` variable in `plugin.go` loop
- Remove commented-out code and refactor `hostPort` function in `plugin.go`
- Add import for `io` package in `plugin_test.go`
- Add new test function `TestPlugin_hostPort` with multiple test cases in `plugin_test.go`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* update

Signed-off-by: appleboy <appleboy.tw@gmail.com>

* update

Signed-off-by: appleboy <appleboy.tw@gmail.com>

* update

Signed-off-by: appleboy <appleboy.tw@gmail.com>

---------

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-06-01 11:40:23 +08:00
appleboy 45ef1287c2 ci: standardize YAML formatting and upgrade GitHub Actions
- Change cron schedule quotes from single to double in codeql.yml
- Update language matrix quotes from single to double in codeql.yml
- Upgrade actions/checkout from v3 to v4 in docker.yml
- Add a blank line after make build_linux_arm64 step in docker.yml
- Change tag pattern quotes from single to double in goreleaser.yml
- Consolidate steps in goreleaser.yml by removing unnecessary line breaks
- Upgrade actions/setup-go from v4 to v5 in goreleaser.yml
- Upgrade golangci-lint-action from v3 to v6 in lint.yml
- Upgrade codecov-action from v3 to v4 in lint.yml

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-06-01 10:51:10 +08:00
appleboy 9a56c98766 style: standardize code style and optimize CI pipeline
- Change single quotes to double quotes for consistency
- Consolidate job steps by removing unnecessary hyphens
- Add caching options for Docker build and push actions

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-06-01 10:50:11 +08:00
appleboy c1ebb32673 chore: update dependencies to latest versions
- Update `github.com/fatih/color` from v1.16.0 to v1.17.0
- Update `github.com/urfave/cli/v2` from v2.27.1 to v2.27.2
- Update `golang.org/x/crypto` from v0.22.0 to v0.23.0
- Update `github.com/xrash/smetrics` from v0.0.0-20240312152122-5f08fbb34913 to v0.0.0-20240521201337-686a1a2994c1
- Update `golang.org/x/sys` from v0.19.0 to v0.20.0

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-06-01 10:12:04 +08:00
Bo-Yi Wu 4a7fa1bdff chore: update dependencies to latest versions
- Update `golang.org/x/crypto` from `v0.18.0` to `v0.22.0`
- Update `github.com/cpuguy83/go-md2man/v2` from `v2.0.3` to `v2.0.4`
- Update `github.com/xrash/smetrics` to a newer commit
- Update `golang.org/x/sys` from `v0.16.0` to `v0.19.0`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-04-17 12:11:47 +08:00
appleboy 6bb71c761c chore: update dependencies in go.mod file
- Update the version of `golang.org/x/crypto` from `v0.17.0` to `v0.18.0` in the `go.mod` file
- Update the version of `golang.org/x/sys` from `v0.15.0` to `v0.16.0` in the `go.mod` file

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-01-11 20:52:49 +08:00
Bo-Yi Wu bb91fba471 chore: update external dependencies versions
- Update the version of `github.com/appleboy/easyssh-proxy` from `v1.4.0` to `v1.5.0`
- Update the version of `github.com/urfave/cli/v2` from `v2.26.0` to `v2.27.1`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-01-01 10:38:36 +08:00
Bo-Yi Wu 86f19b9c1c chore: update dependencies to latest versions
- Update `easyssh-proxy` dependency from `v1.3.10` to `v1.4.0`
- Update `color` library from `v1.15.0` to `v1.16.0`
- Upgrade `urfave/cli` module from `v2.25.5` to `v2.26.0`
- Bump `x/crypto` version from `v0.9.0` to `v0.17.0`
- Increment `go-md2man` indirect dependency from `v2.0.2` to `v2.0.3`
- Update `go-isatty` indirect dependency from `v0.0.19` to `v0.0.20`
- Update `smetrics` indirect dependency to a newer commit
- Upgrade `x/sys` indirect dependency from `v0.8.0` to `v0.15.0`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-12-26 13:46:27 +08:00
appleboy 691ddecf48 chore: update Go version and base images
- Update the `go-version` to `^1` in the `.github/workflows/lint.yml` file
- Change the container in the `.github/workflows/lint.yml` file from `golang:1.20-alpine` to `golang:1.21-alpine`
- Update the base image in the `docker/Dockerfile` file from `alpine:3.19` to `alpine:3.17`

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2023-12-24 20:18:12 +08:00
appleboy a9c0fd3bbd chore: refactor Dockerfile directory creation and ownership commands
- Change the directory creation and ownership commands in the Dockerfile

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2023-12-24 20:11:08 +08:00
appleboy 7df424cbf1 chore: update Dockerfile and add .hadolint.yaml
- Add a new file `.hadolint.yaml`
- Ignore the `DL3018` and `DL3008` rules in `.hadolint.yaml`
- Update the base image in `docker/Dockerfile` from `alpine:3.17` to `alpine:3.19`
- Remove the labels `org.label-schema.name`, `org.label-schema.vendor`, and `org.label-schema.schema-version` in `docker/Dockerfile`
- Update the package installation command in `docker/Dockerfile` to remove the specific version of `ca-certificates`
- Add a new user and group `deploy` with UID and GID `1000` in `docker/Dockerfile`
- Create a directory `/home/deploy` and change its ownership to `deploy:deploy` in `docker/Dockerfile`
- Set the user and group to `deploy:deploy` with UID and GID `1000` in `docker/Dockerfile`
- Copy the `drone-scp` binary to `/bin/` in `docker/Dockerfile`

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2023-12-24 20:09:36 +08:00
appleboy e5bd02fd8e chore: update build process to output executables to bin directory
- Add `bin` to the `.gitignore` file
- Change the build command in the `Makefile` to output the executable to the `bin` directory

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2023-12-24 20:05:24 +08:00
Bo-Yi Wu 7e0d4951b9 ci: update GitHub action workflows to use setup-go v5
- Update the `setup-go` action from version 4 to version 5 in the Docker, Goreleaser, and Lint workflows.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-12-12 20:44:18 +08:00
Bo-Yi Wu ac6c465050 chore: update github.com/stretchr/testify 2023-05-30 23:30:11 +08:00
Bo-Yi Wu 754c91fc38 chore: upgrade dependency 2023-05-30 23:29:24 +08:00
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
32 changed files with 1391 additions and 1256 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',
]),
]
-365
View File
@@ -1,365 +0,0 @@
---
kind: pipeline
name: testing
platform:
os: linux
arch: amd64
steps:
- name: vet
pull: always
image: golang:1.14
commands:
- make vet
volumes:
- name: gopath
path: /go
- name: lint
pull: always
image: golang:1.14
commands:
- make lint
volumes:
- name: gopath
path: /go
- name: misspell
pull: always
image: golang:1.14
commands:
- make misspell-check
volumes:
- name: gopath
path: /go
- name: test
pull: always
image: golang:1.14-alpine
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
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.14
commands:
- "go build -v -ldflags '-X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/amd64/drone-scp"
environment:
CGO_ENABLED: 0
when:
event:
exclude:
- tag
- name: build-tag
pull: always
image: golang:1.14
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
when:
event:
- tag
- name: executable
pull: always
image: golang:1.14
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.14
commands:
- "go build -v -ldflags '-X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/arm64/drone-scp"
environment:
CGO_ENABLED: 0
when:
event:
exclude:
- tag
- name: build-tag
pull: always
image: golang:1.14
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
when:
event:
- tag
- name: executable
pull: always
image: golang:1.14
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.14
commands:
- "go build -v -ldflags '-X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/arm/drone-scp"
environment:
CGO_ENABLED: 0
when:
event:
exclude:
- tag
- name: build-tag
pull: always
image: golang:1.14
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
when:
event:
- tag
- name: executable
pull: always
image: golang:1.14
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.14
commands:
- make release
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
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@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
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@v3
+73
View File
@@ -0,0 +1,73 @@
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@v5
with:
go-version: "^1"
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build binary
run: |
make build_linux_amd64
make build_linux_arm64
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker meta
id: docker-meta
uses: docker/metadata-action@v5
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@v6
with:
context: .
platforms: linux/amd64,linux/arm64
file: docker/Dockerfile
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.docker-meta.outputs.tags }}
labels: ${{ steps.docker-meta.outputs.labels }}
cache-from: type=registry,ref=ghcr.io/${{ github.repository }}:buildcache
cache-to: type=registry,ref=ghcr.io/${{ github.repository }}:buildcache,mode=max
+32
View File
@@ -0,0 +1,32 @@
name: Goreleaser
on:
push:
tags:
- "*"
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup go
uses: actions/setup-go@v5
with:
go-version: "^1"
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
# either 'goreleaser' (default) or 'goreleaser-pro'
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+48
View File
@@ -0,0 +1,48 @@
name: Lint and Testing
on:
push:
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
check-latest: true
- name: Setup golangci-lint
uses: golangci/golangci-lint-action@v6
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.22-alpine
steps:
- name: Checkout repository
uses: actions/checkout@v4
- 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@v4
+2
View File
@@ -28,3 +28,5 @@ coverage.txt
dist dist
.cover .cover
release release
bin
.idea
+123
View File
@@ -0,0 +1,123 @@
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
changelog:
use: github
groups:
- title: Features
regexp: "^.*feat[(\\w)]*:+.*$"
order: 0
- title: "Bug fixes"
regexp: "^.*fix[(\\w)]*:+.*$"
order: 1
- title: "Enhancements"
regexp: "^.*chore[(\\w)]*:+.*$"
order: 2
- title: "Refactor"
regexp: "^.*refactor[(\\w)]*:+.*$"
order: 3
- title: "Build process updates"
regexp: ^.*?(build|ci)(\(.+\))??!?:.+$
order: 4
- title: "Documentation updates"
regexp: ^.*?docs?(\(.+\))??!?:.+$
order: 4
- title: Others
order: 999
+3
View File
@@ -0,0 +1,3 @@
ignored:
- DL3018
- DL3008
-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]
+6
View File
@@ -207,6 +207,9 @@ key
passphrase passphrase
: The purpose of the passphrase is usually to encrypt the private key. : 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 target
: folder path of target host : folder path of target host
@@ -255,6 +258,9 @@ proxy_key_path
proxy_passphrase proxy_passphrase
: The purpose of the passphrase is usually to encrypt the private key. : 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 ## Template Reference
repo.owner repo.owner
+45 -71
View File
@@ -1,17 +1,8 @@
DIST := dist
EXECUTABLE := drone-scp EXECUTABLE := drone-scp
GOFMT ?= gofmt "-s" GOFMT ?= gofumpt -l -s -w
GO ?= go GO ?= go
GOFILES := $(shell find . -name "*.go" -type f)
# for dockerhub HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
DEPLOY_ACCOUNT := appleboy
DEPLOY_IMAGE := $(EXECUTABLE)
TARGETS ?= linux darwin windows
ARCHS ?= amd64 386
SOURCES ?= $(shell find . -name "*.go" -type f)
TAGS ?=
LDFLAGS ?= -X 'main.Version=$(VERSION)'
ifneq ($(shell uname), Darwin) ifneq ($(shell uname), Darwin)
EXTLDFLAGS = -extldflags "-static" $(null) EXTLDFLAGS = -extldflags "-static" $(null)
@@ -19,76 +10,67 @@ else
EXTLDFLAGS = EXTLDFLAGS =
endif 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),) ifneq ($(DRONE_TAG),)
VERSION ?= $(DRONE_TAG) VERSION ?= $(DRONE_TAG)
else else
VERSION ?= $(shell git describe --tags --always || git rev-parse --short HEAD) VERSION ?= $(shell git describe --tags --always || git rev-parse --short HEAD)
endif endif
TAGS ?=
LDFLAGS ?= -X 'main.Version=$(VERSION)'
all: build all: build
fmt: fmt:
$(GOFMT) -w $(SOURCES) @hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install mvdan.cc/gofumpt; \
fi
$(GOFMT) -w $(GOFILES)
vet: vet:
$(GO) vet ./... $(GO) vet ./...
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)
.PHONY: fmt-check .PHONY: fmt-check
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 \ if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \ echo "Please run 'make fmt' and commit the result:"; \
echo "$${diff}"; \ echo "$${diff}"; \
exit 1; \ exit 1; \
fi; fi;
test: fmt-check test:
@$(GO) test -v -cover -coverprofile coverage.txt ./... && echo "\n==>\033[32m Ok\033[m\n" || exit 1 @$(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)' $(GO) install -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)'
build: $(EXECUTABLE) build: $(EXECUTABLE)
$(EXECUTABLE): $(SOURCES) $(EXECUTABLE): $(GOFILES)
$(GO) build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o $@ $(GO) build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o bin/$@
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)" -arch="$(ARCHS)" -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: 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) CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GO) build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/amd64/$(DEPLOY_IMAGE)
@@ -102,32 +84,21 @@ build_linux_arm64:
build_linux_arm: 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) 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: 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 echo drone-scp:1234 | chpasswd
mkdir -p /home/drone-scp/.ssh mkdir -p /home/drone-scp/.ssh
chmod 700 /home/drone-scp/.ssh chmod 700 /home/drone-scp/.ssh
cat 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 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 chown -R drone-scp /home/drone-scp/.ssh
# install ssh and start server
apk add --update openssh openrc apk add --update openssh openrc
rm -rf /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_dsa_key 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 sed -i 's/AllowTcpForwarding no/AllowTcpForwarding yes/g' /etc/ssh/sshd_config
sed -i 's/^#ListenAddress 0.0.0.0/ListenAddress 0.0.0.0/g' /etc/ssh/sshd_config
sed -i 's/^#ListenAddress ::/ListenAddress ::/g' /etc/ssh/sshd_config
./tests/entrypoint.sh /usr/sbin/sshd -D & ./tests/entrypoint.sh /usr/sbin/sshd -D &
coverage: coverage:
@@ -136,3 +107,6 @@ coverage:
clean: clean:
$(GO) clean -x -i ./... $(GO) clean -x -i ./...
rm -rf coverage.txt $(EXECUTABLE) $(DIST) rm -rf coverage.txt $(EXECUTABLE) $(DIST)
version:
@echo $(VERSION)
+1 -2
View File
@@ -1,11 +1,10 @@
# drone-scp # drone-scp
[![GoDoc](https://godoc.org/github.com/appleboy/drone-scp?status.svg)](https://godoc.org/github.com/appleboy/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) [![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) [![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) [![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/) [![Docker Pulls](https://img.shields.io/docker/pulls/appleboy/drone-scp.svg)](https://hub.docker.com/r/appleboy/drone-scp/)
[![micro badger](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")
Copy files and artifacts via SSH using a binary, docker or [Drone CI](http://docs.drone.io/). Copy files and artifacts via SSH using a binary, docker or [Drone CI](http://docs.drone.io/).
+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)
}
}
+34
View File
@@ -0,0 +1,34 @@
FROM alpine:3.17
ARG TARGETOS
ARG TARGETARCH
LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>"
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 && \
rm -rf /var/cache/apk/*
RUN addgroup \
-S -g 1000 \
deploy && \
adduser \
-S -H -D \
-h /home/deploy \
-s /bin/sh \
-u 1000 \
-G deploy \
deploy
RUN mkdir -p /home/deploy && \
chown deploy:deploy /home/deploy
# deploy:deploy
USER 1000:1000
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 -7
View File
@@ -1,12 +1,27 @@
module github.com/appleboy/drone-scp module github.com/appleboy/drone-scp
go 1.13 go 1.22
require ( require (
github.com/appleboy/com v0.0.2 github.com/appleboy/com v0.2.0
github.com/appleboy/easyssh-proxy v1.3.0 github.com/appleboy/easyssh-proxy v1.5.0
github.com/fatih/color v1.9.0 github.com/fatih/color v1.18.0
github.com/joho/godotenv v1.3.0 github.com/joho/godotenv v1.5.1
github.com/stretchr/testify v1.4.0 github.com/stretchr/testify v1.8.4
github.com/urfave/cli/v2 v2.1.1 github.com/urfave/cli/v2 v2.27.5
golang.org/x/crypto v0.28.0
)
require (
github.com/ScaleFT/sshkeys v1.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.5 // 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.20 // 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-20240521201337-686a1a2994c1 // indirect
golang.org/x/sys v0.26.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )
+40 -34
View File
@@ -1,48 +1,54 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/ScaleFT/sshkeys v1.2.0 h1:5BRp6rTVIhJzXT3VcUQrKgXR8zWA3sOsNeuyW15WUA8=
github.com/ScaleFT/sshkeys v0.0.0-20181112160850-82451a803681 h1:JS2rl38kZmHgWa0xINSaSYH0Whtvem64/4+Ef0+Y5pE= github.com/ScaleFT/sshkeys v1.2.0/go.mod h1:gxOHeajFfvGQh/fxlC8oOKBe23xnnJTif00IFFbiT+o=
github.com/ScaleFT/sshkeys v0.0.0-20181112160850-82451a803681/go.mod h1:WfDateMPQ/55dPbZRp5Zxrux5WiEaHsjk9puUhz0KgY= github.com/appleboy/com v0.2.0 h1:0sggtDLRzh9eP8wATOTvbYzjulufRI+vuLbxJilgyHI=
github.com/appleboy/com v0.0.2 h1:sexcPX7gp7peXMlOJMxEYcRucW7DW0XHgFZqUB6PI6g= github.com/appleboy/com v0.2.0/go.mod h1:xlUTmT+fAy+HeLWdWX/saBEMbmkQzaVAqB1xC70Oys4=
github.com/appleboy/com v0.0.2/go.mod h1:jnufjIC3opMlReyPPPye+8JqNvUzLm25o7h6SOy8nv0= github.com/appleboy/easyssh-proxy v1.5.0 h1:OYdSPvYQN3mhnsMH5I2OF1TgwSEcSq33kvjQfTwvZww=
github.com/appleboy/easyssh-proxy v1.3.0 h1:ToH+hZDPWP9/9E58lwxDLJQSHvgGgDAQ9ZVx6x5oofI= github.com/appleboy/easyssh-proxy v1.5.0/go.mod h1:zcEMrStH91/tcUn3gUGP0KpQwUYLm8tX/Ook1AH98uc=
github.com/appleboy/easyssh-proxy v1.3.0/go.mod h1:Kk57I3w7OCafOjp5kgZFvxk2fO8Tca5CriBTOsbSbjY= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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 h1:saTgr5tMLFnmy/yg3qDTft4rE5DY2uJ/cCxCe3q0XTU=
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a/go.mod h1:Bw9BbhOJVNR+t0jCqx2GC6zv0TGBsShs56Y3gfSCvl0= github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a/go.mod h1:Bw9BbhOJVNR+t0jCqx2GC6zv0TGBsShs56Y3gfSCvl0=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.20/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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k= github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 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-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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/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.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+165 -159
View File
@@ -3,11 +3,11 @@ package main
import ( import (
"log" "log"
"os" "os"
"strconv"
"time" "time"
"github.com/appleboy/easyssh-proxy" "github.com/appleboy/easyssh-proxy"
"github.com/joho/godotenv" "github.com/joho/godotenv"
_ "github.com/joho/godotenv/autoload"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@@ -17,10 +17,19 @@ var (
) )
func main() { func main() {
// Load env-file if it exists first
if filename, found := os.LookupEnv("PLUGIN_ENV_FILE"); found {
_ = godotenv.Load(filename)
}
if _, err := os.Stat("/run/drone/env"); err == nil {
_ = godotenv.Overload("/run/drone/env")
}
app := cli.NewApp() app := cli.NewApp()
app.Name = "Drone SCP" app.Name = "Drone SCP"
app.Usage = "Copy files and artifacts via SSH." app.Usage = "Copy files and artifacts via SSH."
app.Copyright = "Copyright (c) 2019 Bo-Yi Wu" app.Copyright = "Copyright (c) " + strconv.Itoa(time.Now().Year()) + " Bo-Yi Wu"
app.Version = Version app.Version = Version
app.Authors = []*cli.Author{ app.Authors = []*cli.Author{
{ {
@@ -32,167 +41,162 @@ func main() {
app.Version = Version app.Version = Version
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
&cli.StringSliceFlag{ &cli.StringSliceFlag{
Name: "host, H", Name: "host",
Usage: "Server host", Aliases: []string{"H"},
EnvVars: []string{"PLUGIN_HOST", "SCP_HOST", "SSH_HOST", "HOST", "INPUT_HOST"}, Usage: "connect to host",
EnvVars: []string{"PLUGIN_HOST", "SSH_HOST", "INPUT_HOST"},
FilePath: ".host",
},
&cli.IntFlag{
Name: "port",
Aliases: []string{"p"},
Usage: "connect to port",
EnvVars: []string{"PLUGIN_PORT", "SSH_PORT", "INPUT_PORT"},
Value: 22,
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "port, P", Name: "protocol",
Value: "22", Usage: "The IP protocol to use. Valid values are \"tcp\". \"tcp4\" or \"tcp6\". Default to tcp.",
Usage: "Server port, default to 22", EnvVars: []string{"PLUGIN_PROTOCOL", "SSH_PROTOCOL", "INPUT_PROTOCOL"},
EnvVars: []string{"PLUGIN_PORT", "SCP_PORT", "SSH_PORT", "PORT", "INPUT_PORT"}, Value: "tcp",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "username, u", Name: "username",
Usage: "Server username", Aliases: []string{"user", "u"},
EnvVars: []string{"PLUGIN_USERNAME", "PLUGIN_USER", "SCP_USERNAME", "SSH_USERNAME", "USERNAME", "INPUT_USERNAME"}, Usage: "connect as user",
EnvVars: []string{"PLUGIN_USERNAME", "PLUGIN_USER", "SSH_USERNAME", "INPUT_USERNAME"},
Value: "root",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "password, p", Name: "password",
Usage: "Password for password-based authentication", Aliases: []string{"P"},
EnvVars: []string{"PLUGIN_PASSWORD", "SCP_PASSWORD", "SSH_PASSWORD", "PASSWORD", "INPUT_PASSWORD"}, Usage: "user password",
EnvVars: []string{"PLUGIN_PASSWORD", "SSH_PASSWORD", "INPUT_PASSWORD"},
}, },
&cli.DurationFlag{ &cli.DurationFlag{
Name: "timeout", Name: "timeout",
Usage: "connection timeout", Usage: "connection timeout",
EnvVars: []string{"PLUGIN_TIMEOUT", "SCP_TIMEOUT", "INPUT_TIMEOUT"}, EnvVars: []string{"PLUGIN_TIMEOUT", "SSH_TIMEOUT", "INPUT_TIMEOUT"},
Value: 30 * time.Second, Value: 30 * 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: "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",
Aliases: []string{"i"},
Usage: "ssh private key path",
EnvVars: []string{"PLUGIN_KEY_PATH", "SSH_KEY_PATH", "INPUT_KEY_PATH"},
},
&cli.StringSliceFlag{
Name: "ciphers",
Usage: "The allowed cipher algorithms. If unspecified then a sensible",
EnvVars: []string{"PLUGIN_CIPHERS", "SSH_CIPHERS", "INPUT_CIPHERS"},
},
&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.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.DurationFlag{ &cli.DurationFlag{
Name: "command.timeout", Name: "command.timeout",
Usage: "command timeout", Usage: "command timeout",
EnvVars: []string{"PLUGIN_COMMAND_TIMEOUT", "SSH_COMMAND_TIMEOUT", "INPUT_COMMAND_TIMEOUT"}, EnvVars: []string{"PLUGIN_COMMAND_TIMEOUT", "SSH_COMMAND_TIMEOUT", "INPUT_COMMAND_TIMEOUT"},
Value: 10 * time.Minute, Value: 10 * time.Minute,
}, },
&cli.StringFlag{
Name: "ssh-key, k",
Usage: "ssh private key",
EnvVars: []string{"PLUGIN_SSH_KEY,", "PLUGIN_KEY", "SCP_KEY", "SSH_KEY", "KEY", "INPUT_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", "PASSPHRASE", "INPUT_PASSPHRASE"},
},
&cli.StringFlag{
Name: "key-path, i",
Usage: "ssh private key path",
EnvVars: []string{"PLUGIN_KEY_PATH", "SCP_KEY_PATH", "SSH_KEY_PATH", "INPUT_KEY_PATH"},
},
&cli.StringSliceFlag{ &cli.StringSliceFlag{
Name: "target, t", Name: "target",
Aliases: []string{"t"},
Usage: "Target path on the server", Usage: "Target path on the server",
EnvVars: []string{"PLUGIN_TARGET", "SCP_TARGET", "TARGET", "INPUT_TARGET"}, EnvVars: []string{"PLUGIN_TARGET", "SSH_TARGET", "INPUT_TARGET"},
}, },
&cli.StringSliceFlag{ &cli.StringSliceFlag{
Name: "source, s", Name: "source",
Aliases: []string{"s"},
Usage: "scp file list", Usage: "scp file list",
EnvVars: []string{"PLUGIN_SOURCE", "SCP_SOURCE", "SOURCE", "INPUT_SOURCE"}, EnvVars: []string{"PLUGIN_SOURCE", "SCP_SOURCE", "INPUT_SOURCE"},
}, },
&cli.BoolFlag{ &cli.BoolFlag{
Name: "rm, r", Name: "rm",
Aliases: []string{"r"},
Usage: "remove target folder before upload data", Usage: "remove target folder before upload data",
EnvVars: []string{"PLUGIN_RM", "SCP_RM", "RM", "INPUT_RM"}, EnvVars: []string{"PLUGIN_RM", "SCP_RM", "INPUT_RM"},
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "repo.owner", Name: "proxy.host",
Usage: "repository owner", Usage: "connect to host of proxy",
EnvVars: []string{"DRONE_REPO_OWNER"}, EnvVars: []string{"PLUGIN_PROXY_HOST", "PROXY_SSH_HOST", "INPUT_PROXY_HOST"},
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "repo.name", Name: "proxy.port",
Usage: "repository name", Usage: "connect to port of proxy",
EnvVars: []string{"DRONE_REPO_NAME"}, EnvVars: []string{"PLUGIN_PROXY_PORT", "PROXY_SSH_PORT", "INPUT_PROXY_PORT"},
Value: "22",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "commit.sha", Name: "proxy.protocol",
Usage: "git commit sha", Usage: "The IP protocol to use for the proxy. Valid values are \"tcp\". \"tcp4\" or \"tcp6\". Default to tcp.",
EnvVars: []string{"DRONE_COMMIT_SHA"}, EnvVars: []string{"PLUGIN_PROXY_PROTOCOL", "SSH_PROXY_PROTOCOL", "INPUT_PROXY_PROTOCOL"},
}, Value: "tcp",
&cli.StringFlag{
Name: "commit.branch",
Value: "master",
Usage: "git commit branch",
EnvVars: []string{"DRONE_COMMIT_BRANCH"},
},
&cli.StringFlag{
Name: "commit.author",
Usage: "git author name",
EnvVars: []string{"DRONE_COMMIT_AUTHOR"},
},
&cli.StringFlag{
Name: "commit.message",
Usage: "commit message",
EnvVars: []string{"DRONE_COMMIT_MESSAGE"},
},
&cli.StringFlag{
Name: "build.event",
Value: "push",
Usage: "build event",
EnvVars: []string{"DRONE_BUILD_EVENT"},
},
&cli.IntFlag{
Name: "build.number",
Usage: "build number",
EnvVars: []string{"DRONE_BUILD_NUMBER"},
},
&cli.StringFlag{
Name: "build.status",
Usage: "build status",
Value: "success",
EnvVars: []string{"DRONE_BUILD_STATUS"},
},
&cli.StringFlag{
Name: "build.link",
Usage: "build link",
EnvVars: []string{"DRONE_BUILD_LINK"},
},
&cli.StringFlag{
Name: "env-file",
Usage: "source env file",
},
&cli.StringFlag{
Name: "proxy.ssh-key",
Usage: "private ssh key of proxy",
EnvVars: []string{"PLUGIN_PROXY_SSH_KEY", "PLUGIN_PROXY_KEY", "PROXY_SSH_KEY", "PROXY_KEY", "INPUT_PROXY_SSH_KEY"},
},
&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", "PROXY_PASSPHRASE", "INPUT_PROXY_PASSPHRASE"},
},
&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_SSH_KEY_PATH"},
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "proxy.username", Name: "proxy.username",
Usage: "connect as user of proxy", Usage: "connect as user of proxy",
EnvVars: []string{"PLUGIN_PROXY_USERNAME", "PLUGIN_PROXY_USER", "PROXY_SSH_USERNAME", "PROXY_USERNAME", "INPUT_PROXY_USERNAME"}, EnvVars: []string{"PLUGIN_PROXY_USERNAME", "PLUGIN_PROXY_USER", "PROXY_SSH_USERNAME", "INPUT_PROXY_USERNAME"},
Value: "root", Value: "root",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "proxy.password", Name: "proxy.password",
Usage: "user password of proxy", Usage: "user password of proxy",
EnvVars: []string{"PLUGIN_PROXY_PASSWORD", "PROXY_SSH_PASSWORD", "PROXY_PASSWORD", "INPUT_PROXY_PASSWORD"}, EnvVars: []string{"PLUGIN_PROXY_PASSWORD", "PROXY_SSH_PASSWORD", "INPUT_PROXY_PASSWORD"},
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "proxy.host", Name: "proxy.ssh-key",
Usage: "connect to host of proxy", Usage: "private ssh key of proxy",
EnvVars: []string{"PLUGIN_PROXY_HOST", "PROXY_SSH_HOST", "PROXY_HOST", "INPUT_PROXY_HOST"}, EnvVars: []string{"PLUGIN_PROXY_SSH_KEY", "PLUGIN_PROXY_KEY", "PROXY_SSH_KEY", "INPUT_PROXY_KEY"},
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "proxy.port", Name: "proxy.ssh-passphrase",
Usage: "connect to port of proxy", Usage: "The purpose of the passphrase is usually to encrypt the private key.",
EnvVars: []string{"PLUGIN_PROXY_PORT", "PROXY_SSH_PORT", "PROXY_PORT", "INPUT_PROXY_PORT"}, EnvVars: []string{"PLUGIN_PROXY_SSH_PASSPHRASE", "PLUGIN_PROXY_PASSPHRASE", "PROXY_SSH_PASSPHRASE", "INPUT_PROXY_PASSPHRASE"},
Value: "22", },
&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.DurationFlag{ &cli.DurationFlag{
Name: "proxy.timeout", Name: "proxy.timeout",
Usage: "proxy connection timeout", Usage: "proxy connection timeout",
EnvVars: []string{"PLUGIN_PROXY_TIMEOUT", "PROXY_SSH_TIMEOUT", "INPUT_PROXY_TIMEOUT"}, EnvVars: []string{"PLUGIN_PROXY_TIMEOUT", "PROXY_SSH_TIMEOUT", "INPUT_PROXY_TIMEOUT"},
}, },
&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.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.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.IntFlag{ &cli.IntFlag{
Name: "strip.components", Name: "strip.components",
Usage: "Remove the specified number of leading path elements.", Usage: "Remove the specified number of leading path elements.",
@@ -201,23 +205,33 @@ func main() {
&cli.StringFlag{ &cli.StringFlag{
Name: "tar.exec", Name: "tar.exec",
Usage: "Alternative `tar` executable to on the dest host", Usage: "Alternative `tar` executable to on the dest host",
EnvVars: []string{"PLUGIN_TAR_EXEC", "SCP_TAR_EXEC", "INPUT_TAR_EXEC"}, EnvVars: []string{"PLUGIN_TAR_EXEC", "SSH_TAR_EXEC", "INPUT_TAR_EXEC"},
Value: "tar", Value: "tar",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "tar.tmp-path", Name: "tar.tmp-path",
Usage: "Temporary path for tar file on the dest host", Usage: "Temporary path for tar file on the dest host",
EnvVars: []string{"PLUGIN_TAR_TMP_PATH", "SCP_TAR_TMP_PATH"}, EnvVars: []string{"PLUGIN_TAR_TMP_PATH", "SSH_TAR_TMP_PATH", "INPUT_TAR_TMP_PATH"},
}, },
&cli.BoolFlag{ &cli.BoolFlag{
Name: "debug", Name: "debug",
Usage: "remove target folder before upload data", Usage: "remove target folder before upload data",
EnvVars: []string{"PLUGIN_DEBUG", "DEBUG", "INPUT_DEBUG"}, EnvVars: []string{"PLUGIN_DEBUG", "INPUT_DEBUG"},
}, },
&cli.BoolFlag{ &cli.BoolFlag{
Name: "overwrite", Name: "overwrite",
Usage: "use --overwrite flag with tar", Usage: "use --overwrite flag with tar",
EnvVars: []string{"PLUGIN_OVERWRITE", "SCP_OVERWRITE", "INPUT_OVERWRITE"}, EnvVars: []string{"PLUGIN_OVERWRITE", "INPUT_OVERWRITE"},
},
&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"},
}, },
} }
@@ -260,52 +274,44 @@ REPOSITORY:
} }
func run(c *cli.Context) error { func run(c *cli.Context) error {
if c.String("env-file") != "" {
_ = godotenv.Load(c.String("env-file"))
}
plugin := Plugin{ 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{ Config: Config{
Host: c.StringSlice("host"), Host: c.StringSlice("host"),
Port: c.String("port"), Port: c.Int("port"),
Username: c.String("username"), Protocol: easyssh.Protocol(c.String("protocol")),
Password: c.String("password"), Username: c.String("username"),
Passphrase: c.String("ssh-passphrase"), Password: c.String("password"),
Timeout: c.Duration("timeout"), Passphrase: c.String("ssh-passphrase"),
CommandTimeout: c.Duration("command.timeout"), Fingerprint: c.String("fingerprint"),
Key: c.String("ssh-key"), Timeout: c.Duration("timeout"),
KeyPath: c.String("key-path"), CommandTimeout: c.Duration("command.timeout"),
Target: c.StringSlice("target"), Key: c.String("ssh-key"),
Source: c.StringSlice("source"), KeyPath: c.String("key-path"),
Remove: c.Bool("rm"), Target: c.StringSlice("target"),
Debug: c.Bool("debug"), Source: c.StringSlice("source"),
StripComponents: c.Int("strip.components"), Remove: c.Bool("rm"),
TarExec: c.String("tar.exec"), Debug: c.Bool("debug"),
TarTmpPath: c.String("tar.tmp-path"), StripComponents: c.Int("strip.components"),
Overwrite: c.Bool("overwrite"), 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{ Proxy: easyssh.DefaultConfig{
Key: c.String("proxy.ssh-key"), Key: c.String("proxy.ssh-key"),
Passphrase: c.String("proxy.ssh-passphrase"), Passphrase: c.String("proxy.ssh-passphrase"),
KeyPath: c.String("proxy.key-path"), Fingerprint: c.String("proxy.fingerprint"),
User: c.String("proxy.username"), KeyPath: c.String("proxy.key-path"),
Password: c.String("proxy.password"), User: c.String("proxy.username"),
Server: c.String("proxy.host"), Password: c.String("proxy.password"),
Port: c.String("proxy.port"), Server: c.String("proxy.host"),
Timeout: c.Duration("proxy.timeout"), Port: c.String("proxy.port"),
Protocol: easyssh.Protocol(c.String("proxy.protocol")),
Timeout: c.Duration("proxy.timeout"),
Ciphers: c.StringSlice("proxy.ciphers"),
UseInsecureCipher: c.Bool("proxy.useInsecureCipher"),
}, },
}, },
} }
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows // +build !windows
package main package main
+1
View File
@@ -1,3 +1,4 @@
//go:build windows
// +build windows // +build windows
package main package main
-256
View File
@@ -1,256 +0,0 @@
{
test:: {
kind: 'pipeline',
name: 'testing',
platform: {
os: 'linux',
arch: 'amd64',
},
steps: [
{
name: 'vet',
image: 'golang:1.14',
pull: 'always',
commands: [
'make vet',
],
volumes: [
{
name: 'gopath',
path: '/go',
},
],
},
{
name: 'lint',
image: 'golang:1.14',
pull: 'always',
commands: [
'make lint',
],
volumes: [
{
name: 'gopath',
path: '/go',
},
],
},
{
name: 'misspell',
image: 'golang:1.14',
pull: 'always',
commands: [
'make misspell-check',
],
volumes: [
{
name: 'gopath',
path: '/go',
},
],
},
{
name: 'test',
image: 'golang:1.14-alpine',
pull: 'always',
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.14',
pull: 'always',
environment: {
CGO_ENABLED: '0',
},
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.14',
pull: 'always',
environment: {
CGO_ENABLED: '0',
},
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.14',
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.14',
pull: 'always',
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,
},
},
],
depends_on: depends_on,
trigger: {
ref: [
'refs/heads/master',
'refs/tags/**',
],
},
},
signature(key):: {
kind: 'signature',
hmac: key,
}
}
+171 -143
View File
@@ -3,7 +3,6 @@ package main
import ( import (
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@@ -20,55 +19,40 @@ import (
var ( var (
errMissingHost = errors.New("Error: missing server host") errMissingHost = errors.New("Error: missing server host")
errMissingPasswordOrKey = errors.New("Error: can't connect without a private SSH key or password") 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") errMissingSourceOrTarget = errors.New("missing source or target config")
) )
type ( 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 for the plugin.
Config struct { Config struct {
Host []string Host []string
Port string Port int
Username string Protocol easyssh.Protocol
Password string Username string
Key string Password string
Passphrase string Key string
KeyPath string Passphrase string
Timeout time.Duration Fingerprint string
CommandTimeout time.Duration KeyPath string
Target []string Timeout time.Duration
Source []string CommandTimeout time.Duration
Remove bool Target []string
StripComponents int Source []string
TarExec string Remove bool
TarTmpPath string StripComponents int
Proxy easyssh.DefaultConfig TarExec string
Debug bool TarTmpPath string
Overwrite bool Proxy easyssh.DefaultConfig
Debug bool
Overwrite bool
UnlinkFirst bool
Ciphers []string
UseInsecureCipher bool
TarDereference bool
} }
// Plugin values. // Plugin values.
Plugin struct { Plugin struct {
Repo Repo
Build Build
Config Config Config Config
DestFile string DestFile string
} }
@@ -83,27 +67,12 @@ func (e copyError) Error() string {
return fmt.Sprintf("error copy file to dest: %s, error message: %s\n", e.host, e.message) 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 { func globList(paths []string) fileList {
var list fileList var list fileList
for _, pattern := range paths { for _, pattern := range paths {
ignore := false ignore := false
pattern = strings.Trim(pattern, " ") pattern = strings.TrimSpace(pattern)
if string(pattern[0]) == "!" { if string(pattern[0]) == "!" {
pattern = pattern[1:] pattern = pattern[1:]
ignore = true ignore = true
@@ -124,21 +93,6 @@ func globList(paths []string) fileList {
return list 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{}) { func (p Plugin) log(host string, message ...interface{}) {
if count := len(p.Config.Host); count == 1 { if count := len(p.Config.Host); count == 1 {
fmt.Printf("%s", fmt.Sprintln(message...)) fmt.Printf("%s", fmt.Sprintln(message...))
@@ -147,10 +101,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) 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 { if err != nil {
return err return err
} }
@@ -163,30 +116,45 @@ func (p *Plugin) removeDestFile(ssh *easyssh.MakeConfig) error {
} }
func (p *Plugin) removeAllDestFile() error { func (p *Plugin) removeAllDestFile() error {
for _, host := range p.Config.Host { for _, h := range trimValues(p.Config.Host) {
host, port := p.hostPort(h)
ssh := &easyssh.MakeConfig{ ssh := &easyssh.MakeConfig{
Server: host, Server: host,
User: p.Config.Username, User: p.Config.Username,
Password: p.Config.Password, Password: p.Config.Password,
Port: p.Config.Port, Port: port,
Key: p.Config.Key, Protocol: p.Config.Protocol,
KeyPath: p.Config.KeyPath, Key: p.Config.Key,
Passphrase: p.Config.Passphrase, KeyPath: p.Config.KeyPath,
Timeout: p.Config.Timeout, Passphrase: p.Config.Passphrase,
Timeout: p.Config.Timeout,
Ciphers: p.Config.Ciphers,
Fingerprint: p.Config.Fingerprint,
UseInsecureCipher: p.Config.UseInsecureCipher,
Proxy: easyssh.DefaultConfig{ Proxy: easyssh.DefaultConfig{
Server: p.Config.Proxy.Server, Server: p.Config.Proxy.Server,
User: p.Config.Proxy.User, User: p.Config.Proxy.User,
Password: p.Config.Proxy.Password, Password: p.Config.Proxy.Password,
Port: p.Config.Proxy.Port, Port: p.Config.Proxy.Port,
Key: p.Config.Proxy.Key, Protocol: p.Config.Proxy.Protocol,
KeyPath: p.Config.Proxy.KeyPath, Key: p.Config.Proxy.Key,
Passphrase: p.Config.Proxy.Passphrase, KeyPath: p.Config.Proxy.KeyPath,
Timeout: p.Config.Proxy.Timeout, 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 // remove tar file
err := p.removeDestFile(ssh) err = p.removeDestFile(systemType, ssh)
if err != nil { if err != nil {
return err return err
} }
@@ -200,12 +168,33 @@ type fileList struct {
Source []string Source []string
} }
func (p *Plugin) buildArgs(target string) []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 := []string{}
args = append(args, args = append(args,
p.Config.TarExec, p.Config.TarExec,
"-xf", "-zxf",
p.DestFile, p.DestFile,
) )
@@ -218,6 +207,10 @@ func (p *Plugin) buildArgs(target string) []string {
args = append(args, "--overwrite") args = append(args, "--overwrite")
} }
if p.Config.UnlinkFirst {
args = append(args, "--unlink-first")
}
args = append(args, args = append(args,
"-C", "-C",
target, target,
@@ -228,35 +221,30 @@ func (p *Plugin) buildArgs(target string) []string {
// Exec executes the plugin. // Exec executes the plugin.
func (p *Plugin) Exec() error { 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 { if len(p.Config.Key) == 0 && len(p.Config.Password) == 0 && len(p.Config.KeyPath) == 0 {
return errMissingPasswordOrKey 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 { if len(p.Config.Source) == 0 || len(p.Config.Target) == 0 {
return errMissingSourceOrTarget return errMissingSourceOrTarget
} }
files := globList(trimPath(p.Config.Source)) hosts := trimValues(p.Config.Host)
p.DestFile = fmt.Sprintf("%s.tar", random.String(10)) if len(hosts) == 0 {
return errMissingHost
}
p.DestFile = fmt.Sprintf("%s.tar.gz", random.String(10))
// create a temporary file for the archive // create a temporary file for the archive
dir, err := ioutil.TempDir("", "") dir := os.TempDir()
if err != nil { src := filepath.Join(dir, p.DestFile)
return err
}
tar := filepath.Join(dir, p.DestFile)
// show current version
fmt.Println("drone-scp version: " + Version)
// run archive command // run archive command
fmt.Println("tar all files into " + tar) fmt.Println("tar all files into " + src)
args := buildArgs(tar, files) args := p.buildTarArgs(src)
cmd := exec.Command(p.Config.TarExec, args...) cmd := exec.Command(p.Config.TarExec, args...)
if p.Config.Debug { if p.Config.Debug {
fmt.Println("$", strings.Join(cmd.Args, " ")) fmt.Println("$", strings.Join(cmd.Args, " "))
@@ -271,71 +259,84 @@ func (p *Plugin) Exec() error {
wg.Add(len(p.Config.Host)) wg.Add(len(p.Config.Host))
errChannel := make(chan error) errChannel := make(chan error)
finished := make(chan struct{}) finished := make(chan struct{})
for _, host := range p.Config.Host { for _, host := range hosts {
go func(host string) { 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. // Create MakeConfig instance with remote username, server address and path to private key.
ssh := &easyssh.MakeConfig{ ssh := &easyssh.MakeConfig{
Server: host, Server: host,
User: p.Config.Username, User: p.Config.Username,
Password: p.Config.Password, Password: p.Config.Password,
Port: p.Config.Port, Port: port,
Key: p.Config.Key, Key: p.Config.Key,
KeyPath: p.Config.KeyPath, KeyPath: p.Config.KeyPath,
Passphrase: p.Config.Passphrase, Passphrase: p.Config.Passphrase,
Timeout: p.Config.Timeout, Timeout: p.Config.Timeout,
Ciphers: p.Config.Ciphers,
Fingerprint: p.Config.Fingerprint,
UseInsecureCipher: p.Config.UseInsecureCipher,
Proxy: easyssh.DefaultConfig{ Proxy: easyssh.DefaultConfig{
Server: p.Config.Proxy.Server, Server: p.Config.Proxy.Server,
User: p.Config.Proxy.User, User: p.Config.Proxy.User,
Password: p.Config.Proxy.Password, Password: p.Config.Proxy.Password,
Port: p.Config.Proxy.Port, Port: p.Config.Proxy.Port,
Key: p.Config.Proxy.Key, Key: p.Config.Proxy.Key,
KeyPath: p.Config.Proxy.KeyPath, KeyPath: p.Config.Proxy.KeyPath,
Passphrase: p.Config.Proxy.Passphrase, Passphrase: p.Config.Proxy.Passphrase,
Timeout: p.Config.Proxy.Timeout, 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 // upload file to the tmp path
p.DestFile = fmt.Sprintf("%s%s", p.Config.TarTmpPath, p.DestFile) 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. // Call Scp method with file you want to upload to remote server.
p.log(host, "scp file to server.") p.log(host, "scp file to server.")
err := ssh.Scp(tar, p.DestFile) err = ssh.Scp(src, p.DestFile)
if err != nil { if err != nil {
errChannel <- copyError{host, err.Error()} errChannel <- copyError{host, err.Error()}
return return
} }
for _, target := range p.Config.Target { 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 { if p.Config.Remove {
p.log(host, "Remove target folder:", target) 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 { if err != nil {
errChannel <- err errChannel <- err
return return
} }
} }
// mkdir path
p.log(host, "create folder", target) 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 { if err != nil {
errChannel <- err errChannel <- err
return return
} }
if len(errStr) != 0 { if len(errStr) != 0 {
errChannel <- fmt.Errorf(errStr) errChannel <- fmt.Errorf("%s", errStr)
return return
} }
// untar file // untar file
p.log(host, "untar file", p.DestFile) p.log(host, "untar file", p.DestFile)
commamd := strings.Join(p.buildArgs(target), " ") commamd := strings.Join(p.buildUnTarArgs(target), " ")
if p.Config.Debug { if p.Config.Debug {
fmt.Println("$", commamd) fmt.Println("$", commamd)
} }
@@ -356,14 +357,11 @@ func (p *Plugin) Exec() error {
} }
// remove tar file // remove tar file
err = p.removeDestFile(ssh) err = p.removeDestFile(systemType, ssh)
if err != nil { if err != nil {
errChannel <- err errChannel <- err
return return
} }
wg.Done()
}(host) }(host)
} }
@@ -380,7 +378,9 @@ func (p *Plugin) Exec() error {
c.Println("drone-scp error: ", err) c.Println("drone-scp error: ", err)
if _, ok := err.(copyError); !ok { if _, ok := err.(copyError); !ok {
fmt.Println("drone-scp rollback: remove all target tmp file") fmt.Println("drone-scp rollback: remove all target tmp file")
p.removeAllDestFile() if err := p.removeAllDestFile(); err != nil {
return err
}
} }
return err return err
} }
@@ -392,3 +392,31 @@ func (p *Plugin) Exec() error {
return nil return nil
} }
func (p Plugin) hostPort(host string) (string, string) {
hosts := strings.Split(host, ":")
port := strconv.Itoa(p.Config.Port)
if len(hosts) > 1 &&
(p.Config.Protocol == easyssh.PROTOCOL_TCP ||
p.Config.Protocol == easyssh.PROTOCOL_TCP4) {
host = hosts[0]
port = hosts[1]
}
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
}
+476 -65
View File
@@ -1,6 +1,8 @@
package main package main
import ( import (
"io"
"log"
"os" "os"
"os/exec" "os/exec"
"os/user" "os/user"
@@ -11,6 +13,7 @@ import (
"github.com/appleboy/easyssh-proxy" "github.com/appleboy/easyssh-proxy"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"golang.org/x/crypto/ssh"
) )
func TestMissingAllConfig(t *testing.T) { func TestMissingAllConfig(t *testing.T) {
@@ -39,7 +42,7 @@ func TestMissingSourceConfig(t *testing.T) {
Config: Config{ Config: Config{
Host: []string{"example.com"}, Host: []string{"example.com"},
Username: "ubuntu", Username: "ubuntu",
Port: "443", Port: 443,
Password: "1234", Password: "1234",
}, },
} }
@@ -49,35 +52,18 @@ func TestMissingSourceConfig(t *testing.T) {
assert.NotNil(t, err) 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) { func TestTrimElement(t *testing.T) {
var input, result []string var input, result []string
input = []string{"1", " ", "3"} input = []string{"1", " ", "3"}
result = []string{"1", "3"} result = []string{"1", "3"}
assert.Equal(t, result, trimPath(input)) assert.Equal(t, result, trimValues(input))
input = []string{"1", "2"} input = []string{"1", "2"}
result = []string{"1", "2"} result = []string{"1", "2"}
assert.Equal(t, result, trimPath(input)) assert.Equal(t, result, trimValues(input))
} }
func TestSCPFileFromPublicKey(t *testing.T) { func TestSCPFileFromPublicKey(t *testing.T) {
@@ -96,7 +82,7 @@ func TestSCPFileFromPublicKey(t *testing.T) {
Config: Config{ Config: Config{
Host: []string{"localhost"}, Host: []string{"localhost"},
Username: "drone-scp", Username: "drone-scp",
Port: "22", Port: 22,
KeyPath: "tests/.ssh/id_rsa", KeyPath: "tests/.ssh/id_rsa",
Source: []string{"tests/a.txt", "tests/b.txt"}, Source: []string{"tests/a.txt", "tests/b.txt"},
Target: []string{filepath.Join(u.HomeDir, "/test")}, Target: []string{filepath.Join(u.HomeDir, "/test")},
@@ -146,7 +132,7 @@ func TestSCPFileFromPublicKeyWithPassphrase(t *testing.T) {
Config: Config{ Config: Config{
Host: []string{"localhost"}, Host: []string{"localhost"},
Username: "drone-scp", Username: "drone-scp",
Port: "22", Port: 22,
KeyPath: "tests/.ssh/test", KeyPath: "tests/.ssh/test",
Passphrase: "1234", Passphrase: "1234",
Source: []string{"tests/a.txt", "tests/b.txt"}, Source: []string{"tests/a.txt", "tests/b.txt"},
@@ -169,6 +155,89 @@ func TestSCPFileFromPublicKeyWithPassphrase(t *testing.T) {
} }
} }
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) { func TestSCPWildcardFileList(t *testing.T) {
if os.Getenv("SSH_AUTH_SOCK") != "" { if os.Getenv("SSH_AUTH_SOCK") != "" {
if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil { if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil {
@@ -185,7 +254,7 @@ func TestSCPWildcardFileList(t *testing.T) {
Config: Config{ Config: Config{
Host: []string{"localhost"}, Host: []string{"localhost"},
Username: "drone-scp", Username: "drone-scp",
Port: "22", Port: 22,
KeyPath: "tests/.ssh/id_rsa", KeyPath: "tests/.ssh/id_rsa",
Source: []string{"tests/global/*"}, Source: []string{"tests/global/*"},
Target: []string{filepath.Join(u.HomeDir, "abc")}, Target: []string{filepath.Join(u.HomeDir, "abc")},
@@ -217,7 +286,7 @@ func TestSCPFromProxySetting(t *testing.T) {
Config: Config{ Config: Config{
Host: []string{"localhost"}, Host: []string{"localhost"},
Username: "drone-scp", Username: "drone-scp",
Port: "22", Port: 22,
KeyPath: "tests/.ssh/id_rsa", KeyPath: "tests/.ssh/id_rsa",
Source: []string{"tests/global/*"}, Source: []string{"tests/global/*"},
Target: []string{filepath.Join(u.HomeDir, "def")}, Target: []string{filepath.Join(u.HomeDir, "def")},
@@ -261,7 +330,7 @@ func TestStripComponentsFlag(t *testing.T) {
Config: Config{ Config: Config{
Host: []string{"localhost"}, Host: []string{"localhost"},
Username: "drone-scp", Username: "drone-scp",
Port: "22", Port: 22,
KeyPath: "tests/.ssh/id_rsa", KeyPath: "tests/.ssh/id_rsa",
Source: []string{"tests/global/*"}, Source: []string{"tests/global/*"},
StripComponents: 2, StripComponents: 2,
@@ -284,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) { func TestIgnoreList(t *testing.T) {
if os.Getenv("SSH_AUTH_SOCK") != "" { if os.Getenv("SSH_AUTH_SOCK") != "" {
if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil { if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil {
@@ -300,7 +403,7 @@ func TestIgnoreList(t *testing.T) {
Config: Config{ Config: Config{
Host: []string{"localhost"}, Host: []string{"localhost"},
Username: "drone-scp", Username: "drone-scp",
Port: "22", Port: 22,
KeyPath: "tests/.ssh/id_rsa", KeyPath: "tests/.ssh/id_rsa",
Source: []string{"tests/global/*", "!tests/global/c.txt", "!tests/global/e.txt"}, Source: []string{"tests/global/*", "!tests/global/c.txt", "!tests/global/e.txt"},
StripComponents: 2, StripComponents: 2,
@@ -315,12 +418,12 @@ func TestIgnoreList(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
// check file exist // 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") t.Fatal("c.txt file exist")
} }
// check 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") t.Fatal("c.txt file exist")
} }
@@ -380,7 +483,7 @@ func TestIncorrectPassword(t *testing.T) {
Config: Config{ Config: Config{
Host: []string{"localhost"}, Host: []string{"localhost"},
Username: "drone-scp", Username: "drone-scp",
Port: "22", Port: 22,
Password: "123456", Password: "123456",
Source: []string{"tests/a.txt", "tests/b.txt"}, Source: []string{"tests/a.txt", "tests/b.txt"},
Target: []string{"/home"}, Target: []string{"/home"},
@@ -403,7 +506,7 @@ func TestNoPermissionCreateFolder(t *testing.T) {
Config: Config{ Config: Config{
Host: []string{"localhost"}, Host: []string{"localhost"},
Username: "drone-scp", Username: "drone-scp",
Port: "22", Port: 22,
KeyPath: "tests/.ssh/id_rsa", KeyPath: "tests/.ssh/id_rsa",
Source: []string{"tests/a.txt", "tests/b.txt"}, Source: []string{"tests/a.txt", "tests/b.txt"},
Target: []string{"/etc/test"}, Target: []string{"/etc/test"},
@@ -452,25 +555,6 @@ func TestGlobList(t *testing.T) {
assert.Equal(t, expectIgnores, result.Ignore) 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) { func TestRemoveDestFile(t *testing.T) {
ssh := &easyssh.MakeConfig{ ssh := &easyssh.MakeConfig{
Server: "localhost", Server: "localhost",
@@ -487,21 +571,25 @@ func TestRemoveDestFile(t *testing.T) {
DestFile: "/etc/resolv.conf", DestFile: "/etc/resolv.conf",
} }
_, _, _, err := ssh.Run("ver", plugin.Config.CommandTimeout)
systemType := "unix"
if err == nil {
systemType = "windows"
}
// ssh io timeout // ssh io timeout
err := plugin.removeDestFile(ssh) err = plugin.removeDestFile(systemType, ssh)
assert.Error(t, err) assert.Error(t, err)
ssh.Timeout = 0 ssh.Timeout = 0
// permission denied // permission denied
err = plugin.removeDestFile(ssh) err = plugin.removeDestFile(systemType, ssh)
assert.Error(t, err) assert.Error(t, err)
} }
func TestPlugin_buildArgs(t *testing.T) { func TestPlugin_buildUnTarArgs(t *testing.T) {
type fields struct { type fields struct {
Repo Repo
Build Build
Config Config Config Config
DestFile string DestFile string
} }
@@ -518,30 +606,32 @@ func TestPlugin_buildArgs(t *testing.T) {
name: "default command", name: "default command",
fields: fields{ fields: fields{
Config: Config{ Config: Config{
Overwrite: false, Overwrite: false,
TarExec: "tar", UnlinkFirst: false,
TarExec: "tar",
}, },
DestFile: "foo.tar", DestFile: "foo.tar.gz",
}, },
args: args{ args: args{
target: "foo", target: "foo",
}, },
want: []string{"tar", "-xf", "foo.tar", "-C", "foo"}, want: []string{"tar", "-zxf", "foo.tar.gz", "-C", "foo"},
}, },
{ {
name: "strip components", name: "strip components",
fields: fields{ fields: fields{
Config: Config{ Config: Config{
Overwrite: false, Overwrite: false,
UnlinkFirst: false,
TarExec: "tar", TarExec: "tar",
StripComponents: 2, StripComponents: 2,
}, },
DestFile: "foo.tar", DestFile: "foo.tar.gz",
}, },
args: args{ args: args{
target: "foo", target: "foo",
}, },
want: []string{"tar", "-xf", "foo.tar", "--strip-components", "2", "-C", "foo"}, want: []string{"tar", "-zxf", "foo.tar.gz", "--strip-components", "2", "-C", "foo"},
}, },
{ {
name: "overwrite", name: "overwrite",
@@ -550,26 +640,347 @@ func TestPlugin_buildArgs(t *testing.T) {
TarExec: "tar", TarExec: "tar",
StripComponents: 2, StripComponents: 2,
Overwrite: true, Overwrite: true,
UnlinkFirst: false,
}, },
DestFile: "foo.tar", DestFile: "foo.tar.gz",
}, },
args: args{ args: args{
target: "foo", target: "foo",
}, },
want: []string{"tar", "-xf", "foo.tar", "--strip-components", "2", "--overwrite", "-C", "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 { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
p := &Plugin{ p := &Plugin{
Repo: tt.fields.Repo,
Build: tt.fields.Build,
Config: tt.fields.Config, Config: tt.fields.Config,
DestFile: tt.fields.DestFile, DestFile: tt.fields.DestFile,
} }
if got := p.buildArgs(tt.args.target); !reflect.DeepEqual(got, tt.want) { if got := p.buildUnTarArgs(tt.args.target); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Plugin.buildArgs() = %v, want %v", 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",
Protocol: easyssh.PROTOCOL_TCP4,
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,
Protocol: easyssh.PROTOCOL_TCP4,
},
}
// 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)
}
}
func TestPlugin_hostPort(t *testing.T) {
type fields struct {
Config Config
Writer io.Writer
}
type args struct {
h string
}
tests := []struct {
name string
fields fields
args args
wantHost string
wantPort string
}{
{
name: "default host and port",
fields: fields{
Config: Config{
Port: 22,
},
},
args: args{
h: "localhost",
},
wantHost: "localhost",
wantPort: "22",
},
{
name: "different port",
fields: fields{
Config: Config{
Port: 22,
Protocol: easyssh.PROTOCOL_TCP4,
},
},
args: args{
h: "localhost:443",
},
wantHost: "localhost",
wantPort: "443",
},
{
name: "ipv6",
fields: fields{
Config: Config{
Port: 22,
Protocol: easyssh.PROTOCOL_TCP6,
},
},
args: args{
h: "::1",
},
wantHost: "::1",
wantPort: "22",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := Plugin{
Config: tt.fields.Config,
}
gotHost, gotPort := p.hostPort(tt.args.h)
if gotHost != tt.wantHost {
t.Errorf("Plugin.hostPort() gotHost = %v, want %v", gotHost, tt.wantHost)
}
if gotPort != tt.wantPort {
t.Errorf("Plugin.hostPort() gotPort = %v, want %v", gotPort, tt.wantPort)
}
})
}
}
func TestIgnoreFolder(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",
Protocol: easyssh.PROTOCOL_TCP4,
Port: 22,
KeyPath: "tests/.ssh/id_rsa",
Source: []string{"tests/*", "!tests/global"},
Target: []string{filepath.Join(u.HomeDir, "test_ignore")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
},
}
err = plugin.Exec()
assert.Nil(t, err)
// check file exist
if _, err := os.Stat(filepath.Join(u.HomeDir, "test_ignore", "global", "c.txt")); !os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
if _, err := os.Stat(filepath.Join(u.HomeDir, "test_ignore", "global", "d.txt")); !os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
}