Complete rewrite!
Switched from LFTP to git-ftp
Upload diffs based on git history by default
lower case kebab argument names
Migrated from shell to typescript
Added FTP and SFTP tests
.git-ftp-ignore and .git-ftp-include support
This commit is contained in:
SamKirkland 2020-02-18 00:34:10 -06:00
parent e62d32ee89
commit 4895f6f251
19 changed files with 6597 additions and 178 deletions

16
.github/workflows/test-ftp-deploy.yaml vendored Normal file
View File

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

18
.github/workflows/test-sftp-deploy.yaml vendored Normal file
View File

@ -0,0 +1,18 @@
on: push
name: Test SFTP Deploy
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
with:
fetch-depth: 2
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action-Typescript@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

93
.gitignore vendored Normal file
View File

@ -0,0 +1,93 @@
__tests__/runner/*
# comment out in distribution branches
node_modules/
# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/

5
.vscode/settings.json vendored Normal file
View File

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

View File

@ -1,18 +1,14 @@
FROM alpine:3.10 FROM debian:stable-slim
LABEL version="1.0.0"
LABEL repository="https://github.com/SamKirkland/FTP-Deploy-Action" LABEL repository="https://github.com/SamKirkland/FTP-Deploy-Action"
LABEL homepage="https://github.com/SamKirkland/FTP-Deploy-Action"
LABEL maintainer="Sam Kirkland <FTP-Deploy-Action@samkirkland.com>" LABEL maintainer="Sam Kirkland <FTP-Deploy-Action@samkirkland.com>"
LABEL "com.github.actions.name"="FTP Deploy Action" RUN apt-get update
LABEL "com.github.actions.description"="Deploy your website via FTP" RUN apt-get install -y git
LABEL "com.github.actions.icon"="upload-cloud" RUN apt-get install -y git-ftp
LABEL "com.github.actions.color"="orange" RUN apt-get install -y nodejs
RUN apk update COPY dist/index.js /deploy.js
RUN apk add openssh sshpass lftp RUN chmod +x deploy.js
COPY entrypoint.sh /entrypoint.sh ENTRYPOINT ["node", "../../deploy.js"]
RUN chmod 777 entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

13
LICENSE
View File

@ -1,6 +1,7 @@
MIT License
Copyright (c) 2019 SamKirkland The MIT License (MIT)
Copyright (c) 2018 GitHub, Inc. and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -9,13 +10,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in
copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
SOFTWARE. THE SOFTWARE.

343
README.md
View File

@ -1,9 +1,13 @@
# FTP Deploy GitHub Action <p align="center">
<img alt="FTP Deploy - Continuous integration for everyone" src="images/ftp-upload-logo-small.png">
</p>
Automate deploying websites and more with this GitHub action. Automate deploying websites and more with this GitHub action
![Action](images/action-preview.gif) ![Action](images/action-preview.gif)
![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)
### Usage Example (Your_Project/.github/workflows/main.yml) ### Usage Example (Your_Project/.github/workflows/main.yml)
```yml ```yml
on: push on: push
@ -14,65 +18,230 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
with:
fetch-depth: 2
- name: FTP-Deploy-Action - name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@2.0.0 uses: SamKirkland/FTP-Deploy-Action@3.0.0
env: with:
FTP_SERVER: ftp.samkirkland.com ftp-server: ftp://ftp.samkirkland.com/
FTP_USERNAME: myFtpUserName ftp-username: myFtpUserName
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }} ftp-password: ${{ secrets.FTP_PASSWORD }}
ARGS: --delete
# --delete arg will delete files on the server if you've deleted them in git
``` ```
#### Setup Steps
1. Select the repository you want to add the action to 1. Select the repository you want to add the action to
2. Select the actions tab 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` 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 above code into your file and save 4. Paste the example above into your yaml file and save
7. 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 `ftp-password`
6. Update your yaml file settings
### Settings ### Settings
**Migrating from v2? See the [migration guide](v2-v3-migration.md)**
Keys can be added directly to your .yml config file or referenced from your project `Secrets` storage. 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`. 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 recommend you store your `ftp-password` as a secret.
| Key Name | Required? | Example | Default | Description | | Key Name | Required? | Example | Default | Description |
|----------------|-----------|----------------------------|-----------------|----------------------------------------------------------| |----------------|-----------|-----------------------------------------------|---------|----------------------------------------------------------|
| `FTP_SERVER` | Yes | ftp.samkirkland.com | N/A | FTP server name (you may need to specify a port) | | `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 | git-action@samkirkland.com | N/A | FTP account username | | `ftp-username` | Yes | username@samkirkland.com | | FTP account username |
| `FTP_PASSWORD` | Yes | CrazyUniquePassword&%123 | N/A | FTP account password | | `ftp-password` | Yes | CrazyUniquePassword&%123 | | FTP account password |
| `METHOD` | No | ftp | ftp | Protocol used to deploy (ftp or sftp) | | `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 |
| `PORT` | No | 21 | ftp=21, sftp=22 | The port used to connect to server | | `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 |
| `LOCAL_DIR` | No | build | . (root project folder) | The local folder to copy, defaults to root project folder. Do NOT include slashes for folders. |
| `REMOTE_DIR` | No | serverFolder | . (root FTP folder) | The remote folder to copy to, deafults to root FTP folder (I recommend you configure this on your server side instead of here). Do NOT include slashes for folders. |
| `ARGS` | No | See `ARGS` section below | N/A | Custom lftp arguments, this field is passed through directly into the lftp script. |
#### ARGS #### Advanced options using `git-ftp-args`
Custom lftp arguments, this field is passed through directly into the lftp script. See [lftp's website](https://lftp.yar.ru/lftp-man.html) for all options. 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 You can use as many arguments as you want, seperate them with a space
Below is an incomplete list of commonly used ARGS: Below is an incomplete list of commonly used args:
| Argument | Description | | Argument | Description |
|------------------------|------------------------------------------------------------------------------------------------------| |------------------------|------------------------------------------------------------------------------------------------------|
| `--verbose` | Outputs which files are being modified, useful for debugging | | `--dry-run` | Does not upload or delete anything, but tries to get the .git-ftp.log file from remote host |
| `--delete` | Delete files not present at the source | | `--silent` | Be silent |
| `--transfer-all` | Transfer all files, even seemingly the same as the target site | | `--all` | Transfer all files, even seemingly the same as the target site (default is differences only) |
| `--dry-run` | Ouputs files that will be modified without making any actual changes | | `--lock` | Locks remote files from being modified while a deployment is running |
| `--include=File.txt` | Include matching files, you can add multiple `--include` | | `--remote-root` | Specifies the remote root directory to deploy to. The remote path in the URL is ignored |
| `--exclude=File.txt` | Exclude matching files, you can add multiple `--exclude` | | `--key` | SSH private key file name for SFTP |
| `--include-glob=*.zip` | Include matching files, you can add multiple `--include-glob` | | `--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) |
| `--exclude-glob=*.zip` | Exclude matching files, you can add multiple `--exclude-glob` | | `--pubkey` | SSH public key file name. Used with `--key` option |
| `--delete-excluded` | Deletes any items you've marked as excluded if they exist on the server | | `--insecure` | Don't verify server's certificate |
| `--no-empty-dirs` | Don't create empty directories | | `--cacert <file>` | Use as CA certificate store. Useful when a server has a self-signed certificate |
| `--parallel=X` | Uploads X files at a time in parallel |
| `-L` | Upload symbolic links as files (FTP doesn't have a way of creating actual symbolic links) |
| `--ignore-time` | ⚠ Temporary workaround to prevent all files being uploaded. See [this issue](https://github.com/SamKirkland/FTP-Deploy-Action/issues/16). |
## Common Examples ### Ignore specific files when deploying
### Build and Publish React/Angular/Vue/Node Website Add patterns to `.git-ftp-ignore` and all matching file names will be ignored. The patterns are interpreted as shell glob patterns.
Make sure you have an npm script named 'build'. This config should work for most node built websites 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.
```yml
on: push
name: Publish Website
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
with:
fetch-depth: 2
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@3.0.0
with:
ftp-server: ftp://ftp.samkirkland.com/
ftp-username: myFtpUserName
ftp-password: ${{ secrets.FTP_PASSWORD }}
```
### FTPS (File Transfer Protocol over SSL)
`ftps://ftp.samkirkland.com:21/mypath`
Use the legacy FTP over a secure encrypted connection.
Notes about sftp:
- 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@master
with:
fetch-depth: 2
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@3.0.0
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
```yml
on: push
name: Publish Website over SFTP
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
with:
fetch-depth: 2
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@3.0.0
with:
ftp-server: sftp://ftp.samkirkland.com:7280/
ftp-username: mySFTPUsername
ftp-password: ${{ secrets.SFTP_PASSWORD }}
git-ftp-args: --insecure # if your certificate is setup correctly this can be removed
```
### 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 ```yml
on: push on: push
name: Build and Publish Front End Framework Website name: Build and Publish Front End Framework Website
@ -82,6 +251,8 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
with:
fetch-depth: 2
- name: Use Node.js 12.x - name: Use Node.js 12.x
uses: actions/setup-node@v1 uses: actions/setup-node@v1
@ -97,36 +268,12 @@ jobs:
run: ls run: ls
- name: FTP-Deploy-Action - name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@2.0.0 uses: SamKirkland/FTP-Deploy-Action@3.0.0
env: with:
FTP_SERVER: ftp.samkirkland.com ftp-server: ftp://ftp.samkirkland.com/
FTP_USERNAME: myFTPUsername ftp-username: myFTPUsername
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }} ftp-password: ${{ secrets.FTP_PASSWORD }}
LOCAL_DIR: build local-dir: build
ARGS: --delete
```
## SFTP Example
```yml
on: push
name: Publish Website over SFTP
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@2.0.0
env:
FTP_SERVER: ftp.samkirkland.com
FTP_USERNAME: mySFTPUsername
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
METHOD: sftp
PORT: 7280
ARGS: --delete
``` ```
### Log only dry run: Use this mode for testing ### Log only dry run: Use this mode for testing
@ -140,34 +287,38 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
with:
fetch-depth: 2
- name: FTP-Deploy-Action - name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@2.0.0 uses: SamKirkland/FTP-Deploy-Action@3.0.0
env: with:
FTP_SERVER: ftp.samkirkland.com ftp-server: ftp://ftp.samkirkland.com/
FTP_USERNAME: myFTPUsername ftp-username: myFTPUsername
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }} ftp-password: ${{ secrets.FTP_PASSWORD }}
ARGS: --delete --dry-run git-ftp-args: --dry-run
``` ```
##### Want another example? Let me know by creating a github issue ##### Want another example? Let me know by creating a github issue
## FAQ ## FAQ
1. `rm: Access failed: 553 Prohibited file name: ./.ftpquota` 1. `Can't access remote 'sftp://', exiting...` or `Can't access remote 'ftps://', exiting...`
* The `.ftpquota` file is created by some FTP Servers and cannot be modified by the user * **Fix 1:** Verify your login credentials are correct, download a ftp client and test with the exact same host/username/password
* **Fix:** Add `--exclude=.ftpquota` to your ARGS * **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.
2. How to exclude .git files from the publish * **Fix 3:** If you are using sftp or ftps you should add `git-ftp-args: --insecure`, most hosts setup certificates incorrectly :(
* **Fix:** Add `--exclude-glob=.git*/** --exclude-glob=.git**` to your ARGS 2. `rm: Access failed: 553 Prohibited file name: ./.ftpquota`
* Note: If you've already published these files you will need to manually delete them on the server or add the `--delete-excluded` option to ARGS * **What is happening?** The `.ftpquota` file is created by some FTP Servers and cannot be modified by the user
* Note: This will exclude all folders and files that start with `.git` no matter the folder they're in * **Fix:** Add `.ftpquota` to your `.git-ftp-ignore` file
3. How to exclude .git files from the publish
* **Fix:** See the `.git-ftp-ignore` example above
4. All files are being uploaded instead of just different files
* By default only different files are uploaded.
* Verify you have `with: fetch-depth: 2` in your `actions/checkout@master` 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
5. How do I set a upload timeout?
* github has a built-in `timeout-minutes` option. Place `timeout-minutes: X` before the `steps:` line. Timeout defaults to 360 minutes.
#### Deprecated main.workflow config (used for beta/legacy apps that haven't been migrated to .yaml workflows yet)
```workflow
action "FTP-Deploy-Action" {
uses = "SamKirkland/FTP-Deploy-Action@1.0.0"
secrets = ["FTP_USERNAME", "FTP_PASSWORD", "FTP_SERVER"]
}
```
### Debugging locally ### Debugging locally
##### Instructions for debugging on windows ##### Instructions for debugging on windows
@ -175,17 +326,9 @@ action "FTP-Deploy-Action" {
- Open powershell - Open powershell
- Navigate to the repo folder - Navigate to the repo folder
- Run `docker build --tag action .` - Run `docker build --tag action .`
- (Optional) This step is only required when editing entrypoint.sh due to windows editors saving the file with windows line breaks instead of linux line breaks
- Download http://dos2unix.sourceforge.net/
- In another powershell window nagivate to the dos2unix folder /bin
- Run this command every time you modify entrypoint.sh `.\dos2unix.exe "{FULL_PATH_TO_REPO\entrypoint.sh}"`
- Run `docker run action` - Run `docker run action`
##### Instructions for debugging on linux ##### Instructions for debugging on linux
- Please submit a PR for linux instructions :) - Please submit a PR for linux instructions :)
#### ToDo
- More examples
#### Pull Requests Welcome! #### Pull Requests Welcome!

View File

@ -1,46 +1,27 @@
name: 'FTP Deploy' name: 'FTP Deploy'
description: 'Syncs files via FTP/SFTP to a remote server' description: 'Syncs files via FTP/SFTP to a remote server'
author: 'Sam Kirkland'
inputs: inputs:
ftp_server: ftp-server:
description: 'FTP server name (you may need to specify a port)' description: 'Deployment destination server & path. Formatted as protocol://domain.com:port/full/destination/path/'
required: true required: true
ftp_username: ftp-username:
description: 'FTP account username' description: 'FTP account username'
required: true required: true
ftp_password: ftp-password:
description: 'FTP account password' description: 'FTP account password'
required: true required: true
method: local-dir:
description: 'Protocol used to deploy (ftp or sftp)'
required: false
default: "ftp"
port:
description: 'The port used to connect to server'
required: false
default: "21"
local_dir:
description: 'The local folder to copy, defaults to root project folder' description: 'The local folder to copy, defaults to root project folder'
defaults: ./
required: false required: false
default: "" git-ftp-args:
remote_dir: description: 'Passes through options into git-ftp'
description: 'The remote folder to copy to, deafults to root FTP folder (I recommend you configure this on your server side instead of here)' defaults:
required: false required: false
default: ""
ARGS:
description: 'Passes through options into lftp'
required: false
default: ""
runs: runs:
using: 'docker' using: 'docker'
image: 'Dockerfile' image: 'Dockerfile'
args:
- ${{ inputs.ftp_server }}
- ${{ inputs.ftp_username }}
- ${{ inputs.ftp_password }}
- ${{ inputs.method }}
- ${{ inputs.port }}
- ${{ inputs.local_dir }}
- ${{ inputs.remote_dir }}
branding: branding:
icon: 'upload-cloud' icon: 'upload-cloud'
color: 'orange' color: 'orange'

1048
dist/index.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +0,0 @@
#!/bin/sh
# "to avoid continuing when errors or undefined variables are present"
set -eu
echo "Starting FTP Deploy"
WDEFAULT_LOCAL_DIR=${LOCAL_DIR:-"."}
WDEFAULT_REMOTE_DIR=${REMOTE_DIR:-"."}
WDEFAULT_ARGS=${ARGS:-""}
WDEFAULT_METHOD=${METHOD:-"ftp"}
if [ $WDEFAULT_METHOD = "sftp" ]; then
WDEFAULT_PORT=${PORT:-"22"}
echo "Establishing SFTP connection..."
sshpass -p $FTP_PASSWORD sftp -o StrictHostKeyChecking=no -P $WDEFAULT_PORT $FTP_USERNAME@$FTP_SERVER
echo "Connection established"
else
WDEFAULT_PORT=${PORT:-"21"}
fi;
echo "Using $WDEFAULT_METHOD to connect to port $WDEFAULT_PORT"
echo "Uploading files..."
lftp $WDEFAULT_METHOD://$FTP_SERVER:$WDEFAULT_PORT -u $FTP_USERNAME,$FTP_PASSWORD -e "set ftp:ssl-allow no; mirror $WDEFAULT_ARGS -R $WDEFAULT_LOCAL_DIR $WDEFAULT_REMOTE_DIR; quit"
echo "FTP Deploy Complete"
exit 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

4928
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

40
package.json Normal file
View File

@ -0,0 +1,40 @@
{
"name": "typescript-action",
"version": "1.0.0",
"private": true,
"description": "TypeScript template action",
"main": "dist/main.js",
"engines": {
"node": ">=10.0.0"
},
"scripts": {
"build:dev": "tsc",
"build:production": "ncc build src/main.ts -o dist",
"build:docker": "docker build --tag action .",
"run:docker": "docker run action --build-arg FTP_SERVER=example.com FTP_USERNAME=test@example.com FTP_PASSWORD=passwordExample"
},
"repository": {
"type": "git",
"url": "git+https://github.com/actions/typescript-action.git"
},
"keywords": [
"actions",
"node",
"setup"
],
"author": "SamKirkland",
"license": "MIT",
"dependencies": {
"@actions/core": "1.2.0",
"@actions/exec": "1.0.1"
},
"devDependencies": {
"@types/jest": "24.0.23",
"@types/node": "12.12.8",
"@zeit/ncc": "0.20.5",
"jest": "24.9.0",
"jest-circus": "24.9.0",
"ts-jest": "24.1.0",
"typescript": "3.7.2"
}
}

54
src/main.ts Normal file
View File

@ -0,0 +1,54 @@
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import { IActionArguments } from './types';
async function run() {
const userArguments = getUserArguments();
try {
await syncFiles(userArguments);
console.log("✅ Deploy Complete");
}
catch (error) {
console.error("⚠️ Error deploying");
core.setFailed(error.message);
}
}
run();
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"), "")
};
}
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}`);
});
}
catch (error) {
console.error("⚠️ Failed to upload files");
core.setFailed(error.message);
throw error;
}
}

28
src/types.ts Normal file
View File

@ -0,0 +1,28 @@
export interface IActionArguments {
ftp_server: string | undefined;
ftp_username: string | undefined;
ftp_password: string | undefined;
/** @default "." */
local_dir: string | undefined;
/** @default "" */
gitFtpArgs: 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,
NotAGitProject = 8,
PreFTPPushHookFailed = 9,
LocalFileOperationFailed = 10
}

63
tsconfig.json Normal file
View File

@ -0,0 +1,63 @@
{
"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. */
},
"exclude": ["node_modules", "**/*.test.ts"]
}

33
v2-v3-migration.md Normal file
View File

@ -0,0 +1,33 @@
# Migrating from v2 to v3
`uses: actions/checkout@master` 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 |