This commit is contained in:
SamKirkland 2020-08-26 01:28:40 -05:00
parent 1053c3278e
commit 3576f3af9c
23 changed files with 7764 additions and 5829 deletions

3
.eslintignore Normal file
View File

@ -0,0 +1,3 @@
dist/
lib/
node_modules/

56
.eslintrc.json Normal file
View File

@ -0,0 +1,56 @@
{
"plugins": [
"jest",
"@typescript-eslint"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 8,
"sourceType": "module",
"project": "./tsconfig.json"
},
"rules": {
"eslint-comments/no-use": "off",
"import/no-namespace": "off",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-member-accessibility": [
"error",
{
"accessibility": "no-public"
}
],
"@typescript-eslint/no-require-imports": "error",
"@typescript-eslint/array-type": "error",
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/func-call-spacing": [
"error",
"never"
],
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-extraneous-class": "error",
"@typescript-eslint/no-for-in-array": "error",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "warn",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-useless-constructor": "error",
"@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-function-type": "warn",
"@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-array-sort-compare": "error",
"@typescript-eslint/restrict-plus-operands": "error",
"@typescript-eslint/type-annotation-spacing": "error"
},
"env": {
"node": true,
"es6": true,
"jest/globals": true
}
}

2
.gitattributes vendored
View File

@ -1,2 +0,0 @@
# Auto detect text files and perform LF normalization
* text=auto

23
.github/workflows/ftp.yml vendored Normal file
View File

@ -0,0 +1,23 @@
name: FTP Test
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
deploy: # make sure the action works on a clean machine without building
name: 🚀 Deploy website every commit
runs-on: ubuntu-latest
steps:
- name: 🚚 Get latest code
uses: actions/checkout@v2
- name: 📂 Sync files
uses: ./
with:
server: ftp.samkirkland.com
username: test@samkirkland.com
password: ${{ secrets.ftp_password }}

24
.github/workflows/ftps.yml vendored Normal file
View File

@ -0,0 +1,24 @@
name: FTPS Test
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
deploy: # make sure the action works on a clean machine without building
name: 🚀 Deploy website every commit
runs-on: ubuntu-latest
steps:
- name: 🚚 Get latest code
uses: actions/checkout@v2
- name: 📂 Sync files
uses: ./
with:
server: wwwssr16.supercp.com
username: test@samkirkland.com
password: ${{ secrets.ftp_password }}
protocol: ftps
secure: strict

View File

@ -1,16 +0,0 @@
on: push
name: Test FTP Deploy
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.1.0
with:
fetch-depth: 2
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@master
with:
ftp-server: ftp://ftp.samkirkland.com/
ftp-username: ${{ secrets.ftp_username }}
ftp-password: ${{ secrets.ftp_password }}

View File

@ -1,18 +0,0 @@
on: push
name: Test SFTP Deploy
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.1.0
with:
fetch-depth: 2
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@master
with:
# deploy to a folder named "sftp-deploy-test.samkirkland.com" on my server
ftp-server: sftp://ftp.samkirkland.com:7822/home/samkirkland/sftp-deploy-test.samkirkland.com/
ftp-username: ${{ secrets.sftp_username }}
ftp-password: ${{ secrets.sftp_password }}
git-ftp-args: --insecure

13
.gitignore vendored
View File

@ -1,7 +1,5 @@
__tests__/runner/*
# comment out in distribution branches
node_modules/
# Dependency directory
node_modules
# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
# Logs
@ -91,3 +89,10 @@ typings/
# DynamoDB Local files
.dynamodb/
# OS metadata
.DS_Store
Thumbs.db
# Ignore built ts files
lib/**/*

View File

@ -1,5 +0,0 @@
{
"files.exclude": {
"**/node_modules": true
}
}

View File

@ -1,14 +0,0 @@
FROM debian:stable-slim
LABEL repository="https://github.com/SamKirkland/FTP-Deploy-Action"
LABEL maintainer="Sam Kirkland <FTP-Deploy-Action@samkirkland.com>"
RUN apt-get update
RUN apt-get install -y git
RUN apt-get install -y git-ftp
RUN apt-get install -y nodejs
COPY dist/index.js /deploy.js
RUN chmod +x deploy.js
ENTRYPOINT ["node", "../../deploy.js"]

455
README.md
View File

@ -1,338 +1,155 @@
<p align="center">
<img alt="FTP Deploy - Continuous integration for everyone" src="images/ftp-upload-logo-small.png">
<img alt="FTP Deploy Action - Continuous integration for everyone" src="images/ftp-deploy-logo-small.png">
</p>
> :warning: **This is a beta branch, use at your own risk**
Automate deploying websites and more with this GitHub action
![Test FTP Deploy](https://github.com/SamKirkland/FTP-Deploy-Action/workflows/Test%20FTP%20Deploy/badge.svg) ![Test SFTP Deploy](https://github.com/SamKirkland/FTP-Deploy-Action/workflows/Test%20SFTP%20Deploy/badge.svg)
![FTP test](https://github.com/SamKirkland/FTP-Deploy-Action/workflows/FTP%20Test/badge.svg)
![FTPS test](https://github.com/SamKirkland/FTP-Deploy-Action/workflows/FTPS%20Test/badge.svg)
---
### Usage Example
Place the following in `Your_Project/.github/workflows/main.yml`
Place the following in `/.github/workflows/main.yml`
```yml
on: push
name: Publish Website
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
web-deploy:
name: 🚀 Deploy website every commit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.1.0
- name: 🚚 Get latest code
uses: actions/checkout@v2.3.2
- name: 📂 Sync files
uses: SamKirkland/FTP-Deploy-Action@beta-4
with:
fetch-depth: 2
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@3.1.1
with:
ftp-server: ftp://ftp.samkirkland.com/
ftp-username: myFtpUserName
ftp-password: ${{ secrets.FTP_PASSWORD }}
server: ftp.samkirkland.com
username: myFtpUserName
password: ${{ secrets.ftp_password }}
```
---
### Requirements
- You must have ftp access to your server. If your host requires ssh please use my web-deploy action
- Some web hosts change the default port (21), check with your host for your port number
---
### Setup Steps
1. Select the repository you want to add the action to
2. Select the `Actions` tab
3. Select `Blank workflow file` or `Set up a workflow yourself`, if you don't see these options manually create a yaml file `Your_Project/.github/workflows/main.yml`
4. Paste the example above into your yaml file and save
5. Now you need to add a key to the `secrets` section in your project. To add a `secret` go to the `Settings` tab in your project then select `Secrets`. Add a new `Secret` for `ftp-password`
5. Now you need to add a key to the `secrets` section in your project. To add a `secret` go to the `Settings` tab in your project then select `Secrets`. Add a new `Secret` for `password`
6. Update your yaml file settings
__Note: Only tracked files will be published by default. If you want to publish files that don't exist in github (example: files generated during the action run) you must add those files/folders to `.git-ftp-include`__
Migrating from v2? See the [migration guide](v2-v3-migration.md)
---
### Settings
Keys can be added directly to your .yml config file or referenced from your project `Secrets` storage.
To add a `secret` go to the `Settings` tab in your project then select `Secrets`.
I recommend you store your `ftp-password` as a secret.
I strongly recommend you store your `password` as a secret.
| Key Name | Required? | Example | Default | Description |
|----------------|-----------|-----------------------------------------------|---------|----------------------------------------------------------|
| `ftp-server` | Yes | ftp://ftp.samkirkland.com/destinationPath/ | | Deployment destination server & path. Formatted as `protocol://domain.com:port/destinationPath/` protocol can be `ftp`, `ftps`, or `sftp`. Port is optional, when not specified it will default to 21 when using ftp, 22 when using sftp, and 990 when using ftps |
| `ftp-username` | Yes | username@samkirkland.com | | FTP account username |
| `ftp-password` | Yes | CrazyUniquePassword&%123 | | FTP account password |
| `local-dir` | No | deploy/ | ./ | Which local folder to deploy, path should be relative to the root and should include trailing slash. `./` is the root of the project |
| `git-ftp-args` | No | See `git-ftp-args` section below | | Custom git-ftp arguments, this field is passed through directly into the git-ftp script |
| `known-hosts` | No | hostname ssh-rsa AAAAB3NzaC1y ... | | The desired contents of your .ssh/known_hosts file. See [known hosts setup](#known-hosts-setup) |
| Key Name | Required | Example | Default Value | Description |
|-------------------------|----------|----------------------------|----------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `server` | Yes | `ftp.samkirkland.com` | | Deployment destination server |
| `username` | Yes | `username@samkirkland.com` | | FTP user name |
| `password` | Yes | `CrazyUniquePassword&%123` | | FTP password, be sure to escape quotes and spaces |
| `port` | No | `990` | `21` | Server port to connect to (read your web hosts docs) |
| `protocol` | No | `ftps` | `ftp` | ftp: provides no encryption, ftps: full encryption newest standard (aka "explicit" ftps), ftps-legacy: full encryption legacy standard (aka "implicit" ftps) |
| `local-dir` | No | `./myFolderToPublish/` | `./` | Path to upload to on the server, must end with trailing slash `/` |
| `server-dir` | No | `public_html/www/` | `./` | Folder to upload from, must end with trailing slash `/` |
| `state-name` | No | `folder/.sync-state.json` | `.ftp-deploy-sync-state.json` | Custom |
| `dry-run` | No | `true` | `false` | :warning: todo - Prints which modifications will be made with current config options, but doesn't actually make any changes |
| `dangerous-clean-slate` | No | `true` | `false` | :warning: todo - Deletes ALL contents of server-dir, even items in excluded with 'exclude' argument |
| `include` | No | | `` | :warning: todo - An array of glob patterns, these files will always be included in the publish/delete process - even if no change occurred |
| `exclude` | No | | `.git*` `.git*/**` `node_modules/**` `node_modules/**/*` | :warning: todo - An array of glob patterns, these files will not be included in the publish/delete process |
| `log-level` | No | `info` | `info` | `warn`: only important/warning info, `info`: default, log important/warning info & progress info, `debug`: log everything for debugging |
#### Advanced options using `git-ftp-args`
Custom arguments, this field is passed through directly into the git-ftp script. See [git-ftp's manual](https://github.com/git-ftp/git-ftp/blob/master/man/git-ftp.1.md) for all options.
You can use as many arguments as you want, seperate them with a space
Below is an incomplete list of commonly used args:
| Argument | Description |
|------------------------|------------------------------------------------------------------------------------------------------|
| `--dry-run` | Does not upload or delete anything, but tries to get the .git-ftp.log file from remote host |
| `--silent` | Be silent |
| `--all` | Transfer all files, even seemingly the same as the target site (default is differences only). Note: Only files committed to github are uploaded, if you'd like to upload files generated during the action run see `.git-ftp-include` |
| `--lock` | Locks remote files from being modified while a deployment is running |
| `--remote-root` | Specifies the remote root directory to deploy to. The remote path in the URL is ignored |
| `--key` | SSH private key file name for SFTP |
| `--branch` | Push a specific branch. I recommend [creating a yaml action for each branch instead](https://github.com/SamKirkland/FTP-Deploy-Action/issues/37#issuecomment-579819486) |
| `--pubkey` | SSH public key file name. Used with `--key` option |
| `--insecure` | Don't verify server's certificate |
| `--cacert <file>` | Use as CA certificate store. Useful when a server has a self-signed certificate |
### Ignore specific files when deploying
Add patterns to `.git-ftp-ignore` and all matching file names will be ignored. The patterns are interpreted as shell glob patterns.
Here are some glob pattern examples:
#### Ignore git related files:
```gitattributes
.gitignore
*/.gitignore # ignore files in sub directories
*/.gitkeep
.git-ftp-ignore
.git-ftp-include
.gitlab-ci.yml
```
#### Ignore a single file called `foobar.txt`
```gitattributes
foobar.txt
```
#### Ignore all files having extension .txt
```gitattributes
*.txt
```
#### Ignore everything in a directory named `config`
```gitattributes
config/*
```
### Force upload specific files
The `.git-ftp-include` file specifies intentionally untracked files to should upload. If you have a file that should always be uploaded, add a line beginning with `!` followed by the file's name.
#### Always upload the file `VERSION.txt`
```gitattributes
!VERSION.txt
```
#### Always upload the folder `build`
```gitattributes
!build/
```
If you have a file that should be uploaded whenever a tracked file changes, add a line beginning with the untracked file's name followed by a colon and the tracked file's name.
#### Upload CSS file compiled from an SCSS file
```gitattributes
css/style.css:scss/style.scss
```
If you have multiple source files, you can add multiple lines for each of them. Whenever one of the tracked files changes, the upload of the paired untracked file will be triggered.
```gitattributes
css/style.css:scss/style.scss
css/style.css:scss/mixins.scss
```
If a local untracked file is deleted, any change of a paired tracked file will trigger the deletion of the remote file on the server.
All paths are usually relative to the Git working directory. When using the `local-dir` option, paths of tracked files (right side of the colon) are relative to the set `local-dir`.
```gitattributes
# upload "html/style.css" triggered by html/style.scss
# with local-dir "html"
html/style.css:style.scss
```
If your source file is outside the `local-dir`, prefix it with a / and define a path relative to the Git working directory.
#### Uploading a file outside of `local-dir`
```gitattributes
# upload "dist/style.css" with local-dir "dist"
dist/style.css:/src/style.scss
```
It is also possible to upload whole directories. For example, if you use a package manager like composer, you can upload all vendor packages when the file composer.lock changes:
```gitattributes
vendor/:composer.lock
```
But keep in mind that this will upload all files in the vendor folder, even those that are on the server already. And it will not delete files from that directory if local files are deleted.
---
# Common Examples
Read more about the differences between these protocols [https://www.sftp.net/sftp-vs-ftps](https://www.sftp.net/sftp-vs-ftps)
### FTP (File Transfer Protocol)
`ftp://ftp.samkirkland.com:21/mypath`
FTP has existed since 1971, it's an ancient protocol with near universal support.
#### Build and Publish React/Angular/Vue Website
Make sure you have an npm script named 'build'. This config should work for most node built websites.
```yml
on: push
name: Publish Website
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
web-deploy:
name: 🚀 Deploy website every commit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.1.0
- name: 🚚 Get latest code
uses: actions/checkout@v2.3.2
- name: Use Node.js 12
uses: actions/setup-node@v2-beta
with:
fetch-depth: 2
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@3.1.1
with:
ftp-server: ftp://ftp.samkirkland.com/
ftp-username: myFtpUserName
ftp-password: ${{ secrets.FTP_PASSWORD }}
```
node-version: '12'
### FTPS (File Transfer Protocol over SSL)
`ftps://ftp.samkirkland.com:21/mypath`
Use the legacy FTP over a secure encrypted connection.
Notes about ftps:
- Most hosts don't offer FTPS, it's more common on windows/.net hosts and less common on linux hosting
- Most hosts don't have a correct certificate setup for ftp domains, [even my host doesn't do it right](https://ftp.samkirkland.com/). This means you'll likely have to add `--insecure` to `git-ftp-args`
```yml
on: push
name: Publish Website over FTPS
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.1.0
with:
fetch-depth: 2
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@3.1.1
with:
ftp-server: ftps://ftp.samkirkland.com:21/
ftp-username: myFTPSUsername
ftp-password: ${{ secrets.FTPS_PASSWORD }}
git-ftp-args: --insecure # if your certificate is setup correctly this can be removed
```
### SFTP (SSH File Transfer Protocol)
`sftp://ftp.samkirkland.com:22/mypath`
Similar in name to FTP but this protocol is entirely new and requires SSH access to the server.
##### Notes about SFTP:
- **You CANNOT use a FTP account - they are not the same!**
- You must have shell access to your server, please read you webhosts documentation
- You will need to create a **SSH** user to deploy over SFTP. Normally this is your cpanel or hosting providers username and password
- Most web hosts change the default port (21), check with your host for your port number
### Known Hosts Setup
**Windows**
In powershell run `ssh-keyscan -p <sshport> <hostname>` and copy the hash output
Example for samkirkland.com `ssh-keyscan -p 7822 samkirkland.com`
**Linux, or OSX (using homebrew)**
Install the OpenSSH packages and use `ssh-keyscan <hostname>` and copy the hash output
On macOS you can use `ssh-keyscan <hostname> | pbcopy` to copy the hash output to your clipboard
Add the `known-hosts` argument with your hosts hash
Example: `knownhosts: ssh-rsa AAAAB3Nza...H1Q5Spw==`
*Note: If you receive a `Connection refused` error, you must specify the ssh port to your host*
```yml
on: push
name: Publish Website over SFTP
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.1.0
with:
fetch-depth: 2
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@3.1.1
with:
ftp-server: sftp://ftp.samkirkland.com:7280/
ftp-username: mySFTPUsername
ftp-password: ${{ secrets.SFTP_PASSWORD }}
known-hosts: [samkirkland.com]:7822 ssh-rsa AAAA...5Spw==
# add the following line instead if your certificate is setup incorrectly
# git-ftp-args: --insecure
```
### Build and Publish React/Angular/Vue Website
Make sure you have an npm script named 'build'. This config should work for most node built websites.
> #### If you don't commit your `build` folder to github you MUST create a `.git-ftp-include` file with the content `!build/` so the folder is always uploaded!
```yml
on: push
name: Build and Publish Front End Framework Website
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.1.0
with:
fetch-depth: 2
- name: Use Node.js 12.x
uses: actions/setup-node@v1
with:
node-version: '12.x'
- name: Build Project
- name: 🔨 Build Project
run: |
npm install
npm run build --if-present
npm run build
- name: List output files
run: ls
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@3.1.1
- name: 📂 Sync files
uses: SamKirkland/FTP-Deploy-Action@beta-4
with:
ftp-server: ftp://ftp.samkirkland.com/
ftp-username: myFTPUsername
ftp-password: ${{ secrets.FTP_PASSWORD }}
local-dir: build # This folder is NOT going to upload by default unless you add it to .git-ftp-include
server: ftp.samkirkland.com
username: myFtpUserName
password: ${{ secrets.password }}
```
### Log only dry run: Use this mode for testing
#### FTPS
```yml
on: push
name: Publish Website Dry Run
jobs:
web-deploy:
name: 🚀 Deploy website every commit
runs-on: ubuntu-latest
steps:
- name: 🚚 Get latest code
uses: actions/checkout@v2.3.2
- name: 📂 Sync files
uses: SamKirkland/FTP-Deploy-Action@beta-4
with:
server: ftp.samkirkland.com
username: myFtpUserName
password: ${{ secrets.password }}
protocol: ftps
```
#### Log only dry run: Use this mode for testing
Ouputs a list of files that will be created/modified to sync your source without making any actual changes
```yml
on: push
name: Publish Website Dry Run
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
web-deploy:
name: 🚀 Deploy website every commit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.1.0
with:
fetch-depth: 2
- name: 🚚 Get latest code
uses: actions/checkout@v2.3.2
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@3.1.1
- name: 📂 Sync files
uses: SamKirkland/FTP-Deploy-Action@beta-4
with:
ftp-server: ftp://ftp.samkirkland.com/
ftp-username: myFTPUsername
ftp-password: ${{ secrets.FTP_PASSWORD }}
git-ftp-args: --dry-run
server: ftp.samkirkland.com
username: myFtpUserName
password: ${{ secrets.password }}
dry-run: true
```
_Want another example? Let me know by creating a github issue_
_Want another example? Let me know by creating a [github issue](https://github.com/SamKirkland/FTP-Deploy-Action/issues/new)_
---
@ -340,21 +157,16 @@ _Want another example? Let me know by creating a github issue_
<details>
<summary>How to exclude .git files from the publish</summary>
See the [`.git-ftp-ignore`](#ignore-specific-files-when-deploying) example section
todo
</details>
<details>
<summary>All files are being uploaded instead of just different files</summary>
<summary>How to exclude a specific file or folder</summary>
By default only different files are uploaded.
Verify you have `with: fetch-depth: 2` in your `actions/checkout@v2.1.0` step. The last 2 checkins are required in order to determine differences
If you've had multiple git commits without deploying, all files will be uploaded to get back in sync
Verify you **don't** have the `--all` git-ftp-args flag set
todo
</details>
<details>
<summary>How do I set a upload timeout?</summary>
@ -364,8 +176,8 @@ github has a built-in `timeout-minutes` option, see customized example below
on: push
name: Publish Website
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
web-deploy:
name: web-deploy
runs-on: ubuntu-latest
timeout-minutes: 15 # time out after 15 minutes (default is 360 minutes)
steps:
@ -373,72 +185,17 @@ jobs:
```
</details>
---
## Common Errors
<details id="failed-to-upload">
<summary>Failed to upload files</summary>
* **Fix 1:** Verify your login credentials are correct, download a ftp client and test with the exact same host/username/password
* **Fix 2:** Remember if you are using SFTP or FTPS you cannot use a normal FTP account username/password. You must use a elevated account. Each host has a different process to setup a FTPS or SFTP account. Please contact your host for help.
* **Fix 3:** If you are using sftp or ftps you should add `git-ftp-args: --insecure`, most hosts setup certificates incorrectly :(
</details>
<details id="cant-access-remote-sftp">
<summary>Can't access remote 'sftp://', exiting...</summary>
See ["Failed to upload files"](#failed-to-upload) section above
</details>
<details id="cant-access-remote-ftps">
<summary>Can't access remote 'ftps://', exiting...</summary>
See ["Failed to upload files"](#failed-to-upload) section above
</details>
<details id="files-arent_uploading">
<summary>My files aren't uploading</summary>
V3+ uses github to determine when files have changes and only publish differences. This means files that aren't committed to github will not upload by default.
To change this behavior please see [`.git-ftp-ignore`](#ignore-specific-files-when-deploying) documentation.
</details>
<details id="prohibited-file-name">
<summary>rm: Access failed: 553 Prohibited file name: ./.ftpquota</summary>
The `.ftpquota` file is created by some FTP Servers and cannot be modified by the user
Add `.ftpquota` to your [`.git-ftp-ignore`](#ignore-specific-files-when-deploying) file
</details>
<details id="ssl-peer-certificate">
<summary>Error: SSL peer certificate or SSH remote key was not OK</summary>
Whitelist your host via the `known-hosts` configuration option (see [known hosts setup](#known-hosts-setup) in SFTP) or add the `--insecure` argument
</details>
---
## Debugging locally
##### Instructions for debugging Windows
- [Install docker](https://docs.docker.com/get-docker/)
- Open powershell **as Administrator**
- Install [act-cli](https://github.com/nektos/act#installation) by running `choco install act-cli`
- Navigate to the repo folder
- Run `npm install` - this will install all dependencies to build this project
- Run `npm build` - this will build the action javascript and watch/rebuild when files change
- Run `npm run build-docker` - this will build the docker container (only needs to be done once)
- Run `npm run run-docker` - this will spin up a local copy of the action defined in `/debug/local-debug-deployment.yaml`. Update package.json to set any secret values
- Install the npm package using `npm install --dev-only @samkirkland/ftp-deploy`
- Add a new key to your `package.json` file under `scripts`
- You can run the script using the following command `npm run deploy` (run this in the folder that has the `package.json` file)
#### Instructions for debugging on Linux
- [Install docker](https://docs.docker.com/get-docker/) on a Debian-based distro you can run `sudo apt install docker docker.io`
- Open the terminal
- Install [act-cli](https://github.com/nektos/act#installation)
- Navigate to the repo folder
- Run `npm install` - this will install all dependencies to build this project
- Run `npm build` - this will build the action javascript and watch/rebuild when files change
- Run `npm run build-docker` - this will build the docker container (only needs to be done once)
- Run `npm run run-docker` - this will spin up a local copy of the action defined in `/debug/local-debug-deployment.yaml`. Update package.json to set any secret values
#### Pull Requests Welcome!
Example of `package.json`:
```json
{
"scripts": {
"deploy": "ftp-deploy --server ftp.samkirkland.com --username test@samkirkland.com --password \"CrazyUniquePassword&%123\"",
},
}
```

View File

@ -1,30 +1,19 @@
name: 'FTP Deploy'
description: 'Syncs files via FTP/SFTP to a remote server'
description: 'Automate deploying websites and more with this GitHub action'
author: 'Sam Kirkland'
inputs:
ftp-server:
description: 'Deployment destination server & path. Formatted as protocol://domain.com:port/full/destination/path/'
required: true
ftp-username:
description: 'FTP account username'
required: true
ftp-password:
description: 'FTP account password'
required: true
local-dir:
description: 'The local folder to copy, defaults to root project folder'
default: ./
required: false
git-ftp-args:
description: 'Passes through options into git-ftp'
default:
required: false
known-hosts:
description: The desired content of your `.ssh/known_hosts` file
required: false
server:
required: true
description: 'ftp server'
username:
required: true
description: 'ftp username'
password:
required: true
description: 'ftp password'
runs:
using: 'docker'
image: 'Dockerfile'
using: 'node12'
main: 'dist/index.js'
branding:
icon: 'upload-cloud'
color: 'orange'

View File

@ -1,18 +0,0 @@
on: push
name: Local Debug Deployment
jobs:
Local-Debug-Deployment:
name: Local-Debug-Deployment
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.1.0
with:
fetch-depth: 2
- name: FTP-Deploy-Action
uses: ./
with:
ftp-server: ftp://ftp.samkirkland.com/
ftp-username: ${{ secrets.username }}
ftp-password: ${{ secrets.password }}
git-ftp-args: --dry-run

7710
dist/index.js vendored

File diff suppressed because it is too large Load Diff

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

4898
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,39 +1,37 @@
{
"name": "typescript-action",
"name": "ftp-deploy-action",
"version": "1.0.0",
"private": true,
"description": "TypeScript template action",
"description": "Automate deploying websites and more with this GitHub action",
"main": "dist/main.js",
"engines": {
"node": ">=12.0.0"
},
"scripts": {
"build": "ncc build src/main.ts -o dist --watch",
"build-docker": "docker build --tag action .",
"run-docker": "act --workflows ./debug/ --secret username=UserNameHere --secret password=PasswordHere"
"build": "ncc build src/main.ts",
"lint": "eslint src/**/*.ts",
"all": "npm run build && npm run lint"
},
"repository": {
"type": "git",
"url": "git+https://github.com/actions/typescript-action.git"
"url": "git+https://github.com/SamKirkland/FTP-Deploy-Action.git"
},
"keywords": [
"actions",
"node",
"setup"
"website deploy",
"continuous integration",
"ftp",
"ftps"
],
"author": "SamKirkland",
"author": "Sam Kirkland",
"license": "MIT",
"dependencies": {
"@actions/core": "1.2.4",
"@actions/exec": "1.0.4"
"@actions/core": "^1.2.4",
"@samkirkland/ftp-deploy": "^0.0.1",
"ts-node-dev": "^1.0.0-pre.56"
},
"devDependencies": {
"@types/jest": "25.2.1",
"@types/node": "12.12.8",
"@zeit/ncc": "0.22.1",
"jest": "25.5.3",
"jest-circus": "25.5.3",
"ts-jest": "25.4.0",
"typescript": "3.8.3"
"@types/node": "^14.0.27",
"@typescript-eslint/parser": "^3.8.0",
"@zeit/ncc": "^0.22.3",
"eslint": "^7.6.0",
"js-yaml": "^3.14.0",
"typescript": "^3.9.7"
}
}

12
project.code-workspace Normal file
View File

@ -0,0 +1,12 @@
{
"folders": [
{
"path": "."
}
],
"settings": {
"files.exclude": {
"**/node_modules": true
}
}
}

View File

@ -1,91 +1,31 @@
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import fs from 'fs';
import { promisify } from 'util';
import { IActionArguments } from './types';
import * as core from "@actions/core";
import { deploy } from "@samkirkland/ftp-deploy";
import { IFtpDeployArguments } from "@samkirkland/ftp-deploy/dist/module/types";
const writeFileAsync = promisify(fs.writeFile);
const errorDeploying = "⚠️ Error deploying";
async function run() {
try {
const userArguments = getUserArguments();
await configureHost(userArguments);
await syncFiles(userArguments);
console.log("✅ Deploy Complete");
}
catch (error) {
console.error(errorDeploying);
core.setFailed(error.message);
}
}
run();
async function configureHost(args: IActionArguments): Promise<void> {
if (args.knownHosts === "") {
return;
}
try {
const sshFolder = `${process.env['HOME']}/.ssh`;
await exec.exec(`mkdir -v -p ${sshFolder}`);
await exec.exec(`chmod 700 ${sshFolder}`);
writeFileAsync(`${sshFolder}/known_hosts`, args.knownHosts);
await exec.exec(`chmod 755 ${sshFolder}/known_hosts`);
console.log("✅ Configured known_hosts");
}
catch (error) {
console.error("⚠️ Error configuring known_hosts");
core.setFailed(error.message);
}
}
function getUserArguments(): IActionArguments {
return {
ftp_server: core.getInput("ftp-server", { required: true }),
ftp_username: core.getInput("ftp-username", { required: true }),
ftp_password: core.getInput("ftp-password", { required: true }),
local_dir: withDefault(core.getInput("local-dir"), "./"),
gitFtpArgs: withDefault(core.getInput("git-ftp-args"), ""),
knownHosts: withDefault(core.getInput("known-hosts"), "")
async function runDeployment() {
const args: IFtpDeployArguments = {
server: core.getInput("server", { required: true }),
username: core.getInput("username", { required: true }),
password: core.getInput("password", { required: true }),
protocol: core.getInput("protocol") as any, // todo fix
port: core.getInput("port") as any, // todo fix
"local-dir": core.getInput("local-dir") as any, // todo fix
"server-dir": core.getInput("server-dir") as any, // todo fix
"state-name": core.getInput("state-name") as any, // todo fix
"dry-run": core.getInput("dry-run") as any, // todo fix
"dangerous-clean-slate": core.getInput("dangerous-clean-slate") as any, // todo fix
"include": core.getInput("include") as any, // todo fix
"exclude": core.getInput("exclude") as any, // todo fix
"log-level": core.getInput("log-level") as any // todo fix
};
}
function withDefault(value: string, defaultValue: string) {
if (value === "" || value === null || value === undefined) {
return defaultValue;
}
return value;
}
/**
* Sync changed files
*/
async function syncFiles(args: IActionArguments) {
try {
await core.group("Uploading files", async () => {
return await exec.exec(
"git ftp push",
[
"--force",
"--auto-init",
"--verbose",
`--syncroot=${args.local_dir}`,
`--user=${args.ftp_username}`,
`--passwd=${args.ftp_password}`,
args.gitFtpArgs!,
args.ftp_server!
]
);
});
await deploy(args);
}
catch (error) {
core.setFailed(error.message);
core.setFailed(error);
}
}
runDeployment();

View File

@ -1,31 +0,0 @@
export interface IActionArguments {
ftp_server: string | undefined;
ftp_username: string | undefined;
ftp_password: string | undefined;
/** @default "." */
local_dir: string | undefined;
/** @default "" */
gitFtpArgs: string | undefined;
/** @default "" */
knownHosts: string | undefined;
}
/**
* @see https://github.com/git-ftp/git-ftp/blob/master/man/git-ftp.1.md#exit-codes
*/
export enum gitFTPExitCode {
Successful = 0,
UnknownError = 1,
WrongUsage = 2,
MissingArguments = 3,
ErrorWhileUploading = 4,
ErrorWhileDownloading = 5,
UnknownProtocol = 6,
RemoteLocked = 7,
GitRelatedError = 8,
PreFTPPushHookFailed = 9,
LocalFileOperationFailed = 10
}

View File

@ -1,63 +1,14 @@
{
"compilerOptions": {
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./lib", /* Redirect output structure to the directory. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
"noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
"target": "ES2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"outDir": "./lib", /* Redirect output structure to the directory. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
},
"exclude": ["node_modules", "**/*.test.ts"]
"exclude": [
"node_modules"
]
}

View File

@ -1,33 +0,0 @@
# Migrating from v2 to v3
`uses: actions/checkout@v2.1.0` must now have the option `fetch-depth: 2`
Without the `fetch-depth` option diffs cannot be calculated and all files will be uploaded.
### Breaking changes
All arguments have been renamed to lower `kebab-case`
| Old Value | New Value | Notes |
|------------------|-----------------|----------------------------|
| `env:` | `with:` | ⚠ Before declaring settings in v2 you set a line to `env:` In v3+ that line must now read `with:` ⚠ |
| `FTP_SERVER` | `ftp-server` | |
| `FTP_USERNAME` | `ftp-username` | |
| `FTP_PASSWORD` | `ftp-password` | |
| `LOCAL_DIR` | `local-dir` | |
| `ARGS` | `git-ftp-args` | |
| `METHOD` | | `METHOD` has been removed. Instead specify the method within `ftp-server` (ex: ftp://server.com, ftps://server.com, sftp://sever.com) |
| `PORT` | | `PORT` has been removed. Instead specify the port between the domain and destination within `ftp-server` (ex: ftp://server.com:PORT/destination/) |
| `REMOTE_DIR` | | `REMOTE_DIR` has been removed. Instead specify the destination path within `ftp-server` (ex: ftp://server.com/full/destination/path/) |
### ARGS changes
| Old ARG | New ARG | Notes |
|---------------------|-----------------|----------------------------------------|
| `--include` | | use `.git-ftp-ignore` instead |
| `--include-glob` | | use `.git-ftp-ignore` instead |
| `--exclude` | | use `.git-ftp-ignore` instead |
| `--exclude-glob` | | use `.git-ftp-ignore` instead |
| `--delete-excluded` | | |
| `--no-empty-dirs` | | |
| `--parallel` | | |
| `--L` | | |
| `--ignore-time` | | v3 only uploads differences by default |