Trong monorepo, một step chạy được sau cd packages/api, nhưng step tiếp theo báo không tìm thấy file. Hai step nhìn thấy cùng filesystem của job, song không dùng chung một shell đang đứng ở thư mục đó. Cần khai báo nơi chạy lệnh cho từng step hoặc đặt mặc định.
Bài này xây một workflow nhỏ không tải repository, không cài package và không gọi dịch vụ ngoài. Các thư mục được tạo ngay trong job để bạn quan sát đường dẫn. Khi áp dụng cho repository thật, cần bổ sung bước checkout phù hợp trước các lệnh đọc source.
Phạm vi kiểm tra
Đối chiếu tài liệu GitHub Actions ngày 11/11/2026. YAML được phân tích cú pháp bằng Ruby; các đoạn Bash được kiểm tra cú pháp và chạy cục bộ trong thư mục tạm. Chưa chạy trên GitHub-hosted runner, chưa đo thời gian, chi phí hay hành vi một action bên thứ ba.
Tài liệu cho phép đặt defaults.run.working-directory ở cấp workflow hoặc job; cấu hình cụ thể hơn được ưu tiên. Thiết lập này dành cho step run. Nó không tự biến đường dẫn của mọi uses action thành đường dẫn tương đối với thư mục ấy.
1. Workflow tự tạo dữ liệu thử
Lưu ví dụ sau thành .github/workflows/directory-demo.yml trong một repository thử nghiệm. Workflow chỉ chạy thủ công và không cần quyền đọc nội dung repository vì không checkout.
name: Directory demo
on:
workflow_dispatch:
permissions: {}
jobs:
inspect:
runs-on: ubuntu-latest
defaults:
run:
shell: bash
working-directory: packages/api
steps:
- name: Create fixture from workspace root
working-directory: ${{ github.workspace }}
run: |
set -euo pipefail
mkdir -p packages/api
printf '%s\n' 'api-demo' > packages/api/name.txt
- name: Read from the job default directory
run: |
set -euo pipefail
test "$(cat name.txt)" = 'api-demo'
cd ..
test -d api
- name: Start in the default directory again
run: |
set -euo pipefail
test -f name.txt
pwd
- name: Override for one step
working-directory: ${{ github.workspace }}
run: |
set -euo pipefail
test -f packages/api/name.txt
pwd
Step đầu phải chạy ở workspace root vì thư mục mặc định chưa tồn tại. Nếu bỏ override này, runner không thể vào thư mục cần tạo trước khi thực thi script tạo nó. Đây là ví dụ về thứ tự chuẩn bị filesystem, không phải lỗi quyền đọc file.
Step thứ hai đọc name.txt, sau đó đi lên packages. Step thứ ba vẫn bắt đầu tại packages/api, nên tiếp tục thấy name.txt. Step cuối chỉ đổi nơi chạy của chính nó về root.
2. Tách filesystem và trạng thái shell
File do step đầu ghi có thể được step khác trong cùng job đọc lại. Ngược lại, cd chỉ thay đổi thư mục làm việc của process hiện tại. Khi process kết thúc, không có một “con trỏ thư mục” chung được chuyển sang step kế tiếp.
Trong fixture local, các script được chạy bằng những process Bash riêng với cwd chỉ định rõ. Điều đó kiểm tra được đường dẫn và điều kiện test, nhưng không mô phỏng toàn bộ runner. Kết quả chạy local không nên được ghi thành một lần workflow đã thành công trên GitHub.
3. Áp dụng cho monorepo thật
Nếu hầu hết lệnh thuộc một package, đặt mặc định cấp job để giảm lặp. Với một lệnh ở root, override ngay tại step và giữ lệnh tương đối ngắn. Tránh vừa thêm packages/api/ vào mọi đường dẫn vừa chạy trong chính packages/api; kết quả dễ thành một đường dẫn lồng sai.
Sau checkout, thêm kiểm tra file quan trọng trước lệnh build: package manifest, script kiểm thử hoặc lockfile mong đợi. Một thông báo lỗi sớm về file thiếu dễ xử lý hơn log dài của package manager đang chạy nhầm package.
Với step uses, đọc input đường dẫn của action đó. Tên input có thể là path, working-directory hoặc một lựa chọn khác; không suy ra từ thiết lập của step run. Ví dụ bài này không dùng action ngoài nên không kiểm chứng hợp đồng của bất kỳ action cụ thể nào.
Kiểm tra và lỗi thường gặp
Chạy workflow thủ công trong repository thử rồi xem hai dòng pwd: một dòng nằm ở package, dòng kia ở root. Những assertion là điều kiện mong đợi để bạn xác minh; chưa có log hosted runner trong bài.
Nếu thất bại trước khi script in gì, kiểm tra thư mục làm việc đã tồn tại chưa. Nếu lệnh đọc file sai, kiểm tra bạn đang dùng đường dẫn tính từ root hay từ package. Nếu chỉ step sau bị sai, tìm giả định rằng cd được giữ lại.
Kết luận
Khai báo nơi chạy lệnh giúp workflow monorepo dễ đọc và kiểm tra. File có thể tồn tại giữa các step trong cùng job; thư mục hiện tại của một shell cần được thiết lập lại theo cấu hình step mới.

