@@ -14,20 +14,18 @@ jobs:
1414 steps :
1515 - uses : actions/checkout@v4
1616 with :
17- fetch-depth : 3
17+ fetch-depth : 4
1818
19- - name : Rebuild fix on upstream main
19+ - name : Build rebased commit object
2020 shell : bash
21+ env :
22+ GITHUB_TOKEN : ${{ github.token }}
2123 run : |
2224 set -euo pipefail
2325
2426 ORIGINAL=ed1a29ad1e4c657e6adbe3f9bde275e14928e6c0
25- BRANCH=fix/readdir-recursive-buffer-path
26-
27- git config user.name "github-actions[bot]"
28- git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
2927 git remote add upstream https://github.com/nodejs/node.git 2>/dev/null || true
30- git fetch upstream main
28+ git fetch --depth=1 upstream main
3129 git checkout --detach upstream/main
3230
3331 python3 <<'PY'
@@ -41,13 +39,11 @@ jobs:
4139 raise SystemExit(f'{path}: expected exactly one match, found {count}: {old!r}')
4240 p.write_text(text.replace(old, new, 1))
4341
44- # Shared Buffer-aware path helpers.
4542 replace_once(
4643 'lib/internal/fs/utils.js',
4744 "const pathModule = require('path');\nconst kType = Symbol('type');",
4845 "const pathModule = require('path');\nconst binding = internalBinding('fs');\nconst kType = Symbol('type');",
4946 )
50-
5147 replace_once(
5248 'lib/internal/fs/utils.js',
5349 "function getDirents(path, { 0: names, 1: types }, callback) {",
@@ -61,82 +57,140 @@ jobs:
6157
6258 function getDirents(path, { 0: names, 1: types }, callback) {""",
6359 )
64-
6560 replace_once(
6661 'lib/internal/fs/utils.js',
6762 " getDirents,\n getOptions,\n getValidatedFd,",
6863 " getDirents,\n getOptions,\n isDirectoryPath,\n join,\n getValidatedFd,",
6964 )
7065
71- # Callback/sync recursive readdir now shares one traversal helper on main.
7266 replace_once(
7367 'lib/fs.js',
7468 " handleErrorFromBinding,\n preprocessSymlinkDestination,",
7569 " handleErrorFromBinding,\n isDirectoryPath,\n join: joinPath,\n preprocessSymlinkDestination,",
7670 )
77-
7871 replace_once(
7972 'lib/fs.js',
8073 " * @param {string} dir\n * @param {string} prefix",
8174 " * @param {string | Buffer} dir\n * @param {string | Buffer} prefix",
8275 )
83-
8476 replace_once(
8577 'lib/fs.js',
8678 " const relative = prefix === '' ? name : `${prefix}${pathModule.sep}${name}`;\n let isDirectory;",
8779 " const relative = prefix === '' ? name : joinPath(prefix, name);\n const fullPath = joinPath(dir, name);\n let isDirectory;",
8880 )
89-
9081 replace_once(
9182 'lib/fs.js',
9283 " (dirent.isSymbolicLink() && binding.internalModuleStat(pathModule.join(dir, name)) === 1);",
9384 " (dirent.isSymbolicLink() && isDirectoryPath(fullPath));",
9485 )
95-
9686 replace_once(
9787 'lib/fs.js',
9888 " binding.internalModuleStat(pathModule.join(dir, name)) === 1);",
9989 " isDirectoryPath(fullPath));",
10090 )
101-
10291 replace_once(
10392 'lib/fs.js',
10493 " ArrayPrototypePush(context.dirs, pathModule.join(dir, name));",
10594 " ArrayPrototypePush(context.dirs, fullPath);",
10695 )
10796
108- # Promise recursive readdir uses the same Buffer-safe helpers.
10997 replace_once(
11098 'lib/internal/fs/promises.js',
11199 " getReadFileBufferByteLengthName,\n preprocessSymlinkDestination,",
112100 " getReadFileBufferByteLengthName,\n isDirectoryPath,\n join: joinPath,\n preprocessSymlinkDestination,",
113101 )
114-
115102 replace_once(
116103 'lib/internal/fs/promises.js',
117104 " const relative = prefix === '' ? name : `${prefix}${pathModule.sep}${name}`;\n let isDirectory;",
118105 " const relative = prefix === '' ? name : joinPath(prefix, name);\n const direntPath = joinPath(path, name);\n let isDirectory;",
119106 )
120-
121107 replace_once(
122108 'lib/internal/fs/promises.js',
123109 " binding.internalModuleStat(pathModule.join(path, name)) === 1);",
124110 " isDirectoryPath(direntPath));",
125111 )
126-
127112 replace_once(
128113 'lib/internal/fs/promises.js',
129114 " if (isDirectory) {\n const direntPath = pathModule.join(path, name);\n ArrayPrototypePush(queue, [direntPath, relative, await readdirWithTypes(direntPath)]);",
130115 " if (isDirectory) {\n ArrayPrototypePush(queue, [direntPath, relative, await readdirWithTypes(direntPath)]);",
131116 )
132117 PY
133118
134- # Keep the regression test from the original PR commit.
135119 git show "$ORIGINAL":test/parallel/test-fs-readdir-recursive-buffer.js \
136120 > test/parallel/test-fs-readdir-recursive-buffer.js
137-
138121 git diff --check
139- git add lib/fs.js lib/internal/fs/promises.js lib/internal/fs/utils.js \
140- test/parallel/test-fs-readdir-recursive-buffer.js
141- git commit -C "$ORIGINAL"
142- git push --force origin HEAD:"$BRANCH"
122+
123+ python3 <<'PY'
124+ import base64
125+ import json
126+ import os
127+ import subprocess
128+ import urllib.request
129+ from pathlib import Path
130+
131+ repo = 'canblmz1/node'
132+ token = os.environ['GITHUB_TOKEN']
133+
134+ def run(*args):
135+ return subprocess.check_output(args, text=True).strip()
136+
137+ def api(path, data):
138+ body = json.dumps(data).encode()
139+ req = urllib.request.Request(
140+ 'https://api.github.com' + path,
141+ data=body,
142+ method='POST',
143+ headers={
144+ 'Authorization': f'Bearer {token}',
145+ 'Accept': 'application/vnd.github+json',
146+ 'X-GitHub-Api-Version': '2022-11-28',
147+ 'User-Agent': 'pr-64954-rebuilder',
148+ 'Content-Type': 'application/json',
149+ },
150+ )
151+ with urllib.request.urlopen(req) as response:
152+ return json.load(response)
153+
154+ parent = run('git', 'rev-parse', 'upstream/main')
155+ base_tree = run('git', 'rev-parse', 'upstream/main^{tree}')
156+ original = 'ed1a29ad1e4c657e6adbe3f9bde275e14928e6c0'
157+ message = run('git', 'show', '-s', '--format=%B', original)
158+
159+ paths = [
160+ 'lib/fs.js',
161+ 'lib/internal/fs/promises.js',
162+ 'lib/internal/fs/utils.js',
163+ 'test/parallel/test-fs-readdir-recursive-buffer.js',
164+ ]
165+ entries = []
166+ for path in paths:
167+ content = base64.b64encode(Path(path).read_bytes()).decode()
168+ blob = api(f'/repos/{repo}/git/blobs', {
169+ 'content': content,
170+ 'encoding': 'base64',
171+ })
172+ entries.append({
173+ 'path': path,
174+ 'mode': '100644',
175+ 'type': 'blob',
176+ 'sha': blob['sha'],
177+ })
178+
179+ tree = api(f'/repos/{repo}/git/trees', {
180+ 'base_tree': base_tree,
181+ 'tree': entries,
182+ })
183+ commit = api(f'/repos/{repo}/git/commits', {
184+ 'message': message,
185+ 'tree': tree['sha'],
186+ 'parents': [parent],
187+ 'author': {
188+ 'name': 'Can',
189+ 'email': 'hello@syntaxandco.com',
190+ 'date': '2026-08-02T10:00:57Z',
191+ },
192+ })
193+ print('CREATED_COMMIT_SHA=' + commit['sha'])
194+ print('PARENT_SHA=' + parent)
195+ print('TREE_SHA=' + tree['sha'])
196+ PY
0 commit comments