Compare commits

...

280 Commits

Author SHA1 Message Date
Bo-Yi Wu 256ad7447c ci(docker): fail push when trivy finds CRITICAL/HIGH issues 2026-04-16 23:01:09 +08:00
Bo-Yi Wu f06dda2b3e ci(trivy): use existing build_docker make target 2026-04-16 22:49:10 +08:00
Bo-Yi Wu 262e7e16b7 ci: enable check-latest in docker and goreleaser workflows 2026-04-16 22:42:52 +08:00
Bo-Yi Wu f93104aeb7 fix: skip integration tests without telegram secrets; apply modernize fix 2026-04-16 22:39:45 +08:00
Bo-Yi Wu cd05adc191 ci: pin golangci-lint to v2.11 2026-04-16 21:11:20 +08:00
Bo-Yi Wu af4fd887b2 ci: bump GitHub Actions and add Go 1.25/1.26 to test matrix 2026-04-16 21:03:29 +08:00
Bo-Yi Wu cf36b35b36 chore: bump go directive to 1.25.9 2026-04-16 20:57:59 +08:00
Bo-Yi Wu 90d58d2f98 ci: add Trivy security scanning for source code and Docker image
- Add independent trivy.yml workflow with repo scan and image scan jobs
- Add Trivy image scan step in docker.yml before pushing Docker image
- Add security-events permission for SARIF upload
- Add Trivy Security Scan badge to README
2026-04-16 18:10:11 +08:00
Bo-Yi Wu a4fc564fc9 fix(deps): upgrade golang.org/x/crypto to fix CVE vulnerabilities
- bump golang.org/x/crypto to v0.45.0 (fixes CVE-2024-45337 CRITICAL,
  CVE-2025-22869 HIGH, CVE-2025-47914 MEDIUM, CVE-2025-58181 MEDIUM)
- bump golang.org/x/sys to v0.38.0
2026-04-16 12:13:16 +08:00
Bo-Yi Wu 7d363fb2b0 ci(actions): upgrade GitHub Actions to latest versions
- bump actions/checkout to v6
- bump actions/setup-go to v6
- bump actions/cache to v5
- bump goreleaser/goreleaser-action to v7
- bump golangci/golangci-lint-action to v9
- bump github/codeql-action/* to v4
- bump codecov/codecov-action to v5
- bump docker/build-push-action to v7
- bump docker/login-action to v4
- bump docker/metadata-action to v6
- bump docker/setup-buildx-action to v4
- bump docker/setup-qemu-action to v4
- bump hadolint/hadolint-action to v3.3.0
- bump aquasecurity/trivy-action to v0.35.0
2026-04-16 12:06:53 +08:00
appleboy 2b178e9a27 chore: bump dependencies to latest stable versions
- Update dependencies: bump github.com/appleboy/com to v1.1.0, github.com/urfave/cli/v2 to v2.27.7, golang.org/x/crypto to v0.41.0, github.com/xrash/smetrics and golang.org/x/sys to newer versions

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-09-02 00:01:06 +08:00
appleboy aad3a6ad27 docs: improve consistency and accuracy of Chinese language selection
- Correct the display of Chinese script names for Simplified and Traditional Chinese
- Reorder language selection links for consistency across documentation files

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-08-31 11:06:02 +08:00
Florian Maurer dd5217c90a add woodpecker compatible metadata (#197)
See https://github.com/woodpecker-ci/woodpecker/pull/4871 for more information
2025-05-03 07:22:11 +08:00
appleboy 110008c84a docs: update README files with correct workflow links and formatting
- Update workflow badge links in all README files to reference testing.yml instead of lint.yml
- Fix bullet formatting in Chinese README files for better markdown display

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-04-27 11:43:48 +08:00
appleboy cc35c73edd feat: expand proxy configuration with new flags and env support
- Add multiple new proxy-related flags, including protocol, username, password, SSH key, key path, SSH passphrase, connection timeout, ciphers, use of insecure ciphers, and fingerprint
- Enable proxy configuration using environment variables for each new flag
- Set default values for several proxy options (e.g., protocol defaults to tcp, username defaults to root)

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-04-27 11:41:44 +08:00
appleboy e8f6afdd34 chore: update go-md2man dependency to v2.0.7
- Bump github.com/cpuguy83/go-md2man/v2 from version 2.0.6 to 2.0.7 in dependencies

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-04-26 23:09:46 +08:00
Bo-Yi Wu 05df7845ab feat: integrate godump for enhanced debugging functionality
- Add `github.com/yassinebenaid/godump` dependency in `go.mod`
- Import `github.com/yassinebenaid/godump` in `main.go`
- Add debug dump functionality using `godump` in `run` function

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2025-04-15 11:29:31 +08:00
Bo-Yi Wu 928be3e7e7 chore: upgrade Go dependencies to latest versions
- Update Go version from `1.23.0` to `1.23.8`
- Upgrade `github.com/appleboy/com` from `v0.2.0` to `v0.3.0`
- Upgrade `github.com/urfave/cli/v2` from `v2.27.5` to `v2.27.6`
- Upgrade `golang.org/x/crypto` from `v0.36.0` to `v0.37.0`
- Upgrade `github.com/ScaleFT/sshkeys` from `v1.2.0` to `v1.4.0`
- Upgrade `github.com/cpuguy83/go-md2man/v2` from `v2.0.5` to `v2.0.6`
- Upgrade `github.com/mattn/go-colorable` from `v0.1.13` to `v0.1.14`
- Upgrade `golang.org/x/sys` from `v0.31.0` to `v0.32.0`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2025-04-15 10:42:01 +08:00
Bo-Yi Wu e4f03f3543 build: enhance build process and testing across environments
- Add a new `all` target to the Makefile

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2025-04-15 10:35:36 +08:00
appleboy 419eff8b22 build: revamp make targets and update build instructions
- Replace `make build_linux_amd64` and `make build_linux_arm64` with `make build_docker`
- Add a help target with usage instructions and target descriptions
- Update `fmt` to install the latest version of `gofumpt`
- Add descriptions for `vet`, `fmt-check`, `test`, `install`, `build`, `ssh-server`, and `clean` targets
- Remove several build targets (`amd64`, `i386`, `arm64`, `arm`)
- Remove the `coverage` and `version` targets

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-04-14 14:12:46 +08:00
appleboy 0c387532cf refactor: improve code clarity and testing reliability across modules
- Use `strings.ReplaceAll` instead of `strings.Replace` for clarity and conciseness

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-04-12 19:42:12 +08:00
appleboy e2a386e6ec ci: enhance linting and string manipulations in plugin code
- Update golangci-lint action to v7 and specify version v2.0 in the GitHub testing workflow
- Add `.golangci.yaml` configuration file with various linters and settings
- Refactor string concatenation method for destination file name in `plugin.go`
- Use `strings.ReplaceAll` for replacing spaces in target paths in `plugin.go`
- Change error handling to use `errors.As` for type assertion in `plugin.go`

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-04-12 19:41:17 +08:00
appleboy 7a4b5f1fad build: update dependencies and optimize Docker configuration
- Update base image in Dockerfile from `alpine:3.17` to `alpine:3.21`

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-10 22:17:06 +08:00
appleboy eb083b1019 docs: enhance documentation and streamline configuration options
- Update usage descriptions for better clarity and detail
- Remove various proxy-related flags, streamlining the configuration options
- Add comments to indicate unchanged proxy settings
- Improve descriptions of tar-related flags for better understanding

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-10 22:16:39 +08:00
appleboy 5c956e2bfa ci: refactor CI workflows and enhance test configurations
- Rename `.github/workflows/lint.yml` to `.github/workflows/testing.yml`

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-10 22:06:50 +08:00
appleboy 1536096428 chore: update Go version and dependencies to 1.23-alpine
- Update golang container version in GitHub Actions file to `1.23-alpine`
- Change go module version to `1.23.0`
- Upgrade `golang.org/x/crypto` to `v0.36.0`
- Upgrade `golang.org/x/sys` to `v0.31.0`

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-10 22:06:25 +08:00
appleboy aab544b837 docs: improve documentation clarity and consistency throughout files
- Enhance description of SSH file transfer method
- Update heading from "Feature" to "Features"
- Reformulate feature list for clarity and readability
- Ensure list formatting consistency in documentation

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-03-10 22:05:21 +08:00
appleboy 4a529bdfd2 feat(bearer): configure scanning and reporting settings
- Add a new configuration file for bearer settings
- Set logging level to info
- Define reporting options including severity levels and output format
- Specify rules for scanning, including disabling default rules and skipping a specific rule
- Configure scanning parameters such as domain resolution and exit code settings

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-12-01 17:47:06 +08:00
appleboy 4f744b8f8b ci(bearer): enhance security with Bearer GitHub Action integration
- Add Bearer GitHub Action to scan for sensitive data in the codebase, configured to only scan changes in the current pull request or commit

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-12-01 10:32:50 +08:00
Bo-Yi Wu 19f2d8e319 docs: update 2024-11-19 13:57:12 +08:00
Bo-Yi Wu c250624789 docs: translate zh-tw and zh-ch 2024-11-19 13:52:15 +08:00
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
Bo-Yi Wu bad565d475 update success message format.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-02-27 09:53:36 +08:00
Bo-Yi Wu 8216bd8fb8 update to go 1.14
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-02-27 09:51:12 +08:00
Daniel Bingham 3d36432240 Fix typo in EnvVars for ssh-passphrase (#109) 2020-02-27 08:58:49 +08:00
Bo-Yi Wu 2fcaffcac8 docs: update passphrase variable
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-02-07 13:27:23 +08:00
Bo-Yi Wu c1e3242f53 update module
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-02-07 13:24:23 +08:00
Bo-Yi Wu 8e4a3f5e0c chore(makefile): remove GOPACKAGE variable 2020-02-01 00:41:34 +08:00
Bo-Yi Wu fe231a1c43 docs: add passphrase 2020-01-20 22:37:45 +08:00
Bo-Yi Wu 177625c6e7 chore: support passphrase (#107)
* chore: support passphrase
2020-01-20 22:34:16 +08:00
Bo-Yi Wu bb6466e8d9 chore: upgrade easyssh-proxy to v1.3.0 2020-01-19 23:40:00 +08:00
Bo-Yi Wu e5eae442c3 chore: update urfave/cli to v2 2020-01-19 23:38:47 +08:00
Bo-Yi Wu b73ec894ab chore: update default timeout to 10 minutes 2019-11-30 23:08:26 +08:00
Bo-Yi Wu 05eba8f809 docs(install): Add export GO111MODULE=on 2019-11-12 10:34:51 +08:00
Bo-Yi Wu a2493062f7 upgrade go module
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-11-12 10:11:21 +08:00
Bo-Yi Wu b2b346a0ca update example
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-11-04 14:11:57 +08:00
Bo-Yi Wu 9d8f5ac419 update
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-11-04 13:43:54 +08:00
Bo-Yi Wu 5d93e7b8ab docs: update diff format 2019-10-18 22:40:46 +08:00
Bo-Yi Wu bf812f8e29 update docs
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-10-14 23:34:52 +08:00
Bo-Yi Wu 8814cfe72c docs: update drone 2019-10-14 23:33:18 +08:00
Bo-Yi Wu 954e0069e6 docs: update readme 2019-10-10 01:25:32 +08:00
Bo-Yi Wu 03524ed8bd docs: update to drone 1.0 format. 2019-09-29 02:01:24 +08:00
Bo-Yi Wu 531df19c8c docs: update drone docs. 2019-09-28 21:36:07 +08:00
Bo-Yi Wu df8214b645 chore: remove microbadge url 2019-09-28 17:33:25 +08:00
Bo-Yi Wu c85ca1ffd2 feat(tar): add Overwrite flag (#102)
* feat(tar): add Overwrite flag

* chore: remove

* chore: output

* chore: output
2019-09-28 16:59:01 +08:00
Ivo Nunes 933b45bc15 Add variable to set temporary tar upload path (#100) 2019-09-28 16:36:05 +08:00
Bo-Yi Wu 15344d67ae fix strip-components
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-09-28 16:30:07 +08:00
Bo-Yi Wu cf9e6f260d chore: debug command 2019-09-28 14:52:31 +08:00
Bo-Yi Wu cfa325a8c4 refactor: Add args command 2019-09-28 14:40:28 +08:00
Bo-Yi Wu c8dbddab25 chore: support -arch= 2019-09-28 14:14:15 +08:00
Bo-Yi Wu 1b27d28b27 chore: upgrade package 2019-09-28 12:52:08 +08:00
Bo-Yi Wu 8a0b0f3c0c chore(GitHub): support actions parameter. 2019-09-28 10:30:15 +08:00
Bo-Yi Wu ec489106f9 chore: upgrade to go1.13 2019-09-28 10:04:29 +08:00
Bo-Yi Wu 9ed20ee32d docs: fix markdown lint 2019-09-28 09:59:58 +08:00
Bo-Yi Wu 2aee5a3df1 docs: update 2019-08-03 23:51:16 +08:00
Bo-Yi Wu bc633e27cf docs: fix markdown lint 2019-08-03 18:55:27 +08:00
Bo-Yi Wu 9dad691d4f docs: update example 2019-08-03 18:55:02 +08:00
Bo-Yi Wu 66579b6dae chore: add proxy variable 2019-05-11 19:51:39 +08:00
Bo-Yi Wu 06609f35cf add key variable
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-05-11 16:50:50 +08:00
Bo-Yi Wu c9771cce78 chore: add variable 2019-05-11 16:49:20 +08:00
Bo-Yi Wu 6088f7da5a chore: update build tag 2019-05-11 16:34:36 +08:00
Bo-Yi Wu 6de8f74170 docs: add ignore list example. 2019-05-11 14:34:40 +08:00
Bo-Yi Wu bb63d55f89 Update README.md 2019-05-09 14:08:52 +08:00
Bo-Yi Wu da44b071c4 chore: switch finished to struct{} for zero allocate (#96) 2019-03-30 07:26:53 +08:00
Bo-Yi Wu a7eddc4b11 docs: fix setting
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-11 17:22:33 +08:00
Bo-Yi Wu 813faf56be chore: remove build number 2019-03-10 23:43:06 +08:00
Bo-Yi Wu 4117d2ca30 fix: trigger build fail if error (#94)
fix #93
2019-03-10 23:41:21 +08:00
Bo-Yi Wu 15bd1a11e4 chore: change command timeout flag (#92)
* chore: change command timeout flag

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

* docs: update setting

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

* doc: update readme.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-07 13:56:40 +08:00
Bo-Yi Wu be0d85245a update go module
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-07 11:15:54 +08:00
Bo-Yi Wu 9cc27c6724 refactor: err check
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-06 11:05:15 +08:00
Bo-Yi Wu b36ffb0d5d fix: add empty line 2019-03-04 21:46:05 +08:00
Bo-Yi Wu ca7485443c chore(docker): replace ADD with COPY 2019-03-04 21:43:11 +08:00
Bo-Yi Wu f8a64791a4 chore: add lint check
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-04 16:11:12 +08:00
Bo-Yi Wu fe8e5e3483 fix: remove check username exist. (#91) 2019-03-03 07:16:57 +08:00
Bo-Yi Wu 2344618287 docs: update badge 2019-03-03 00:28:21 +08:00
Bo-Yi Wu 24926998c1 fix: binary name 2019-03-03 00:09:58 +08:00
Bo-Yi Wu a82a76903c fix: ssh config 2019-03-03 00:07:55 +08:00
Bo-Yi Wu 8e1c446a58 chore: update testing. 2019-03-02 23:53:27 +08:00
Bo-Yi Wu a2e6a07e44 feat: switch from govender to module. 2019-03-02 23:52:35 +08:00
Bo-Yi Wu bc7d0d7a7a docs: update 2019-01-27 11:34:27 +08:00
Bo-Yi Wu 26223d7b71 docs: Example ignore list configuration 2019-01-18 23:17:23 +08:00
Bo-Yi Wu b3f09b7592 refactor(lint): replace tool 2019-01-18 22:58:17 +08:00
Bo-Yi Wu 75d2ee1e10 fix missing exclude files (#88)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-01-18 16:40:50 +08:00
Bo-Yi Wu 699675c8fa add debug command. (#87)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-01-18 16:06:22 +08:00
Bo-Yi Wu d921289474 feat(ignore): support ignore list (#86)
fix #85
2019-01-18 15:12:36 +08:00
Bo-Yi Wu 4f7d31bd86 fix: missing tar config (#83) 2018-11-05 15:22:19 +08:00
natlibfi-arlehiko d798a8cc75 Add TarExec parameter (#82)
Add TarExec parameter to provide an alternative tar-command (E.g. On old non-Linux systems it may be necessary to use gtar).
2018-11-05 15:11:00 +08:00
Bo-Yi Wu 147005589b support user key. 2018-11-05 09:05:34 +08:00
Bo-Yi Wu 7fa57c038a add error action preference
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2018-06-27 14:18:19 +08:00
Bo-Yi Wu e6e048f198 fix: Provide a password using STDIN 2018-06-27 14:16:43 +08:00
Bo-Yi Wu 8096419bd2 chore: upgrade to 1.10 golang version. 2018-04-06 10:18:08 +08:00
Bo-Yi Wu 985badff42 mark arm and arm64 docker
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-12-22 13:51:15 +08:00
Bo-Yi Wu f68e09cf01 fix: arm32 image 2017-12-22 13:47:14 +08:00
Bo-Yi Wu 9150f669c9 fix: missing binary 2017-12-22 13:42:29 +08:00
Bo-Yi Wu ceb2b47958 feat(docker): suport arm arm64 image 2017-12-22 12:43:46 +08:00
Bo-Yi Wu acc220475c fix: Add build number. 2017-12-22 11:41:04 +08:00
Bo-Yi Wu 43d4f0d781 fix(error): show error log. 2017-12-22 11:38:13 +08:00
Bo-Yi Wu 357e2db0ff fix: update example. 2017-12-22 11:30:53 +08:00
Bo-Yi Wu 7764e754fe feat(docker): support windows build 2017-12-22 11:26:07 +08:00
Bo-Yi Wu 5bf5231d41 remove arm alpine arm64 i386 image.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-12-22 11:24:11 +08:00
Bo-Yi Wu 0261361be4 fix: stat /tmp: no such file or directory 2017-12-22 11:09:29 +08:00
Bo-Yi Wu f410f5e6ca chore(git): add release folder to ignore list. 2017-12-22 10:58:32 +08:00
Bo-Yi Wu e8f0048a45 refactor(notify): change fb to discord. 2017-12-22 10:55:01 +08:00
Bo-Yi Wu 41ace25862 feat(docker): suport arm arm64 alpine i386 image (#77) 2017-12-22 10:52:42 +08:00
Bo-Yi Wu 9c958f8637 docs(drone): add secret section 2017-12-18 09:45:38 +08:00
Bo-Yi Wu 9352413b30 add maintainer label.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-10-05 11:35:16 +08:00
Bo-Yi Wu f22cd46f46 Add some ssh env (#73) 2017-07-28 09:03:38 +08:00
Bo-Yi Wu 2cc69e2c03 update notify condition.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-06-24 22:55:10 +08:00
Bo-Yi Wu 637dcaaccc update drone ci website link.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-06-10 11:16:22 +08:00
Bo-Yi Wu 7c9b1d8b79 refactor: update gofmt check command. (#71) 2017-05-22 11:09:42 +08:00
Bo-Yi Wu 7a88a784b2 refactor: hide domain info if only single domain in drone setting. (#70) 2017-05-15 17:16:21 +08:00
Bo-Yi Wu 13e681cc3b refactor: wait group 2017-05-15 17:08:19 +08:00
Bo-Yi Wu a363fa22bf upgrade easyssh-proxy (#69)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-14 18:28:13 +08:00
Bo-Yi Wu 2ee4b54624 upgrade drone config. (#68)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-14 18:22:06 +08:00
Bo-Yi Wu a2708638cf [ci skip] update docs.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-01 08:55:15 +08:00
Bo-Yi Wu 35c2f7a14c feat: support strip components flag for tar command (#65)
Remove the specified number of leading path elements.
2017-04-30 23:18:22 +08:00
Bo-Yi Wu 8dba1e8e32 fix: quick fix. (#63) 2017-04-21 19:34:32 +08:00
Bo-Yi Wu 049263e847 refactor: show errors if set password and key at the same time (#62) 2017-04-21 16:38:43 +08:00
Bo-Yi Wu 88f5a95f3e add scp error message (#60)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-04-20 14:59:09 +08:00
Bo-Yi Wu 7bdc9fc05e refactor: HostKeyCallback is the function type used for verifying server (#59)
* refactor: HostKeyCallback is the function type used for verifying server

* update ssh package.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-04-15 20:45:16 +08:00
Bo-Yi Wu 3b2dbe955b remove drone sig file. (#57)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-04-14 09:19:05 +08:00
Bo-Yi Wu 464f0edc7e feat: add fmt check command. (#56) 2017-04-02 19:59:50 +08:00
Bo-Yi Wu 6aa6653378 update testing for remove single dest file. (#55)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-03-25 23:05:13 +08:00
Bo-Yi Wu d326bfe5a4 feat: update easyssh-proxy to 1.1.1 (#54) 2017-03-25 22:46:03 +08:00
Bo-Yi Wu 2ebb608269 feat: add color (#53) 2017-03-25 20:35:10 +08:00
Bo-Yi Wu f223505d46 add copy error handle. (#52) 2017-03-25 20:19:07 +08:00
Bo-Yi Wu b1ca6d49a2 feat: remove temp file if encounter errors. (#51) 2017-03-25 17:23:03 +08:00
Bo-Yi Wu c612c8c5c0 [ci skip] add proxy config docs
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-03-23 13:48:14 +08:00
Bo-Yi Wu e8dfaea058 Update README.md 2017-03-10 17:11:22 +08:00
Bo-Yi Wu 3121cb2aaa [ci skip] docs: add ProxyCommand docs. (#49)
* docs: add ProxyCommand docs.
2017-03-07 11:12:49 +08:00
Bo-Yi Wu 72c123f390 feat: Support scp files from proxy command. (#47)
* feat: Support scp files from proxy command.
2017-03-06 14:43:52 +08:00
Bo-Yi Wu 04c639cfa8 feat: upgrade to easyssh-proxy package. (#45)
* feat: upgrade to easyssh-proxy package.

* add command timeout flag
* upgrade easyssh to easyssh-proxy
2017-03-06 12:35:57 +08:00
Bo-Yi Wu ef521d1e98 refactor: hash is a much faster shell-builtin alternative to which. (#43) 2017-02-27 22:08:26 +08:00
Bo-Yi Wu 496e23a7e9 feat: improve coverage for easyssh (#42)
* feat: improve coverage for easyssh
2017-02-14 15:23:41 +08:00
Bo-Yi Wu 3e7ff1f928 refactor: remove travis 2017-02-14 12:34:53 +08:00
Bo-Yi Wu 6179afcde8 test: improve code coverage for easyssh. (#39)
* test: improve code coverage.

* feat: test password
2017-02-14 12:33:19 +08:00
Bo-Yi Wu 4f2e0c2096 refactor: remove travis (#41) 2017-02-14 12:30:51 +08:00
Bo-Yi Wu e2b890d217 remove glide config.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-02-14 09:49:48 +08:00
Bo-Yi Wu cdfa646abf docs: fix diff format. 2017-02-13 12:00:35 +08:00
Bo-Yi Wu ed37a75097 docs: [ci skip] update docs 2017-02-13 11:17:05 +08:00
Bo-Yi Wu baa413d348 feat: support wildcard file list. (#37)
* feat: support wildcard file list.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-02-13 11:09:14 +08:00
Bo-Yi Wu 79f352a5fa refactor: remove glide from drone config (#36)
* refactor: remove glide from drone config
2017-02-13 10:29:42 +08:00
Bo-Yi Wu 9787fcfb60 refactor: add vendor folder. (#34)
* refactor: add vendor folder.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-02-12 17:51:17 +08:00
Bo-Yi Wu ae6b001406 docs: [ci skip] add drone plugin document link. 2017-02-08 10:28:21 +08:00
Bo-Yi Wu 0d84586fb1 test: add easyssh scp and ssh command testing. (#29) 2017-02-04 20:50:51 +08:00
Bo-Yi Wu d673dc3a68 fix: [ci skip] drone link. 2017-02-04 18:39:22 +08:00
Bo-Yi Wu 1f05c75ba3 docs: [ci skip] update doc 2017-02-04 18:38:42 +08:00
Bo-Yi Wu 6472931282 refactor: add ssh-server command. (#28) 2017-02-04 17:35:31 +08:00
Bo-Yi Wu bb6e686f9a feat: initial easyssh testing. (#27) 2017-02-04 17:21:42 +08:00
Bo-Yi Wu 3911edcd30 docs: [ci skip] add timeout description 2017-01-31 21:17:09 +08:00
Bo-Yi Wu 212aa456c6 fix: duplicate of -t flag 2017-01-30 16:31:38 +08:00
Bo-Yi Wu 87fcf060aa refactor: update ssh host using JoinHostPort 2017-01-30 00:46:53 +08:00
Bo-Yi Wu 57d83dcfe0 feat: Add timeout flag. (#26) 2017-01-29 13:56:23 +08:00
Bo-Yi Wu e5ead0fb9c feat: Add unconvert command 2017-01-28 11:41:52 +08:00
Bo-Yi Wu 4e0a131533 docs: [ci skip] remove secret section. 2017-01-20 15:03:14 +08:00
Bo-Yi Wu 2704d9d275 fix: Enforce custom LDFLAGS within makefile 2017-01-17 10:37:41 +08:00
Bo-Yi Wu e9832010f8 fix: Clone tags within drone for proper version generation 2017-01-15 12:06:47 +08:00
Bo-Yi Wu 28824dfd1a fix: golint error: missing ',' before newline 2017-01-07 11:33:51 +08:00
Bo-Yi Wu 22b6f8b9b4 docs: [ci skip] update document. 2017-01-06 14:02:28 +08:00
Bo-Yi Wu 1d806cc9ed docs: [ci skip] add drone docs link. 2017-01-06 12:19:46 +08:00
Bo-Yi Wu dd049e69b9 docs: [ci skip] add drone docs. (#23) 2017-01-06 12:07:21 +08:00
Bo-Yi Wu 61940b4c0e docs: [ci skip] update example code. 2017-01-04 16:37:41 +08:00
Bo-Yi Wu f20fc0b114 fix: GOMAXPROCS set to the number of cores available in 1.5 2017-01-04 16:10:33 +08:00
Bo-Yi Wu ed00c6ef85 docs: [ci skip] update doc 2017-01-04 10:47:40 +08:00
Bo-Yi Wu cc822cd578 update commmand line.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-01-04 10:36:04 +08:00
43 changed files with 3259 additions and 851 deletions
-84
View File
@@ -1,84 +0,0 @@
workspace:
base: /srv/app
path: src/github.com/appleboy/drone-scp
pipeline:
# restore the cache from an sftp server
restore_cache:
image: appleboy/drone-sftp-cache
restore: true
mount: [ .glide, vendor ]
ignore_branch: true
test:
image: appleboy/golang-testing
pull: true
environment:
TAGS: netgo
GOPATH: /srv/app
commands:
- adduser -h /home/drone-scp -s /bin/bash -D -S drone-scp
- passwd -d drone-scp
- mkdir -p /home/drone-scp/.ssh
- chmod 700 /home/drone-scp/.ssh
- cp tests/.ssh/id_rsa.pub /home/drone-scp/.ssh/authorized_keys
- chown -R drone-scp /home/drone-scp/.ssh
# install ssh and start server
- apk update && apk add openssh openrc
- rm -rf /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_dsa_key
- ./tests/entrypoint.sh /usr/sbin/sshd -D &
- make dep_install
- make vet
- make lint
- make test
- make coverage
- make build
# build binary for docker image
- make static_build
when:
event: [ push, tag, pull_request ]
release:
image: appleboy/golang-testing
pull: true
environment:
TAGS: netgo
GOPATH: /srv/app
commands:
- make release
when:
event: [ tag ]
branch: [ refs/tags/* ]
docker:
image: plugins/docker
repo: ${DRONE_REPO}
tags: [ '${DRONE_TAG}' ]
when:
event: [ tag ]
branch: [ refs/tags/* ]
docker:
image: plugins/docker
repo: ${DRONE_REPO}
tags: [ 'latest' ]
when:
event: [ push ]
branch: [ master ]
github:
image: plugins/github-release
files:
- dist/release/*
when:
event: [ tag ]
branch: [ refs/tags/* ]
# rebuild the cache on the sftp server
rebuild_cache:
image: appleboy/drone-sftp-cache
rebuild: true
mount: [ .glide, vendor ]
ignore_branch: true
when:
branch: master
-1
View File
@@ -1 +0,0 @@
eyJhbGciOiJIUzI1NiJ9.d29ya3NwYWNlOgogIGJhc2U6IC9zcnYvYXBwCiAgcGF0aDogc3JjL2dpdGh1Yi5jb20vYXBwbGVib3kvZHJvbmUtc2NwCgpwaXBlbGluZToKICAjIHJlc3RvcmUgdGhlIGNhY2hlIGZyb20gYW4gc2Z0cCBzZXJ2ZXIKICByZXN0b3JlX2NhY2hlOgogICAgaW1hZ2U6IGFwcGxlYm95L2Ryb25lLXNmdHAtY2FjaGUKICAgIHJlc3RvcmU6IHRydWUKICAgIG1vdW50OiBbIC5nbGlkZSwgdmVuZG9yIF0KICAgIGlnbm9yZV9icmFuY2g6IHRydWUKCiAgdGVzdDoKICAgIGltYWdlOiBhcHBsZWJveS9nb2xhbmctdGVzdGluZwogICAgcHVsbDogdHJ1ZQogICAgZW52aXJvbm1lbnQ6CiAgICAgIFRBR1M6IG5ldGdvCiAgICAgIEdPUEFUSDogL3Nydi9hcHAKICAgIGNvbW1hbmRzOgogICAgICAtIGFkZHVzZXIgLWggL2hvbWUvZHJvbmUtc2NwIC1zIC9iaW4vYmFzaCAtRCAtUyBkcm9uZS1zY3AKICAgICAgLSBwYXNzd2QgLWQgZHJvbmUtc2NwCiAgICAgIC0gbWtkaXIgLXAgL2hvbWUvZHJvbmUtc2NwLy5zc2gKICAgICAgLSBjaG1vZCA3MDAgL2hvbWUvZHJvbmUtc2NwLy5zc2gKICAgICAgLSBjcCB0ZXN0cy8uc3NoL2lkX3JzYS5wdWIgL2hvbWUvZHJvbmUtc2NwLy5zc2gvYXV0aG9yaXplZF9rZXlzCiAgICAgIC0gY2hvd24gLVIgZHJvbmUtc2NwIC9ob21lL2Ryb25lLXNjcC8uc3NoCiAgICAgICMgaW5zdGFsbCBzc2ggYW5kIHN0YXJ0IHNlcnZlcgogICAgICAtIGFwayB1cGRhdGUgJiYgYXBrIGFkZCBvcGVuc3NoIG9wZW5yYwogICAgICAtIHJtIC1yZiAvZXRjL3NzaC9zc2hfaG9zdF9yc2Ffa2V5IC9ldGMvc3NoL3NzaF9ob3N0X2RzYV9rZXkKICAgICAgLSAuL3Rlc3RzL2VudHJ5cG9pbnQuc2ggL3Vzci9zYmluL3NzaGQgLUQgJgogICAgICAtIG1ha2UgZGVwX2luc3RhbGwKICAgICAgLSBtYWtlIHZldAogICAgICAtIG1ha2UgbGludAogICAgICAtIG1ha2UgdGVzdAogICAgICAtIG1ha2UgY292ZXJhZ2UKICAgICAgLSBtYWtlIGJ1aWxkCiAgICAgICMgYnVpbGQgYmluYXJ5IGZvciBkb2NrZXIgaW1hZ2UKICAgICAgLSBtYWtlIHN0YXRpY19idWlsZAogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCwgdGFnLCBwdWxsX3JlcXVlc3QgXQoKICByZWxlYXNlOgogICAgaW1hZ2U6IGFwcGxlYm95L2dvbGFuZy10ZXN0aW5nCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgVEFHUzogbmV0Z28KICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gbWFrZSByZWxlYXNlCiAgICB3aGVuOgogICAgICBldmVudDogWyB0YWcgXQogICAgICBicmFuY2g6IFsgcmVmcy90YWdzLyogXQoKICBkb2NrZXI6CiAgICBpbWFnZTogcGx1Z2lucy9kb2NrZXIKICAgIHJlcG86ICR7RFJPTkVfUkVQT30KICAgIHRhZ3M6IFsgJyR7RFJPTkVfVEFHfScgXQogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgdGFnIF0KICAgICAgYnJhbmNoOiBbIHJlZnMvdGFncy8qIF0KCiAgZG9ja2VyOgogICAgaW1hZ2U6IHBsdWdpbnMvZG9ja2VyCiAgICByZXBvOiAke0RST05FX1JFUE99CiAgICB0YWdzOiBbICdsYXRlc3QnIF0KICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHB1c2ggXQogICAgICBicmFuY2g6IFsgbWFzdGVyIF0KCiAgZ2l0aHViOgogICAgaW1hZ2U6IHBsdWdpbnMvZ2l0aHViLXJlbGVhc2UKICAgIGZpbGVzOgogICAgICAtIGRpc3QvcmVsZWFzZS8qCiAgICB3aGVuOgogICAgICBldmVudDogWyB0YWcgXQogICAgICBicmFuY2g6IFsgcmVmcy90YWdzLyogXQoKICAjIHJlYnVpbGQgdGhlIGNhY2hlIG9uIHRoZSBzZnRwIHNlcnZlcgogIHJlYnVpbGRfY2FjaGU6CiAgICBpbWFnZTogYXBwbGVib3kvZHJvbmUtc2Z0cC1jYWNoZQogICAgcmVidWlsZDogdHJ1ZQogICAgbW91bnQ6IFsgLmdsaWRlLCB2ZW5kb3IgXQogICAgaWdub3JlX2JyYW5jaDogdHJ1ZQogICAgd2hlbjoKICAgICAgYnJhbmNoOiBtYXN0ZXIK.iJq2DIBtHk-IH2ioZdNEkFcxDj-5mtNikSX66Jdt_pM
-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@v6
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
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@v4
+103
View File
@@ -0,0 +1,103 @@
name: Docker Image
on:
push:
branches:
- master
tags:
- "v*"
pull_request:
branches:
- "master"
permissions:
contents: read
packages: write
security-events: write
jobs:
build-docker:
runs-on: ubuntu-latest
steps:
- name: Setup go
uses: actions/setup-go@v6
with:
go-version: "^1"
check-latest: true
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Build binary
run: |
make build_docker
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to Docker Hub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker meta
id: docker-meta
uses: docker/metadata-action@v6
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 image for scanning
uses: docker/build-push-action@v7
with:
context: .
file: docker/Dockerfile
platforms: linux/amd64
push: false
load: true
tags: drone-scp:scan
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@v0.35.0
with:
image-ref: "drone-scp:scan"
format: "sarif"
output: "trivy-image-results.sarif"
severity: "CRITICAL,HIGH"
exit-code: '1'
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: "trivy-image-results.sarif"
category: "trivy-docker-image"
- name: Build and push
uses: docker/build-push-action@v7
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
+33
View File
@@ -0,0 +1,33 @@
name: Goreleaser
on:
push:
tags:
- "*"
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup go
uses: actions/setup-go@v6
with:
go-version: "^1"
check-latest: true
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v7
with:
# either 'goreleaser' (default) or 'goreleaser-pro'
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+61
View File
@@ -0,0 +1,61 @@
name: Lint and Testing
on:
push:
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Setup go
uses: actions/setup-go@v6
with:
go-version-file: go.mod
check-latest: true
- name: Setup golangci-lint
uses: golangci/golangci-lint-action@v9
with:
version: v2.11
args: --verbose
- uses: hadolint/hadolint-action@v3.3.0
name: hadolint for Dockerfile
with:
dockerfile: docker/Dockerfile
# This step uses the Bearer GitHub Action to scan for sensitive data in the codebase.
# The 'uses' keyword specifies the action to be used, in this case, 'bearer/bearer-action' at version 'v2'.
# The 'with' keyword provides input parameters for the action:
# - 'diff: true' indicates that the action should only scan the changes in the current pull request or commit.
- name: Bearer
uses: bearer/bearer-action@v2
with:
diff: true
testing:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ["1.25", "1.26"]
container:
image: golang:${{ matrix.go-version }}-alpine
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: setup sshd server
run: |
apk add git make curl perl bash build-base zlib-dev ucl-dev gpg
make ssh-server
- name: testing
run: |
make test
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
+85
View File
@@ -0,0 +1,85 @@
name: Trivy Security Scan
on:
push:
branches:
- master
pull_request:
branches:
- master
schedule:
# Run daily at 00:00 UTC
- cron: "0 0 * * *"
workflow_dispatch:
permissions:
contents: read
security-events: write
jobs:
trivy-repo-scan:
name: Trivy Repository Scan
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Run Trivy vulnerability scanner (repo)
uses: aquasecurity/trivy-action@v0.35.0
with:
scan-type: "fs"
scan-ref: "."
format: "sarif"
output: "trivy-repo-results.sarif"
severity: "CRITICAL,HIGH"
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: "trivy-repo-results.sarif"
trivy-image-scan:
name: Trivy Image Scan
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Setup go
uses: actions/setup-go@v6
with:
go-version-file: go.mod
check-latest: true
- name: Build binary
run: |
make build_docker
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build Docker image for scanning
uses: docker/build-push-action@v7
with:
context: .
file: docker/Dockerfile
platforms: linux/amd64
push: false
load: true
tags: drone-scp:scan
- name: Run Trivy vulnerability scanner (image)
uses: aquasecurity/trivy-action@v0.35.0
with:
image-ref: "drone-scp:scan"
format: "sarif"
output: "trivy-image-results.sarif"
severity: "CRITICAL,HIGH"
- name: Upload Trivy image scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: "trivy-image-results.sarif"
category: "trivy-image"
+4 -1
View File
@@ -22,8 +22,11 @@ _testmain.go
*.exe
*.test
*.prof
vendor
drone-scp
coverage.txt
.env
dist
.cover
release
bin
.idea
+54
View File
@@ -0,0 +1,54 @@
version: "2"
linters:
enable:
- asciicheck
- durationcheck
- errorlint
- gosec
- misspell
- nakedret
- nilerr
- nolintlint
- perfsprint
- revive
- usestdlibvars
- wastedassign
settings:
gosec:
includes:
- G102
- G106
- G108
- G109
- G111
- G112
- G201
- G203
perfsprint:
int-conversion: true
err-error: true
errorf: true
sprintf1: true
strconcat: true
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gci
- gofmt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
+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
-30
View File
@@ -1,30 +0,0 @@
sudo: required
language: go
go:
- 1.6.x
- 1.7.x
- tip
cache:
directories:
- vendor
- ${HOME}/.glide
before_install:
- mkdir -p $GOPATH/bin
- curl https://glide.sh/get | sh
- sudo useradd -m -d /home/drone-scp -s /bin/bash drone-scp
- sudo mkdir -p /home/drone-scp/.ssh
- sudo chmod 700 /home/drone-scp/.ssh
- sudo cp tests/.ssh/id_rsa.pub /home/drone-scp/.ssh/authorized_keys
- sudo chown -R drone-scp /home/drone-scp/.ssh
install:
- make dep_install
script:
- make vet
- make lint
- make test
- make build
+302
View File
@@ -0,0 +1,302 @@
---
date: 2017-01-06T00:00:00+00:00
title: SCP
name: SCP
description: Deploy artifacts using SSH/SCP
author: appleboy
tags: [ publish, ssh, scp ]
logo: term.svg
repo: appleboy/drone-scp
image: appleboy/drone-scp
containerImage: appleboy/drone-scp
containerImageUrl: https://hub.docker.com/r/appleboy/drone-scp
url: https://github.com/appleboy/drone-scp
---
The SCP plugin copy files and artifacts to target host machine via SSH. The below pipeline configuration demonstrates simple usage:
```yaml
- name: scp files
image: appleboy/drone-scp
settings:
host: example.com
username: foo
password: bar
port: 22
target: /var/www/deploy/${DRONE_REPO_OWNER}/${DRONE_REPO_NAME}
source: release.tar.gz
```
Example configuration with multiple source and target folder:
```diff
- name: scp files
image: appleboy/drone-scp
settings:
host: example.com
target:
+ - /home/deploy/web1
+ - /home/deploy/web2
source:
+ - release_1.tar.gz
+ - release_2.tar.gz
```
Example configuration with multiple host:
```diff
- name: scp files
image: appleboy/drone-scp
settings:
- host: example.com
+ host:
+ - example1.com
+ - example2.com
target: /home/deploy/web
source: release.tar.gz
```
Example configuration with wildcard pattern of source list:
```diff
- name: scp files
image: appleboy/drone-scp
settings:
host:
- example1.com
- example2.com
target: /home/deploy/web
source:
- - release/backend.tar.gz
- - release/images.tar.gz
+ - release/*.tar.gz
```
Remove target folder before copy files and artifacts to target:
```diff
- name: scp files
image: appleboy/drone-scp
settings:
target: /home/deploy/web
source: release.tar.gz
+ rm: true
```
Example for remove the specified number of leading path elements:
```diff
- name: scp files
image: appleboy/drone-scp
settings:
host: example.com
target: /home/deploy/web
source: dist/release.tar.gz
+ strip_components: 1
```
Example configuration using SSHProxyCommand:
```diff
- name: scp files
image: appleboy/drone-scp
settings:
host:
- example1.com
- example2.com
target: /home/deploy/web
source:
- release/*.tar.gz
+ proxy_host: 10.130.33.145
+ proxy_user: ubuntu
+ proxy_port: 22
+ proxy_password: 1234
```
Example configuration using password from secrets:
```diff
- name: scp files
image: appleboy/drone-scp
settings:
host:
- example1.com
- example2.com
user: ubuntu
port: 22
- password: 1234
+ password:
+ from_secret: ssh_password
target: /home/deploy/web
source:
- release/*.tar.gz
```
Example configuration using command timeout:
```diff
- name: scp files
image: appleboy/drone-scp
settings:
host:
- example1.com
- example2.com
user: ubuntu
password:
from_secret: ssh_password
port: 22
- command_timeout: 120
+ command_timeout: 2m
target: /home/deploy/web
source:
- release/*.tar.gz
```
Example configuration for ignore list:
```diff
- name: scp files
image: appleboy/drone-scp
settings:
host:
- example1.com
- example2.com
user: ubuntu
password:
from_secret: ssh_password
port: 22
command_timeout: 2m
target: /home/deploy/web
source:
+ - !release/README.md
- release/*
```
Example configuration for passphrase which protecting a private key:
```diff
- name: scp files
image: appleboy/drone-scp
settings:
host:
- example1.com
- example2.com
user: ubuntu
+ key:
+ from_secret: ssh_key
+ passphrase: 1234
port: 22
command_timeout: 2m
target: /home/deploy/web
source:
- release/*
```
## Parameter Reference
host
: target hostname or IP
port
: ssh port of target host
username
: account for target host user
password
: password for target host user
key
: plain text of user private key
passphrase
: The purpose of the passphrase is usually to encrypt the private key.
fingerprint
: fingerprint SHA256 of the host public key, default is to skip verification
target
: folder path of target host
source
: source lists you want to copy
rm
: remove target folder before copy files and artifacts
timeout
: Timeout is the maximum amount of time for the ssh connection to establish, default is 30 seconds.
command_timeout
: Command timeout is the maximum amount of time for the execute commands, default is 10 minutes.
strip_components
: remove the specified number of leading path elements
tar_tmp_path
: temporary path for tar file on the dest host
tar_exec
: alternative `tar` executable to on the dest host
overwrite
: use `--overwrite` flag with tar
proxy_host
: proxy hostname or IP
proxy_port
: ssh port of proxy host
proxy_username
: account for proxy host user
proxy_password
: password for proxy host user
proxy_key
: plain text of proxy private key
proxy_key_path
: key path of proxy private key
proxy_passphrase
: The purpose of the passphrase is usually to encrypt the private key.
proxy_fingerprint
: fingerprint SHA256 of the host public key, default is to skip verification
## Template Reference
repo.owner
: repository owner
repo.name
: repository name
build.status
: build status type enumeration, either `success` or `failure`
build.event
: build event type enumeration, one of `push`, `pull_request`, `tag`, `deployment`
build.number
: build number
build.commit
: git sha for current commit
build.branch
: git branch for current commit
build.tag
: git tag for current commit
build.ref
: git ref for current commit
build.author
: git author for current commit
build.link
: link the the build results in drone
-9
View File
@@ -1,9 +0,0 @@
FROM alpine:3.4
RUN apk update && \
apk add ca-certificates && \
rm -rf /var/cache/apk/*
ADD drone-scp /
ENTRYPOINT ["/drone-scp"]
-8
View File
@@ -1,8 +0,0 @@
FROM armhfbuild/alpine:3.4
RUN apk update && \
apk add ca-certificates && \
rm -rf /var/cache/apk/*
ADD drone-scp /bin/
ENTRYPOINT ["/bin/drone-scp"]
+79 -87
View File
@@ -1,17 +1,8 @@
.PHONY: test drone-scp build fmt vet errcheck lint install update release-dirs release-build release-copy release-check release coverage
DIST := dist
EXECUTABLE := drone-scp
# for dockerhub
DEPLOY_ACCOUNT := appleboy
DEPLOY_IMAGE := $(EXECUTABLE)
TARGETS ?= linux darwin windows
PACKAGES ?= $(shell go list ./... | grep -v /vendor/)
SOURCES ?= $(shell find . -name "*.go" -type f)
TAGS ?=
LDFLAGS += -X 'main.Version=$(VERSION)'
GOFMT ?= gofumpt -l -s -w
GO ?= go
GOFILES := $(shell find . -name "*.go" -type f)
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
ifneq ($(shell uname), Darwin)
EXTLDFLAGS = -extldflags "-static" $(null)
@@ -19,96 +10,97 @@ else
EXTLDFLAGS =
endif
ifeq ($(HAS_GO), GO)
GOPATH ?= $(shell $(GO) env GOPATH)
export PATH := $(GOPATH)/bin:$(PATH)
CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766
CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS)
endif
ifeq ($(OS), Windows_NT)
GOFLAGS := -v -buildmode=exe
EXECUTABLE ?= $(EXECUTABLE).exe
else ifeq ($(OS), Windows)
GOFLAGS := -v -buildmode=exe
EXECUTABLE ?= $(EXECUTABLE).exe
else
GOFLAGS := -v
EXECUTABLE ?= $(EXECUTABLE)
endif
ifneq ($(DRONE_TAG),)
VERSION ?= $(DRONE_TAG)
else
VERSION ?= $(shell git describe --tags --always || git rev-parse --short HEAD)
endif
TAGS ?=
LDFLAGS ?= -X 'main.Version=$(VERSION)'
all: build
fmt:
find . -name "*.go" -type f -not -path "./vendor/*" | xargs gofmt -s -w
.PHONY: help
help: ## Print this help message.
@echo "Usage: make [target]"
@echo ""
@echo "Targets:"
@echo ""
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
vet:
go vet $(PACKAGES)
errcheck:
@which errcheck > /dev/null; if [ $$? -ne 0 ]; then \
go get -u github.com/kisielk/errcheck; \
fmt: ## Format the code
@hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install mvdan.cc/gofumpt@latest; \
fi
errcheck $(PACKAGES)
$(GOFMT) -w $(GOFILES)
lint:
@which golint > /dev/null; if [ $$? -ne 0 ]; then \
go get -u github.com/golang/lint/golint; \
vet: ## Run go vet
$(GO) vet ./...
.PHONY: fmt-check
fmt-check: ## Check if the code is formatted
@hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install mvdan.cc/gofumpt; \
fi
for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
@diff=$$($(GOFMT) -d $(GOFILES)); \
if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \
echo "$${diff}"; \
exit 1; \
fi;
test:
for PKG in $(PACKAGES); do go test -v -cover -coverprofile $$GOPATH/src/$$PKG/coverage.txt $$PKG || exit 1; done;
test: ## Run tests
@$(GO) test -v -cover -coverprofile coverage.txt ./... && echo "\n==>\033[32m Ok\033[m\n" || exit 1
html:
go tool cover -html=coverage.txt
install: $(GOFILES) ## Install the package
$(GO) install -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)'
dep_install:
glide install
build: $(EXECUTABLE) ## Build the package
dep_update:
glide up
$(EXECUTABLE): $(GOFILES) ## Build the package
$(GO) build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o bin/$@
install: $(SOURCES)
go install -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)'
build_docker:
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=arm64 $(GO) build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/arm64/$(DEPLOY_IMAGE)
build: $(EXECUTABLE)
ssh-server: ## Run ssh server
adduser -h /home/drone-scp -s /bin/sh -D -S drone-scp
echo drone-scp:1234 | chpasswd
mkdir -p /home/drone-scp/.ssh
chmod 700 /home/drone-scp/.ssh
cat tests/.ssh/id_rsa.pub >> /home/drone-scp/.ssh/authorized_keys
cat tests/.ssh/test.pub >> /home/drone-scp/.ssh/authorized_keys
chmod 600 /home/drone-scp/.ssh/authorized_keys
chown -R drone-scp /home/drone-scp/.ssh
apk add --update openssh openrc
rm -rf /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_dsa_key
sed -i 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/g' /etc/ssh/sshd_config
sed -i 's/AllowTcpForwarding no/AllowTcpForwarding yes/g' /etc/ssh/sshd_config
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 &
$(EXECUTABLE): $(SOURCES)
go build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o $@
release: release-dirs release-build release-copy release-check
release-dirs:
mkdir -p $(DIST)/binaries $(DIST)/release
release-build:
@which gox > /dev/null; if [ $$? -ne 0 ]; then \
go get -u github.com/mitchellh/gox; \
fi
gox -os="$(TARGETS)" -arch="amd64 386" -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;)
# for docker.
static_build:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o $(DEPLOY_IMAGE)
docker_image:
docker build -t $(DEPLOY_ACCOUNT)/$(DEPLOY_IMAGE) .
docker: static_build 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)
coverage:
sed -i '/main.go/d' coverage.txt
curl -s https://codecov.io/bash > .codecov && \
chmod +x .codecov && \
./.codecov -f coverage.txt
clean:
go clean -x -i ./...
rm -rf coverage.txt $(EXECUTABLE) $(DIST) vendor
version:
@echo $(VERSION)
clean: ## Clean the build
$(GO) clean -x -i ./...
rm -rf coverage.txt $(EXECUTABLE)
+112 -80
View File
@@ -1,83 +1,126 @@
# drone-scp
[![GoDoc](https://godoc.org/github.com/appleboy/drone-scp?status.svg)](https://godoc.org/github.com/appleboy/drone-scp) [![Build Status](http://drone.wu-boy.com/api/badges/appleboy/drone-scp/status.svg)](http://drone.wu-boy.com/appleboy/drone-scp) [![codecov](https://codecov.io/gh/appleboy/drone-scp/branch/master/graph/badge.svg)](https://codecov.io/gh/appleboy/drone-scp) [![Go Report Card](https://goreportcard.com/badge/github.com/appleboy/drone-scp)](https://goreportcard.com/report/github.com/appleboy/drone-scp) [![Docker Pulls](https://img.shields.io/docker/pulls/appleboy/drone-scp.svg)](https://hub.docker.com/r/appleboy/drone-scp/) [![](https://images.microbadger.com/badges/image/appleboy/drone-scp.svg)](https://microbadger.com/images/appleboy/drone-scp "Get your own image badge on microbadger.com")
[繁體中文](README.zh-tw.md) | [簡體中文](README.zh-cn.md)
[Drone](https://github.com/drone/drone) plugin to copy files and artifacts via SSH.
[![GoDoc](https://godoc.org/github.com/appleboy/drone-scp?status.svg)](https://godoc.org/github.com/appleboy/drone-scp)
[![Lint and Testing](https://github.com/appleboy/drone-scp/actions/workflows/testing.yml/badge.svg)](https://github.com/appleboy/drone-scp/actions/workflows/testing.yml)
[![Trivy Security Scan](https://github.com/appleboy/drone-scp/actions/workflows/trivy.yml/badge.svg?branch=master)](https://github.com/appleboy/drone-scp/actions/workflows/trivy.yml)
[![codecov](https://codecov.io/gh/appleboy/drone-scp/branch/master/graph/badge.svg)](https://codecov.io/gh/appleboy/drone-scp)
[![Go Report Card](https://goreportcard.com/badge/github.com/appleboy/drone-scp)](https://goreportcard.com/report/github.com/appleboy/drone-scp)
[![Docker Pulls](https://img.shields.io/docker/pulls/appleboy/drone-scp.svg)](https://hub.docker.com/r/appleboy/drone-scp/)
## Feature
Securely transfer files and artifacts via SSH using a standalone binary, Docker container, or [Drone CI](http://docs.drone.io/) integration.
* [x] Support routines.
* [x] Support send files to multiple host.
* [x] Support send files to multiple target folder on host.
* [x] Support load ssh key from absolute path or raw body.
## Features
- [x] Parallel file transfer with multiple routines
- [x] Support for wildcard patterns in source file selection
- [x] Ability to transfer files to multiple destination hosts
- [x] Support for multiple target directories on each host
- [x] Flexible SSH key authentication via file path or raw content
- [x] Advanced networking with SSH ProxyCommand support
```sh
+--------+ +----------+ +-----------+
| Laptop | <--> | Jumphost | <--> | FooServer |
+--------+ +----------+ +-----------+
OR
+--------+ +----------+ +-----------+
| Laptop | <--> | Firewall | <--> | FooServer |
+--------+ +----------+ +-----------+
192.168.1.5 121.1.2.3 10.10.29.68
```
## Breaking changes
`v1.5.0`: change command timeout flag to `Duration`. See the following setting:
```diff
- name: scp files
image: appleboy/drone-scp
settings:
host:
- example1.com
- example2.com
username: ubuntu
password:
from_secret: ssh_password
port: 22
- command_timeout: 120
+ command_timeout: 2m
target: /home/deploy/web
source:
- release/*.tar.gz
```
## Build or Download a binary
The pre-compiled binaries can be downloaded from [release page](https://github.com/appleboy/drone-scp/releases). Support the following OS type.
* Windows amd64/386
* Linux amd64/386
* Darwin amd64/386
- Windows amd64/386
- Linux arm/amd64/386
- Darwin amd64/386
With `Go` installed
```sh
export GO111MODULE=on
go get -u -v github.com/appleboy/drone-scp
```
$ go get -u -v github.com/appleboy/drone-scp
```
or build the binary with the following command:
```
$ make build
```sh
export GOOS=linux
export GOARCH=amd64
export CGO_ENABLED=0
export GO111MODULE=on
go test -cover ./...
go build -v -a -tags netgo -o release/linux/amd64/drone-scp .
```
## Docker
Build the docker image with the following commands:
```
$ make docker
```
Please note incorrectly building the image for the correct x64 linux and with
CGO disabled will result in an error when running the Docker image:
```
docker: Error response from daemon: Container command
'/bin/drone-scp' not found or does not exist..
```sh
make docker
```
## Usage
There are three ways to send notification.
* [usage from binary](#usage-from-binary)
* [usage from docker](#usage-from-docker)
* [usage from drone ci](#usage-from-drone-ci)
- [usage from binary](#usage-from-binary)
- [usage from docker](#usage-from-docker)
- [usage from drone ci](#usage-from-drone-ci)
<a name="usage-from-binary"></a>
### Usage from binary
#### Using public key
```bash
drone-scp --host=example.com \
--port=22 \
--username=appleboy \
--key-path="${HOME}/.ssh/id_rsa" \
--target=/home/appleboy/test \
--source=your_local_folder_path
drone-scp --host example.com \
--port 22 \
--username appleboy \
--key-path "${HOME}/.ssh/id_rsa" \
--target /home/appleboy/test \
--source your_local_folder_path
```
#### Using password
```diff
drone-scp --host=example.com \
--port=22 \
--username=appleboy \
+ --password=xxxxxxx \
--target=/home/appleboy/test \
--source=your_local_folder_path
drone-scp --host example.com \
--port 22 \
--username appleboy \
+ --password xxxxxxx \
--target /home/appleboy/test \
--source your_local_folder_path
```
#### Using ssh-agent
@@ -90,38 +133,37 @@ eval `ssh-agent -s`
Import your local public key `~/.ssh/id_rsa`
```bash
$ ssh-add
```sh
ssh-add
```
You don't need to add `--password` or `--key-path` arguments.
```bash
drone-scp --host=example.com \
--port=22 \
--username=appleboy \
--target=/home/appleboy/test \
--source=your_local_folder_path
drone-scp --host example.com \
--port 22 \
--username appleboy \
--target /home/appleboy/test \
--source your_local_folder_path
```
#### Send multiple source or target folder and hosts
```diff
drone-scp --host=example1.com \
+ --host=example2.com \
--port=22 \
--username=appleboy \
--password= xxxxxxx
--target=/home/appleboy/test1 \
+ --target=/home/appleboy/test2 \
--source=your_local_folder_path_1
+ --source=your_local_folder_path_2
drone-scp --host example1.com \
+ --host example2.com \
--port 22 \
--username appleboy \
--password xxxxxxx
--target /home/appleboy/test1 \
+ --target /home/appleboy/test2 \
--source your_local_folder_path_1
+ --source your_local_folder_path_2
```
<a name="usage-from-docker"></a>
### Usage from docker
#### Using public key
Using public key
```bash
docker run --rm \
@@ -136,14 +178,14 @@ docker run --rm \
appleboy/drone-scp
```
#### Using password
Using password
```diff
docker run --rm \
-e SCP_HOST=example.com \
-e SCP_USERNAME=xxxxxxx \
-e SCP_PORT=22 \
+ -e SCP_PASSWORD="xxxxxxx"
+ -e SCP_PASSWORD="xxxxxxx"
-e SCP_SOURCE=SOURCE_FILE_LIST \
-e SCP_TARGET=TARGET_FOLDER_PATH \
-v $(pwd):$(pwd) \
@@ -151,9 +193,7 @@ docker run --rm \
appleboy/drone-scp
```
#### Using ssh-agent
Start your local ssh agent:
Using ssh-agent, start your local ssh agent:
```bash
eval `ssh-agent -s`
@@ -161,11 +201,11 @@ eval `ssh-agent -s`
Import your local public key `~/.ssh/id_rsa`
```bash
$ ssh-add
```sh
ssh-add
```
You don't need to add `SCP_PASSWORD` or `SCP_KEY_PATH ` arguments.
You don't need to add `SCP_PASSWORD` or `SCP_KEY_PATH` arguments.
```bash
docker run --rm \
@@ -179,7 +219,7 @@ docker run --rm \
appleboy/drone-scp
```
#### Send multiple source or target folder and hosts
Send multiple source or target folder and hosts
```bash
docker run --rm \
@@ -194,7 +234,6 @@ docker run --rm \
appleboy/drone-scp
```
<a name="usage-from-drone-ci"></a>
### Usage from drone ci
Execute from the working directory:
@@ -205,28 +244,21 @@ docker run --rm \
-e PLUGIN_USERNAME=xxxxxxx \
-e PLUGIN_PASSWORD=xxxxxxx \
-e PLUGIN_PORT=xxxxxxx \
-e PLUGIN_KEY="$(cat ${HOME}/.ssh/id_rsa)"
-e PLUGIN_SOURCE=SOURCE_FILE_LIST \
-e PLUGIN_TARGET=TARGET_FOLDER_PATH \
-e PLUGIN_RM=false \
-e PLUGIN_DEBUG=false \
-e DRONE_REPO_OWNER=appleboy \
-e DRONE_REPO_NAME=go-hello \
-e DRONE_COMMIT_SHA=e5e82b5eb3737205c25955dcc3dcacc839b7be52 \
-e DRONE_COMMIT_BRANCH=master \
-e DRONE_COMMIT_AUTHOR=appleboy \
-e DRONE_BUILD_NUMBER=1 \
-e DRONE_BUILD_STATUS=success \
-e DRONE_BUILD_LINK=http://github.com/appleboy/go-hello \
-e PLUGIN_DEBUG=true \
-v $(pwd):$(pwd) \
-w $(pwd) \
appleboy/drone-scp
```
You can get more [information](http://plugins.drone.io/appleboy/drone-scp/) about how to use scp in drone.
## Testing
Test the package with the following command:
```sh
make test
```
$ make test
```
+265
View File
@@ -0,0 +1,265 @@
# drone-scp
[English](README.md) | [繁體中文](README.zh-tw.md)
[![GoDoc](https://godoc.org/github.com/appleboy/drone-scp?status.svg)](https://godoc.org/github.com/appleboy/drone-scp)
[![Lint and Testing](https://github.com/appleboy/drone-scp/actions/workflows/testing.yml/badge.svg)](https://github.com/appleboy/drone-scp/actions/workflows/testing.yml)
[![codecov](https://codecov.io/gh/appleboy/drone-scp/branch/master/graph/badge.svg)](https://codecov.io/gh/appleboy/drone-scp)
[![Go Report Card](https://goreportcard.com/badge/github.com/appleboy/drone-scp)](https://goreportcard.com/report/github.com/appleboy/drone-scp)
[![Docker Pulls](https://img.shields.io/docker/pulls/appleboy/drone-scp.svg)](https://hub.docker.com/r/appleboy/drone-scp/)
复制文件和工件通过 SSH 使用二进制文件、docker 或 [Drone CI](http://docs.drone.io/)。
[English](README.md) | [繁體中文](README.zh-tw.md)
## 功能
- [x] 支持例程。
- [x] 支持来源列表中的通配符模式。
- [x] 支持将文件发送到多个主机。
- [x] 支持将文件发送到主机上的多个目标文件夹。
- [x] 支持从绝对路径或原始主体加载 ssh 密钥。
- [x] 支持 SSH ProxyCommand。
```sh
+--------+ +----------+ +-----------+
| Laptop | <--> | Jumphost | <--> | FooServer |
+--------+ +----------+ +-----------+
OR
+--------+ +----------+ +-----------+
| Laptop | <--> | Firewall | <--> | FooServer |
+--------+ +----------+ +-----------+
192.168.1.5 121.1.2.3 10.10.29.68
```
## Breaking changes
`v1.5.0`: change command timeout flag to `Duration`. See the following setting:
```diff
- name: scp files
image: appleboy/drone-scp
settings:
host:
- example1.com
- example2.com
username: ubuntu
password:
from_secret: ssh_password
port: 22
- command_timeout: 120
+ command_timeout: 2m
target: /home/deploy/web
source:
- release/*.tar.gz
```
## Build or Download a binary
The pre-compiled binaries can be downloaded from [release page](https://github.com/appleboy/drone-scp/releases). Support the following OS type.
- Windows amd64/386
- Linux arm/amd64/386
- Darwin amd64/386
With `Go` installed
```sh
export GO111MODULE=on
go get -u -v github.com/appleboy/drone-scp
```
or build the binary with the following command:
```sh
export GOOS=linux
export GOARCH=amd64
export CGO_ENABLED=0
export GO111MODULE=on
go test -cover ./...
go build -v -a -tags netgo -o release/linux/amd64/drone-scp .
```
## Docker
Build the docker image with the following commands:
```sh
make docker
```
## Usage
There are three ways to send notification.
- [usage from binary](#usage-from-binary)
- [usage from docker](#usage-from-docker)
- [usage from drone ci](#usage-from-drone-ci)
### Usage from binary
#### Using public key
```bash
drone-scp --host example.com \
--port 22 \
--username appleboy \
--key-path "${HOME}/.ssh/id_rsa" \
--target /home/appleboy/test \
--source your_local_folder_path
```
#### Using password
```diff
drone-scp --host example.com \
--port 22 \
--username appleboy \
+ --password xxxxxxx \
--target /home/appleboy/test \
--source your_local_folder_path
```
#### Using ssh-agent
Start your local ssh agent:
```bash
eval `ssh-agent -s`
```
Import your local public key `~/.ssh/id_rsa`
```sh
ssh-add
```
You don't need to add `--password` or `--key-path` arguments.
```bash
drone-scp --host example.com \
--port 22 \
--username appleboy \
--target /home/appleboy/test \
--source your_local_folder_path
```
#### Send multiple source or target folder and hosts
```diff
drone-scp --host example1.com \
+ --host example2.com \
--port 22 \
--username appleboy \
--password xxxxxxx
--target /home/appleboy/test1 \
+ --target /home/appleboy/test2 \
--source your_local_folder_path_1
+ --source your_local_folder_path_2
```
### Usage from docker
Using public key
```bash
docker run --rm \
-e SCP_HOST=example.com \
-e SCP_USERNAME=xxxxxxx \
-e SCP_PORT=22 \
-e SCP_KEY_PATH="${HOME}/.ssh/id_rsa"
-e SCP_SOURCE=SOURCE_FILE_LIST \
-e SCP_TARGET=TARGET_FOLDER_PATH \
-v $(pwd):$(pwd) \
-w $(pwd) \
appleboy/drone-scp
```
Using password
```diff
docker run --rm \
-e SCP_HOST=example.com \
-e SCP_USERNAME=xxxxxxx \
-e SCP_PORT=22 \
+ -e SCP_PASSWORD="xxxxxxx"
-e SCP_SOURCE=SOURCE_FILE_LIST \
-e SCP_TARGET=TARGET_FOLDER_PATH \
-v $(pwd):$(pwd) \
-w $(pwd) \
appleboy/drone-scp
```
Using ssh-agent, start your local ssh agent:
```bash
eval `ssh-agent -s`
```
Import your local public key `~/.ssh/id_rsa`
```sh
ssh-add
```
You don't need to add `SCP_PASSWORD` or `SCP_KEY_PATH` arguments.
```bash
docker run --rm \
-e SCP_HOST=example.com \
-e SCP_USERNAME=xxxxxxx \
-e SCP_PORT=22 \
-e SCP_SOURCE=SOURCE_FILE_LIST \
-e SCP_TARGET=TARGET_FOLDER_PATH \
-v $(pwd):$(pwd) \
-w $(pwd) \
appleboy/drone-scp
```
Send multiple source or target folder and hosts
```bash
docker run --rm \
-e SCP_HOST=example1.com,example2.com \
-e SCP_USERNAME=xxxxxxx \
-e SCP_PASSWORD=xxxxxxx \
-e SCP_PORT=22 \
-e SCP_SOURCE=SOURCE_FILE_LIST_1,SOURCE_FILE_LIST_2 \
-e SCP_TARGET=TARGET_FOLDER_PATH_1,TARGET_FOLDER_PATH_2 \
-v $(pwd):$(pwd) \
-w $(pwd) \
appleboy/drone-scp
```
### Usage from drone ci
Execute from the working directory:
```bash
docker run --rm \
-e PLUGIN_HOST=example.com \
-e PLUGIN_USERNAME=xxxxxxx \
-e PLUGIN_PASSWORD=xxxxxxx \
-e PLUGIN_PORT=xxxxxxx \
-e PLUGIN_SOURCE=SOURCE_FILE_LIST \
-e PLUGIN_TARGET=TARGET_FOLDER_PATH \
-e PLUGIN_RM=false \
-e PLUGIN_DEBUG=true \
-v $(pwd):$(pwd) \
-w $(pwd) \
appleboy/drone-scp
```
You can get more [information](http://plugins.drone.io/appleboy/drone-scp/) about how to use scp in drone.
## Testing
Test the package with the following command:
```sh
make test
```
+265
View File
@@ -0,0 +1,265 @@
# drone-scp
[English](README.md) | [簡體中文](README.zh-cn.md)
[![GoDoc](https://godoc.org/github.com/appleboy/drone-scp?status.svg)](https://godoc.org/github.com/appleboy/drone-scp)
[![Lint and Testing](https://github.com/appleboy/drone-scp/actions/workflows/testing.yml/badge.svg)](https://github.com/appleboy/drone-scp/actions/workflows/testing.yml)
[![codecov](https://codecov.io/gh/appleboy/drone-scp/branch/master/graph/badge.svg)](https://codecov.io/gh/appleboy/drone-scp)
[![Go Report Card](https://goreportcard.com/badge/github.com/appleboy/drone-scp)](https://goreportcard.com/report/github.com/appleboy/drone-scp)
[![Docker Pulls](https://img.shields.io/docker/pulls/appleboy/drone-scp.svg)](https://hub.docker.com/r/appleboy/drone-scp/)
複製檔案和工件通過 SSH 使用二進制檔案、docker 或 [Drone CI](http://docs.drone.io/)。
[English](README.md) | [簡體中文](README.zh-cn.md)
## 功能
- [x] 支援例程。
- [x] 支援來源列表中的萬用字元模式。
- [x] 支援將檔案發送到多個主機。
- [x] 支援將檔案發送到主機上的多個目標資料夾。
- [x] 支援從絕對路徑或原始主體載入 ssh 金鑰。
- [x] 支援 SSH ProxyCommand。
```sh
+--------+ +----------+ +-----------+
| Laptop | <--> | Jumphost | <--> | FooServer |
+--------+ +----------+ +-----------+
OR
+--------+ +----------+ +-----------+
| Laptop | <--> | Firewall | <--> | FooServer |
+--------+ +----------+ +-----------+
192.168.1.5 121.1.2.3 10.10.29.68
```
## Breaking changes
`v1.5.0`: change command timeout flag to `Duration`. See the following setting:
```diff
- name: scp files
image: appleboy/drone-scp
settings:
host:
- example1.com
- example2.com
username: ubuntu
password:
from_secret: ssh_password
port: 22
- command_timeout: 120
+ command_timeout: 2m
target: /home/deploy/web
source:
- release/*.tar.gz
```
## Build or Download a binary
The pre-compiled binaries can be downloaded from [release page](https://github.com/appleboy/drone-scp/releases). Support the following OS type.
- Windows amd64/386
- Linux arm/amd64/386
- Darwin amd64/386
With `Go` installed
```sh
export GO111MODULE=on
go get -u -v github.com/appleboy/drone-scp
```
or build the binary with the following command:
```sh
export GOOS=linux
export GOARCH=amd64
export CGO_ENABLED=0
export GO111MODULE=on
go test -cover ./...
go build -v -a -tags netgo -o release/linux/amd64/drone-scp .
```
## Docker
Build the docker image with the following commands:
```sh
make docker
```
## Usage
There are three ways to send notification.
- [usage from binary](#usage-from-binary)
- [usage from docker](#usage-from-docker)
- [usage from drone ci](#usage-from-drone-ci)
### Usage from binary
#### Using public key
```bash
drone-scp --host example.com \
--port 22 \
--username appleboy \
--key-path "${HOME}/.ssh/id_rsa" \
--target /home/appleboy/test \
--source your_local_folder_path
```
#### Using password
```diff
drone-scp --host example.com \
--port 22 \
--username appleboy \
+ --password xxxxxxx \
--target /home/appleboy/test \
--source your_local_folder_path
```
#### Using ssh-agent
Start your local ssh agent:
```bash
eval `ssh-agent -s`
```
Import your local public key `~/.ssh/id_rsa`
```sh
ssh-add
```
You don't need to add `--password` or `--key-path` arguments.
```bash
drone-scp --host example.com \
--port 22 \
--username appleboy \
--target /home/appleboy/test \
--source your_local_folder_path
```
#### Send multiple source or target folder and hosts
```diff
drone-scp --host example1.com \
+ --host example2.com \
--port 22 \
--username appleboy \
--password xxxxxxx
--target /home/appleboy/test1 \
+ --target /home/appleboy/test2 \
--source your_local_folder_path_1
+ --source your_local_folder_path_2
```
### Usage from docker
Using public key
```bash
docker run --rm \
-e SCP_HOST=example.com \
-e SCP_USERNAME=xxxxxxx \
-e SCP_PORT=22 \
-e SCP_KEY_PATH="${HOME}/.ssh/id_rsa"
-e SCP_SOURCE=SOURCE_FILE_LIST \
-e SCP_TARGET=TARGET_FOLDER_PATH \
-v $(pwd):$(pwd) \
-w $(pwd) \
appleboy/drone-scp
```
Using password
```diff
docker run --rm \
-e SCP_HOST=example.com \
-e SCP_USERNAME=xxxxxxx \
-e SCP_PORT=22 \
+ -e SCP_PASSWORD="xxxxxxx"
-e SCP_SOURCE=SOURCE_FILE_LIST \
-e SCP_TARGET=TARGET_FOLDER_PATH \
-v $(pwd):$(pwd) \
-w $(pwd) \
appleboy/drone-scp
```
Using ssh-agent, start your local ssh agent:
```bash
eval `ssh-agent -s`
```
Import your local public key `~/.ssh/id_rsa`
```sh
ssh-add
```
You don't need to add `SCP_PASSWORD` or `SCP_KEY_PATH` arguments.
```bash
docker run --rm \
-e SCP_HOST=example.com \
-e SCP_USERNAME=xxxxxxx \
-e SCP_PORT=22 \
-e SCP_SOURCE=SOURCE_FILE_LIST \
-e SCP_TARGET=TARGET_FOLDER_PATH \
-v $(pwd):$(pwd) \
-w $(pwd) \
appleboy/drone-scp
```
Send multiple source or target folder and hosts
```bash
docker run --rm \
-e SCP_HOST=example1.com,example2.com \
-e SCP_USERNAME=xxxxxxx \
-e SCP_PASSWORD=xxxxxxx \
-e SCP_PORT=22 \
-e SCP_SOURCE=SOURCE_FILE_LIST_1,SOURCE_FILE_LIST_2 \
-e SCP_TARGET=TARGET_FOLDER_PATH_1,TARGET_FOLDER_PATH_2 \
-v $(pwd):$(pwd) \
-w $(pwd) \
appleboy/drone-scp
```
### Usage from drone ci
Execute from the working directory:
```bash
docker run --rm \
-e PLUGIN_HOST=example.com \
-e PLUGIN_USERNAME=xxxxxxx \
-e PLUGIN_PASSWORD=xxxxxxx \
-e PLUGIN_PORT=xxxxxxx \
-e PLUGIN_SOURCE=SOURCE_FILE_LIST \
-e PLUGIN_TARGET=TARGET_FOLDER_PATH \
-e PLUGIN_RM=false \
-e PLUGIN_DEBUG=true \
-v $(pwd):$(pwd) \
-w $(pwd) \
appleboy/drone-scp
```
You can get more [information](http://plugins.drone.io/appleboy/drone-scp/) about how to use scp in drone.
## Testing
Test the package with the following command:
```sh
make test
```
+29
View File
@@ -0,0 +1,29 @@
disable-version-check: false
log-level: info
report:
fail-on-severity: critical,high,medium,low
format: ""
no-color: false
output: ""
report: security
severity: critical,high,medium,low,warning
rule:
disable-default-rules: false
only-rule: []
skip-rule: ["go_lang_logger_leak"]
scan:
context: ""
data_subject_mapping: ""
disable-domain-resolution: true
domain-resolution-timeout: 3s
exit-code: -1
external-rule-dir: []
force: false
hide_progress_bar: false
internal-domains: []
parallel: 0
quiet: false
scanner:
- sast
skip-path: []
skip-test: true
+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.21
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"]
-197
View File
@@ -1,197 +0,0 @@
// Package easyssh provides a simple implementation of some SSH protocol
// features in Go. You can simply run a command on a remote server or get a file
// even simpler than native console SSH client. You don't need to think about
// Dials, sessions, defers, or public keys... Let easyssh think about it!
package easyssh
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"net"
"os"
"path/filepath"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
// MakeConfig Contains main authority information.
// User field should be a name of user on remote server (ex. john in ssh john@example.com).
// Server field should be a remote machine address (ex. example.com in ssh john@example.com)
// Key is a path to private key on your local machine.
// Port is SSH server port on remote machine.
// Note: easyssh looking for private key in user's home directory (ex. /home/john + Key).
// Then ensure your Key begins from '/' (ex. /.ssh/id_rsa)
type MakeConfig struct {
User string
Server string
Key string
KeyPath string
Port string
Password string
}
// returns ssh.Signer from user you running app home path + cutted key path.
// (ex. pubkey,err := getKeyFile("/.ssh/id_rsa") )
func getKeyFile(keypath string) (ssh.Signer, error) {
buf, err := ioutil.ReadFile(keypath)
if err != nil {
return nil, err
}
pubkey, err := ssh.ParsePrivateKey(buf)
if err != nil {
return nil, err
}
return pubkey, nil
}
// connects to remote server using MakeConfig struct and returns *ssh.Session
func (ssh_conf *MakeConfig) connect() (*ssh.Session, error) {
// auths holds the detected ssh auth methods
auths := []ssh.AuthMethod{}
// figure out what auths are requested, what is supported
if ssh_conf.Password != "" {
auths = append(auths, ssh.Password(ssh_conf.Password))
}
if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
auths = append(auths, ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers))
defer sshAgent.Close()
}
if ssh_conf.KeyPath != "" {
if pubkey, err := getKeyFile(ssh_conf.KeyPath); err == nil {
auths = append(auths, ssh.PublicKeys(pubkey))
}
}
if ssh_conf.Key != "" {
signer, _ := ssh.ParsePrivateKey([]byte(ssh_conf.Key))
auths = append(auths, ssh.PublicKeys(signer))
}
config := &ssh.ClientConfig{
User: ssh_conf.User,
Auth: auths,
}
client, err := ssh.Dial("tcp", ssh_conf.Server+":"+ssh_conf.Port, config)
if err != nil {
return nil, err
}
session, err := client.NewSession()
if err != nil {
return nil, err
}
return session, nil
}
// Stream returns one channel that combines the stdout and stderr of the command
// as it is run on the remote machine, and another that sends true when the
// command is done. The sessions and channels will then be closed.
func (ssh_conf *MakeConfig) Stream(command string) (output chan string, done chan bool, err error) {
// connect to remote host
session, err := ssh_conf.connect()
if err != nil {
return output, done, err
}
// connect to both outputs (they are of type io.Reader)
outReader, err := session.StdoutPipe()
if err != nil {
return output, done, err
}
errReader, err := session.StderrPipe()
if err != nil {
return output, done, err
}
// combine outputs, create a line-by-line scanner
outputReader := io.MultiReader(outReader, errReader)
err = session.Start(command)
scanner := bufio.NewScanner(outputReader)
// continuously send the command's output over the channel
outputChan := make(chan string)
done = make(chan bool)
go func(scanner *bufio.Scanner, out chan string, done chan bool) {
defer close(outputChan)
defer close(done)
for scanner.Scan() {
outputChan <- scanner.Text()
}
// close all of our open resources
done <- true
session.Close()
}(scanner, outputChan, done)
return outputChan, done, err
}
// Run command on remote machine and returns its stdout as a string
func (ssh_conf *MakeConfig) Run(command string) (outStr string, err error) {
outChan, doneChan, err := ssh_conf.Stream(command)
if err != nil {
return outStr, err
}
// read from the output channel until the done signal is passed
stillGoing := true
for stillGoing {
select {
case <-doneChan:
stillGoing = false
case line := <-outChan:
outStr += line + "\n"
}
}
// return the concatenation of all signals from the output channel
return outStr, err
}
// Scp uploads sourceFile to remote machine like native scp console app.
func (ssh_conf *MakeConfig) Scp(sourceFile string) error {
session, err := ssh_conf.connect()
if err != nil {
return err
}
defer session.Close()
targetFile := filepath.Base(sourceFile)
src, srcErr := os.Open(sourceFile)
if srcErr != nil {
return srcErr
}
srcStat, statErr := src.Stat()
if statErr != nil {
return statErr
}
go func() {
w, _ := session.StdinPipe()
fmt.Fprintln(w, "C0644", srcStat.Size(), targetFile)
if srcStat.Size() > 0 {
io.Copy(w, src)
fmt.Fprint(w, "\x00")
w.Close()
} else {
fmt.Fprint(w, "\x00")
w.Close()
}
}()
if err := session.Run(fmt.Sprintf("scp -t %s", targetFile)); err != nil {
return err
}
return nil
}
Generated
-34
View File
@@ -1,34 +0,0 @@
hash: 324c76f4ece1989f584ec84aab8252020da4dcbc20e38990465a9a0b7400f8ec
updated: 2016-12-28T15:52:54.896825557+08:00
imports:
- name: github.com/appleboy/com
version: c2e1fea1b771a26cb55774843ebd8955d723ee4e
subpackages:
- random
- name: github.com/joho/godotenv
version: a01a834e1654b4c9ca5b3ad05159445cc9c7ad08
subpackages:
- autoload
- name: github.com/urfave/cli
version: 0bdeddeeb0f650497d603c4ad7b20cfe685682f6
- name: golang.org/x/crypto
version: c2f4947f41766b144bb09066e919466da5eddeae
subpackages:
- curve25519
- ed25519
- ed25519/internal/edwards25519
- ssh
- ssh/agent
testImports:
- name: github.com/davecgh/go-spew
version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9
subpackages:
- spew
- name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages:
- difflib
- name: github.com/stretchr/testify
version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0
subpackages:
- assert
-20
View File
@@ -1,20 +0,0 @@
package: github.com/appleboy/drone-scp
import:
- package: github.com/joho/godotenv
version: ^1.0.0
subpackages:
- autoload
- package: github.com/urfave/cli
version: ^1.19.1
- package: golang.org/x/crypto
subpackages:
- ssh
- ssh/agent
- package: github.com/appleboy/com
subpackages:
- random
testImport:
- package: github.com/stretchr/testify
version: ^1.1.4
subpackages:
- assert
+28
View File
@@ -0,0 +1,28 @@
module github.com/appleboy/drone-scp
go 1.25.9
require (
github.com/appleboy/com v1.1.0
github.com/appleboy/easyssh-proxy v1.5.0
github.com/fatih/color v1.18.0
github.com/joho/godotenv v1.5.1
github.com/stretchr/testify v1.8.4
github.com/urfave/cli/v2 v2.27.7
github.com/yassinebenaid/godump v0.11.1
golang.org/x/crypto v0.45.0
)
require (
github.com/ScaleFT/sshkeys v1.4.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.7 // 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.14 // 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-20250705151800-55b8f293f342 // indirect
golang.org/x/sys v0.38.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
+43
View File
@@ -0,0 +1,43 @@
github.com/ScaleFT/sshkeys v1.4.0 h1:Yqd0cKA5PUvwV0dgRI67BDHGTsMHtGQBZbLXh1dthmE=
github.com/ScaleFT/sshkeys v1.4.0/go.mod h1:GineMkS8SEiELq8q5DzA2Wnrw65SqdD9a+hm8JOU1I4=
github.com/appleboy/com v1.1.0 h1:HLgRzhtj+4PLuFPPutKexd9zI9F74ymgWhkgPfPtnkc=
github.com/appleboy/com v1.1.0/go.mod h1:IbC1mLvqcIYn2YVNJgAYB9XnhbUh1xYKsOzdEOy0n+c=
github.com/appleboy/easyssh-proxy v1.5.0 h1:OYdSPvYQN3mhnsMH5I2OF1TgwSEcSq33kvjQfTwvZww=
github.com/appleboy/easyssh-proxy v1.5.0/go.mod h1:zcEMrStH91/tcUn3gUGP0KpQwUYLm8tX/Ook1AH98uc=
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a h1:saTgr5tMLFnmy/yg3qDTft4rE5DY2uJ/cCxCe3q0XTU=
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a/go.mod h1:Bw9BbhOJVNR+t0jCqx2GC6zv0TGBsShs56Y3gfSCvl0=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU=
github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4=
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg=
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
github.com/yassinebenaid/godump v0.11.1 h1:SPujx/XaYqGDfmNh7JI3dOyCUVrG0bG2duhO3Eh2EhI=
github.com/yassinebenaid/godump v0.11.1/go.mod h1:dc/0w8wmg6kVIvNGAzbKH1Oa54dXQx8SNKh4dPRyW44=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+281 -122
View File
@@ -1,166 +1,325 @@
package main
import (
"log"
"os"
"runtime"
"strconv"
"time"
"github.com/appleboy/easyssh-proxy"
"github.com/joho/godotenv"
_ "github.com/joho/godotenv/autoload"
"github.com/urfave/cli"
"github.com/urfave/cli/v2"
"github.com/yassinebenaid/godump"
)
// Version set at compile-time
var Version = "v1.0.0-dev"
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
}
var (
Version string
)
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.Name = "scp plugin"
app.Usage = "scp plugin"
app.Name = "Drone SCP"
app.Usage = "Copy files and artifacts via SSH."
app.Copyright = "Copyright (c) " + strconv.Itoa(time.Now().Year()) + " Bo-Yi Wu"
app.Version = Version
app.Authors = []*cli.Author{
{
Name: "Bo-Yi Wu",
Email: "appleboy.tw@gmail.com",
},
}
app.Action = run
app.Version = Version
app.Flags = []cli.Flag{
cli.StringSliceFlag{
Name: "host",
Usage: "Server host",
EnvVar: "PLUGIN_HOST,SCP_HOST",
&cli.StringSliceFlag{
Name: "host",
Aliases: []string{"H"},
Usage: "Remote server host address or IP",
EnvVars: []string{"PLUGIN_HOST", "SSH_HOST", "INPUT_HOST"},
FilePath: ".host",
},
cli.StringFlag{
Name: "port",
Value: "22",
Usage: "Server port, default to 22",
EnvVar: "PLUGIN_PORT,SCP_PORT",
&cli.IntFlag{
Name: "port",
Aliases: []string{"p"},
Usage: "SSH port number (default: 22)",
EnvVars: []string{"PLUGIN_PORT", "SSH_PORT", "INPUT_PORT"},
Value: 22,
},
cli.StringFlag{
Name: "username",
Usage: "Server username",
EnvVar: "PLUGIN_USERNAME,SCP_USERNAME",
&cli.StringFlag{
Name: "protocol",
Usage: "Network protocol to use (tcp, tcp4, tcp6)",
EnvVars: []string{"PLUGIN_PROTOCOL", "SSH_PROTOCOL", "INPUT_PROTOCOL"},
Value: "tcp",
},
cli.StringFlag{
Name: "password",
Usage: "Password for password-based authentication",
EnvVar: "PLUGIN_PASSWORD,SCP_PASSWORD",
&cli.StringFlag{
Name: "username",
Aliases: []string{"user", "u"},
Usage: "SSH username for authentication",
EnvVars: []string{"PLUGIN_USERNAME", "PLUGIN_USER", "SSH_USERNAME", "INPUT_USERNAME"},
Value: "root",
},
cli.StringFlag{
Name: "key",
Usage: "ssh private key",
EnvVar: "PLUGIN_KEY,SCP_KEY",
&cli.StringFlag{
Name: "password",
Aliases: []string{"P"},
Usage: "SSH password for authentication",
EnvVars: []string{"PLUGIN_PASSWORD", "SSH_PASSWORD", "INPUT_PASSWORD"},
},
cli.StringFlag{
Name: "key-path",
Usage: "ssh private key path",
EnvVar: "PLUGIN_KEY_PATH,SCP_KEY_PATH",
&cli.DurationFlag{
Name: "timeout",
Usage: "SSH connection timeout duration (default: 30s)",
EnvVars: []string{"PLUGIN_TIMEOUT", "SSH_TIMEOUT", "INPUT_TIMEOUT"},
Value: 30 * time.Second,
},
cli.StringSliceFlag{
Name: "target",
Usage: "Target path on the server",
EnvVar: "PLUGIN_TARGET,SCP_TARGET",
&cli.StringFlag{
Name: "ssh-key",
Usage: "SSH private key content for authentication",
EnvVars: []string{"PLUGIN_SSH_KEY", "PLUGIN_KEY", "SSH_KEY", "INPUT_KEY"},
},
cli.StringSliceFlag{
Name: "source",
Usage: "scp file list",
EnvVar: "PLUGIN_SOURCE,SCP_SOURCE",
&cli.StringFlag{
Name: "ssh-passphrase",
Usage: "Passphrase to decrypt the SSH private key",
EnvVars: []string{"PLUGIN_SSH_PASSPHRASE", "PLUGIN_PASSPHRASE", "SSH_PASSPHRASE", "INPUT_PASSPHRASE"},
},
cli.BoolFlag{
Name: "rm",
Usage: "remove target folder before upload data",
EnvVar: "PLUGIN_RM,SCP_RM",
&cli.StringFlag{
Name: "key-path",
Aliases: []string{"i"},
Usage: "Path to SSH private key file",
EnvVars: []string{"PLUGIN_KEY_PATH", "SSH_KEY_PATH", "INPUT_KEY_PATH"},
},
cli.StringFlag{
Name: "repo.owner",
Usage: "repository owner",
EnvVar: "DRONE_REPO_OWNER",
&cli.StringSliceFlag{
Name: "ciphers",
Usage: "List of allowed SSH encryption algorithms",
EnvVars: []string{"PLUGIN_CIPHERS", "SSH_CIPHERS", "INPUT_CIPHERS"},
},
cli.StringFlag{
Name: "repo.name",
Usage: "repository name",
EnvVar: "DRONE_REPO_NAME",
&cli.BoolFlag{
Name: "useInsecureCipher",
Usage: "Enable less secure encryption algorithms (not recommended)",
EnvVars: []string{"PLUGIN_USE_INSECURE_CIPHER", "SSH_USE_INSECURE_CIPHER", "INPUT_USE_INSECURE_CIPHER"},
},
cli.StringFlag{
Name: "commit.sha",
Usage: "git commit sha",
EnvVar: "DRONE_COMMIT_SHA",
&cli.StringFlag{
Name: "fingerprint",
Usage: "SHA256 fingerprint of host public key for verification",
EnvVars: []string{"PLUGIN_FINGERPRINT", "SSH_FINGERPRINT", "INPUT_FINGERPRINT"},
},
cli.StringFlag{
Name: "commit.branch",
Value: "master",
Usage: "git commit branch",
EnvVar: "DRONE_COMMIT_BRANCH",
&cli.DurationFlag{
Name: "command.timeout",
Usage: "Maximum time allowed for command execution (default: 10m)",
EnvVars: []string{"PLUGIN_COMMAND_TIMEOUT", "SSH_COMMAND_TIMEOUT", "INPUT_COMMAND_TIMEOUT"},
Value: 10 * time.Minute,
},
cli.StringFlag{
Name: "commit.author",
Usage: "git author name",
EnvVar: "DRONE_COMMIT_AUTHOR",
&cli.StringSliceFlag{
Name: "target",
Aliases: []string{"t"},
Usage: "Destination path on remote server",
EnvVars: []string{"PLUGIN_TARGET", "SSH_TARGET", "INPUT_TARGET"},
},
cli.StringFlag{
Name: "commit.message",
Usage: "commit message",
EnvVar: "DRONE_COMMIT_MESSAGE",
&cli.StringSliceFlag{
Name: "source",
Aliases: []string{"s"},
Usage: "Local files/directories to copy",
EnvVars: []string{"PLUGIN_SOURCE", "SCP_SOURCE", "INPUT_SOURCE"},
},
cli.StringFlag{
Name: "build.event",
Value: "push",
Usage: "build event",
EnvVar: "DRONE_BUILD_EVENT",
&cli.BoolFlag{
Name: "rm",
Aliases: []string{"r"},
Usage: "Delete destination folder before copying",
EnvVars: []string{"PLUGIN_RM", "SCP_RM", "INPUT_RM"},
},
cli.IntFlag{
Name: "build.number",
Usage: "build number",
EnvVar: "DRONE_BUILD_NUMBER",
// Proxy settings remain the same as they are already clear
&cli.StringFlag{
Name: "proxy.host",
Usage: "Proxy server host address or IP",
EnvVars: []string{"PLUGIN_PROXY_HOST", "PROXY_SSH_HOST", "INPUT_PROXY_HOST"},
},
cli.StringFlag{
Name: "build.status",
Usage: "build status",
Value: "success",
EnvVar: "DRONE_BUILD_STATUS",
&cli.StringFlag{
Name: "proxy.port",
Usage: "Proxy server SSH port (default: 22)",
EnvVars: []string{"PLUGIN_PROXY_PORT", "PROXY_SSH_PORT", "INPUT_PROXY_PORT"},
Value: "22",
},
cli.StringFlag{
Name: "build.link",
Usage: "build link",
EnvVar: "DRONE_BUILD_LINK",
&cli.StringFlag{
Name: "proxy.protocol",
Usage: "The IP protocol to use for the proxy. Valid values are \"tcp\". \"tcp4\" or \"tcp6\". Default to tcp.",
EnvVars: []string{"PLUGIN_PROXY_PROTOCOL", "SSH_PROXY_PROTOCOL", "INPUT_PROXY_PROTOCOL"},
Value: "tcp",
},
cli.StringFlag{
Name: "env-file",
Usage: "source env file",
&cli.StringFlag{
Name: "proxy.username",
Usage: "connect as user of proxy",
EnvVars: []string{"PLUGIN_PROXY_USERNAME", "PLUGIN_PROXY_USER", "PROXY_SSH_USERNAME", "INPUT_PROXY_USERNAME"},
Value: "root",
},
&cli.StringFlag{
Name: "proxy.password",
Usage: "user password of proxy",
EnvVars: []string{"PLUGIN_PROXY_PASSWORD", "PROXY_SSH_PASSWORD", "INPUT_PROXY_PASSWORD"},
},
&cli.StringFlag{
Name: "proxy.ssh-key",
Usage: "private ssh key of proxy",
EnvVars: []string{"PLUGIN_PROXY_SSH_KEY", "PLUGIN_PROXY_KEY", "PROXY_SSH_KEY", "INPUT_PROXY_KEY"},
},
&cli.StringFlag{
Name: "proxy.ssh-passphrase",
Usage: "The purpose of the passphrase is usually to encrypt the private key.",
EnvVars: []string{"PLUGIN_PROXY_SSH_PASSPHRASE", "PLUGIN_PROXY_PASSPHRASE", "PROXY_SSH_PASSPHRASE", "INPUT_PROXY_PASSPHRASE"},
},
&cli.StringFlag{
Name: "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{
Name: "proxy.timeout",
Usage: "proxy connection 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{
Name: "strip.components",
Usage: "Strip N leading components from file paths",
EnvVars: []string{"PLUGIN_STRIP_COMPONENTS", "TAR_STRIP_COMPONENTS", "INPUT_STRIP_COMPONENTS"},
},
&cli.StringFlag{
Name: "tar.exec",
Usage: "Custom tar executable path on remote host",
EnvVars: []string{"PLUGIN_TAR_EXEC", "SSH_TAR_EXEC", "INPUT_TAR_EXEC"},
Value: "tar",
},
&cli.StringFlag{
Name: "tar.tmp-path",
Usage: "Temporary directory for tar files on remote host",
EnvVars: []string{"PLUGIN_TAR_TMP_PATH", "SSH_TAR_TMP_PATH", "INPUT_TAR_TMP_PATH"},
},
&cli.BoolFlag{
Name: "debug",
Usage: "Enable debug logging",
EnvVars: []string{"PLUGIN_DEBUG", "INPUT_DEBUG"},
},
&cli.BoolFlag{
Name: "overwrite",
Usage: "Force overwrite of existing files",
EnvVars: []string{"PLUGIN_OVERWRITE", "INPUT_OVERWRITE"},
},
&cli.BoolFlag{
Name: "unlink.first",
Usage: "Remove files before extracting new ones",
EnvVars: []string{"PLUGIN_UNLINK_FIRST", "INPUT_UNLINK_FIRST"},
},
&cli.BoolFlag{
Name: "tar.dereference",
Usage: "Follow symbolic links when copying",
EnvVars: []string{"PLUGIN_TAR_DEREFERENCE", "INPUT_TAR_DEREFERENCE"},
},
}
app.Run(os.Args)
// Override a template
cli.AppHelpTemplate = `
________ ____________________________
\______ \_______ ____ ____ ____ / _____/\_ ___ \______ \
| | \_ __ \/ _ \ / \_/ __ \ ______ \_____ \ / \ \/| ___/
| | \ | \( <_> ) | \ ___/ /_____/ / \\ \___| |
/_______ /__| \____/|___| /\___ > /_______ / \______ /____|
\/ \/ \/ \/ \/
version: {{.Version}}
NAME:
{{.Name}} - {{.Usage}}
USAGE:
{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
{{if len .Authors}}
AUTHOR:
{{range .Authors}}{{ . }}{{end}}
{{end}}{{if .Commands}}
COMMANDS:
{{range .Commands}}{{if not .HideHelp}} {{join .Names ", "}}{{ "\t"}}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
GLOBAL OPTIONS:
{{range .VisibleFlags}}{{.}}
{{end}}{{end}}{{if .Copyright }}
COPYRIGHT:
{{.Copyright}}
{{end}}{{if .Version}}
VERSION:
{{.Version}}
{{end}}
REPOSITORY:
Github: https://github.com/appleboy/drone-scp
`
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
func run(c *cli.Context) error {
if c.String("env-file") != "" {
_ = godotenv.Load(c.String("env-file"))
plugin := Plugin{
Config: Config{
Host: c.StringSlice("host"),
Port: c.Int("port"),
Protocol: easyssh.Protocol(c.String("protocol")),
Username: c.String("username"),
Password: c.String("password"),
Passphrase: c.String("ssh-passphrase"),
Fingerprint: c.String("fingerprint"),
Timeout: c.Duration("timeout"),
CommandTimeout: c.Duration("command.timeout"),
Key: c.String("ssh-key"),
KeyPath: c.String("key-path"),
Target: c.StringSlice("target"),
Source: c.StringSlice("source"),
Remove: c.Bool("rm"),
Debug: c.Bool("debug"),
StripComponents: c.Int("strip.components"),
TarExec: c.String("tar.exec"),
TarTmpPath: c.String("tar.tmp-path"),
Overwrite: c.Bool("overwrite"),
UnlinkFirst: c.Bool("unlink.first"),
Ciphers: c.StringSlice("ciphers"),
UseInsecureCipher: c.Bool("useInsecureCipher"),
TarDereference: c.Bool("tar.dereference"),
Proxy: easyssh.DefaultConfig{
Key: c.String("proxy.ssh-key"),
Passphrase: c.String("proxy.ssh-passphrase"),
Fingerprint: c.String("proxy.fingerprint"),
KeyPath: c.String("proxy.key-path"),
User: c.String("proxy.username"),
Password: c.String("proxy.password"),
Server: c.String("proxy.host"),
Port: c.String("proxy.port"),
Protocol: easyssh.Protocol(c.String("proxy.protocol")),
Timeout: c.Duration("proxy.timeout"),
Ciphers: c.StringSlice("proxy.ciphers"),
UseInsecureCipher: c.Bool("proxy.useInsecureCipher"),
},
},
}
plugin := Plugin{
Repo: Repo{
Owner: c.String("repo.owner"),
Name: c.String("repo.name"),
},
Build: Build{
Number: c.Int("build.number"),
Event: c.String("build.event"),
Status: c.String("build.status"),
Commit: c.String("commit.sha"),
Branch: c.String("commit.branch"),
Author: c.String("commit.author"),
Message: c.String("commit.message"),
Link: c.String("build.link"),
},
Config: Config{
Host: c.StringSlice("host"),
Port: c.String("port"),
Username: c.String("username"),
Password: c.String("password"),
Key: c.String("key"),
KeyPath: c.String("key-path"),
Target: c.StringSlice("target"),
Source: c.StringSlice("source"),
Remove: c.Bool("rm"),
},
if plugin.Config.Debug {
_ = godump.Dump(plugin)
}
return plugin.Exec()
+2 -1
View File
@@ -1,4 +1,5 @@
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
//go:build !windows
// +build !windows
package main
+2 -1
View File
@@ -1,3 +1,4 @@
//go:build windows
// +build windows
package main
@@ -7,5 +8,5 @@ import (
)
func getRealPath(path string) string {
return "/" + strings.Replace(strings.Replace(path, ":", "", -1), "\\", "/", -1)
return "/" + strings.ReplaceAll(strings.ReplaceAll(path, ":", ""), "\\", "/")
}
+5 -3
View File
@@ -1,6 +1,8 @@
package main
import "testing"
import (
"testing"
)
func TestGetRealPath(t *testing.T) {
type args struct {
@@ -14,8 +16,8 @@ func TestGetRealPath(t *testing.T) {
{
"Test Windows Path",
"C:\\Users\\appleboy\\test.txt",
"/C/Users/appleboy/test.txt"
}
"/C/Users/appleboy/test.txt",
},
}
for _, tt := range tests {
if got := getRealPath(tt.args.path); got != tt.want {
+323 -94
View File
@@ -3,174 +3,365 @@ package main
import (
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
"github.com/appleboy/com/random"
"github.com/appleboy/drone-scp/easyssh"
"github.com/appleboy/easyssh-proxy"
"github.com/fatih/color"
)
var (
errMissingHost = errors.New("Error: missing server host")
errMissingPasswordOrKey = errors.New("Error: can't connect without a private SSH key or password")
errMissingSourceOrTarget = errors.New("missing source or target config")
)
type (
// Repo information.
Repo struct {
Owner string
Name string
}
// Build information.
Build struct {
Event string
Number int
Commit string
Message string
Branch string
Author string
Status string
Link string
}
// Config for the plugin.
Config struct {
Host []string
Port string
Username string
Password string
Key string
KeyPath string
Target []string
Source []string
Remove bool
Host []string
Port int
Protocol easyssh.Protocol
Username string
Password string
Key string
Passphrase string
Fingerprint string
KeyPath string
Timeout time.Duration
CommandTimeout time.Duration
Target []string
Source []string
Remove bool
StripComponents int
TarExec string
TarTmpPath string
Proxy easyssh.DefaultConfig
Debug bool
Overwrite bool
UnlinkFirst bool
Ciphers []string
UseInsecureCipher bool
TarDereference bool
}
// Plugin values.
Plugin struct {
Repo Repo
Build Build
Config Config
Config Config
DestFile string
}
copyError struct {
host string
message string
}
)
var wg sync.WaitGroup
func (e copyError) Error() string {
return fmt.Sprintf("error copy file to dest: %s, error message: %s\n", e.host, e.message)
}
func trimPath(keys []string) []string {
var newKeys []string
func globList(paths []string) fileList {
var list fileList
for _, value := range keys {
value = strings.Trim(value, " ")
if len(value) == 0 {
for _, pattern := range paths {
ignore := false
pattern = strings.TrimSpace(pattern)
if string(pattern[0]) == "!" {
pattern = pattern[1:]
ignore = true
}
matches, err := filepath.Glob(pattern)
if err != nil {
fmt.Printf("Glob error for %q: %s\n", pattern, err)
continue
}
newKeys = append(newKeys, value)
if ignore {
list.Ignore = append(list.Ignore, matches...)
} else {
list.Source = append(list.Source, matches...)
}
}
return newKeys
return list
}
func (p Plugin) log(host string, message ...interface{}) {
log.Printf("%s: %s", host, fmt.Sprintln(message...))
if count := len(p.Config.Host); count == 1 {
fmt.Printf("%s", fmt.Sprintln(message...))
} else {
fmt.Printf("%s: %s", host, fmt.Sprintln(message...))
}
}
// Exec executes the plugin.
func (p Plugin) Exec() error {
if len(p.Config.Host) == 0 || len(p.Config.Username) == 0 {
return errors.New("missing ssh config (Host, Username)")
}
if len(p.Config.Source) == 0 || len(p.Config.Target) == 0 {
return errors.New("missing source or target config")
}
files := trimPath(p.Config.Source)
dest := fmt.Sprintf("%s.tar", random.String(10))
// create a temporary file for the archive
dir, err := ioutil.TempDir("", "")
func (p *Plugin) removeDestFile(os string, ssh *easyssh.MakeConfig) error {
p.log(ssh.Server, "remove file", p.DestFile)
_, errStr, _, err := ssh.Run(rmcmd(os, p.DestFile), p.Config.CommandTimeout)
if err != nil {
return err
}
tar := filepath.Join(dir, dest)
if errStr != "" {
return errors.New(errStr)
}
return nil
}
func (p *Plugin) removeAllDestFile() error {
for _, h := range trimValues(p.Config.Host) {
host, port := p.hostPort(h)
ssh := &easyssh.MakeConfig{
Server: host,
User: p.Config.Username,
Password: p.Config.Password,
Port: port,
Protocol: p.Config.Protocol,
Key: p.Config.Key,
KeyPath: p.Config.KeyPath,
Passphrase: p.Config.Passphrase,
Timeout: p.Config.Timeout,
Ciphers: p.Config.Ciphers,
Fingerprint: p.Config.Fingerprint,
UseInsecureCipher: p.Config.UseInsecureCipher,
Proxy: easyssh.DefaultConfig{
Server: p.Config.Proxy.Server,
User: p.Config.Proxy.User,
Password: p.Config.Proxy.Password,
Port: p.Config.Proxy.Port,
Protocol: p.Config.Proxy.Protocol,
Key: p.Config.Proxy.Key,
KeyPath: p.Config.Proxy.KeyPath,
Passphrase: p.Config.Proxy.Passphrase,
Timeout: p.Config.Proxy.Timeout,
Ciphers: p.Config.Proxy.Ciphers,
Fingerprint: p.Config.Proxy.Fingerprint,
UseInsecureCipher: p.Config.Proxy.UseInsecureCipher,
},
}
_, _, _, err := ssh.Run("ver", p.Config.CommandTimeout)
systemType := "unix"
if err == nil {
systemType = "windows"
}
// remove tar file
err = p.removeDestFile(systemType, ssh)
if err != nil {
return err
}
}
return nil
}
type fileList struct {
Ignore []string
Source []string
}
func (p *Plugin) buildTarArgs(src string) []string {
files := globList(trimValues(p.Config.Source))
args := []string{}
if len(files.Ignore) > 0 {
for _, v := range files.Ignore {
args = append(args, "--exclude")
args = append(args, v)
}
}
if p.Config.TarDereference {
args = append(args, "--dereference")
}
args = append(args, "-zcf")
args = append(args, getRealPath(src))
args = append(args, files.Source...)
return args
}
func (p *Plugin) buildUnTarArgs(target string) []string {
args := []string{}
args = append(args,
p.Config.TarExec,
"-zxf",
p.DestFile,
)
if p.Config.StripComponents > 0 {
args = append(args, "--strip-components")
args = append(args, strconv.Itoa(p.Config.StripComponents))
}
if p.Config.Overwrite {
args = append(args, "--overwrite")
}
if p.Config.UnlinkFirst {
args = append(args, "--unlink-first")
}
args = append(args,
"-C",
target,
)
return args
}
// Exec executes the plugin.
func (p *Plugin) Exec() error {
if len(p.Config.Key) == 0 && len(p.Config.Password) == 0 && len(p.Config.KeyPath) == 0 {
return errMissingPasswordOrKey
}
if len(p.Config.Source) == 0 || len(p.Config.Target) == 0 {
return errMissingSourceOrTarget
}
hosts := trimValues(p.Config.Host)
if len(hosts) == 0 {
return errMissingHost
}
p.DestFile = random.String(10) + ".tar.gz"
// create a temporary file for the archive
dir := os.TempDir()
src := filepath.Join(dir, p.DestFile)
// show current version
fmt.Println("drone-scp version: " + Version)
// run archive command
log.Println("tar all files into " + tar)
args := append(append([]string{}, "-cf", getRealPath(tar)), files...)
cmd := exec.Command("tar", args...)
fmt.Println("tar all files into " + src)
args := p.buildTarArgs(src)
cmd := exec.Command(p.Config.TarExec, args...)
if p.Config.Debug {
fmt.Println("$", strings.Join(cmd.Args, " "))
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return err
}
wg := sync.WaitGroup{}
wg.Add(len(p.Config.Host))
errChannel := make(chan error, 1)
finished := make(chan bool, 1)
for _, host := range p.Config.Host {
go func(host string) {
errChannel := make(chan error)
finished := make(chan struct{})
for _, host := range hosts {
go func(h string) {
defer wg.Done()
host, port := p.hostPort(h)
// Create MakeConfig instance with remote username, server address and path to private key.
ssh := &easyssh.MakeConfig{
Server: host,
User: p.Config.Username,
Password: p.Config.Password,
Port: p.Config.Port,
Key: p.Config.Key,
KeyPath: p.Config.KeyPath,
Server: host,
User: p.Config.Username,
Password: p.Config.Password,
Port: port,
Key: p.Config.Key,
KeyPath: p.Config.KeyPath,
Passphrase: p.Config.Passphrase,
Timeout: p.Config.Timeout,
Ciphers: p.Config.Ciphers,
Fingerprint: p.Config.Fingerprint,
UseInsecureCipher: p.Config.UseInsecureCipher,
Proxy: easyssh.DefaultConfig{
Server: p.Config.Proxy.Server,
User: p.Config.Proxy.User,
Password: p.Config.Proxy.Password,
Port: p.Config.Proxy.Port,
Key: p.Config.Proxy.Key,
KeyPath: p.Config.Proxy.KeyPath,
Passphrase: p.Config.Proxy.Passphrase,
Timeout: p.Config.Proxy.Timeout,
Ciphers: p.Config.Proxy.Ciphers,
Fingerprint: p.Config.Proxy.Fingerprint,
UseInsecureCipher: p.Config.Proxy.UseInsecureCipher,
},
}
systemType := "unix"
_, _, _, err := ssh.Run("ver", p.Config.CommandTimeout)
if err == nil {
systemType = "windows"
}
// upload file to the tmp path
p.DestFile = fmt.Sprintf("%s%s", p.Config.TarTmpPath, p.DestFile)
p.log(host, "remote server os type is "+systemType)
// Call Scp method with file you want to upload to remote server.
p.log(host, "scp file to server.")
err = ssh.Scp(tar)
// Handle errors
err = ssh.Scp(src, p.DestFile)
if err != nil {
errChannel <- err
errChannel <- copyError{host, err.Error()}
return
}
for _, target := range p.Config.Target {
// remove target before upload data
target = strings.ReplaceAll(target, " ", "\\ ")
// remove target folder before upload data
if p.Config.Remove {
p.log(host, "Remove target folder:", target)
_, err := ssh.Run(fmt.Sprintf("rm -rf %s", target))
_, _, _, err := ssh.Run(rmcmd(systemType, target), p.Config.CommandTimeout)
if err != nil {
errChannel <- err
return
}
}
// mkdir path
p.log(host, "create folder", target)
response, _ := ssh.Run(fmt.Sprintf("mkdir -p %s", target))
_, errStr, _, err := ssh.Run(mkdircmd(systemType, target), p.Config.CommandTimeout)
if err != nil {
errChannel <- err
return
}
if response != "" {
errChannel <- errors.New(response)
if len(errStr) != 0 {
errChannel <- fmt.Errorf("%s", errStr)
return
}
// untar file
p.log(host, "untar file", dest)
_, err = ssh.Run(fmt.Sprintf("tar -xf %s -C %s", dest, target))
p.log(host, "untar file", p.DestFile)
commamd := strings.Join(p.buildUnTarArgs(target), " ")
if p.Config.Debug {
fmt.Println("$", commamd)
}
outStr, errStr, _, err := ssh.Run(commamd, p.Config.CommandTimeout)
if outStr != "" {
p.log(host, "output: ", outStr)
}
if errStr != "" {
p.log(host, "error: ", errStr)
}
if err != nil {
errChannel <- err
return
}
}
// remove tar file
p.log(host, "remove file", dest)
_, err = ssh.Run(fmt.Sprintf("rm -rf %s", dest))
err = p.removeDestFile(systemType, ssh)
if err != nil {
errChannel <- err
return
}
wg.Done()
}(host)
}
@@ -183,12 +374,50 @@ func (p Plugin) Exec() error {
case <-finished:
case err := <-errChannel:
if err != nil {
fmt.Println("drone-scp error: ", err)
c := color.New(color.FgRed)
c.Println("drone-scp error: ", err)
var cerr copyError
if !errors.As(err, &cerr) {
fmt.Println("drone-scp rollback: remove all target tmp file")
if err := p.removeAllDestFile(); err != nil {
return err
}
}
return err
}
}
fmt.Println("Successfully executed transfer data to all host.")
fmt.Println("===================================================")
fmt.Println("✅ Successfully executed transfer data to all host")
fmt.Println("===================================================")
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
}
+823 -37
View File
@@ -1,12 +1,19 @@
package main
import (
"github.com/stretchr/testify/assert"
"io"
"log"
"os"
"os/exec"
"os/user"
"path/filepath"
"reflect"
"testing"
"time"
"github.com/appleboy/easyssh-proxy"
"github.com/stretchr/testify/assert"
"golang.org/x/crypto/ssh"
)
func TestMissingAllConfig(t *testing.T) {
@@ -35,7 +42,7 @@ func TestMissingSourceConfig(t *testing.T) {
Config: Config{
Host: []string{"example.com"},
Username: "ubuntu",
Port: "443",
Port: 443,
Password: "1234",
},
}
@@ -51,17 +58,19 @@ func TestTrimElement(t *testing.T) {
input = []string{"1", " ", "3"}
result = []string{"1", "3"}
assert.Equal(t, result, trimPath(input))
assert.Equal(t, result, trimValues(input))
input = []string{"1", "2"}
result = []string{"1", "2"}
assert.Equal(t, result, trimPath(input))
assert.Equal(t, result, trimValues(input))
}
func TestSCPFileFromPublicKey(t *testing.T) {
if os.Getenv("SSH_AUTH_SOCK") != "" {
exec.Command("eval", "`ssh-agent -k`").Run()
if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil {
t.Fatalf("exec: %v", err)
}
}
u, err := user.Lookup("drone-scp")
@@ -71,12 +80,14 @@ func TestSCPFileFromPublicKey(t *testing.T) {
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{u.HomeDir + "/test"},
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, "/test")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
},
}
@@ -84,11 +95,11 @@ func TestSCPFileFromPublicKey(t *testing.T) {
assert.Nil(t, err)
// check file exist
if _, err := os.Stat(u.HomeDir + "/test/tests/a.txt"); os.IsNotExist(err) {
if _, err := os.Stat(filepath.Join(u.HomeDir, "/test/tests/a.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
if _, err := os.Stat(u.HomeDir + "/test/tests/b.txt"); os.IsNotExist(err) {
if _, err := os.Stat(filepath.Join(u.HomeDir, "/test/tests/b.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
@@ -100,7 +111,323 @@ func TestSCPFileFromPublicKey(t *testing.T) {
assert.Nil(t, err)
// check file exist
if _, err := os.Stat(u.HomeDir + "/test/tests/b.txt"); os.IsExist(err) {
if _, err := os.Stat(filepath.Join(u.HomeDir, "/test/tests/b.txt")); os.IsExist(err) {
t.Fatalf("SCP-error: %v", err)
}
}
func TestSCPFileFromPublicKeyWithPassphrase(t *testing.T) {
if os.Getenv("SSH_AUTH_SOCK") != "" {
if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil {
t.Fatalf("exec: %v", err)
}
}
u, err := user.Lookup("drone-scp")
if err != nil {
t.Fatalf("Lookup: %v", err)
}
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "tests/.ssh/test",
Passphrase: "1234",
Source: []string{"tests/a.txt", "tests/b.txt"},
Target: []string{filepath.Join(u.HomeDir, "/test2")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
},
}
err = plugin.Exec()
assert.Nil(t, err)
// check file exist
if _, err := os.Stat(filepath.Join(u.HomeDir, "/test2/tests/a.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
if _, err := os.Stat(filepath.Join(u.HomeDir, "/test2/tests/b.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
}
func TestWrongFingerprint(t *testing.T) {
u, err := user.Lookup("drone-scp")
if err != nil {
t.Fatalf("Lookup: %v", err)
}
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Source: []string{"tests/a.txt", "tests/b.txt"},
Target: []string{filepath.Join(u.HomeDir, "/test2")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
Fingerprint: "wrong",
},
}
err = plugin.Exec()
log.Println(err)
assert.NotNil(t, err)
}
func getHostPublicKeyFile(keypath string) (ssh.PublicKey, error) {
var pubkey ssh.PublicKey
var err error
buf, err := os.ReadFile(keypath)
if err != nil {
return nil, err
}
pubkey, _, _, _, err = ssh.ParseAuthorizedKey(buf)
if err != nil {
return nil, err
}
return pubkey, nil
}
func TestSCPFileFromPublicKeyWithFingerprint(t *testing.T) {
if os.Getenv("SSH_AUTH_SOCK") != "" {
if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil {
t.Fatalf("exec: %v", err)
}
}
u, err := user.Lookup("drone-scp")
if err != nil {
t.Fatalf("Lookup: %v", err)
}
hostKey, err := getHostPublicKeyFile("/etc/ssh/ssh_host_rsa_key.pub")
assert.NoError(t, err)
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Fingerprint: ssh.FingerprintSHA256(hostKey),
Source: []string{"tests/a.txt", "tests/b.txt"},
Target: []string{filepath.Join(u.HomeDir, "/test2")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
},
}
err = plugin.Exec()
assert.Nil(t, err)
// check file exist
if _, err := os.Stat(filepath.Join(u.HomeDir, "/test2/tests/a.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
if _, err := os.Stat(filepath.Join(u.HomeDir, "/test2/tests/b.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
}
func TestSCPWildcardFileList(t *testing.T) {
if os.Getenv("SSH_AUTH_SOCK") != "" {
if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil {
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/*"},
Target: []string{filepath.Join(u.HomeDir, "abc")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
},
}
err = plugin.Exec()
assert.Nil(t, err)
// check file exist
if _, err := os.Stat(filepath.Join(u.HomeDir, "abc/tests/global/c.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
if _, err := os.Stat(filepath.Join(u.HomeDir, "abc/tests/global/d.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
}
func TestSCPFromProxySetting(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/*"},
Target: []string{filepath.Join(u.HomeDir, "def")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
Proxy: easyssh.DefaultConfig{
Server: "localhost",
User: "drone-scp",
Port: "22",
KeyPath: "./tests/.ssh/id_rsa",
},
},
}
err = plugin.Exec()
assert.Nil(t, err)
// check file exist
if _, err := os.Stat(filepath.Join(u.HomeDir, "def/tests/global/c.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
if _, err := os.Stat(filepath.Join(u.HomeDir, "def/tests/global/d.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
}
func TestStripComponentsFlag(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")},
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/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 TestUseInsecureCipherFlag(t *testing.T) {
u, err := user.Lookup("drone-scp")
if err != nil {
t.Fatalf("Lookup: %v", err)
}
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "tests/.ssh/id_rsa",
Source: []string{"tests/global/*"},
StripComponents: 2,
Target: []string{filepath.Join(u.HomeDir, "123")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
UseInsecureCipher: true,
},
}
err = plugin.Exec()
assert.Nil(t, err)
// check file exist
if _, err := os.Stat(filepath.Join(u.HomeDir, "123/c.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
if _, err := os.Stat(filepath.Join(u.HomeDir, "123/d.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
}
func TestIgnoreList(t *testing.T) {
if os.Getenv("SSH_AUTH_SOCK") != "" {
if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil {
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/*", "!tests/global/c.txt", "!tests/global/e.txt"},
StripComponents: 2,
Target: []string{filepath.Join(u.HomeDir, "ignore")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
Debug: true,
},
}
err = plugin.Exec()
assert.Nil(t, err)
// check file exist
if _, err := os.Stat(filepath.Join(u.HomeDir, "ignore/c.txt")); !os.IsNotExist(err) {
t.Fatal("c.txt file exist")
}
// check file exist
if _, err := os.Stat(filepath.Join(u.HomeDir, "ignore/e.txt")); !os.IsNotExist(err) {
t.Fatal("c.txt file exist")
}
if _, err := os.Stat(filepath.Join(u.HomeDir, "ignore/d.txt")); os.IsNotExist(err) {
t.Fatalf("SCP-error: %v", err)
}
}
@@ -154,12 +481,14 @@ func TestSCPFileFromPublicKey(t *testing.T) {
func TestIncorrectPassword(t *testing.T) {
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: "22",
Password: "123456",
Source: []string{"tests/a.txt", "tests/b.txt"},
Target: []string{"/home"},
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
Password: "123456",
Source: []string{"tests/a.txt", "tests/b.txt"},
Target: []string{"/home"},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
},
}
@@ -168,33 +497,490 @@ func TestIncorrectPassword(t *testing.T) {
}
func TestNoPermissionCreateFolder(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{"/etc/test"},
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "tests/.ssh/id_rsa",
Source: []string{"tests/a.txt", "tests/b.txt"},
Target: []string{"/etc/test"},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
},
}
err := plugin.Exec()
err = plugin.Exec()
assert.NotNil(t, err)
// check tmp file exist
if _, err = os.Stat(filepath.Join(u.HomeDir, plugin.DestFile)); os.IsExist(err) {
t.Fatalf("SCP-error: %v", err)
}
}
func TestSourceNotFound(t *testing.T) {
func TestGlobList(t *testing.T) {
// wrong patern
paterns := []string{"[]a]", "tests/?.txt"}
expects := []string{"tests/a.txt", "tests/b.txt"}
assert.Equal(t, expects, globList(paterns).Source)
paterns = []string{"tests/*.txt", "tests/.ssh/*", "abc*"}
expects = []string{"tests/a.txt", "tests/b.txt", "tests/.ssh/id_rsa", "tests/.ssh/id_rsa.pub", "tests/.ssh/test", "tests/.ssh/test.pub"}
assert.Equal(t, expects, globList(paterns).Source)
paterns = []string{"tests/?.txt"}
expects = []string{"tests/a.txt", "tests/b.txt"}
assert.Equal(t, expects, globList(paterns).Source)
// remove item which file not found.
paterns = []string{"tests/aa.txt", "tests/b.txt"}
expects = []string{"tests/b.txt"}
assert.Equal(t, expects, globList(paterns).Source)
paterns = []string{"./tests/b.txt"}
expects = []string{"./tests/b.txt"}
assert.Equal(t, expects, globList(paterns).Source)
paterns = []string{"./tests/*.txt", "!./tests/b.txt"}
expectSources := []string{"tests/a.txt", "tests/b.txt"}
expectIgnores := []string{"./tests/b.txt"}
result := globList(paterns)
assert.Equal(t, expectSources, result.Source)
assert.Equal(t, expectIgnores, result.Ignore)
}
func TestRemoveDestFile(t *testing.T) {
ssh := &easyssh.MakeConfig{
Server: "localhost",
User: "drone-scp",
Port: "22",
KeyPath: "tests/.ssh/id_rsa",
// io timeout
Timeout: 1,
}
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: "22",
KeyPath: "tests/.ssh/id_rsa",
Source: []string{"tests/aa.txt", "tests/b.txt"},
Target: []string{"/test"},
CommandTimeout: 60 * time.Second,
},
DestFile: "/etc/resolv.conf",
}
_, _, _, err := ssh.Run("ver", plugin.Config.CommandTimeout)
systemType := "unix"
if err == nil {
systemType = "windows"
}
// ssh io timeout
err = plugin.removeDestFile(systemType, ssh)
assert.Error(t, err)
ssh.Timeout = 0
// permission denied
err = plugin.removeDestFile(systemType, ssh)
assert.Error(t, err)
}
func TestPlugin_buildUnTarArgs(t *testing.T) {
type fields struct {
Config Config
DestFile string
}
type args struct {
target string
}
tests := []struct {
name string
fields fields
args args
want []string
}{
{
name: "default command",
fields: fields{
Config: Config{
Overwrite: false,
UnlinkFirst: false,
TarExec: "tar",
},
DestFile: "foo.tar.gz",
},
args: args{
target: "foo",
},
want: []string{"tar", "-zxf", "foo.tar.gz", "-C", "foo"},
},
{
name: "strip components",
fields: fields{
Config: Config{
Overwrite: false,
UnlinkFirst: false,
TarExec: "tar",
StripComponents: 2,
},
DestFile: "foo.tar.gz",
},
args: args{
target: "foo",
},
want: []string{"tar", "-zxf", "foo.tar.gz", "--strip-components", "2", "-C", "foo"},
},
{
name: "overwrite",
fields: fields{
Config: Config{
TarExec: "tar",
StripComponents: 2,
Overwrite: true,
UnlinkFirst: false,
},
DestFile: "foo.tar.gz",
},
args: args{
target: "foo",
},
want: []string{"tar", "-zxf", "foo.tar.gz", "--strip-components", "2", "--overwrite", "-C", "foo"},
},
{
name: "unlink first",
fields: fields{
Config: Config{
TarExec: "tar",
StripComponents: 2,
Overwrite: true,
UnlinkFirst: true,
},
DestFile: "foo.tar.gz",
},
args: args{
target: "foo",
},
want: []string{"tar", "-zxf", "foo.tar.gz", "--strip-components", "2", "--overwrite", "--unlink-first", "-C", "foo"},
},
{
name: "output folder path with space",
fields: fields{
Config: Config{
TarExec: "tar",
StripComponents: 2,
Overwrite: true,
UnlinkFirst: true,
},
DestFile: "foo.tar.gz",
},
args: args{
target: "foo\\ bar",
},
want: []string{"tar", "-zxf", "foo.tar.gz", "--strip-components", "2", "--overwrite", "--unlink-first", "-C", "foo\\ bar"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := &Plugin{
Config: tt.fields.Config,
DestFile: tt.fields.DestFile,
}
if got := p.buildUnTarArgs(tt.args.target); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Plugin.buildArgs() = %v, want %v", got, tt.want)
}
})
}
}
func TestPlugin_buildTarArgs(t *testing.T) {
type fields struct {
Config Config
}
type args struct {
src string
}
tests := []struct {
name string
fields fields
args args
want []string
}{
{
name: "default command",
fields: fields{
Config: Config{
TarExec: "tar",
},
},
args: args{
src: "foo.tar.gz",
},
want: []string{"-zcf", "foo.tar.gz"},
},
{
name: "ignore list",
fields: fields{
Config: Config{
TarExec: "tar",
Source: []string{
"tests/*.txt",
"!tests/a.txt",
},
},
},
args: args{
src: "foo.tar.gz",
},
want: []string{"--exclude", "tests/a.txt", "-zcf", "foo.tar.gz", "tests/a.txt", "tests/b.txt"},
},
{
name: "dereference flag",
fields: fields{
Config: Config{
TarExec: "tar",
TarDereference: true,
Source: []string{
"tests/*.txt",
"!tests/a.txt",
},
},
},
args: args{
src: "foo.tar.gz",
},
want: []string{"--exclude", "tests/a.txt", "--dereference", "-zcf", "foo.tar.gz", "tests/a.txt", "tests/b.txt"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := &Plugin{
Config: tt.fields.Config,
}
if got := p.buildTarArgs(tt.args.src); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Plugin.buildTarArgs() = %v, want %v", got, tt.want)
}
})
}
}
func TestTargetFolderWithSpaces(t *testing.T) {
if os.Getenv("SSH_AUTH_SOCK") != "" {
if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil {
t.Fatalf("exec: %v", err)
}
}
u, err := user.Lookup("drone-scp")
if err != nil {
t.Fatalf("Lookup: %v", err)
}
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "tests/.ssh/id_rsa",
Source: []string{"tests/global/*"},
StripComponents: 2,
Target: []string{filepath.Join(u.HomeDir, "123 456 789")},
CommandTimeout: 60 * time.Second,
TarExec: "tar",
},
}
err := plugin.Exec()
assert.NotNil(t, err)
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)
}
}
+50
View File
@@ -0,0 +1,50 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAZka7A7i
FscMeJBPyPteclAAAAEAAAAAEAAAIXAAAAB3NzaC1yc2EAAAADAQABAAACAQDz6aZ1jY2o
nnuj2YNHJ/HhfvIu0B973v/+pFFOavnTUOhEEKEy3TASu+s9CkHrYZAtRc+QYIkNZI31mh
HBhotdeP/7GoO2UirkFtrzyQKPNJxEcv0RBoG9ssN8jex0PyK6DHIYYFnIWadVBEEOh/H+
rK7j7u2/big3oTzYBuFrCwmYFcz5na99MzFeAUhazF44gVBma+zO+1quGeqF51UDIg1SMG
vX8I7LNEqrKEBaIUQJKFQcxlOWlRLQsjJCymrOujsXsRrXHAQWcnxDcNevv2ZMOUl0ybvv
9yH0BiGbRBd1Hy8/QPILbAQaqu0oQE7fubN8Q8lqb3Jg0loID4x/5GPhSY8WAXpuLcXTOr
b93SnCw1JsAgJDNqpuuRFy3BSZ7wBOr1jfeIoo7xk14OHiUjJ0uXDL9cLMkcw6ElWz81mr
D2VCkXUz+qFyjJ+G7aGWRtctZoOzKln4yfNfUmwW8/8ra3QnmrMZ2xW2Ylw3ZhO+tLi7jI
NHYFb54bAdLVPUU1ctIuJns2qkWnjJCxxMiynIqCif20/OU1n8CTJuOWiURmRdmvKOH4PE
3JxC2Qnk/3tV3Cf8hp1CH5VjBZ9AjGj5MDMHXyu34VY2WvYo5QyzfS3ySPoT8kCO0G0xpv
jwCMHOK+G2RP4kqb/KKZguiKdgintBXuskTlJmD7kcMQAAB1CnEMQGwAKZbd3F1DJqwfPf
KWjoUJKbTRiav6h5pQr65JaqDe/7YE2ZHYo5917AC2vPLwPxAnoHFMsbObd5mWcmpATg/0
K/qkN5Z4Ml5U3bwr51wfSPh1MiAP21Aickt09BDstIJzNNwwgcY31O3k/d6VBjqyM6Ezop
66LI4s/IIni1BI+cALyEfzE4Qu16GfzIeM+JVxildP4VImhvNBESmmbBL8rNmSzlQ+FTuF
JVmowUbcon1O0CppM1MRVPeG805XDwjxHXKwOp5O7MdTz7H8JeORoe8D6+4rNfJE0eQGY7
Nm4+Wa97HzAFbT9IS433rxoGx9Qps3LAySFONso2JWSOEfo8rxnqO04DrfVHQhY3DkkwQt
FsDnMtkthJa+ZzUYc75fnS0DBPGuF9DZUCqrev5oAUHP6C4Vc4b33JJQD4FZJ+ehk3Xsci
cwJQsmgLyc5Jdh543Dm7kZoM9ku7HDNrB4H/1p45Vo6aBZMAY50x+fTdBeTgCzzhzzTbf+
0IF8W3yW3/BYD+S2Byo3JKp6NH0Q8cgPJrGTl6GltGfpVuc6kLjMZ5zvxRbyWaqtIygM46
W1izbA+9jwbHhitCtOk42e/ff6iEB1MVC13LqPty3gPNR8Pv0rDUDjJS4KiVwXqUY+bMr0
C8l/hx93euHjLUJ49Ru6uy/2fBlHZEj6GmEAJhu/i6t2c1Rq0HBLis9X356oQT+YZnIai2
ym0MknPxjeYBAItOV3zhRd1cYnk7CDcl1XALcnh0tqP712x24IJ+Ytqg7nvB2NZV8T469I
8Fp254Nr89HOMAXaZD0UcIPm7D2rfWV+YJFI3ZcJ/8DM99H3tpXe2j4oHMdmAbBd++09sx
KBRdFLcvnBfd1lqwxpA7hbxzrxi/yehYCqzh5KQGaf2UXej6TPiVzBWVYbp34cMZtsT6mF
K8SS3l5TXoNK2DNEk30o8K3q+vngQpfC9GZ/id4B7LS/3ybellxemZHXQoU4PxDkLKt7jd
AAsd5WO13dv3n/qgyu8iBRiFU+W66NX0RJGkp+lZMnta0YzukafM2n6GDn/r/Cx/y21PAi
ah8i41ByI1QLI4m1r+bRHdUxAarS/XJw4tTSFiZu3zddMYrlzeG9O3VUX9zBvBtfQbSmeJ
omml0zlr/qD7TMsORiujy7XIn7sMW+Ls/NA8TvX8oRnACjXe/MYNEZ8WDu2rkZuY/Dfc+o
NyYWO7kZ3kcejQZ1NusJSA7MG0FFGYSIaC9T9CWqYd5IcRSJW4dZnCt9z8CIJ6TSUFqMb/
H1Y5Rmi0IIX+8qbGGXVBDIBk5y9xtS43+nz1nsdXwDmkTiXN9+ZX+GDsLxCWoHGryrWDbk
EuOAlqpvxFKzEkNsx+AC5wae6i/hBeiEce9bm4nZp+hFv1ic1Z9WS8B37YOFgJ4utGeOjB
6hnywUUJ3aH0LnCQNB3UzeFR7BmEaxmYD/phJodmjA5SD3CWpeizdXfrUjtqXGhYlr2jzq
vBAeeYEO4uaHIGxg8GqoqtaseqVcIdtouHxrVAxxXkjShV2ji7oJ/AtrLZNlkKYxMk0TpX
fFiKqL/uKfS78FfvVOhOkHZTD6ZeMgmdL/uOghEAtrf08ChyRvdp7QLjA802aio9eUVIQm
lHb1ltPEbIZNuvQ5kTIwk2eM6EAkOh0MBMoAYOxOpIb00XHNRDGJYuLewByjMQa8EoT6VM
NoiFIzJU9lLAXE6yz6JswctpTpLHK9Aq5vY7ObaOvrmpCQqsXfOuVUo2nR/FyEes97zuXG
E4aKaHK4IAW4UY/oGYk7pU/yRpudhiNRMXzmcQXfVmBEHuvDrh2chg8lDYn++07F7RWqkI
nfMAOWR8UEl4xp4zJtThDjRxNW6QLl8E1ADjndA9wVaKNSzv2i1TLXKBr5luFqY9MSJ2rm
yBR5EwairH/Qn9TUxaDD+0p6J+E9iz1l8UPTJa/cjtwiySljahY/6tHHnr9YQVnox92yfU
UXpfINGjYrpqh6EFwmyRw9fryIMvMhgZYo6ZoCRBCK2GfGAB0VTzJy2FGs4GecZK5ptXKu
sOX8BgGX/Q/nAJ7PWf9hgYlX2YyjmLjQZDMWECp05VFx9znEETNKlwF1FX5/E/37ISyz4d
I1LVSKOEccJX7jCR32LzvRW1UBX47Z+q3LVE4sa0QAV/JoISq6Qn6zAsVIV0yEPmVbd/xx
aX2uBUGHhmd99YJDh81xJIoYEMRzoGVfp0JjfYcDUc+2I6JdrOMF9/KmMA5wsZl4OKiu/F
cTRGjUkgw/cF2EFRGWknee2esYRB7tOr4y56qZ4gxqw8q9rYXhyB42jbdTvt5xcCm/ynid
sn4InokRRoIiMIPL5Ur7FZQHOP+915MWUBsrTJtkCWQuqJheYUi3mCzh/7NadAKplRpaKb
rS/DJIOOkjnGni/sDxJzPq7STDBVy4WStwQl6NI5hq+/c+JvN9GI4Vu/kz0z8qUcdShLaH
l4njcaMpg4tpQMHtCBOicGyV0=
-----END OPENSSH PRIVATE KEY-----
+1
View File
@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDz6aZ1jY2onnuj2YNHJ/HhfvIu0B973v/+pFFOavnTUOhEEKEy3TASu+s9CkHrYZAtRc+QYIkNZI31mhHBhotdeP/7GoO2UirkFtrzyQKPNJxEcv0RBoG9ssN8jex0PyK6DHIYYFnIWadVBEEOh/H+rK7j7u2/big3oTzYBuFrCwmYFcz5na99MzFeAUhazF44gVBma+zO+1quGeqF51UDIg1SMGvX8I7LNEqrKEBaIUQJKFQcxlOWlRLQsjJCymrOujsXsRrXHAQWcnxDcNevv2ZMOUl0ybvv9yH0BiGbRBd1Hy8/QPILbAQaqu0oQE7fubN8Q8lqb3Jg0loID4x/5GPhSY8WAXpuLcXTOrb93SnCw1JsAgJDNqpuuRFy3BSZ7wBOr1jfeIoo7xk14OHiUjJ0uXDL9cLMkcw6ElWz81mrD2VCkXUz+qFyjJ+G7aGWRtctZoOzKln4yfNfUmwW8/8ra3QnmrMZ2xW2Ylw3ZhO+tLi7jINHYFb54bAdLVPUU1ctIuJns2qkWnjJCxxMiynIqCif20/OU1n8CTJuOWiURmRdmvKOH4PE3JxC2Qnk/3tV3Cf8hp1CH5VjBZ9AjGj5MDMHXyu34VY2WvYo5QyzfS3ySPoT8kCO0G0xpvjwCMHOK+G2RP4kqb/KKZguiKdgintBXuskTlJmD7kcMQ== deploy@easyssh
+1
View File
@@ -0,0 +1 @@
appleboy
View File
View File
View File