mirror of
https://ghproxy.net/https://github.com/appleboy/scp-action.git
synced 2025-05-01 12:33:54 +00:00
Compare commits
131 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
7f18bf0ec8 | ||
|
35c03a241d | ||
|
8b7c180c3f | ||
|
ff85246aca | ||
|
6aff6492ae | ||
|
6b2d3092e3 | ||
|
f5c6c234bd | ||
|
17026f90b8 | ||
|
bf323b8729 | ||
|
e55e4eabdc | ||
|
bc835cba55 | ||
|
98b7132065 | ||
|
3d59448764 | ||
|
2a829c0ed2 | ||
|
4f2c27bbc2 | ||
|
b03d7257ae | ||
|
f042d742db | ||
|
ad9a378b7f | ||
|
172d4632fe | ||
|
93e17a47f9 | ||
|
c6ff96b7f6 | ||
|
7622c01418 | ||
|
9ba62064d2 | ||
|
f314a5399e | ||
|
699fa1181c | ||
|
9f34cc3e55 | ||
|
917f8b81df | ||
|
78e7f475f3 | ||
|
dfde1f50eb | ||
|
35093a99f9 | ||
|
96947ea2bd | ||
|
aef31a66e3 | ||
|
950981a11d | ||
|
5878fc908f | ||
|
abb6d70bee | ||
|
b03ad1c124 | ||
|
d398e64fcf | ||
|
3710327b67 | ||
|
d47d818ab7 | ||
|
7435be3541 | ||
|
11da0c97f9 | ||
|
ec73feb854 | ||
|
cdeb36bbf9 | ||
|
c209399d24 | ||
|
952a6e3250 | ||
|
82ebdbe3ed | ||
|
2cd029d317 | ||
|
e0dbae8ff0 | ||
|
3e84ad0651 | ||
|
8a92fcdb1e | ||
|
6cd4f0cace | ||
|
43abfa778d | ||
|
c8e0cef94a | ||
|
d47875703f | ||
|
a4e63f0f1a | ||
|
7cc0f645c7 | ||
|
dcb457bb6f | ||
|
11c56b52d3 | ||
|
51b937b31f | ||
|
98930d398c | ||
|
9ec0623f29 | ||
|
7f8a7c1019 | ||
|
2ce642f289 | ||
|
6291b9e86b | ||
|
6d1fc191a8 | ||
|
233f762873 | ||
|
b3f8d37ead | ||
|
f57f59fba9 | ||
|
8a54b39459 | ||
|
eb319b796f | ||
|
3c3575eb49 | ||
|
edc8ec9139 | ||
|
167d6d7ff4 | ||
|
ecd6a3623b | ||
|
31b514c281 | ||
|
5924b2b6d4 | ||
|
a2fea1040d | ||
|
8535291767 | ||
|
faff4f4218 | ||
|
ddd9176502 | ||
|
326e14ddd1 | ||
|
0329cffdaa | ||
|
6df9245376 | ||
|
4df1959b05 | ||
|
1c43a9662a | ||
|
2949c755a2 | ||
|
aefa39daef | ||
|
2305e4000a | ||
|
c51573a06a | ||
|
d068cd7f84 | ||
|
8ba3cfe760 | ||
|
1a6b426141 | ||
|
8b3eebcc8d | ||
|
861f2e0e7b | ||
|
6971270956 | ||
|
bac6c9e026 | ||
|
b04405242e | ||
|
5cb36bda99 | ||
|
6c5771fab8 | ||
|
193fd4eaa9 | ||
|
a5de8af6d5 | ||
|
671c934c80 | ||
|
8da6e3d335 | ||
|
196ea3f88f | ||
|
034b0ad00c | ||
|
95e250284b | ||
|
a593d18cb8 | ||
|
2e28e2ddc9 | ||
|
f8189f0fbf | ||
|
722ddfc32b | ||
|
e506e72e83 | ||
|
bd7b71696a | ||
|
b1b9ed628c | ||
|
72fe6fa2ca | ||
|
f1b7ce641c | ||
|
722d935a90 | ||
|
6fd371aeaf | ||
|
5138976c70 | ||
|
d322577e98 | ||
|
c0a815a115 | ||
|
afd2e26f9f | ||
|
2ef3f5e459 | ||
|
f0de4fea6f | ||
|
03e93ae863 | ||
|
bffdab6759 | ||
|
e22c039905 | ||
|
44284b60e4 | ||
|
b154adaf5c | ||
|
a6224ab4f0 | ||
|
1a31789cbc | ||
|
74e3e1df58 |
13
.github/FUNDING.yml
vendored
Normal file
13
.github/FUNDING.yml
vendored
Normal 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
.github/dependabot.yml
vendored
Normal file
10
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directory: /
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
- package-ecosystem: gomod
|
||||||
|
directory: /
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
65
.github/main.workflow
vendored
65
.github/main.workflow
vendored
@ -1,65 +0,0 @@
|
|||||||
workflow "Copy File Via SSH" {
|
|
||||||
on = "push"
|
|
||||||
resolves = [
|
|
||||||
"Copy file via ssh password",
|
|
||||||
"Copy file via ssh key",
|
|
||||||
"Add source in args",
|
|
||||||
"Add secret in args",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
action "Copy file via ssh password" {
|
|
||||||
uses = "appleboy/scp-action@master"
|
|
||||||
env = {
|
|
||||||
SOURCE = "tests/a.txt,tests/b.txt"
|
|
||||||
TARGET = "/home/actions/test"
|
|
||||||
}
|
|
||||||
secrets = [
|
|
||||||
"HOST",
|
|
||||||
"USERNAME",
|
|
||||||
"PASSWORD",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
action "Copy file via ssh key" {
|
|
||||||
uses = "appleboy/scp-action@master"
|
|
||||||
env = {
|
|
||||||
SOURCE = "tests/a.txt,tests/b.txt"
|
|
||||||
TARGET = "/home/actions/test"
|
|
||||||
}
|
|
||||||
secrets = [
|
|
||||||
"HOST",
|
|
||||||
"USERNAME",
|
|
||||||
"KEY",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
action "Add source in args" {
|
|
||||||
uses = "appleboy/scp-action@master"
|
|
||||||
env = {
|
|
||||||
TARGET = "/home/actions/test1234"
|
|
||||||
}
|
|
||||||
secrets = [
|
|
||||||
"HOST",
|
|
||||||
"USERNAME",
|
|
||||||
"KEY",
|
|
||||||
]
|
|
||||||
args = ["--source", "tests/a.txt", "--source", "tests/b.txt"]
|
|
||||||
}
|
|
||||||
|
|
||||||
action "Add secret in args" {
|
|
||||||
uses = "appleboy/scp-action@master"
|
|
||||||
env = {
|
|
||||||
TARGET = "/home/actions/test1234"
|
|
||||||
}
|
|
||||||
secrets = [
|
|
||||||
"HOST",
|
|
||||||
"TEST_USERNAME",
|
|
||||||
"KEY",
|
|
||||||
]
|
|
||||||
args = [
|
|
||||||
"--username", "$TEST_USERNAME",
|
|
||||||
"--source", "tests/a.txt",
|
|
||||||
"--source", "tests/b.txt",
|
|
||||||
]
|
|
||||||
}
|
|
33
.github/workflows/goreleaser.yml
vendored
Normal file
33
.github/workflows/goreleaser.yml
vendored
Normal 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@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: "^1"
|
||||||
|
|
||||||
|
- name: Run GoReleaser
|
||||||
|
uses: goreleaser/goreleaser-action@v6
|
||||||
|
with:
|
||||||
|
# either 'goreleaser' (default) or 'goreleaser-pro'
|
||||||
|
distribution: goreleaser
|
||||||
|
version: latest
|
||||||
|
args: release --clean
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
150
.github/workflows/stable.yml
vendored
Normal file
150
.github/workflows/stable.yml
vendored
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
name: v1 version
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
testing:
|
||||||
|
name: test scp action
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: copy file via ssh password
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
password: ${{ secrets.PASSWORD }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: "test"
|
||||||
|
|
||||||
|
- name: copy file via ssh key
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: "test"
|
||||||
|
|
||||||
|
- name: remove the specified number of leading path elements
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: "foobar"
|
||||||
|
strip_components: 1
|
||||||
|
|
||||||
|
- name: ssh key with passphrase
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.SSH2 }}
|
||||||
|
passphrase: ${{ secrets.PASSPHRASE }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: "test"
|
||||||
|
|
||||||
|
- name: use insecure cipher
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.SSH2 }}
|
||||||
|
passphrase: ${{ secrets.PASSPHRASE }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: "test"
|
||||||
|
use_insecure_cipher: true
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
name: test deploy artifact
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- run: echo hello > world.txt
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: my-artifact
|
||||||
|
path: world.txt
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: my-artifact
|
||||||
|
path: distfiles
|
||||||
|
|
||||||
|
- name: copy file to server
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: distfiles/*
|
||||||
|
target: test
|
||||||
|
|
||||||
|
changes:
|
||||||
|
name: test changed-files
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v45
|
||||||
|
with:
|
||||||
|
since_last_remote_commit: true
|
||||||
|
separator: ","
|
||||||
|
|
||||||
|
- name: copy file to server
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: ${{ steps.changed-files.outputs.all_changed_files }}
|
||||||
|
target: test
|
||||||
|
|
||||||
|
target:
|
||||||
|
name: test target folder
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: copy file to server
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: tests/a.txt,tests/b.txt
|
||||||
|
target: foobar foobar 1234
|
||||||
|
|
||||||
|
multipleHost:
|
||||||
|
name: test Multiple Host
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: copy file to server
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}:${{ secrets.PORT }},${{ secrets.HOST }}:${{ secrets.PORT }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: 1024
|
||||||
|
source: tests/a.txt,tests/b.txt
|
||||||
|
target: foobar
|
150
.github/workflows/testing.yml
vendored
Normal file
150
.github/workflows/testing.yml
vendored
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
name: lint and test
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
testing:
|
||||||
|
name: test scp action
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: copy file via ssh password
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
password: ${{ secrets.PASSWORD }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: "test"
|
||||||
|
|
||||||
|
- name: copy file via ssh key
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: "test"
|
||||||
|
|
||||||
|
- name: remove the specified number of leading path elements
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: "foobar"
|
||||||
|
strip_components: 1
|
||||||
|
|
||||||
|
- name: ssh key with passphrase
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.SSH2 }}
|
||||||
|
passphrase: ${{ secrets.PASSPHRASE }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: "test"
|
||||||
|
|
||||||
|
- name: use insecure cipher
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.SSH2 }}
|
||||||
|
passphrase: ${{ secrets.PASSPHRASE }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: "test"
|
||||||
|
use_insecure_cipher: true
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
name: test deploy artifact
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- run: echo hello > world.txt
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: my-artifact
|
||||||
|
path: world.txt
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: my-artifact
|
||||||
|
path: distfiles
|
||||||
|
|
||||||
|
- name: copy file to server
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: distfiles/*
|
||||||
|
target: test
|
||||||
|
|
||||||
|
changes:
|
||||||
|
name: test changed-files
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v45
|
||||||
|
with:
|
||||||
|
since_last_remote_commit: true
|
||||||
|
separator: ","
|
||||||
|
|
||||||
|
- name: copy file to server
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: ${{ steps.changed-files.outputs.all_changed_files }}
|
||||||
|
target: test
|
||||||
|
|
||||||
|
target:
|
||||||
|
name: test target folder
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: copy file to server
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: tests/a.txt,tests/b.txt
|
||||||
|
target: foobar foobar 1234
|
||||||
|
|
||||||
|
multipleHost:
|
||||||
|
name: test Multiple Host
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: copy file to server
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}:${{ secrets.PORT }},${{ secrets.HOST }}:${{ secrets.PORT }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: 1024
|
||||||
|
source: tests/a.txt,tests/b.txt
|
||||||
|
target: foobar
|
28
.goreleaser.yaml
Normal file
28
.goreleaser.yaml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
builds:
|
||||||
|
- # If true, skip the build.
|
||||||
|
# Useful for library projects.
|
||||||
|
# Default is false
|
||||||
|
skip: true
|
||||||
|
|
||||||
|
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
|
16
Dockerfile
16
Dockerfile
@ -1,16 +0,0 @@
|
|||||||
FROM appleboy/drone-scp:1.5.1-linux-amd64
|
|
||||||
|
|
||||||
# Github labels
|
|
||||||
LABEL "com.github.actions.name"="SCP Files"
|
|
||||||
LABEL "com.github.actions.description"="Copy files and artifacts via SSH"
|
|
||||||
LABEL "com.github.actions.icon"="copy"
|
|
||||||
LABEL "com.github.actions.color"="gray-dark"
|
|
||||||
|
|
||||||
LABEL "repository"="https://github.com/appleboy/scp-action"
|
|
||||||
LABEL "homepage"="https://github.com/appleboy"
|
|
||||||
LABEL "maintainer"="Bo-Yi Wu <appleboy.tw@gmail.com>"
|
|
||||||
LABEL "version"="0.0.1"
|
|
||||||
|
|
||||||
ADD entrypoint.sh /entrypoint.sh
|
|
||||||
RUN chmod +x /entrypoint.sh
|
|
||||||
ENTRYPOINT ["/entrypoint.sh"]
|
|
403
README.md
403
README.md
@ -1,97 +1,348 @@
|
|||||||
# 🚀 SCP for GitHub Actions
|
# 🚀 SCP for GitHub Actions
|
||||||
|
|
||||||
[GitHub Action](https://developer.github.com/actions/) for copying files and artifacts via SSH.
|
[繁體中文](README.zh-tw.md) | [简体中文](README.zh-cn.md)
|
||||||
|
|
||||||
<img src="./images/copy-multiple-file.png">
|
[GitHub Action](https://github.com/features/actions) for copying files and artifacts via SSH.
|
||||||
|
|
||||||
## Usage
|
[](https://github.com/appleboy/scp-action/actions/workflows/stable.yml)
|
||||||
|
[](https://github.com/appleboy/scp-action/actions/workflows/testing.yml)
|
||||||
|
|
||||||
copy files and artifacts via SSH as blow.
|
> **Note:** Only supports **Linux** [docker](https://www.docker.com/) containers.
|
||||||
|
|
||||||
```
|
---
|
||||||
action "Copy multiple file" {
|
|
||||||
uses = "appleboy/scp-action@master"
|
## ✨ Features
|
||||||
env = {
|
|
||||||
HOST = "example.com"
|
- ✅ Copy files and artifacts to one or multiple remote servers via SSH
|
||||||
USERNAME = "foo"
|
- ✅ Supports both SSH key and password authentication
|
||||||
PASSWORD = "bar"
|
- ✅ Full SSH Proxy (jump host) support
|
||||||
PORT = "22"
|
- ✅ Handles Linux ↔ Windows path conversion
|
||||||
SOURCE = "tests/a.txt,tests/b.txt"
|
- ✅ Integrates with GitHub Artifacts workflow
|
||||||
TARGET = "/home/foo/test"
|
- ✅ Incremental and differential file transfer
|
||||||
}
|
- ✅ Rich configuration options for advanced use cases
|
||||||
secrets = [
|
|
||||||
"PASSWORD",
|
---
|
||||||
]
|
|
||||||
}
|
## 📦 Table of Contents
|
||||||
|
|
||||||
|
- [🚀 SCP for GitHub Actions](#-scp-for-github-actions)
|
||||||
|
- [✨ Features](#-features)
|
||||||
|
- [📦 Table of Contents](#-table-of-contents)
|
||||||
|
- [🚀 Quick Start](#-quick-start)
|
||||||
|
- [⚙️ Configuration](#️-configuration)
|
||||||
|
- [🔌 Connection Settings](#-connection-settings)
|
||||||
|
- [📁 File Transfer Settings](#-file-transfer-settings)
|
||||||
|
- [🌐 Proxy Settings](#-proxy-settings)
|
||||||
|
- [🛡️ Best Practices \& Security](#️-best-practices--security)
|
||||||
|
- [🖥️ Cross-Platform Notes](#️-cross-platform-notes)
|
||||||
|
- [💡 Usage Examples](#-usage-examples)
|
||||||
|
- [🧩 Scenario Guide](#-scenario-guide)
|
||||||
|
- [Example 1: Basic SSH Password](#example-1-basic-ssh-password)
|
||||||
|
- [Example 2: Multi-server](#example-2-multi-server)
|
||||||
|
- [Example 3: Changed Files Only](#example-3-changed-files-only)
|
||||||
|
- [Example 4: Artifacts Integration](#example-4-artifacts-integration)
|
||||||
|
- [Example 5: Windows Server](#example-5-windows-server)
|
||||||
|
- [🗝️ SSH Key Setup](#️-ssh-key-setup)
|
||||||
|
- [🧰 Common Error Codes](#-common-error-codes)
|
||||||
|
- [🔄 Workflow Diagram](#-workflow-diagram)
|
||||||
|
- [FAQ \& Troubleshooting](#faq--troubleshooting)
|
||||||
|
- [📝 License](#-license)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Quick Start
|
||||||
|
|
||||||
|
Copy files and artifacts via SSH in your GitHub Actions workflow:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: scp files
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Copy files via SSH
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
password: ${{ secrets.PASSWORD }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: your_server_target_folder_path
|
||||||
```
|
```
|
||||||
|
|
||||||
## Environment variables
|
---
|
||||||
|
|
||||||
* HOST - ssh server host
|
## ⚙️ Configuration
|
||||||
* PORT - ssh server port
|
|
||||||
* USERNAME - ssh server username
|
|
||||||
* PASSWORD - ssh server password
|
|
||||||
* KEY - ssh server private key
|
|
||||||
* TARGET - target folder
|
|
||||||
* SOURCE - scp file list
|
|
||||||
|
|
||||||
### Example
|
### 🔌 Connection Settings
|
||||||
|
|
||||||
Copy file via ssh password
|
| Variable | Description | Default | Required |
|
||||||
|
| --------------- | -------------------------------------------- | ------- | -------- |
|
||||||
|
| host | Remote host(s), comma-separated for multiple | - | ✓ |
|
||||||
|
| port | SSH port | 22 | |
|
||||||
|
| username | SSH username | - | ✓ |
|
||||||
|
| password | SSH password (prefer SSH key for security) | - | |
|
||||||
|
| key | SSH private key content | - | |
|
||||||
|
| key_path | Path to SSH private key file | - | |
|
||||||
|
| passphrase | Passphrase for SSH private key | - | |
|
||||||
|
| fingerprint | SHA256 fingerprint for host key verification | - | |
|
||||||
|
| protocol | IP protocol: 'tcp', 'tcp4', or 'tcp6' | tcp | |
|
||||||
|
| timeout | SSH connection timeout | 30s | |
|
||||||
|
| command_timeout | SCP command timeout | 10m | |
|
||||||
|
|
||||||
```
|
### 📁 File Transfer Settings
|
||||||
action "Copy multiple file" {
|
|
||||||
uses = "appleboy/scp-action@master"
|
| Variable | Description | Default | Security Note |
|
||||||
env = {
|
| ---------------- | ------------------------------------------------------- | ------- | ---------------------- |
|
||||||
HOST = "example.com"
|
| source | Local files/directories to transfer (comma-separated) | - | Use explicit paths |
|
||||||
USERNAME = "foo"
|
| target | Target directory on remote server (must be a directory) | - | Avoid root directories |
|
||||||
PORT = "22"
|
| rm | Remove target directory before upload | - | Use with caution |
|
||||||
SOURCE = "tests/a.txt,tests/b.txt"
|
| strip_components | Remove leading path elements when extracting | - | |
|
||||||
TARGET = "/home/foo/test"
|
| overwrite | Overwrite existing files with tar | - | |
|
||||||
}
|
| tar_dereference | Follow symlinks with tar | - | |
|
||||||
secrets = [
|
| tar_tmp_path | Temp path for tar file on destination | - | |
|
||||||
"PASSWORD",
|
| tar_exec | Path to tar executable on destination | tar | |
|
||||||
]
|
| debug | Enable debug output | - | |
|
||||||
}
|
| curl_insecure | Use --insecure with curl | false | Not recommended |
|
||||||
|
| capture_stdout | Capture command stdout as action output | false | |
|
||||||
|
| version | Version of drone-scp to use | - | |
|
||||||
|
|
||||||
|
### 🌐 Proxy Settings
|
||||||
|
|
||||||
|
| Variable | Description | Default | Required |
|
||||||
|
| ------------------------- | ------------------------------------ | ------- | -------- |
|
||||||
|
| proxy_host | SSH proxy host | - | |
|
||||||
|
| proxy_port | SSH proxy port | 22 | |
|
||||||
|
| proxy_username | SSH proxy username | - | |
|
||||||
|
| proxy_password | SSH proxy password | - | |
|
||||||
|
| proxy_key | SSH proxy private key content | - | |
|
||||||
|
| proxy_key_path | Path to SSH proxy private key file | - | |
|
||||||
|
| proxy_passphrase | Passphrase for SSH proxy private key | - | |
|
||||||
|
| proxy_fingerprint | SHA256 fingerprint for proxy host | - | |
|
||||||
|
| proxy_use_insecure_cipher | Enable less secure ciphers for proxy | - | |
|
||||||
|
| proxy_timeout | SSH proxy connection timeout | 30s | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛡️ Best Practices & Security
|
||||||
|
|
||||||
|
- **Prefer SSH key authentication** over passwords for better security.
|
||||||
|
- Store all sensitive values (host, username, password, key) in **GitHub Secrets**.
|
||||||
|
- Regularly **rotate deployment keys** (suggested every 90 days).
|
||||||
|
- Restrict write permissions on the target server directory.
|
||||||
|
- Enable host key fingerprint verification to prevent MITM attacks.
|
||||||
|
- Avoid using root as the SSH user.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ Cross-Platform Notes
|
||||||
|
|
||||||
|
| Scenario | Linux Server | Windows Server |
|
||||||
|
| ---------------- | -------------- | ----------------------- |
|
||||||
|
| Path Format | `/path/to/dir` | `/c/path/to/dir` |
|
||||||
|
| Required Setting | None | `tar_dereference: true` |
|
||||||
|
| Permissions | Preserved | May require manual ACL |
|
||||||
|
| Shell | bash (default) | Git Bash via OpenSSH |
|
||||||
|
|
||||||
|
> 🚩 **Important:**
|
||||||
|
> When copying to Windows servers:
|
||||||
|
>
|
||||||
|
> - Install Git for Windows and set OpenSSH default shell to Git Bash
|
||||||
|
> - Use Unix-style target paths (e.g., `/c/Users/...`)
|
||||||
|
> - Enable `tar_dereference` for symlink handling
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 Usage Examples
|
||||||
|
|
||||||
|
### 🧩 Scenario Guide
|
||||||
|
|
||||||
|
- **Basic file transfer** → [Example 1](#example-1-basic-ssh-password)
|
||||||
|
- **Multi-server deployment** → [Example 2](#example-2-multi-server)
|
||||||
|
- **Incremental/changed files only** → [Example 3](#example-3-changed-files-only)
|
||||||
|
- **Artifacts integration** → [Example 4](#example-4-artifacts-integration)
|
||||||
|
- **Windows server setup** → [Example 5](#example-5-windows-server)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### Example 1: Basic SSH Password
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Copy file via SSH password
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: example.com
|
||||||
|
username: foo
|
||||||
|
password: bar
|
||||||
|
port: 22
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: your_server_target_folder_path
|
||||||
```
|
```
|
||||||
|
|
||||||
Copy file via ssh key
|
#### Example 2: Multi-server
|
||||||
|
|
||||||
```
|
```yaml
|
||||||
action "Copy file via ssh key" {
|
- name: Copy to multiple servers
|
||||||
uses = "appleboy/scp-action@master"
|
uses: appleboy/scp-action@v1
|
||||||
env = {
|
with:
|
||||||
HOST = "example.com"
|
host: "foo.com,bar.com"
|
||||||
USERNAME = "foo"
|
username: foo
|
||||||
PORT = "22"
|
password: bar
|
||||||
SOURCE = "tests/c.txt,tests/d.txt"
|
port: 22
|
||||||
TARGET = "/home/actions/test"
|
source: "tests/a.txt,tests/b.txt"
|
||||||
}
|
target: your_server_target_folder_path
|
||||||
secrets = [
|
|
||||||
"KEY",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Example configuration for ignore list:
|
#### Example 3: Changed Files Only
|
||||||
|
|
||||||
```
|
```yaml
|
||||||
action "reqular expression list" {
|
- name: Get changed files
|
||||||
uses = "appleboy/scp-action@master"
|
id: changed-files
|
||||||
env = {
|
uses: tj-actions/changed-files@v35
|
||||||
HOST = "example.com"
|
with:
|
||||||
USERNAME = "foo"
|
since_last_remote_commit: true
|
||||||
PORT = "22"
|
separator: ","
|
||||||
SOURCE = "tests/*.txt,!tests/a.txt"
|
|
||||||
TARGET = "/home/actions/test"
|
- name: Copy changed files to server
|
||||||
}
|
uses: appleboy/scp-action@v1
|
||||||
secrets = [
|
with:
|
||||||
"KEY",
|
host: ${{ secrets.HOST }}
|
||||||
]
|
username: ${{ secrets.USERNAME }}
|
||||||
}
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: ${{ steps.changed-files.outputs.all_changed_files }}
|
||||||
|
target: your_server_target_folder_path
|
||||||
```
|
```
|
||||||
|
|
||||||
## Secrets
|
#### Example 4: Artifacts Integration
|
||||||
|
|
||||||
* `PASSWORD` - ssh server password
|
```yaml
|
||||||
* `KEY` - ssh server private key
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: my-artifact
|
||||||
|
path: world.txt
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: my-artifact
|
||||||
|
path: distfiles
|
||||||
|
|
||||||
|
- name: Copy artifact to server
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: distfiles/*
|
||||||
|
target: your_server_target_folder_path
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Example 5: Windows Server
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Copy to Windows
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
port: 22
|
||||||
|
source: "your_source_path"
|
||||||
|
target: "/c/path/to/target/"
|
||||||
|
tar_dereference: true
|
||||||
|
rm: true
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🗝️ SSH Key Setup
|
||||||
|
|
||||||
|
1. **Generate SSH Key** (on your local machine):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# RSA
|
||||||
|
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
|
||||||
|
# ED25519
|
||||||
|
ssh-keygen -t ed25519 -a 200 -C "your_email@example.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Add Public Key to Server**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat .ssh/id_rsa.pub | ssh user@host 'cat >> .ssh/authorized_keys'
|
||||||
|
# or for ed25519
|
||||||
|
cat .ssh/id_ed25519.pub | ssh user@host 'cat >> .ssh/authorized_keys'
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Copy Private Key Content to GitHub Secrets**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
clip < ~/.ssh/id_rsa
|
||||||
|
# or
|
||||||
|
clip < ~/.ssh/id_ed25519
|
||||||
|
```
|
||||||
|
|
||||||
|
> See [SSH login without password](http://www.linuxproblem.org/art_9.html) for more details.
|
||||||
|
|
||||||
|
**OpenSSH Note:**
|
||||||
|
If you see `ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey]`, ensure your key algorithm is supported.
|
||||||
|
On Ubuntu 20.04+, add to `/etc/ssh/sshd_config` or `/etc/ssh/sshd_config.d/`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
CASignatureAlgorithms +ssh-rsa
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use ed25519 keys, which are accepted by default.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧰 Common Error Codes
|
||||||
|
|
||||||
|
| Error Code | Possible Cause | Solution |
|
||||||
|
| -------------- | ---------------------------- | --------------------------------------------- |
|
||||||
|
| `ECONNREFUSED` | Wrong port / firewall blocks | Check port and firewall settings |
|
||||||
|
| `ENOENT` | Source file not found | Use absolute path or check checkout step |
|
||||||
|
| `EAUTH` | Authentication failed | Check key format and permissions (PEM format) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Workflow Diagram
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant G as GitHub Runner
|
||||||
|
participant S as Target Server
|
||||||
|
G->>S: Establish SSH connection
|
||||||
|
S-->>G: Authenticate credentials
|
||||||
|
G->>S: (Optional) Remove target directory
|
||||||
|
G->>G: Archive source files
|
||||||
|
G->>S: Transfer archive
|
||||||
|
S->>S: Extract and process files
|
||||||
|
S-->>G: Return result
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## FAQ & Troubleshooting
|
||||||
|
|
||||||
|
- **Q: Why does authentication fail?**
|
||||||
|
A: Check SSH key format, permissions, and that the key is added to the server.
|
||||||
|
|
||||||
|
- **Q: How do I copy only changed files?**
|
||||||
|
A: Use `tj-actions/changed-files` to get changed files and pass to `source`.
|
||||||
|
|
||||||
|
- **Q: How to deploy to multiple servers?**
|
||||||
|
A: Use comma-separated host list: `host: "foo.com,bar.com"`
|
||||||
|
|
||||||
|
- **Q: How to copy to Windows?**
|
||||||
|
A: Set up Git Bash, use Unix-style paths, and enable `tar_dereference`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 License
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
348
README.zh-cn.md
Normal file
348
README.zh-cn.md
Normal file
@ -0,0 +1,348 @@
|
|||||||
|
# 🚀 GitHub Actions 的 SCP
|
||||||
|
|
||||||
|
[English](README.md) | [繁體中文](README.zh-tw.md)
|
||||||
|
|
||||||
|
[GitHub Action](https://github.com/features/actions) 用于通过 SSH 复制文件和构建产物。
|
||||||
|
|
||||||
|
[](https://github.com/appleboy/scp-action/actions/workflows/stable.yml)
|
||||||
|
[](https://github.com/appleboy/scp-action/actions/workflows/testing.yml)
|
||||||
|
|
||||||
|
> **注意:** 仅支持 **Linux** [docker](https://www.docker.com/) 容器。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✨ 功能特性
|
||||||
|
|
||||||
|
- ✅ 通过 SSH 将文件和产物复制到一台或多台远程服务器
|
||||||
|
- ✅ 支持 SSH 密钥和密码认证
|
||||||
|
- ✅ 完全支持 SSH 代理(跳板机)
|
||||||
|
- ✅ 处理 Linux ↔ Windows 路径转换
|
||||||
|
- ✅ 集成 GitHub Artifacts 工作流
|
||||||
|
- ✅ 支持增量与差异文件传输
|
||||||
|
- ✅ 丰富的高级配置选项
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 目录
|
||||||
|
|
||||||
|
- [🚀 GitHub Actions 的 SCP](#-github-actions-的-scp)
|
||||||
|
- [✨ 功能特性](#-功能特性)
|
||||||
|
- [📦 目录](#-目录)
|
||||||
|
- [🚀 快速开始](#-快速开始)
|
||||||
|
- [⚙️ 配置说明](#️-配置说明)
|
||||||
|
- [🔌 连接设置](#-连接设置)
|
||||||
|
- [📁 文件传输设置](#-文件传输设置)
|
||||||
|
- [🌐 代理设置](#-代理设置)
|
||||||
|
- [🛡️ 最佳实践与安全性](#️-最佳实践与安全性)
|
||||||
|
- [🖥️ 跨平台注意事项](#️-跨平台注意事项)
|
||||||
|
- [💡 使用示例](#-使用示例)
|
||||||
|
- [🧩 场景导览](#-场景导览)
|
||||||
|
- [示例 1:基本 SSH 密码](#示例-1基本-ssh-密码)
|
||||||
|
- [示例 2:多台服务器](#示例-2多台服务器)
|
||||||
|
- [示例 3:仅传输变更文件](#示例-3仅传输变更文件)
|
||||||
|
- [示例 4:集成 Artifacts](#示例-4集成-artifacts)
|
||||||
|
- [示例 5:Windows 服务器](#示例-5windows-服务器)
|
||||||
|
- [🗝️ SSH 密钥设置](#️-ssh-密钥设置)
|
||||||
|
- [🧰 常见错误代码](#-常见错误代码)
|
||||||
|
- [🔄 工作流程图](#-工作流程图)
|
||||||
|
- [FAQ 与故障排查](#faq-与故障排查)
|
||||||
|
- [📝 许可证](#-许可证)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 快速开始
|
||||||
|
|
||||||
|
在 GitHub Actions 工作流中通过 SSH 复制文件和产物:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: scp files
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: 通过 SSH 复制文件
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
password: ${{ secrets.PASSWORD }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: your_server_target_folder_path
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ 配置说明
|
||||||
|
|
||||||
|
### 🔌 连接设置
|
||||||
|
|
||||||
|
| 变量 | 说明 | 默认值 | 必填 |
|
||||||
|
| --------------- | -------------------------------- | ------ | ---- |
|
||||||
|
| host | 远程主机(多台用逗号分隔) | - | ✓ |
|
||||||
|
| port | SSH 端口 | 22 | |
|
||||||
|
| username | SSH 用户名 | - | ✓ |
|
||||||
|
| password | SSH 密码(建议优先使用密钥认证) | - | |
|
||||||
|
| key | SSH 私钥内容 | - | |
|
||||||
|
| key_path | SSH 私钥文件路径 | - | |
|
||||||
|
| passphrase | SSH 私钥密码 | - | |
|
||||||
|
| fingerprint | 主机密钥 SHA256 指纹验证 | - | |
|
||||||
|
| protocol | IP 协议:'tcp'、'tcp4' 或 'tcp6' | tcp | |
|
||||||
|
| timeout | SSH 连接超时 | 30s | |
|
||||||
|
| command_timeout | SCP 命令超时 | 10m | |
|
||||||
|
|
||||||
|
### 📁 文件传输设置
|
||||||
|
|
||||||
|
| 变量 | 说明 | 默认值 | 安全性说明 |
|
||||||
|
| ---------------- | --------------------------------- | ------ | -------------- |
|
||||||
|
| source | 本地要传输的文件/目录(逗号分隔) | - | 请使用明确路径 |
|
||||||
|
| target | 远程目标目录(必须为目录) | - | 避免使用根目录 |
|
||||||
|
| rm | 上传前移除目标目录 | - | 谨慎使用 |
|
||||||
|
| strip_components | 传输时移除前置路径元素 | - | |
|
||||||
|
| overwrite | 使用 tar 覆盖现有文件 | - | |
|
||||||
|
| tar_dereference | tar 传输时跟随符号链接 | - | |
|
||||||
|
| tar_tmp_path | 目标端 tar 临时文件路径 | - | |
|
||||||
|
| tar_exec | 目标端 tar 执行文件路径 | tar | |
|
||||||
|
| debug | 启用调试输出 | - | |
|
||||||
|
| curl_insecure | curl 使用 --insecure | false | 不推荐 |
|
||||||
|
| capture_stdout | 将命令 stdout 作为 action 输出 | false | |
|
||||||
|
| version | 指定 drone-scp 版本 | - | |
|
||||||
|
|
||||||
|
### 🌐 代理设置
|
||||||
|
|
||||||
|
| 变量 | 说明 | 默认值 | 必填 |
|
||||||
|
| ------------------------- | -------------------------- | ------ | ---- |
|
||||||
|
| proxy_host | SSH 代理主机 | - | |
|
||||||
|
| proxy_port | SSH 代理端口 | 22 | |
|
||||||
|
| proxy_username | SSH 代理用户名 | - | |
|
||||||
|
| proxy_password | SSH 代理密码 | - | |
|
||||||
|
| proxy_key | SSH 代理私钥内容 | - | |
|
||||||
|
| proxy_key_path | SSH 代理私钥文件路径 | - | |
|
||||||
|
| proxy_passphrase | SSH 代理私钥密码 | - | |
|
||||||
|
| proxy_fingerprint | 代理主机 SHA256 指纹验证 | - | |
|
||||||
|
| proxy_use_insecure_cipher | 启用较不安全的代理加密算法 | - | |
|
||||||
|
| proxy_timeout | SSH 代理连接超时 | 30s | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛡️ 最佳实践与安全性
|
||||||
|
|
||||||
|
- **建议优先使用 SSH 密钥认证**,提升安全性。
|
||||||
|
- 将所有敏感信息(host、username、password、key)存放于 **GitHub Secrets**。
|
||||||
|
- 定期**更换部署密钥**(建议每 90 天一次)。
|
||||||
|
- 限制目标服务器目录的写入权限。
|
||||||
|
- 启用主机密钥指纹验证以防止中间人攻击。
|
||||||
|
- 避免使用 root 用户登录 SSH。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ 跨平台注意事项
|
||||||
|
|
||||||
|
| 场景 | Linux 服务器 | Windows 服务器 |
|
||||||
|
| -------- | -------------- | ----------------------- |
|
||||||
|
| 路径格式 | `/path/to/dir` | `/c/path/to/dir` |
|
||||||
|
| 必要设置 | 无 | `tar_dereference: true` |
|
||||||
|
| 权限 | 保留 | 可能需手动设置 ACL |
|
||||||
|
| Shell | bash(默认) | Git Bash(OpenSSH) |
|
||||||
|
|
||||||
|
> 🚩 **重要提醒:**
|
||||||
|
> 复制到 Windows 服务器时:
|
||||||
|
>
|
||||||
|
> - 安装 Git for Windows 并将 OpenSSH 默认 shell 设为 Git Bash
|
||||||
|
> - 使用类 Unix 目标路径(如 `/c/Users/...`)
|
||||||
|
> - 启用 `tar_dereference` 处理符号链接
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 使用示例
|
||||||
|
|
||||||
|
### 🧩 场景导览
|
||||||
|
|
||||||
|
- **基本文件传输** → [示例 1](#示例-1基本-ssh-密码)
|
||||||
|
- **多台服务器部署** → [示例 2](#示例-2多台服务器)
|
||||||
|
- **仅传输变更文件** → [示例 3](#示例-3仅传输变更文件)
|
||||||
|
- **集成 Artifacts** → [示例 4](#示例-4集成-artifacts)
|
||||||
|
- **Windows 服务器设置** → [示例 5](#示例-5windows-服务器)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 示例 1:基本 SSH 密码
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: 通过 SSH 密码复制文件
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: example.com
|
||||||
|
username: foo
|
||||||
|
password: bar
|
||||||
|
port: 22
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: your_server_target_folder_path
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 示例 2:多台服务器
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: 复制到多台服务器
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: "foo.com,bar.com"
|
||||||
|
username: foo
|
||||||
|
password: bar
|
||||||
|
port: 22
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: your_server_target_folder_path
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 示例 3:仅传输变更文件
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: 获取变更文件
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v35
|
||||||
|
with:
|
||||||
|
since_last_remote_commit: true
|
||||||
|
separator: ","
|
||||||
|
|
||||||
|
- name: 复制变更文件到服务器
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: ${{ steps.changed-files.outputs.all_changed_files }}
|
||||||
|
target: your_server_target_folder_path
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 示例 4:集成 Artifacts
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: my-artifact
|
||||||
|
path: world.txt
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: my-artifact
|
||||||
|
path: distfiles
|
||||||
|
|
||||||
|
- name: 复制 artifact 到服务器
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: distfiles/*
|
||||||
|
target: your_server_target_folder_path
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 示例 5:Windows 服务器
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: 复制到 Windows
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
port: 22
|
||||||
|
source: "your_source_path"
|
||||||
|
target: "/c/path/to/target/"
|
||||||
|
tar_dereference: true
|
||||||
|
rm: true
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🗝️ SSH 密钥设置
|
||||||
|
|
||||||
|
1. **生成 SSH 密钥**(在本地执行):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# RSA
|
||||||
|
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
|
||||||
|
# ED25519
|
||||||
|
ssh-keygen -t ed25519 -a 200 -C "your_email@example.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **将公钥添加到服务器**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat .ssh/id_rsa.pub | ssh user@host 'cat >> .ssh/authorized_keys'
|
||||||
|
# 或 ed25519
|
||||||
|
cat .ssh/id_ed25519.pub | ssh user@host 'cat >> .ssh/authorized_keys'
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **将私钥内容复制到 GitHub Secrets**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
clip < ~/.ssh/id_rsa
|
||||||
|
# 或
|
||||||
|
clip < ~/.ssh/id_ed25519
|
||||||
|
```
|
||||||
|
|
||||||
|
> 更多细节请参考 [SSH 免密登录](http://www.linuxproblem.org/art_9.html)。
|
||||||
|
|
||||||
|
**OpenSSH 注意事项:**
|
||||||
|
如遇到 `ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey]`,请确认密钥算法已被支持。
|
||||||
|
Ubuntu 20.04+ 可在 `/etc/ssh/sshd_config` 或 `/etc/ssh/sshd_config.d/` 添加:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
CASignatureAlgorithms +ssh-rsa
|
||||||
|
```
|
||||||
|
|
||||||
|
或使用 ed25519 密钥(默认支持)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧰 常见错误代码
|
||||||
|
|
||||||
|
| 错误代码 | 可能原因 | 解决方法 |
|
||||||
|
| -------------- | ------------------- | --------------------------------- |
|
||||||
|
| `ECONNREFUSED` | 端口错误/防火墙阻挡 | 检查端口和防火墙设置 |
|
||||||
|
| `ENOENT` | 找不到源文件 | 使用绝对路径或检查 checkout 步骤 |
|
||||||
|
| `EAUTH` | 认证失败 | 检查密钥格式和权限(需 PEM 格式) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 工作流程图
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant G as GitHub Runner
|
||||||
|
participant S as Target Server
|
||||||
|
G->>S: 建立 SSH 连接
|
||||||
|
S-->>G: 验证凭证
|
||||||
|
G->>S: (可选)移除目标目录
|
||||||
|
G->>G: 打包源文件
|
||||||
|
G->>S: 传输打包文件
|
||||||
|
S->>S: 解压和处理文件
|
||||||
|
S-->>G: 返回结果
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## FAQ 与故障排查
|
||||||
|
|
||||||
|
- **Q: 为什么认证失败?**
|
||||||
|
A: 请检查 SSH 密钥格式、权限,以及密钥是否已添加到服务器。
|
||||||
|
|
||||||
|
- **Q: 如何只复制变更文件?**
|
||||||
|
A: 使用 `tj-actions/changed-files` 获取变更文件并传递给 `source`。
|
||||||
|
|
||||||
|
- **Q: 如何部署到多台服务器?**
|
||||||
|
A: `host` 参数用逗号分隔多台主机,例如:`host: "foo.com,bar.com"`
|
||||||
|
|
||||||
|
- **Q: 如何复制到 Windows?**
|
||||||
|
A: 设置 Git Bash,使用类 Unix 路径,并启用 `tar_dereference`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 许可证
|
||||||
|
|
||||||
|
MIT License
|
348
README.zh-tw.md
Normal file
348
README.zh-tw.md
Normal file
@ -0,0 +1,348 @@
|
|||||||
|
# 🚀 GitHub Actions 的 SCP
|
||||||
|
|
||||||
|
[English](README.md) | [简体中文](README.zh-cn.md)
|
||||||
|
|
||||||
|
[GitHub Action](https://github.com/features/actions) 用於透過 SSH 複製檔案與產物。
|
||||||
|
|
||||||
|
[](https://github.com/appleboy/scp-action/actions/workflows/stable.yml)
|
||||||
|
[](https://github.com/appleboy/scp-action/actions/workflows/testing.yml)
|
||||||
|
|
||||||
|
> **注意:** 只支援 **Linux** [docker](https://www.docker.com/) 容器。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✨ 功能特色
|
||||||
|
|
||||||
|
- ✅ 透過 SSH 將檔案與產物複製到一台或多台遠端伺服器
|
||||||
|
- ✅ 支援 SSH 金鑰與密碼驗證
|
||||||
|
- ✅ 完整支援 SSH Proxy(跳板機)
|
||||||
|
- ✅ 處理 Linux ↔ Windows 路徑轉換
|
||||||
|
- ✅ 整合 GitHub Artifacts 工作流程
|
||||||
|
- ✅ 支援增量與差異檔案傳輸
|
||||||
|
- ✅ 豐富的進階設定選項
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 目錄
|
||||||
|
|
||||||
|
- [🚀 GitHub Actions 的 SCP](#-github-actions-的-scp)
|
||||||
|
- [✨ 功能特色](#-功能特色)
|
||||||
|
- [📦 目錄](#-目錄)
|
||||||
|
- [🚀 快速開始](#-快速開始)
|
||||||
|
- [⚙️ 設定說明](#️-設定說明)
|
||||||
|
- [🔌 連線設定](#-連線設定)
|
||||||
|
- [📁 檔案傳輸設定](#-檔案傳輸設定)
|
||||||
|
- [🌐 Proxy 設定](#-proxy-設定)
|
||||||
|
- [🛡️ 最佳實踐與安全性](#️-最佳實踐與安全性)
|
||||||
|
- [🖥️ 跨平台注意事項](#️-跨平台注意事項)
|
||||||
|
- [💡 使用範例](#-使用範例)
|
||||||
|
- [🧩 情境導覽](#-情境導覽)
|
||||||
|
- [範例 1:基本 SSH 密碼](#範例-1基本-ssh-密碼)
|
||||||
|
- [範例 2:多台伺服器](#範例-2多台伺服器)
|
||||||
|
- [範例 3:僅傳送變更檔案](#範例-3僅傳送變更檔案)
|
||||||
|
- [範例 4:整合 Artifacts](#範例-4整合-artifacts)
|
||||||
|
- [範例 5:Windows 伺服器](#範例-5windows-伺服器)
|
||||||
|
- [🗝️ SSH 金鑰設定](#️-ssh-金鑰設定)
|
||||||
|
- [🧰 常見錯誤代碼](#-常見錯誤代碼)
|
||||||
|
- [🔄 工作流程圖](#-工作流程圖)
|
||||||
|
- [FAQ 與疑難排解](#faq-與疑難排解)
|
||||||
|
- [📝 授權條款](#-授權條款)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 快速開始
|
||||||
|
|
||||||
|
在 GitHub Actions 工作流程中透過 SSH 複製檔案與產物:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: scp files
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: 透過 SSH 複製檔案
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
password: ${{ secrets.PASSWORD }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: your_server_target_folder_path
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ 設定說明
|
||||||
|
|
||||||
|
### 🔌 連線設定
|
||||||
|
|
||||||
|
| 變數 | 說明 | 預設值 | 必填 |
|
||||||
|
| --------------- | ------------------------------------ | ------ | ---- |
|
||||||
|
| host | 遠端主機(多台以逗號分隔) | - | ✓ |
|
||||||
|
| port | SSH 連接埠 | 22 | |
|
||||||
|
| username | SSH 使用者名稱 | - | ✓ |
|
||||||
|
| password | SSH 密碼(建議使用金鑰以提升安全性) | - | |
|
||||||
|
| key | SSH 私鑰內容 | - | |
|
||||||
|
| key_path | SSH 私鑰檔案路徑 | - | |
|
||||||
|
| passphrase | SSH 私鑰密碼 | - | |
|
||||||
|
| fingerprint | 主機金鑰 SHA256 指紋驗證 | - | |
|
||||||
|
| protocol | IP 協定:'tcp'、'tcp4' 或 'tcp6' | tcp | |
|
||||||
|
| timeout | SSH 連線逾時 | 30s | |
|
||||||
|
| command_timeout | SCP 指令逾時 | 10m | |
|
||||||
|
|
||||||
|
### 📁 檔案傳輸設定
|
||||||
|
|
||||||
|
| 變數 | 說明 | 預設值 | 安全性說明 |
|
||||||
|
| ---------------- | --------------------------------- | ------ | -------------- |
|
||||||
|
| source | 本地要傳送的檔案/目錄(逗號分隔) | - | 請使用明確路徑 |
|
||||||
|
| target | 遠端目標目錄(必須為目錄) | - | 避免使用根目錄 |
|
||||||
|
| rm | 上傳前移除目標目錄 | - | 請小心使用 |
|
||||||
|
| strip_components | 傳送時移除前置路徑元素 | - | |
|
||||||
|
| overwrite | 使用 tar 覆蓋現有檔案 | - | |
|
||||||
|
| tar_dereference | tar 傳送時跟隨符號連結 | - | |
|
||||||
|
| tar_tmp_path | 目標端 tar 暫存檔路徑 | - | |
|
||||||
|
| tar_exec | 目標端 tar 執行檔路徑 | tar | |
|
||||||
|
| debug | 啟用除錯輸出 | - | |
|
||||||
|
| curl_insecure | curl 使用 --insecure | false | 不建議 |
|
||||||
|
| capture_stdout | 將指令 stdout 作為 action 輸出 | false | |
|
||||||
|
| version | 指定 drone-scp 版本 | - | |
|
||||||
|
|
||||||
|
### 🌐 Proxy 設定
|
||||||
|
|
||||||
|
| 變數 | 說明 | 預設值 | 必填 |
|
||||||
|
| ------------------------- | ------------------------------- | ------ | ---- |
|
||||||
|
| proxy_host | SSH Proxy 主機 | - | |
|
||||||
|
| proxy_port | SSH Proxy 連接埠 | 22 | |
|
||||||
|
| proxy_username | SSH Proxy 使用者名稱 | - | |
|
||||||
|
| proxy_password | SSH Proxy 密碼 | - | |
|
||||||
|
| proxy_key | SSH Proxy 私鑰內容 | - | |
|
||||||
|
| proxy_key_path | SSH Proxy 私鑰檔案路徑 | - | |
|
||||||
|
| proxy_passphrase | SSH Proxy 私鑰密碼 | - | |
|
||||||
|
| proxy_fingerprint | Proxy 主機 SHA256 指紋驗證 | - | |
|
||||||
|
| proxy_use_insecure_cipher | 啟用較不安全的 Proxy 加密演算法 | - | |
|
||||||
|
| proxy_timeout | SSH Proxy 連線逾時 | 30s | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛡️ 最佳實踐與安全性
|
||||||
|
|
||||||
|
- **建議優先使用 SSH 金鑰驗證**,提升安全性。
|
||||||
|
- 將所有敏感資訊(host、username、password、key)存放於 **GitHub Secrets**。
|
||||||
|
- 定期**更換部署金鑰**(建議每 90 天一次)。
|
||||||
|
- 限制目標伺服器目錄的寫入權限。
|
||||||
|
- 啟用主機金鑰指紋驗證以防止中間人攻擊。
|
||||||
|
- 避免使用 root 帳號登入 SSH。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ 跨平台注意事項
|
||||||
|
|
||||||
|
| 情境 | Linux 伺服器 | Windows 伺服器 |
|
||||||
|
| -------- | -------------- | ----------------------- |
|
||||||
|
| 路徑格式 | `/path/to/dir` | `/c/path/to/dir` |
|
||||||
|
| 必要設定 | 無 | `tar_dereference: true` |
|
||||||
|
| 權限 | 保留 | 可能需手動設定 ACL |
|
||||||
|
| Shell | bash (預設) | Git Bash(OpenSSH) |
|
||||||
|
|
||||||
|
> 🚩 **重要提醒:**
|
||||||
|
> 複製到 Windows 伺服器時:
|
||||||
|
>
|
||||||
|
> - 安裝 Git for Windows 並將 OpenSSH 預設 shell 設為 Git Bash
|
||||||
|
> - 使用 Unix 風格目標路徑(如 `/c/Users/...`)
|
||||||
|
> - 啟用 `tar_dereference` 處理符號連結
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 使用範例
|
||||||
|
|
||||||
|
### 🧩 情境導覽
|
||||||
|
|
||||||
|
- **基本檔案傳輸** → [範例 1](#範例-1基本-ssh-密碼)
|
||||||
|
- **多台伺服器部署** → [範例 2](#範例-2多台伺服器)
|
||||||
|
- **僅傳送變更檔案** → [範例 3](#範例-3僅傳送變更檔案)
|
||||||
|
- **整合 Artifacts** → [範例 4](#範例-4整合-artifacts)
|
||||||
|
- **Windows 伺服器設定** → [範例 5](#範例-5windows-伺服器)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 範例 1:基本 SSH 密碼
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: 透過 SSH 密碼複製檔案
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: example.com
|
||||||
|
username: foo
|
||||||
|
password: bar
|
||||||
|
port: 22
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: your_server_target_folder_path
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 範例 2:多台伺服器
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: 複製到多台伺服器
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: "foo.com,bar.com"
|
||||||
|
username: foo
|
||||||
|
password: bar
|
||||||
|
port: 22
|
||||||
|
source: "tests/a.txt,tests/b.txt"
|
||||||
|
target: your_server_target_folder_path
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 範例 3:僅傳送變更檔案
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: 取得變更檔案
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v35
|
||||||
|
with:
|
||||||
|
since_last_remote_commit: true
|
||||||
|
separator: ","
|
||||||
|
|
||||||
|
- name: 複製變更檔案到伺服器
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: ${{ steps.changed-files.outputs.all_changed_files }}
|
||||||
|
target: your_server_target_folder_path
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 範例 4:整合 Artifacts
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: my-artifact
|
||||||
|
path: world.txt
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: my-artifact
|
||||||
|
path: distfiles
|
||||||
|
|
||||||
|
- name: 複製 artifact 到伺服器
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: distfiles/*
|
||||||
|
target: your_server_target_folder_path
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 範例 5:Windows 伺服器
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: 複製到 Windows
|
||||||
|
uses: appleboy/scp-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
port: 22
|
||||||
|
source: "your_source_path"
|
||||||
|
target: "/c/path/to/target/"
|
||||||
|
tar_dereference: true
|
||||||
|
rm: true
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🗝️ SSH 金鑰設定
|
||||||
|
|
||||||
|
1. **產生 SSH 金鑰**(於本地端執行):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# RSA
|
||||||
|
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
|
||||||
|
# ED25519
|
||||||
|
ssh-keygen -t ed25519 -a 200 -C "your_email@example.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **將公鑰加入伺服器**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat .ssh/id_rsa.pub | ssh user@host 'cat >> .ssh/authorized_keys'
|
||||||
|
# 或 ed25519
|
||||||
|
cat .ssh/id_ed25519.pub | ssh user@host 'cat >> .ssh/authorized_keys'
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **將私鑰內容複製到 GitHub Secrets**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
clip < ~/.ssh/id_rsa
|
||||||
|
# 或
|
||||||
|
clip < ~/.ssh/id_ed25519
|
||||||
|
```
|
||||||
|
|
||||||
|
> 更多細節請參考 [SSH 無密碼登入](http://www.linuxproblem.org/art_9.html)。
|
||||||
|
|
||||||
|
**OpenSSH 注意事項:**
|
||||||
|
若出現 `ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey]`,請確認金鑰演算法支援。
|
||||||
|
Ubuntu 20.04+ 可於 `/etc/ssh/sshd_config` 或 `/etc/ssh/sshd_config.d/` 加入:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
CASignatureAlgorithms +ssh-rsa
|
||||||
|
```
|
||||||
|
|
||||||
|
或改用 ed25519 金鑰(預設支援)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧰 常見錯誤代碼
|
||||||
|
|
||||||
|
| 錯誤代碼 | 可能原因 | 解決方式 |
|
||||||
|
| -------------- | --------------------- | --------------------------------- |
|
||||||
|
| `ECONNREFUSED` | 連接埠錯誤/防火牆阻擋 | 檢查連接埠與防火牆設定 |
|
||||||
|
| `ENOENT` | 找不到來源檔案 | 請用絕對路徑或檢查 checkout 步驟 |
|
||||||
|
| `EAUTH` | 驗證失敗 | 檢查金鑰格式與權限(需 PEM 格式) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 工作流程圖
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant G as GitHub Runner
|
||||||
|
participant S as Target Server
|
||||||
|
G->>S: 建立 SSH 連線
|
||||||
|
S-->>G: 驗證憑證
|
||||||
|
G->>S: (可選)移除目標目錄
|
||||||
|
G->>G: 封存來源檔案
|
||||||
|
G->>S: 傳送封存檔
|
||||||
|
S->>S: 解壓與處理檔案
|
||||||
|
S-->>G: 回傳結果
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## FAQ 與疑難排解
|
||||||
|
|
||||||
|
- **Q: 為什麼驗證失敗?**
|
||||||
|
A: 請檢查 SSH 金鑰格式、權限,以及金鑰是否已加入伺服器。
|
||||||
|
|
||||||
|
- **Q: 如何只複製變更檔案?**
|
||||||
|
A: 使用 `tj-actions/changed-files` 取得變更檔案並傳給 `source`。
|
||||||
|
|
||||||
|
- **Q: 如何部署到多台伺服器?**
|
||||||
|
A: `host` 參數用逗號分隔多台主機,例如:`host: "foo.com,bar.com"`
|
||||||
|
|
||||||
|
- **Q: 如何複製到 Windows?**
|
||||||
|
A: 設定 Git Bash,使用 Unix 風格路徑,並啟用 `tar_dereference`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 授權條款
|
||||||
|
|
||||||
|
MIT License
|
142
action.yml
Normal file
142
action.yml
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
name: "SCP Command to Transfer Files"
|
||||||
|
description: "Easily transfer files and folders using the SCP command in Linux."
|
||||||
|
author: "Bo-Yi Wu"
|
||||||
|
inputs:
|
||||||
|
host:
|
||||||
|
description: "Remote host address for SCP (e.g., example.com or 192.168.1.1)."
|
||||||
|
port:
|
||||||
|
description: "Remote SSH port for SCP. Default: 22."
|
||||||
|
default: "22"
|
||||||
|
username:
|
||||||
|
description: "Username for SSH authentication."
|
||||||
|
password:
|
||||||
|
description: "Password for SSH authentication (not recommended; use SSH keys if possible)."
|
||||||
|
protocol:
|
||||||
|
description: "IP protocol to use. Valid values: 'tcp', 'tcp4', or 'tcp6'. Default: tcp."
|
||||||
|
default: "tcp"
|
||||||
|
timeout:
|
||||||
|
description: "Timeout for establishing SSH connection to the remote host. Default: 30s."
|
||||||
|
default: "30s"
|
||||||
|
command_timeout:
|
||||||
|
description: "Timeout for the SCP command execution. Default: 10m."
|
||||||
|
default: "10m"
|
||||||
|
key:
|
||||||
|
description: "Content of the SSH private key (e.g., the raw content of ~/.ssh/id_rsa)."
|
||||||
|
key_path:
|
||||||
|
description: "Path to the SSH private key file."
|
||||||
|
passphrase:
|
||||||
|
description: "Passphrase for the SSH private key, if required."
|
||||||
|
fingerprint:
|
||||||
|
description: "SHA256 fingerprint of the host's public key. If not set, host key verification is skipped (not recommended for production)."
|
||||||
|
use_insecure_cipher:
|
||||||
|
description: "Enable additional, less secure ciphers for compatibility. Not recommended unless required."
|
||||||
|
target:
|
||||||
|
description: "Target directory path on the remote server. Must be a directory."
|
||||||
|
source:
|
||||||
|
description: "List of files or directories to transfer (local paths)."
|
||||||
|
rm:
|
||||||
|
description: "Remove the target directory on the server before uploading new data."
|
||||||
|
debug:
|
||||||
|
description: "Enable debug messages for troubleshooting."
|
||||||
|
strip_components:
|
||||||
|
description: "Remove the specified number of leading path elements when extracting files."
|
||||||
|
overwrite:
|
||||||
|
description: "Use the --overwrite flag with tar to overwrite existing files."
|
||||||
|
tar_dereference:
|
||||||
|
description: "Use the --dereference flag with tar to follow symlinks."
|
||||||
|
tar_tmp_path:
|
||||||
|
description: "Temporary path for the tar file on the destination host."
|
||||||
|
tar_exec:
|
||||||
|
description: "Path to the tar executable on the destination host. Default: tar."
|
||||||
|
default: "tar"
|
||||||
|
proxy_host:
|
||||||
|
description: "Remote host address for SSH proxy."
|
||||||
|
proxy_port:
|
||||||
|
description: "SSH proxy port. Default: 22."
|
||||||
|
default: "22"
|
||||||
|
proxy_username:
|
||||||
|
description: "Username for SSH proxy authentication."
|
||||||
|
proxy_password:
|
||||||
|
description: "Password for SSH proxy authentication."
|
||||||
|
proxy_passphrase:
|
||||||
|
description: "Passphrase for the SSH proxy private key, if required."
|
||||||
|
proxy_timeout:
|
||||||
|
description: "Timeout for establishing SSH connection to the proxy host. Default: 30s."
|
||||||
|
default: "30s"
|
||||||
|
proxy_key:
|
||||||
|
description: "Content of the SSH proxy private key (e.g., the raw content of ~/.ssh/id_rsa)."
|
||||||
|
proxy_key_path:
|
||||||
|
description: "Path to the SSH proxy private key file."
|
||||||
|
proxy_fingerprint:
|
||||||
|
description: "SHA256 fingerprint of the proxy host's public key. If not set, host key verification is skipped (not recommended for production)."
|
||||||
|
proxy_use_insecure_cipher:
|
||||||
|
description: "Enable additional, less secure ciphers for the proxy connection. Not recommended unless required."
|
||||||
|
curl_insecure:
|
||||||
|
description: "When true, uses the --insecure option with curl for insecure downloads."
|
||||||
|
default: "false"
|
||||||
|
capture_stdout:
|
||||||
|
description: "When true, captures and returns standard output from the commands as action output."
|
||||||
|
default: "false"
|
||||||
|
version:
|
||||||
|
description: |
|
||||||
|
The version of drone-scp to use.
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
stdout:
|
||||||
|
description: "Standard output of the executed commands when capture_stdout is enabled."
|
||||||
|
value: ${{ steps.entrypoint.outputs.stdout }}
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Set GitHub Path
|
||||||
|
run: echo "$GITHUB_ACTION_PATH" >> $GITHUB_PATH
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
GITHUB_ACTION_PATH: ${{ github.action_path }}
|
||||||
|
- id: entrypoint
|
||||||
|
name: Run entrypoint.sh
|
||||||
|
run: entrypoint.sh
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
GITHUB_ACTION_PATH: ${{ github.action_path }}
|
||||||
|
INPUT_HOST: ${{ inputs.host }}
|
||||||
|
INPUT_PORT: ${{ inputs.port }}
|
||||||
|
INPUT_PROTOCOL: ${{ inputs.protocol }}
|
||||||
|
INPUT_USERNAME: ${{ inputs.username }}
|
||||||
|
INPUT_PASSWORD: ${{ inputs.password }}
|
||||||
|
INPUT_PASSPHRASE: ${{ inputs.passphrase }}
|
||||||
|
INPUT_KEY: ${{ inputs.key }}
|
||||||
|
INPUT_KEY_PATH: ${{ inputs.key_path }}
|
||||||
|
INPUT_FINGERPRINT: ${{ inputs.fingerprint }}
|
||||||
|
INPUT_PROXY_HOST: ${{ inputs.proxy_host }}
|
||||||
|
INPUT_PROXY_PORT: ${{ inputs.proxy_port }}
|
||||||
|
INPUT_PROXY_USERNAME: ${{ inputs.proxy_username }}
|
||||||
|
INPUT_PROXY_PASSWORD: ${{ inputs.proxy_password }}
|
||||||
|
INPUT_PROXY_PASSPHRASE: ${{ inputs.proxy_passphrase }}
|
||||||
|
INPUT_PROXY_KEY: ${{ inputs.proxy_key }}
|
||||||
|
INPUT_PROXY_KEY_PATH: ${{ inputs.proxy_key_path }}
|
||||||
|
INPUT_PROXY_FINGERPRINT: ${{ inputs.proxy_fingerprint }}
|
||||||
|
INPUT_USE_INSECURE_CIPHER: ${{ inputs.use_insecure_cipher }}
|
||||||
|
INPUT_CIPHER: ${{ inputs.cipher }}
|
||||||
|
INPUT_PROXY_USE_INSECURE_CIPHER: ${{ inputs.proxy_use_insecure_cipher }}
|
||||||
|
INPUT_PROXY_CIPHER: ${{ inputs.proxy_cipher }}
|
||||||
|
INPUT_DEBUG: ${{ inputs.debug }}
|
||||||
|
INPUT_TIMEOUT: ${{ inputs.timeout }}
|
||||||
|
INPUT_COMMAND_TIMEOUT: ${{ inputs.command_timeout }}
|
||||||
|
INPUT_TARGET: ${{ inputs.target }}
|
||||||
|
INPUT_SOURCE: ${{ inputs.source }}
|
||||||
|
INPUT_RM: ${{ inputs.rm }}
|
||||||
|
INPUT_STRIP_COMPONENTS: ${{ inputs.strip_components }}
|
||||||
|
INPUT_OVERWRITE: ${{ inputs.overwrite }}
|
||||||
|
INPUT_TAR_DEREFERENCE: ${{ inputs.tar_dereference }}
|
||||||
|
INPUT_TAR_TMP_PATH: ${{ inputs.tar_tmp_path }}
|
||||||
|
INPUT_TAR_EXEC: ${{ inputs.tar_exec }}
|
||||||
|
INPUT_PROXY_TIMEOUT: ${{ inputs.proxy_timeout }}
|
||||||
|
INPUT_CAPTURE_STDOUT: ${{ inputs.capture_stdout }}
|
||||||
|
INPUT_CURL_INSECURE: ${{ inputs.curl_insecure }}
|
||||||
|
DRONE_SCP_VERSION: ${{ inputs.version }}
|
||||||
|
|
||||||
|
branding:
|
||||||
|
icon: "copy"
|
||||||
|
color: "gray-dark"
|
@ -1,7 +1,56 @@
|
|||||||
#!/bin/sh
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -eu
|
set -euo pipefail
|
||||||
|
|
||||||
export GITHUB="true"
|
export GITHUB="true"
|
||||||
|
|
||||||
sh -c "/bin/drone-scp $*"
|
GITHUB_ACTION_PATH="${GITHUB_ACTION_PATH%/}"
|
||||||
|
DRONE_SCP_RELEASE_URL="${DRONE_SCP_RELEASE_URL:-https://github.com/appleboy/drone-scp/releases/download}"
|
||||||
|
DRONE_SCP_VERSION="${DRONE_SCP_VERSION:-1.8.0}"
|
||||||
|
|
||||||
|
function log_error() {
|
||||||
|
echo "$1" >&2
|
||||||
|
exit "$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
function detect_client_info() {
|
||||||
|
CLIENT_PLATFORM="${SCP_CLIENT_OS:-$(uname -s | tr '[:upper:]' '[:lower:]')}"
|
||||||
|
CLIENT_ARCH="${SCP_CLIENT_ARCH:-$(uname -m)}"
|
||||||
|
|
||||||
|
case "${CLIENT_PLATFORM}" in
|
||||||
|
darwin | linux | windows) ;;
|
||||||
|
*) log_error "Unknown or unsupported platform: ${CLIENT_PLATFORM}. Supported platforms are Linux, Darwin, and Windows." 2 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "${CLIENT_ARCH}" in
|
||||||
|
x86_64* | i?86_64* | amd64*) CLIENT_ARCH="amd64" ;;
|
||||||
|
aarch64* | arm64*) CLIENT_ARCH="arm64" ;;
|
||||||
|
*) log_error "Unknown or unsupported architecture: ${CLIENT_ARCH}. Supported architectures are x86_64, i686, and arm64." 3 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
detect_client_info
|
||||||
|
DOWNLOAD_URL_PREFIX="${DRONE_SCP_RELEASE_URL}/v${DRONE_SCP_VERSION}"
|
||||||
|
CLIENT_BINARY="drone-scp-${DRONE_SCP_VERSION}-${CLIENT_PLATFORM}-${CLIENT_ARCH}"
|
||||||
|
TARGET="${GITHUB_ACTION_PATH}/${CLIENT_BINARY}"
|
||||||
|
echo "Downloading ${CLIENT_BINARY} from ${DOWNLOAD_URL_PREFIX}"
|
||||||
|
INSECURE_OPTION=""
|
||||||
|
if [[ "${INPUT_CURL_INSECURE}" == 'true' ]]; then
|
||||||
|
INSECURE_OPTION="--insecure"
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl -fsSL --retry 5 --keepalive-time 2 ${INSECURE_OPTION} "${DOWNLOAD_URL_PREFIX}/${CLIENT_BINARY}" -o "${TARGET}"
|
||||||
|
chmod +x "${TARGET}"
|
||||||
|
|
||||||
|
echo "======= CLI Version Information ======="
|
||||||
|
"${TARGET}" --version
|
||||||
|
echo "======================================="
|
||||||
|
if [[ "${INPUT_CAPTURE_STDOUT}" == 'true' ]]; then
|
||||||
|
{
|
||||||
|
echo 'stdout<<EOF'
|
||||||
|
"${TARGET}" "$@" | tee -a "${GITHUB_OUTPUT}"
|
||||||
|
echo 'EOF'
|
||||||
|
} >>"${GITHUB_OUTPUT}"
|
||||||
|
else
|
||||||
|
"${TARGET}" "$@"
|
||||||
|
fi
|
||||||
|
@ -1 +1,2 @@
|
|||||||
foo
|
foo
|
||||||
|
foobar
|
||||||
|
@ -1 +1,2 @@
|
|||||||
bar
|
bar
|
||||||
|
foobar
|
||||||
|
@ -1 +1,3 @@
|
|||||||
c
|
c
|
||||||
|
foobar
|
||||||
|
test1234
|
||||||
|
@ -1 +1,3 @@
|
|||||||
d
|
d
|
||||||
|
foobar
|
||||||
|
foobar
|
||||||
|
Loading…
Reference in New Issue
Block a user