diff --git a/.github/workflows/ftp.yml b/.github/workflows/ftp.yml index c579d9c..06f273e 100644 --- a/.github/workflows/ftp.yml +++ b/.github/workflows/ftp.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: 🚚 Get latest code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: 📂 Sync files uses: ./ diff --git a/.github/workflows/ftps.yml b/.github/workflows/ftps.yml index d75b7fd..b4aed1b 100644 --- a/.github/workflows/ftps.yml +++ b/.github/workflows/ftps.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: 🚚 Get latest code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: 📂 Sync files uses: ./ diff --git a/README.md b/README.md index f7792a4..471a064 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,10 @@ jobs: runs-on: ubuntu-latest steps: - name: 🚚 Get latest code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: 📂 Sync files - uses: SamKirkland/FTP-Deploy-Action@v4.3.4 + uses: SamKirkland/FTP-Deploy-Action@v4.3.5 with: server: ftp.samkirkland.com username: myFtpUserName @@ -86,7 +86,7 @@ jobs: runs-on: ubuntu-latest steps: - name: 🚚 Get latest code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Use Node.js 16 uses: actions/setup-node@v2 @@ -99,7 +99,7 @@ jobs: npm run build - name: 📂 Sync files - uses: SamKirkland/FTP-Deploy-Action@v4.3.4 + uses: SamKirkland/FTP-Deploy-Action@v4.3.5 with: server: ftp.samkirkland.com username: myFtpUserName @@ -116,10 +116,10 @@ jobs: runs-on: ubuntu-latest steps: - name: 🚚 Get latest code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: 📂 Sync files - uses: SamKirkland/FTP-Deploy-Action@v4.3.4 + uses: SamKirkland/FTP-Deploy-Action@v4.3.5 with: server: ftp.samkirkland.com username: myFtpUserName @@ -139,10 +139,10 @@ jobs: runs-on: ubuntu-latest steps: - name: 🚚 Get latest code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: 📂 Sync files - uses: SamKirkland/FTP-Deploy-Action@v4.3.4 + uses: SamKirkland/FTP-Deploy-Action@v4.3.5 with: server: ftp.samkirkland.com username: myFtpUserName @@ -161,10 +161,10 @@ jobs: runs-on: ubuntu-latest steps: - name: 🚚 Get latest code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: 📂 Sync files - uses: SamKirkland/FTP-Deploy-Action@v4.3.4 + uses: SamKirkland/FTP-Deploy-Action@v4.3.5 with: server: ftp.samkirkland.com username: myFtpUserName diff --git a/action.yml b/action.yml index 1bb1b1c..db4552d 100644 --- a/action.yml +++ b/action.yml @@ -45,7 +45,7 @@ inputs: required: false description: "Timeout in milliseconds for FTP operations" runs: - using: "node16" + using: "node20" main: "dist/index.js" branding: icon: "upload-cloud" diff --git a/dist/index.js b/dist/index.js index 0a22f7d..fa7c245 100644 --- a/dist/index.js +++ b/dist/index.js @@ -4122,8 +4122,8 @@ const fsStat = (0, util_1.promisify)(fs_1.stat); const fsOpen = (0, util_1.promisify)(fs_1.open); const fsClose = (0, util_1.promisify)(fs_1.close); const fsUnlink = (0, util_1.promisify)(fs_1.unlink); -const LIST_COMMANDS_DEFAULT = ["LIST -a", "LIST"]; -const LIST_COMMANDS_MLSD = ["MLSD", "LIST -a", "LIST"]; +const LIST_COMMANDS_DEFAULT = () => ["LIST -a", "LIST"]; +const LIST_COMMANDS_MLSD = () => ["MLSD", "LIST -a", "LIST"]; /** * High-level API to interact with an FTP server. */ @@ -4134,7 +4134,7 @@ class Client { * @param timeout Timeout in milliseconds, use 0 for no timeout. Optional, default is 30 seconds. */ constructor(timeout = 30000) { - this.availableListCommands = LIST_COMMANDS_DEFAULT; + this.availableListCommands = LIST_COMMANDS_DEFAULT(); this.ftp = new FtpContext_1.FTPContext(timeout); this.prepareTransfer = this._enterFirstCompatibleMode([transfer_1.enterPassiveModeIPv6, transfer_1.enterPassiveModeIPv4]); this.parseList = parseList_1.parseList; @@ -4284,10 +4284,10 @@ class Client { // Use MLSD directory listing if possible. See https://tools.ietf.org/html/rfc3659#section-7.8: // "The presence of the MLST feature indicates that both MLST and MLSD are supported." const supportsMLSD = features.has("MLST"); - this.availableListCommands = supportsMLSD ? LIST_COMMANDS_MLSD : LIST_COMMANDS_DEFAULT; + this.availableListCommands = supportsMLSD ? LIST_COMMANDS_MLSD() : LIST_COMMANDS_DEFAULT(); await this.send("TYPE I"); // Binary mode await this.sendIgnoringError("STRU F"); // Use file structure - await this.sendIgnoringError("OPTS UTF8 ON"); // Some servers expect UTF-8 to be enabled explicitly + await this.sendIgnoringError("OPTS UTF8 ON"); // Some servers expect UTF-8 to be enabled explicitly and setting before login might not have worked. if (supportsMLSD) { await this.sendIgnoringError("OPTS MLST type;size;modify;unique;unix.mode;unix.owner;unix.group;unix.ownername;unix.groupname;"); // Make sure MLSD listings include all we can parse } @@ -4322,6 +4322,9 @@ class Client { secureOptions.host = (_b = secureOptions.host) !== null && _b !== void 0 ? _b : options.host; await this.useTLS(secureOptions); } + // Set UTF-8 on before login in case there are non-ascii characters in user or password. + // Note that this might not work before login depending on server. + await this.sendIgnoringError("OPTS UTF8 ON"); await this.login(options.user, options.password); await this.useDefaultSettings(); return welcome; @@ -4419,7 +4422,10 @@ class Client { */ async remove(path, ignoreErrorCodes = false) { const validPath = await this.protectWhitespace(path); - return this.send(`DELE ${validPath}`, ignoreErrorCodes); + if (ignoreErrorCodes) { + return this.sendIgnoringError(`DELE ${validPath}`); + } + return this.send(`DELE ${validPath}`); } /** * Report transfer progress for any upload or download to a given handler. @@ -4628,10 +4634,13 @@ class Client { async removeDir(remoteDirPath) { return this._exitAtCurrentDirectory(async () => { await this.cd(remoteDirPath); + // Get the absolute path of the target because remoteDirPath might be a relative path, even `../` is possible. + const absoluteDirPath = await this.pwd(); await this.clearWorkingDir(); - if (remoteDirPath !== "/") { + const dirIsRoot = absoluteDirPath === "/"; + if (!dirIsRoot) { await this.cdup(); - await this.removeEmptyDir(remoteDirPath); + await this.removeEmptyDir(absoluteDirPath); } }); } @@ -4878,7 +4887,7 @@ var FileType; FileType[FileType["File"] = 1] = "File"; FileType[FileType["Directory"] = 2] = "Directory"; FileType[FileType["SymbolicLink"] = 3] = "SymbolicLink"; -})(FileType = exports.FileType || (exports.FileType = {})); +})(FileType || (exports.FileType = FileType = {})); /** * Describes a file, directory or symbolic link. */ @@ -4985,6 +4994,9 @@ class FTPError extends Error { } } exports.FTPError = FTPError; +function doNothing() { + /** Do nothing */ +} /** * FTPContext holds the control and data sockets of an FTP connection and provides a * simplified way to interact with an FTP server, handle responses, errors and timeouts. @@ -5037,9 +5049,8 @@ class FTPContext { return; } this._closingError = err; - this.send("QUIT"); // Don't wait for an answer // Close the sockets but don't fully reset this context to preserve `this._closingError`. - this._closeSocket(this._socket); + this._closeControlSocket(); this._closeSocket(this._dataSocket); // Give the user's task a chance to react, maybe cleanup resources. this._passToHandler(err); @@ -5080,7 +5091,7 @@ class FTPContext { this._removeSocketListeners(this.socket); } else { - this._closeSocket(this.socket); + this._closeControlSocket(); } } if (socket) { @@ -5289,16 +5300,23 @@ class FTPContext { }); } /** - * Close a socket. + * Close the control socket. Sends QUIT, then FIN, and ignores any response or error. + */ + _closeControlSocket() { + this._removeSocketListeners(this._socket); + this._socket.on("error", doNothing); + this.send("QUIT"); + this._closeSocket(this._socket); + } + /** + * Close a socket, ignores any error. * @protected */ _closeSocket(socket) { if (socket) { this._removeSocketListeners(socket); - socket.on("error", () => { }); - socket.on("timeout", () => socket.destroy()); - socket.setTimeout(this.timeout); - socket.end(); + socket.on("error", doNothing); + socket.destroy(); } } /** @@ -5790,8 +5808,8 @@ function parseSize(value, info) { * Parsers for MLSD facts. */ const factHandlersByName = { - "size": parseSize, - "sizd": parseSize, + "size": parseSize, // File size + "sizd": parseSize, // Directory size "unique": (value, info) => { info.uniqueID = value; }, diff --git a/migration.md b/migration.md index b7da241..e6200d7 100644 --- a/migration.md +++ b/migration.md @@ -25,7 +25,7 @@ Most features have been carried forward and improved upon. However, some feature ### How to upgrade 1. Remove `with: fetch-depth: 2`. It is no longer needed and removing it will _slightly_ speed up deployments. -2. Change the version to `v4.X.X`, for example `SamKirkland/FTP-Deploy-Action@v4.3.4` (please check the [README](https://github.com/SamKirkland/FTP-Deploy-Action/blob/master/README.md) or the [releases page](https://github.com/SamKirkland/FTP-Deploy-Action/releases/latest) for the latest version). +2. Change the version to `v4.X.X`, for example `SamKirkland/FTP-Deploy-Action@v4.3.5` (please check the [README](https://github.com/SamKirkland/FTP-Deploy-Action/blob/master/README.md) or the [releases page](https://github.com/SamKirkland/FTP-Deploy-Action/releases/latest) for the latest version). 3. If you have a `.git-ftp-include` file you should delete it. Version 4 tracks files differently and no longer needs this config file. 4. If you have a `.git-ftp-ignore` file, you should transfer the options to the new `exclude` argument. **Note:** version 4 excludes any `.git*` and `node_modules/` files / folders by default. 5. Update your arguments to reflect the following changes: diff --git a/package-lock.json b/package-lock.json index 261452a..7ed8671 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,23 +1,23 @@ { "name": "ftp-deploy-action", - "version": "4.3.4", + "version": "4.3.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ftp-deploy-action", - "version": "4.3.4", + "version": "4.3.5", "license": "MIT", "dependencies": { "@actions/core": "^1.9.1", - "@samkirkland/ftp-deploy": "^1.2.3", + "@samkirkland/ftp-deploy": "^1.2.4", "@types/jest": "^29.4.1", "jest": "^29.5.0", "ts-jest": "^29.0.5", "ts-node-dev": "^2.0.0" }, "devDependencies": { - "@types/node": "^14.0.27", + "@types/node": "^20.11.24", "@typescript-eslint/eslint-plugin": "^5.33.1", "@typescript-eslint/parser": "^5.33.1", "@vercel/ncc": "^0.34.0", @@ -1097,11 +1097,11 @@ } }, "node_modules/@samkirkland/ftp-deploy": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@samkirkland/ftp-deploy/-/ftp-deploy-1.2.3.tgz", - "integrity": "sha512-7DZEnyNlg78FdJ86Lm2BgBccI31mrMUnUxDt+Le/j0DCQpOA4Wl0u+jH2Mt6i6xOYtrVADX/LUeiZ8x+Epr/UA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@samkirkland/ftp-deploy/-/ftp-deploy-1.2.4.tgz", + "integrity": "sha512-MF5BoP1mQS3HBdx2pTMX/sIxSt9S4IgdL6ttrcGpUWC9U/IIPcUnyVEQiiBQJePLXpHI93dT9b8VDoS+cUknNg==", "dependencies": { - "basic-ftp": "^5.0.2", + "basic-ftp": "^5.0.5", "lodash": "^4.17.21", "multimatch": "^5.0.0", "pretty-bytes": "^5.6.0", @@ -1241,9 +1241,12 @@ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" }, "node_modules/@types/node": { - "version": "14.18.25", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.25.tgz", - "integrity": "sha512-9pLfceRSrKIsv/MISN6RoFWTIzka36Uk2Uuf5a8cHyDYhEgl5Hm5dXoe621KULeBjt+cFsY18mILsWWtJeG80w==" + "version": "20.11.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", + "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/prettier": { "version": "2.7.2", @@ -1722,9 +1725,9 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/basic-ftp": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.2.tgz", - "integrity": "sha512-NgkBwqp7rkhIUBaxLwL601lvUuBUvShJocrLYdiyTsH1WeP/wofMdooZ4p6hz+4hqiU59PBOj0EkaqELwFJLuQ==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", "engines": { "node": ">=10.0.0" } @@ -4729,6 +4732,11 @@ "node": ">=4.2.0" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "node_modules/update-browserslist-db": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", diff --git a/package.json b/package.json index d975416..fd9f1d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ftp-deploy-action", - "version": "4.3.4", + "version": "4.3.5", "private": true, "description": "Automate deploying websites and more with this GitHub action", "main": "dist/index.js", @@ -23,14 +23,14 @@ "license": "MIT", "dependencies": { "@actions/core": "^1.9.1", - "@samkirkland/ftp-deploy": "^1.2.3", + "@samkirkland/ftp-deploy": "^1.2.4", "@types/jest": "^29.4.1", "jest": "^29.5.0", "ts-jest": "^29.0.5", "ts-node-dev": "^2.0.0" }, "devDependencies": { - "@types/node": "^14.0.27", + "@types/node": "^20.11.24", "@typescript-eslint/eslint-plugin": "^5.33.1", "@typescript-eslint/parser": "^5.33.1", "@vercel/ncc": "^0.34.0",