TL;DR: Cách khắc phục nhanh
Robocopy không tuân theo các quy tắc thông thường. Trong khi hầu hết các công cụ sử dụng 0 để báo thành công và bất kỳ giá trị nào khác cho thất bại, Robocopy lại trả về 1 khi nó sao chép tệp thành công. Hầu hết các nền tảng CI/CD như GitHub Actions hoặc Azure DevOps coi giá trị 1 đó là lỗi và dừng quá trình build của bạn ngay lập tức.
Để khắc phục điều này, bạn cần chặn mã thoát. Nếu giá trị nhỏ hơn 8, hãy yêu cầu pipeline coi đó là thành công:
robocopy source destination /options
if %ERRORLEVEL% LEQ 1 exit 0
Tại sao pipeline của bạn bị lỗi
Các công cụ CLI tiêu chuẩn thường có dạng nhị phân: 0 nghĩa là hoạt động tốt, và 1 nghĩa là bị lỗi. Các trình chạy (runner) CI/CD được thiết lập mặc định để dừng build ngay khi chúng thấy một mã thoát khác không. Tuy nhiên, Robocopy được thiết kế để ghi nhật ký chi tiết bằng hệ thống bitmask. Nó sử dụng các mã thoát để cho bạn biết chính xác điều gì đã xảy ra trong quá trình đồng bộ hóa.
Dưới đây là ý nghĩa các giá trị trả về của Robocopy:
- 0: Không có tệp nào được sao chép. Nguồn và đích đã giống hệt nhau.
- 1: Thành công. Một hoặc nhiều tệp đã được sao chép thành công đến đích.
- 2: Có các tệp dư thừa ở đích mà không có ở nguồn.
- 4: Phát hiện các tệp hoặc thư mục không khớp.
- 8: Thất bại. Một số tệp không thể sao chép.
- 16: Lỗi nghiêm trọng. Điều này thường có nghĩa là đĩa đầy, quyền truy cập bị từ chối hoặc đường dẫn mạng bị mất.
Vì 1 lớn hơn 0, runner của bạn thấy ROBOCOPY : Exit : 1 (0x01) và giả định kết quả xấu nhất. Nó đánh dấu thất bại ngay cả khi 500MB tài nguyên production của bạn vừa mới được tải lên hoàn hảo.
Khắc phục logic mã thoát
Cách 1: Sử dụng Batch Script Wrapper
Batch script là cách phổ biến nhất để kích hoạt Robocopy trên các runner Windows. Nếu bạn đang sử dụng tệp .bat hoặc .cmd, hãy thêm một kiểm tra ngay sau lệnh của bạn. Điều này đảm bảo script trả về giá trị 0 sạch sẽ cho runner.
robocopy "C:\build\artifacts" "\\deploy\server" /E /Z /R:5 /W:5
:: Nếu mã nằm trong khoảng từ 0 đến 7, ép buộc nó về 0 để build thành công
if %ERRORLEVEL% LSS 8 exit /b 0
Cách 2: Xử lý bằng PowerShell
PowerShell là shell mặc định cho nhiều runner Windows hiện đại. Nó theo dõi mã thoát cuối cùng trong biến $LASTEXITCODE. Bạn có thể đặt lại giá trị này theo cách thủ công để giữ cho pipeline tiếp tục chạy.
robocopy "source" "destination" /MIR
if ($LASTEXITCODE -lt 8) {
$global:LASTEXITCODE = 0
}
Cách tiếp cận này an toàn hơn cho việc triển khai tự động. Nó cho phép các cảnh báo nhỏ (như mã thoát 2 cho các tệp dư thừa) trong khi vẫn báo lỗi nếu xảy ra lỗi thực sự (mã 8 hoặc 16).
Cách 3: Khắc phục trong YAML của GitHub Actions
Khi gọi trực tiếp Robocopy bên trong tệp main.yml, bạn có thể chuỗi các lệnh lại với nhau. Đây là cách gọn gàng nhất để xử lý logic mà không cần tạo các tệp script riêng biệt.
- name: Deploy via Robocopy
shell: cmd
run: |
robocopy "src" "dest" /E /NP
if %ERRORLEVEL% LEQ 1 exit 0
Cách xác minh khắc phục
Kiểm tra nhật ký pipeline của bạn sau khi áp dụng các thay đổi này. Bạn vẫn sẽ thấy ROBOCOPY : Exit : 1 trong đầu ra văn bản, nhưng bản thân bước đó hiện sẽ hiển thị dấu kiểm màu xanh lá cây.
- Kích hoạt một bản build thủ công.
- Tìm tác vụ Robocopy trong nhật ký.
- Xác nhận rằng pipeline chuyển sang bước tiếp theo thay vì bị dừng lại.
- Kiểm tra ngẫu nhiên thư mục đích để đảm bảo các tệp của bạn—cho dù đó là 10 hình ảnh hay 1.000 tệp DLL—thực sự đã đến nơi.
Những mã nào thực sự quan trọng?
Đừng bỏ qua mọi lỗi. Nếu Robocopy trả về 8 hoặc 16, pipeline của bạn nên thất bại. Các mã này chỉ ra các vấn đề nghiêm trọng như Access Denied hoặc Insufficient Disk Space. Bằng cách sử dụng logic LSS 8 (Nhỏ hơn 8), bạn sẽ bỏ qua các thông báo "tệp đã sao chép" hữu ích trong khi vẫn bắt được các lỗi thực sự làm hỏng quá trình triển khai của bạn.

