Compare commits

...

275 Commits

Author SHA1 Message Date
Bo-Yi Wu 6edcc9f91a chore: bump go directive to 1.25.10
- Update go.mod go directive from 1.25.9 to 1.25.10
2026-05-08 21:19:20 +08:00
Bo-Yi Wu 75f25c2850 ci: bump golangci-lint to v2.12
- Upgrade golangci-lint version from v2.11 to v2.12
2026-05-08 20:13:40 +08:00
Bo-Yi Wu 9cadb84410 ci(actions): bump trivy-action to v0.36.0 and codecov-action to v6 2026-04-25 16:51:03 +08:00
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
44 changed files with 3113 additions and 936 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.36.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.12
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@v6
+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.36.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.36.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
+193 -77
View File
@@ -1,130 +1,198 @@
---
date: 2017-01-06T00:00:00+00:00
title: SCP
name: SCP
description: Deploy artifacts using SSH/SCP
author: appleboy
tags: [ publish, ssh, scp ]
repo: appleboy/drone-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
pipeline:
scp:
image: appleboy/drone-scp
- name: scp files
image: appleboy/drone-scp
settings:
host: example.com
target: /home/deploy/web
source: release.tar.gz
```
Example configuration with custom username, password and port:
```diff
pipeline:
scp:
image: appleboy/drone-scp
host: example.com
+ username: appleboy
+ password: 12345678
+ port: 4430
target: /home/deploy/web
username: foo
password: bar
port: 22
target: /var/www/deploy/${DRONE_REPO_OWNER}/${DRONE_REPO_NAME}
source: release.tar.gz
```
Example configuration with multiple source and target folder:
```diff
pipeline:
scp:
- name: scp files
image: appleboy/drone-scp
host: example.com
target:
+ - /home/deploy/web1
+ - /home/deploy/web2
source:
+ - release_1.tar.gz
+ - release_2.tar.gz
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
pipeline:
scp:
- name: scp files
image: appleboy/drone-scp
- host: example.com
+ host:
+ - example1.com
+ - example2.com
target: /home/deploy/web
source: release.tar.gz
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
scp:
- name: scp files
image: appleboy/drone-scp
host: example.com
target: /home/deploy/web
source: release.tar.gz
+ rm: true
settings:
target: /home/deploy/web
source: release.tar.gz
+ rm: true
```
Example configuration for success build:
Example for remove the specified number of leading path elements:
```diff
pipeline:
scp:
- name: scp files
image: appleboy/drone-scp
host: example.com
target: /home/deploy/web
source: release.tar.gz
+ when:
+ status: success
settings:
host: example.com
target: /home/deploy/web
source: dist/release.tar.gz
+ strip_components: 1
```
Example configuration for tag event:
Example configuration using SSHProxyCommand:
```diff
pipeline:
scp:
- name: scp files
image: appleboy/drone-scp
host: example.com
target: /home/deploy/web
source: release.tar.gz
+ when:
+ status: success
+ event: tag
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
```
# Secrets
The SCP plugin supports reading credentials from the Drone secret store. This is strongly recommended instead of storing credentials in the pipeline configuration in plain text.
Example configuration using password from secrets:
```diff
pipeline:
scp:
- name: scp files
image: appleboy/drone-scp
host: example.com
username: appleboy
- password: 12345678
port: 4430
target: /home/deploy/web
source: release.tar.gz
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
```
The `password` or `key` attributes can be replaced with the below secret environment variables. Please see the Drone documentation to learn more about secrets.
Example configuration using command timeout:
SCP_PASSWORD
: password of target host user
```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
```
SCP_KEY
: plain text of user private key
Example configuration for ignore list:
# Parameter Reference
```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
@@ -141,6 +209,12 @@ password
key
: plain text of user private key
passphrase
: The purpose of the passphrase is usually to encrypt the private key.
fingerprint
: fingerprint SHA256 of the host public key, default is to skip verification
target
: folder path of target host
@@ -150,7 +224,49 @@ source
rm
: remove target folder before copy files and artifacts
# Template Reference
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
@@ -183,4 +299,4 @@ build.author
: git author for current commit
build.link
: link the the build results in drone
: 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)
+118 -88
View File
@@ -1,61 +1,104 @@
# 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)
Copy files and artifacts via SSH using a binary, docker or [Drone CI](http://readme.drone.io/0.5/).
[![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
@@ -75,7 +118,7 @@ drone-scp --host example.com \
drone-scp --host example.com \
--port 22 \
--username appleboy \
+ --password xxxxxxx \
+ --password xxxxxxx \
--target /home/appleboy/test \
--source your_local_folder_path
```
@@ -90,8 +133,8 @@ eval `ssh-agent -s`
Import your local public key `~/.ssh/id_rsa`
```bash
$ ssh-add
```sh
ssh-add
```
You don't need to add `--password` or `--key-path` arguments.
@@ -108,52 +151,49 @@ drone-scp --host example.com \
```diff
drone-scp --host example1.com \
+ --host example2.com \
+ --host example2.com \
--port 22 \
--username appleboy \
--password xxxxxxx
--target /home/appleboy/test1 \
+ --target /home/appleboy/test2 \
+ --target /home/appleboy/test2 \
--source your_local_folder_path_1
+ --source your_local_folder_path_2
+ --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 \
-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 \
-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
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 \
-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:
Using ssh-agent, start your local ssh agent:
```bash
eval `ssh-agent -s`
@@ -161,74 +201,64 @@ 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 \
-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 \
-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
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 \
-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
```
<a name="usage-from-drone-ci"></a>
### 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_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_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](DOCS.md) about how to use scp in drone.
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:
```
$ make test
```sh
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.10
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=
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="256px" height="210px" viewBox="0 0 256 210" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<g>
<rect fill="#000000" x="0" y="0" width="256" height="209.342334" rx="5"></rect>
<path d="M28.2414658,21.7735776 C27.3856638,20.9177756 26.3529412,20.4898746 25.143298,20.4898746 C23.9336548,20.4898746 22.8968177,20.9218901 22.0327869,21.7859209 C21.1810993,22.6376085 20.7490839,23.6744455 20.7490839,24.8840887 C20.7490839,26.0937319 21.1810993,27.1305689 22.0327869,27.9822565 L35.4746384,41.424108 L22.0451302,54.8536162 C21.1810993,55.7176471 20.7490839,56.7544841 20.7367406,57.9641273 C20.7490839,59.1737705 21.1810993,60.2106075 22.0327869,61.0622951 C22.8968177,61.9139826 23.9336548,62.3459981 25.1309547,62.3583414 C26.3529412,62.3583414 27.3897782,61.9263259 28.2538091,61.0622951 L43.1891996,46.1145612 C46.3243973,42.9917068 46.3243973,39.8565092 43.1891996,36.7213115 L28.2414658,21.7735776 L28.2414658,21.7735776 Z M86.7857281,54.8783028 C85.9216972,54.0142719 84.8725169,53.5822565 83.6505304,53.5822565 L83.6505304,53.5760849 L54.8165863,53.5760849 L54.8165863,53.5822565 C53.5945998,53.5822565 52.5577628,54.0142719 51.6937319,54.8783028 C50.8297011,55.7423337 50.3976856,56.7791707 50.3976856,58.0011572 C50.3976856,59.2231437 50.8297011,60.272324 51.6937319,61.1363549 C52.5577628,62.0003857 53.5945998,62.4324012 54.8165863,62.4324012 L54.8165863,62.4262295 L83.6505304,62.4262295 L83.6505304,62.4324012 C84.8725169,62.4324012 85.9216972,62.0003857 86.7857281,61.1363549 C87.6497589,60.272324 88.0817743,59.2231437 88.0817743,58.0011572 C88.0817743,56.7791707 87.6497589,55.7423337 86.7857281,54.8783028 L86.7857281,54.8783028 L86.7857281,54.8783028 Z" fill="#FFFFFF"></path>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

+240 -117
View File
@@ -1,23 +1,38 @@
package main
import (
"log"
"os"
"strconv"
"time"
"github.com/appleboy/easyssh-proxy"
"github.com/joho/godotenv"
_ "github.com/joho/godotenv/autoload"
"github.com/urfave/cli"
"github.com/urfave/cli/v2"
"github.com/yassinebenaid/godump"
)
// Version set at compile-time
var Version = "v1.0.0-dev"
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 = "Drone SCP"
app.Usage = "Copy files and artifacts via SSH."
app.Copyright = "Copyright (c) 2017 Bo-Yi Wu"
app.Authors = []cli.Author{
app.Copyright = "Copyright (c) " + strconv.Itoa(time.Now().Year()) + " Bo-Yi Wu"
app.Version = Version
app.Authors = []*cli.Author{
{
Name: "Bo-Yi Wu",
Email: "appleboy.tw@gmail.com",
@@ -26,108 +41,199 @@ func main() {
app.Action = run
app.Version = Version
app.Flags = []cli.Flag{
cli.StringSliceFlag{
Name: "host, H",
Usage: "Server host",
EnvVar: "PLUGIN_HOST,SCP_HOST",
&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, P",
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, u",
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, p",
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, k",
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, i",
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, t",
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, s",
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, r",
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"},
},
}
@@ -163,40 +269,57 @@ VERSION:
REPOSITORY:
Github: https://github.com/appleboy/drone-scp
`
app.Run(os.Args)
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, ":", ""), "\\", "/")
}
+3 -1
View File
@@ -1,6 +1,8 @@
package main
import "testing"
import (
"testing"
)
func TestGetRealPath(t *testing.T) {
type args struct {
+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