Repository: streamich/memfs (ts)

Issue:
"utimes" doesn't work for directories: "EISDIR: illegal operation on a directory, open ..." error
`utimes` calls `utimesBase` which uses `openSync` call internally but `openSync` call on a directory obviously throws `EISDIR` error.

https://github.com/streamich/memfs/blob/674a1e78469e1e9e766db7e3160538e958fdd97b/src/volume.ts#L1771-L1778

Pull request description:
fix: support calling `utimes` on a directory
- "EISDIR: illegal operation on a directory, open ..." error
- https://github.com/streamich/memfs/issues/391

Resolves #391

Patch:
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
new file mode 100644
index 00000000..4407bb3f
--- /dev/null
+++ b/.github/workflows/lint.yml
@@ -0,0 +1,15 @@
+name: Lint
+on: [pull_request]
+
+jobs:
+  commitlint:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          fetch-depth: 0
+      - uses: wagoid/commitlint-github-action@v5
+        with:
+          configFile: './package.json'
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/package.json b/package.json
index aa0a83d9..891fd6c4 100644
--- a/package.json
+++ b/package.json
@@ -49,6 +49,11 @@
       "path": "git-cz"
     }
   },
+  "commitlint": {
+    "extends": [
+      "@commitlint/config-conventional"
+    ]
+  },
   "jest": {
     "moduleFileExtensions": [
       "ts",
diff --git a/src/volume.ts b/src/volume.ts
index 4f635324..18cbf780 100644
--- a/src/volume.ts
+++ b/src/volume.ts
@@ -1881,7 +1881,7 @@ export class Volume {
   }
 
   private utimesBase(filename: string, atime: number, mtime: number) {
-    const fd = this.openSync(filename, 'r+');
+    const fd = this.openSync(filename, 'r');
     try {
       this.futimesBase(fd, atime, mtime);
     } finally {


Test patch:
diff --git a/src/__tests__/volume.test.ts b/src/__tests__/volume.test.ts
index 9950c247..7f393a31 100644
--- a/src/__tests__/volume.test.ts
+++ b/src/__tests__/volume.test.ts
@@ -968,10 +968,17 @@ describe('volume', () => {
     });
     describe('.utimesSync(path, atime, mtime)', () => {
       const vol = new Volume();
+      vol.mkdirSync('/foo');
       it('Set times on file', () => {
-        vol.writeFileSync('/lol', '12345');
-        vol.utimesSync('/lol', 1234, 12345);
-        const stats = vol.statSync('/lol');
+        vol.writeFileSync('/foo/lol', '12345');
+        vol.utimesSync('/foo/lol', 1234, 12345);
+        const stats = vol.statSync('/foo/lol');
+        expect(Math.round(stats.atime.getTime() / 1000)).toBe(1234);
+        expect(Math.round(stats.mtime.getTime() / 1000)).toBe(12345);
+      });
+      it('Sets times on a directory', () => {
+        vol.utimesSync('/foo', 1234, 12345);
+        const stats = vol.statSync('/foo');
         expect(Math.round(stats.atime.getTime() / 1000)).toBe(1234);
         expect(Math.round(stats.mtime.getTime() / 1000)).toBe(12345);
       });