From ae463107f908109b131ec42ad1ee60306c6d7032 Mon Sep 17 00:00:00 2001 From: Ayyadurai Date: Sun, 9 Nov 2025 16:52:51 +0530 Subject: [PATCH] feat: add 'flatten' option to copy directory contents without parent folder structure --- README.md | 27 +++++++++++++++++++++++++++ README.zh-cn.md | 27 +++++++++++++++++++++++++++ README.zh-tw.md | 27 +++++++++++++++++++++++++++ action.yml | 4 ++++ entrypoint.sh | 38 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 123 insertions(+) diff --git a/README.md b/README.md index eb7c683..8892675 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ jobs: | Variable | Description | Default | Security Note | | ---------------- | ------------------------------------------------------- | ------- | ---------------------- | | source | Local files/directories to transfer (comma-separated) | - | Use explicit paths | +| flatten | Copy directory contents without parent folder structure | false | Perfect for build dirs | | target | Target directory on remote server (must be a directory) | - | Avoid root directories | | rm | Remove target directory before upload | - | Use with caution | | strip_components | Remove leading path elements when extracting | - | | @@ -165,6 +166,7 @@ jobs: - **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) +- **Flatten directory structure (build outputs)** → [Example 6](#example-6-flatten-directory-structure) --- @@ -257,6 +259,25 @@ jobs: rm: true ``` +#### Example 6: Flatten Directory Structure + +```yaml +- name: Deploy build folder contents + uses: appleboy/scp-action@v1 + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.KEY }} + port: ${{ secrets.PORT }} + source: "build/*" + target: "/www/htdocs/production/" + flatten: true +``` + +**Result:** +- ✅ Without `flatten`: `/www/htdocs/production/build/index.html` +- ✅ With `flatten: true`: `/www/htdocs/production/index.html` + --- ## 🗝️ SSH Key Setup @@ -341,6 +362,12 @@ sequenceDiagram - **Q: How to copy to Windows?** A: Set up Git Bash, use Unix-style paths, and enable `tar_dereference`. +- **Q: How do I copy only folder contents without the parent folder?** + A: Use `flatten: true`. This automatically handles directory structure flattening: + - `source: "build/*"` + `flatten: true` → copies contents directly to target + - `source: "dist/"` + `flatten: true` → copies contents without creating `dist/` subdirectory + - Perfect for deploying build outputs where you don't want the build folder name in the target path. + --- ## 📝 License diff --git a/README.zh-cn.md b/README.zh-cn.md index 4fe61eb..8bc4da2 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -98,6 +98,7 @@ jobs: | 变量 | 说明 | 默认值 | 安全性说明 | | ---------------- | --------------------------------- | ------ | -------------- | | source | 本地要传输的文件/目录(逗号分隔) | - | 请使用明确路径 | +| flatten | 仅复制目录内容,不包含父文件夹 | false | 适用于构建目录 | | target | 远程目标目录(必须为目录) | - | 避免使用根目录 | | rm | 上传前移除目标目录 | - | 谨慎使用 | | strip_components | 传输时移除前置路径元素 | - | | @@ -165,6 +166,7 @@ jobs: - **仅传输变更文件** → [示例 3](#示例-3仅传输变更文件) - **集成 Artifacts** → [示例 4](#示例-4集成-artifacts) - **Windows 服务器设置** → [示例 5](#示例-5windows-服务器) +- **扁平化目录结构(构建输出)** → [示例 6](#示例-6扁平化目录结构) --- @@ -257,6 +259,25 @@ jobs: rm: true ``` +#### 示例 6:扁平化目录结构 + +```yaml +- name: 部署构建文件夹内容 + uses: appleboy/scp-action@v1 + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.KEY }} + port: ${{ secrets.PORT }} + source: "build/*" + target: "/www/htdocs/production/" + flatten: true +``` + +**结果:** +- ✅ 不使用 `flatten`:`/www/htdocs/production/build/index.html` +- ✅ 使用 `flatten: true`:`/www/htdocs/production/index.html` + --- ## 🗝️ SSH 密钥设置 @@ -341,6 +362,12 @@ sequenceDiagram - **Q: 如何复制到 Windows?** A: 设置 Git Bash,使用类 Unix 路径,并启用 `tar_dereference`。 +- **Q: 如何只复制文件夹内容而不包含父文件夹?** + A: 使用 `flatten: true`。这会自动处理目录结构扁平化: + - `source: "build/*"` + `flatten: true` → 直接将内容复制到目标目录 + - `source: "dist/"` + `flatten: true` → 复制内容而不创建 `dist/` 子目录 + - 非常适合部署构建输出,避免在目标路径中包含构建文件夹名称。 + --- ## 📝 许可证 diff --git a/README.zh-tw.md b/README.zh-tw.md index 9b39b42..1019a20 100644 --- a/README.zh-tw.md +++ b/README.zh-tw.md @@ -98,6 +98,7 @@ jobs: | 變數 | 說明 | 預設值 | 安全性說明 | | ---------------- | --------------------------------- | ------ | -------------- | | source | 本地要傳送的檔案/目錄(逗號分隔) | - | 請使用明確路徑 | +| flatten | 僅複製目錄內容,不包含父資料夾 | false | 適用於建置目錄 | | target | 遠端目標目錄(必須為目錄) | - | 避免使用根目錄 | | rm | 上傳前移除目標目錄 | - | 請小心使用 | | strip_components | 傳送時移除前置路徑元素 | - | | @@ -165,6 +166,7 @@ jobs: - **僅傳送變更檔案** → [範例 3](#範例-3僅傳送變更檔案) - **整合 Artifacts** → [範例 4](#範例-4整合-artifacts) - **Windows 伺服器設定** → [範例 5](#範例-5windows-伺服器) +- **扁平化目錄結構(建置輸出)** → [範例 6](#範例-6扁平化目錄結構) --- @@ -257,6 +259,25 @@ jobs: rm: true ``` +#### 範例 6:扁平化目錄結構 + +```yaml +- name: 部署建置資料夾內容 + uses: appleboy/scp-action@v1 + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.KEY }} + port: ${{ secrets.PORT }} + source: "build/*" + target: "/www/htdocs/production/" + flatten: true +``` + +**結果:** +- ✅ 不使用 `flatten`:`/www/htdocs/production/build/index.html` +- ✅ 使用 `flatten: true`:`/www/htdocs/production/index.html` + --- ## 🗝️ SSH 金鑰設定 @@ -341,6 +362,12 @@ sequenceDiagram - **Q: 如何複製到 Windows?** A: 設定 Git Bash,使用 Unix 風格路徑,並啟用 `tar_dereference`。 +- **Q: 如何只複製資料夾內容而不包含父資料夾?** + A: 使用 `flatten: true`。這會自動處理目錄結構扁平化: + - `source: "build/*"` + `flatten: true` → 直接將內容複製到目標目錄 + - `source: "dist/"` + `flatten: true` → 複製內容而不建立 `dist/` 子目錄 + - 非常適合部署建置輸出,避免在目標路徑中包含建置資料夾名稱。 + --- ## 📝 授權條款 diff --git a/action.yml b/action.yml index e523cb6..d34f6e1 100644 --- a/action.yml +++ b/action.yml @@ -49,6 +49,9 @@ inputs: tar_exec: description: "Path to the tar executable on the destination host. Default: tar." default: "tar" + flatten: + description: "Copy only directory contents without parent folder structure. Useful for deploying build outputs." + default: "false" proxy_host: description: "Remote host address for SSH proxy." proxy_port: @@ -132,6 +135,7 @@ runs: INPUT_TAR_DEREFERENCE: ${{ inputs.tar_dereference }} INPUT_TAR_TMP_PATH: ${{ inputs.tar_tmp_path }} INPUT_TAR_EXEC: ${{ inputs.tar_exec }} + INPUT_FLATTEN: ${{ inputs.flatten }} INPUT_PROXY_TIMEOUT: ${{ inputs.proxy_timeout }} INPUT_CAPTURE_STDOUT: ${{ inputs.capture_stdout }} INPUT_CURL_INSECURE: ${{ inputs.curl_insecure }} diff --git a/entrypoint.sh b/entrypoint.sh index f9449e8..f45639d 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -29,7 +29,45 @@ function detect_client_info() { esac } +function process_flatten() { + # Only process if flatten is enabled and strip_components is not manually set + if [[ "${INPUT_FLATTEN}" == 'true' ]] && [[ -z "${INPUT_STRIP_COMPONENTS}" ]]; then + # Parse the source paths (comma-separated) + IFS=',' read -ra SOURCE_PATHS <<< "${INPUT_SOURCE}" + local max_depth=0 + + for source_path in "${SOURCE_PATHS[@]}"; do + # Trim whitespace + source_path=$(echo "$source_path" | xargs) + + # Calculate directory depth (count slashes before wildcard or end) + if [[ "$source_path" == *"*"* ]]; then + # Has wildcard - count slashes before the * + local path_before_wildcard="${source_path%%\**}" + local depth=$(echo "$path_before_wildcard" | tr -cd '/' | wc -c) + else + # No wildcard - treat as directory, count all slashes + local depth=$(echo "$source_path" | sed 's:/*$::' | tr -cd '/' | wc -c) + # Add 1 to strip the directory itself + depth=$((depth + 1)) + fi + + # Track maximum depth for multiple sources + if [[ $depth -gt $max_depth ]]; then + max_depth=$depth + fi + done + + # Set strip_components if we found paths to flatten + if [[ $max_depth -gt 0 ]]; then + export INPUT_STRIP_COMPONENTS="$max_depth" + echo "Flatten enabled: automatically setting strip_components=${max_depth}" + fi + fi +} + detect_client_info +process_flatten 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}"