Compare commits

..

No commits in common. "master" and "1.5.0" have entirely different histories.

24 changed files with 217 additions and 15176 deletions

View File

@ -1,2 +0,0 @@
dist/
node_modules/

View File

@ -1,56 +0,0 @@
{
"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 Normal file
View File

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

View File

@ -1,27 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Bug Description**
A clear and concise description of what the bug is.
**My Action Config**
```yaml
on: push
name: Publish Website
jobs:
web-deploy:
name: 🚀 Deploy website every commit
# !!!!!!! TODO Fill Out !!!!!!!
```
**My Action Log**
```
# Paste Log here
# you may want enable verbose logging with log-level: verbose
```

View File

@ -1,20 +0,0 @@
name: FTP Test
on:
push:
branches: [master]
jobs:
deploy:
name: 🚀 Deploy website every commit
runs-on: ubuntu-latest
steps:
- name: 🚚 Get latest code
uses: actions/checkout@v4
- name: 📂 Sync files
uses: ./
with:
server: ftp.samkirkland.com
username: test@samkirkland.com
password: ${{ secrets.ftp_password }}

View File

@ -1,21 +0,0 @@
name: FTPS Test
on:
push:
branches: [master]
jobs:
deploy:
name: 🚀 Deploy website every commit
runs-on: ubuntu-latest
steps:
- name: 🚚 Get latest code
uses: actions/checkout@v4
- name: 📂 Sync files
uses: ./
with:
server: ftp.samkirkland.com
username: test@samkirkland.com
password: ${{ secrets.ftp_password }}
protocol: ftps

95
.gitignore vendored
View File

@ -1,95 +0,0 @@
# Dependency directory
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/
# OS metadata
.DS_Store
Thumbs.db

17
Dockerfile Normal file
View File

@ -0,0 +1,17 @@
FROM alpine:3.10
LABEL version="1.0.0"
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 "com.github.actions.name"="FTP Deploy Action"
LABEL "com.github.actions.description"="Deploy your website via FTP"
LABEL "com.github.actions.icon"="upload-cloud"
LABEL "com.github.actions.color"="orange"
RUN apk add lftp
COPY entrypoint.sh /entrypoint.sh
RUN chmod 777 entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

13
LICENSE
View File

@ -1,7 +1,6 @@
MIT License
The MIT License (MIT) Copyright (c) 2019 SamKirkland
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
@ -10,13 +9,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 The above copyright notice and this permission notice shall be included in all
all copies or substantial portions of the Software. 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
THE SOFTWARE. SOFTWARE.

424
README.md
View File

@ -1,286 +1,160 @@
<p align="center"> # FTP Deploy GitHub Action
<img alt="FTP Deploy Action - Continuous integration for everyone" src="images/ftp-deploy-logo-small.png">
</p>
Automate deploying websites and more with this GitHub action. **It's free!** Automate deploying websites and more with this GitHub action.
![FTP test](https://github.com/SamKirkland/FTP-Deploy-Action/workflows/FTP%20Test/badge.svg) ![Action](images/action-preview.gif)
![FTPS test](https://github.com/SamKirkland/FTP-Deploy-Action/workflows/FTPS%20Test/badge.svg)
--- ### Usage Example (Your_Project/.github/workflows/main.yml)
```shell
### Usage Example
Place the following in `/.github/workflows/main.yml`
```yml
on: push
name: 🚀 Deploy website on push
jobs:
web-deploy:
name: 🎉 Deploy
runs-on: ubuntu-latest
steps:
- name: 🚚 Get latest code
uses: actions/checkout@v4
- name: 📂 Sync files
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
with:
server: ftp.samkirkland.com
username: myFtpUserName
password: ${{ secrets.ftp_password }}
```
---
### Requirements
- You must have ftp access to your server. If your host allows or requires ssh please use my [web-deploy](https://github.com/SamKirkland/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 `password`
6. Update your yaml file settings
7. If you appreciate this github action give it a :star: or show off with one of the [badges below](#badge).
---
### 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 strongly recommend you store your `password` as a secret.
| 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/` | `./` | Folder to upload from, must end with trailing slash `/` |
| `server-dir` | No | `public_html/www/` | `./` | Folder to upload to (on the server), must end with trailing slash `/` |
| `state-name` | No | `folder/.sync-state.json` | `.ftp-deploy-sync-state.json` | Path and name of the state file - this file is used to track which files have been deployed |
| `dry-run` | No | `true` | `false` | Prints which modifications will be made with current config options, but doesn't actually make any changes |
| `dangerous-clean-slate` | No | `true` | `false` | Deletes ALL contents of server-dir, even items in excluded with 'exclude' argument |
| `exclude` | No | [See Example](#exclude-files) | [See Example](#exclude-files) | An array of glob patterns, these files will not be included in the publish/delete process. [List MUST be in this format](#exclude-files). You can use [a glob tester](https://www.digitalocean.com/community/tools/glob?comments=true&glob=%2A%2A%2F.git%2A%2F%2A%2A&matches=false&tests=test%2Fsam&tests=.git%2F%0D&tests=.github%2F%0D&tests=.git%2Ftest%0D&tests=.gitattributes%0D&tests=.gitignore%0D&tests=.git%2Fconfig%0D&tests=.git%2Ftest%2Ftest&tests=.github%2Fworkflows%2Fmain.yml&tests=node_modules%2Ffolder%2F%0D&tests=node_modules%2Fotherfolder%2F%0D&tests=subfolder%2Fnode_modules%2F) to test your pattern(s). |
| `log-level` | No | `minimal` | `standard` | `minimal`: only important info, `standard`: important info and basic file changes, `verbose`: print everything the script is doing |
| `security` | No | `strict` | `loose` | `strict`: Reject any connection which is not authorized with the list of supplied CAs. `loose`: Allow connection even when the domain is not certificate |
| `timeout` | No | `60000` | `30000` | Timeout in milliseconds for FTP operations |
# Common Examples
#### 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: 🚀 Deploy website on push
jobs:
web-deploy:
name: 🎉 Deploy
runs-on: ubuntu-latest
steps:
- name: 🚚 Get latest code
uses: actions/checkout@v4
- name: Use Node.js 16
uses: actions/setup-node@v2
with:
node-version: '16'
- name: 🔨 Build Project
run: |
npm install
npm run build
- name: 📂 Sync files
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
with:
server: ftp.samkirkland.com
username: myFtpUserName
password: ${{ secrets.password }}
```
#### FTPS
```yml
on: push
name: 🚀 Deploy website on push
jobs:
web-deploy:
name: 🎉 Deploy
runs-on: ubuntu-latest
steps:
- name: 🚚 Get latest code
uses: actions/checkout@v4
- name: 📂 Sync files
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
with:
server: ftp.samkirkland.com
username: myFtpUserName
password: ${{ secrets.password }}
protocol: ftps
port: 1234 # todo replace with your web hosts ftps port
```
#### Log only dry run: Use this option 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: 🚀 Deploy website on push
jobs:
web-deploy:
name: 🎉 Deploy
runs-on: ubuntu-latest
steps:
- name: 🚚 Get latest code
uses: actions/checkout@v4
- name: 📂 Sync files
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
with:
server: ftp.samkirkland.com
username: myFtpUserName
password: ${{ secrets.password }}
dry-run: true
```
#### Exclude files
Excludes files
```yml
on: push
name: 🚀 Deploy website on push
jobs:
web-deploy:
name: 🎉 Deploy
runs-on: ubuntu-latest
steps:
- name: 🚚 Get latest code
uses: actions/checkout@v4
- name: 📂 Sync files
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
with:
server: ftp.samkirkland.com
username: myFtpUserName
password: ${{ secrets.password }}
exclude: |
**/.git*
**/.git*/**
**/node_modules/**
fileToExclude.txt
```
`exclude` has the following default value
```yml
exclude: |
**/.git*
**/.git*/**
**/node_modules/**
```
if you overwrite the default value you will probably want to respecify them
---
_Want another example? Let me know by creating a [github issue](https://github.com/SamKirkland/FTP-Deploy-Action/issues/new)_
---
## Badge
If you appreciate this github action give it a :star: or show off with one of the badges below. Feel free to edit the text or color.
[<img alt="Deployed with FTP Deploy Action" src="https://img.shields.io/badge/Deployed With-FTP DEPLOY ACTION-%3CCOLOR%3E?style=for-the-badge&color=0077b6">](https://github.com/SamKirkland/FTP-Deploy-Action)
```md
[<img alt="Deployed with FTP Deploy Action" src="https://img.shields.io/badge/Deployed With-FTP DEPLOY ACTION-%3CCOLOR%3E?style=for-the-badge&color=0077b6">](https://github.com/SamKirkland/FTP-Deploy-Action)
```
[<img alt="Deployed with FTP Deploy Action" src="https://img.shields.io/badge/Deployed With-FTP DEPLOY ACTION-%3CCOLOR%3E?style=for-the-badge&color=2b9348">](https://github.com/SamKirkland/FTP-Deploy-Action)
```md
[<img alt="Deployed with FTP Deploy Action" src="https://img.shields.io/badge/Deployed With-FTP DEPLOY ACTION-%3CCOLOR%3E?style=for-the-badge&color=2b9348">](https://github.com/SamKirkland/FTP-Deploy-Action)
```
[<img alt="Deployed with FTP Deploy Action" src="https://img.shields.io/badge/Deployed With-FTP DEPLOY ACTION-%3CCOLOR%3E?style=for-the-badge&color=d00000">](https://github.com/SamKirkland/FTP-Deploy-Action)
```md
[<img alt="Deployed with FTP Deploy Action" src="https://img.shields.io/badge/Deployed With-FTP DEPLOY ACTION-%3CCOLOR%3E?style=for-the-badge&color=d00000">](https://github.com/SamKirkland/FTP-Deploy-Action)
```
---
[<img alt="Website Deployed for Free with FTP Deploy Action" src="https://img.shields.io/badge/Website deployed for free with-FTP DEPLOY ACTION-%3CCOLOR%3E?style=for-the-badge&color=297FA9">](https://github.com/SamKirkland/FTP-Deploy-Action)
```md
[<img alt="Website Deployed for Free with FTP Deploy Action" src="https://img.shields.io/badge/Website deployed for free with-FTP DEPLOY ACTION-%3CCOLOR%3E?style=for-the-badge&color=297FA9">](https://github.com/SamKirkland/FTP-Deploy-Action)
```
[<img alt="Website Deployed for Free with FTP Deploy Action" src="https://img.shields.io/badge/Website deployed for free with-FTP DEPLOY ACTION-%3CCOLOR%3E?style=for-the-badge&color=2b9348">](https://github.com/SamKirkland/FTP-Deploy-Action)
```md
[<img alt="Website Deployed for Free with FTP Deploy Action" src="https://img.shields.io/badge/Website deployed for free with-FTP DEPLOY ACTION-%3CCOLOR%3E?style=for-the-badge&color=2b9348">](https://github.com/SamKirkland/FTP-Deploy-Action)
```
[<img alt="Website Deployed for Free with FTP Deploy Action" src="https://img.shields.io/badge/Website deployed for free with-FTP DEPLOY ACTION-%3CCOLOR%3E?style=for-the-badge&color=d00000">](https://github.com/SamKirkland/FTP-Deploy-Action)
```md
[<img alt="Website Deployed for Free with FTP Deploy Action" src="https://img.shields.io/badge/Website deployed for free with-FTP DEPLOY ACTION-%3CCOLOR%3E?style=for-the-badge&color=d00000">](https://github.com/SamKirkland/FTP-Deploy-Action)
```
---
## FAQ
<details>
<summary>How to exclude .git files from the publish</summary>
Git files are excluded by default! If you customize the `exclude` option make sure you re-add the default options.
</details>
<details>
<summary>How to exclude a specific file or folder</summary>
You can use the `exclude` option to ignore specific files/folders from the publish. Keep in mind you will need to re-add the default exclude options if you want to keep them. For example the below option excludes all `.txt` files.
```yml
exclude:
- *.txt
```
</details>
<details>
<summary>How do I set a upload timeout?</summary>
github has a built-in `timeout-minutes` option, see customized example below
```yaml
on: push on: push
name: Publish Website name: Publish Website
jobs: jobs:
web-deploy: FTP-Deploy-Action:
name: web-deploy name: FTP-Deploy-Action
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 15 # time out after 15 minutes (default is 360 minutes)
steps: steps:
.... - uses: actions/checkout@master
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@master
env:
FTP_SERVER: ftp.samkirkland.com
FTP_USERNAME: ${{ secrets.FTP_USERNAME }}
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
ARGS: --delete
# --delete arg will delete files on the server if you've deleted them in git
``` ```
</details>
## Debugging your config locally 1. Select the repository you want to add the action to
This action is a basic wrapper around my `@samkirkland/ftp-deploy` npm package. To test your config you can install [@samkirkland/ftp-deploy](https://github.com/SamKirkland/ftp-deploy) and then convert your config to a yml action. Settings are one-to-one, this action is only a wrapper. 2. Select the actions tab `(currently only for beta testers)`
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
7. Now you need to add a few keys to the `secrets` section in your project, the following are required at a minimum. To add a `secret` go to the `Settings` tab in your project then select `Secrets`. Add a new `Secret` for each of the following
* FTP_SERVER
* FTP_USERNAME
* FTP_PASSWORD
* (see optional settings below)
## Contributing to this project ### Settings
To test this action locally you will need to setup **docker** and **act** to run a environment similar to the one github uses for actions. To add a `secret` go to the `Settings` tab in your project then select `Secrets`. Add a new `Secret` for each of the following.
- Download/install docker for windows, make sure it is running I recommend you use a secrets to store your FTP_USERNAME and FTP_PASSWORD.
- `choco install act-cli` install [act](https://github.com/nektos/act)
- Install the npm package using `npm install --dev-only @samkirkland/ftp-deploy` | Key Name | Required? | Example | Default | Description |
- Update the `deploy` script in `package.json` with a actual server/username/password |----------------|-----------|-----------------------------|---------|-------------|
- You can run the script using the following command `npm run deploy` (run this in the folder that has the `package.json` file) | `FTP_SERVER` | Yes | ftp.samkirkland.com | N/A | FTP server name (you may need to specify a port) |
| `FTP_USERNAME` | Yes | git-action@samkirkland.com | N/A | FTP account username |
| `FTP_PASSWORD` | Yes | CrazyUniquePassword&%123 | N/A | FTP account password |
| `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 `Commonly used ARGS` section below | N/A | Custom lftp arguments, this field is passed through directly into the lftp script. |
#### Commonly used 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.
You can use as many arguments as you want, seperate them with a space
| Argument | Description |
|------------------------|------------------------------------------------------------------------------------------------------|
| `--delete` | Delete files not present at the source |
| `--transfer-all` | Transfer all files, even seemingly the same as the target site |
| `--dry-run` | Ouputs files that will be modified without making any actual changes |
| `--include=File.txt` | Include matching files, you can add multiple `--include` |
| `--exclude=File.txt` | Exclude matching files, you can add multiple `--exclude` |
| `--include-glob=*.zip` | Include matching files, you can add multiple `--include-glob` |
| `--exclude-glob=*.zip` | Exclude matching files, you can add multiple `--exclude-glob` |
| `--no-empty-dirs` | Don't create empty directories |
## Common Examples
### Build and Publish React/Angular/Vue/Node Website
Make sure you have an npm script named 'build'. This config should work for most node built websites
```shell
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@master
- name: Use Node.js 12.x
uses: actions/setup-node@v1
with:
node-version: '12.x'
- name: Build Project
run: |
npm install
npm run build --if-present
- name: List output files
run: ls
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@master
env:
FTP_SERVER: ftp.samkirkland.com
FTP_USERNAME: ${{ secrets.FTP_USERNAME }}
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
LOCAL_DIR: build
ARGS: --delete
```
### 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
```shell
on: push
name: Publish Website Dry Run
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@master
env:
FTP_SERVER: ftp.samkirkland.com
FTP_USERNAME: ${{ secrets.FTP_USERNAME }}
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
ARGS: --delete --dry-run
```
##### Want another example? Let me know by creating a github issue
## FAQ
1. `rm: Access failed: 553 Prohibited file name: ./.ftpquota`
* The `.ftpquota` file is created by some FTP Servers and cannot be modified by the user
* **Fix:** Add `--exclude=.ftpquota` to your ARGS
2. How do I exclude .git files from the publish
* **Fix:** Add `--exclude-glob=**/.git*/** --exclude-glob=**/.git**` to your ARGS
#### Deprecated main.workflow config (used for beta/legacy apps that haven't been migrated to .yaml workflows yet)
```json
action "FTP-Deploy-Action" {
uses = "SamKirkland/FTP-Deploy-Action@master"
secrets = ["FTP_USERNAME", "FTP_PASSWORD", "FTP_SERVER"]
}
```
### Debugging locally
##### Instructions for debugging on windows
- Install docker for windows
- Open powershell
- Navigate to the repo folder
- 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`
##### Instructions for debugging on linux
- Please submit a PR for linux instructions :)
#### ToDo
- SFTP example
- More examples
#### Pull Requests Welcome!

View File

@ -1,52 +1,36 @@
name: "FTP Deploy" name: 'FTP Deploy'
description: "Automate deploying websites and more with this GitHub action via FTP and FTPS" description: 'Syncs files via FTP to a remote server'
author: "Sam Kirkland"
inputs: inputs:
server: ftp_server:
description: 'FTP server name (you may need to specify a port)'
required: true required: true
description: "ftp server" ftp_username:
username: description: 'FTP account username'
required: true required: true
description: "ftp username" ftp_password:
password: description: 'FTP account password'
required: true required: true
description: "ftp password" local_dir:
port: description: 'The local folder to copy, defaults to root project folder'
required: false required: false
description: "Server port to connect to (read your web hosts docs)" default: ''
protocol: remote_dir:
description: 'The remote folder to copy to, deafults to root FTP folder (I recommend you configure this on your server side instead of here)'
required: false required: false
description: "protocol to deploy with - ftp, ftps, or ftps-legacy" default: ''
local-dir: ARGS:
description: 'Passes through options into lftp'
required: false required: false
description: "Folder to upload from, must end with trailing slash /" default: ""
server-dir:
required: false
description: "Path to upload to on the server. Must end with trailing slash /"
state-name:
required: false
description: "Path and name of the state file - this file is used to track which files have been deployed"
dry-run:
required: false
description: "Prints which modifications will be made with current config options, but doesnt actually make any changes"
dangerous-clean-slate:
required: false
description: "Deletes ALL contents of server-dir, even items in excluded with exclude argument"
exclude:
required: false
description: "An array of glob patterns, these files will not be included in the publish/delete process"
log-level:
required: false
description: "How verbose should the information be - minimal, standard, or verbose"
security:
required: false
description: "strict or loose"
timeout:
required: false
description: "Timeout in milliseconds for FTP operations"
runs: runs:
using: "node20" using: 'docker'
main: "dist/index.js" image: 'Dockerfile'
args:
- ${{ inputs.ftp_server }}
- ${{ inputs.ftp_username }}
- ${{ inputs.ftp_password }}
- ${{ inputs.local_dir }}
- ${{ inputs.remote_dir }}
branding: branding:
icon: "upload-cloud" icon: 'pload-cloud'
color: "blue" color: 'orange'

9336
dist/index.js vendored

File diff suppressed because it is too large Load Diff

16
entrypoint.sh Normal file
View File

@ -0,0 +1,16 @@
#!/bin/sh
# "to avoid continuing when errors or undefined variables are present"
set -eu
echo "Starting FTP Deploy"
echo "Uploading files..."
WDEFAULT_LOCAL_DIR=${LOCAL_DIR:-"."}
WDEFAULT_REMOTE_DIR=${REMOTE_DIR:-"."}
WDEFAULT_ARGS=${ARGS:-""}
lftp $FTP_SERVER -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

BIN
images/action-preview.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

View File

@ -1,40 +0,0 @@
# How to migrate between versions
## Migrating from v4.1.0 to v4.2.0
`v4.2.0` parses the `exclude` option in a more standard way. Going forward the `exclude` option **must** be in the following format:
```yml
exclude: |
**/.git*
**/.git*/**
**/node_modules/**
fileToExclude.txt
```
## Migrating from v3 to v4
Migrating from v3 to v4 should be fairly straightforward. Version 4 was designed with speed and ease of initial setup in mind. Going forward version 4 will be the only supported version.
### Those who can't upgrade
Most features have been carried forward and improved upon. However, some features did not make the cut:
- **`sftp` is no longer supported**. If you have `sftp` access you are using `ssh`, that means you have access to a much more modern and capable protocol. I plan on releasing a separate github action that will deploy over `sftp`/`ssh` using `rsync`. Until then you can continue using version 3.
- The `include` argument has been removed. I didn't see much need for it in the initial release. If you need this feature please create a support ticket.
### 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.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:
- `ftp-server` was split into 4 arguments:
- `server`
- `port`
- `protocol`
- `server-dir`
- `ftp-username` was renamed to `username`.
- `ftp-password` was renamed to `password`.
- `local-dir` and `server-dir` now **must** end with `/`.
- `git-ftp-args` and `known-hosts` arguments were removed.

4941
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,44 +0,0 @@
{
"name": "ftp-deploy-action",
"version": "4.3.5",
"private": true,
"description": "Automate deploying websites and more with this GitHub action",
"main": "dist/index.js",
"scripts": {
"build": "ncc build src/main.ts --no-cache",
"test": "jest",
"lint": "eslint src/**/*.ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/SamKirkland/FTP-Deploy-Action.git"
},
"keywords": [
"ftp",
"website deploy",
"continuous integration",
"ftps"
],
"author": "Sam Kirkland",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.9.1",
"@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": "^20.11.24",
"@typescript-eslint/eslint-plugin": "^5.33.1",
"@typescript-eslint/parser": "^5.33.1",
"@vercel/ncc": "^0.34.0",
"eslint": "^8.22.0",
"eslint-plugin-jest": "^26.8.7",
"typescript": "^4.7.4"
},
"jest": {
"preset": "ts-jest"
}
}

View File

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

View File

@ -1,105 +0,0 @@
import { optionalBoolean, optionalInt, optionalLogLevel, optionalProtocol, optionalSecurity, optionalString } from "./parse";
describe("boolean", () => {
test("false", () => {
expect(optionalBoolean("test", "false")).toBe(false);
});
test("FALSE", () => {
expect(optionalBoolean("test", "FALSE")).toBe(false);
});
test("true", () => {
expect(optionalBoolean("test", "true")).toBe(true);
});
test("TRUE", () => {
expect(optionalBoolean("test", "TRUE")).toBe(true);
});
test("optional", () => {
expect(optionalBoolean("test", "")).toBe(undefined);
});
});
describe("string", () => {
test("empty", () => {
expect(optionalString("")).toBe(undefined);
});
test("populated", () => {
expect(optionalString("test")).toBe("test");
});
});
describe("int", () => {
test("empty", () => {
expect(optionalInt("test", "")).toBe(undefined);
});
test("0", () => {
expect(optionalInt("test", "0")).toBe(0);
});
test("1", () => {
expect(optionalInt("test", "1")).toBe(1);
});
test("500", () => {
expect(optionalInt("test", "500")).toBe(500);
});
test("non-int", () => {
expect(() => optionalInt("test", "12.345")).toThrow();
});
});
describe("protocol", () => {
test("empty", () => {
expect(optionalProtocol("test", "")).toBe(undefined);
});
test("ftp", () => {
expect(optionalProtocol("test", "ftp")).toBe("ftp");
});
test("ftps", () => {
expect(optionalProtocol("test", "ftps")).toBe("ftps");
});
test("ftps-legacy", () => {
expect(optionalProtocol("test", "ftps-legacy")).toBe("ftps-legacy");
});
});
describe("log level", () => {
test("empty", () => {
expect(optionalLogLevel("test", "")).toBe(undefined);
});
test("minimal", () => {
expect(optionalLogLevel("test", "minimal")).toBe("minimal");
});
test("standard", () => {
expect(optionalLogLevel("test", "standard")).toBe("standard");
});
test("verbose", () => {
expect(optionalLogLevel("test", "verbose")).toBe("verbose");
});
});
describe("security", () => {
test("empty", () => {
expect(optionalSecurity("test", "")).toBe(undefined);
});
test("loose", () => {
expect(optionalSecurity("test", "loose")).toBe("loose");
});
test("strict", () => {
expect(optionalSecurity("test", "strict")).toBe("strict");
});
});

View File

@ -1,32 +0,0 @@
import * as core from "@actions/core";
import { deploy } from "@samkirkland/ftp-deploy";
import { IFtpDeployArguments } from "@samkirkland/ftp-deploy/dist/types";
import { optionalInt, optionalProtocol, optionalString, optionalBoolean, optionalStringArray, optionalLogLevel, optionalSecurity } from "./parse";
async function runDeployment() {
try {
const args: IFtpDeployArguments = {
server: core.getInput("server", { required: true }),
username: core.getInput("username", { required: true }),
password: core.getInput("password", { required: true }),
port: optionalInt("port", core.getInput("port")),
protocol: optionalProtocol("protocol", core.getInput("protocol")),
"local-dir": optionalString(core.getInput("local-dir")),
"server-dir": optionalString(core.getInput("server-dir")),
"state-name": optionalString(core.getInput("state-name")),
"dry-run": optionalBoolean("dry-run", core.getInput("dry-run")),
"dangerous-clean-slate": optionalBoolean("dangerous-clean-slate", core.getInput("dangerous-clean-slate")),
"exclude": optionalStringArray("exclude", core.getMultilineInput("exclude")),
"log-level": optionalLogLevel("log-level", core.getInput("log-level")),
"security": optionalSecurity("security", core.getInput("security")),
"timeout": optionalInt("timeout", core.getInput("timeout"))
};
await deploy(args);
}
catch (error: any) {
core.setFailed(error);
}
}
runDeployment();

View File

@ -1,103 +0,0 @@
export function optionalString(rawValue: string): string | undefined {
if (rawValue.length === 0) {
return undefined;
}
return rawValue;
}
export function optionalBoolean(argumentName: string, rawValue: string): boolean | undefined {
if (rawValue.length === 0) {
return undefined;
}
const cleanValue = rawValue.toLowerCase();
if (cleanValue === "true") {
return true;
}
if (cleanValue === "false") {
return false;
}
throw new Error(`${argumentName}: invalid parameter - please use a boolean, you provided "${rawValue}". Try true or false instead.`);
}
export function optionalProtocol(argumentName: string, rawValue: string): "ftp" | "ftps" | "ftps-legacy" | undefined {
if (rawValue.length === 0) {
return undefined;
}
const cleanValue = rawValue.toLowerCase();
if (cleanValue === "ftp") {
return "ftp";
}
if (cleanValue === "ftps") {
return "ftps";
}
if (cleanValue === "ftps-legacy") {
return "ftps-legacy";
}
throw new Error(`${argumentName}: invalid parameter - you provided "${rawValue}". Try "ftp", "ftps", or "ftps-legacy" instead.`);
}
export function optionalLogLevel(argumentName: string, rawValue: string): "minimal" | "standard" | "verbose" | undefined {
if (rawValue.length === 0) {
return undefined;
}
const cleanValue = rawValue.toLowerCase();
if (cleanValue === "minimal") {
return "minimal";
}
if (cleanValue === "standard") {
return "standard";
}
if (cleanValue === "verbose") {
return "verbose";
}
throw new Error(`${argumentName}: invalid parameter - you provided "${rawValue}". Try "minimal", "standard", or "verbose" instead.`);
}
export function optionalSecurity(argumentName: string, rawValue: string): "loose" | "strict" | undefined {
if (rawValue.length === 0) {
return undefined;
}
const cleanValue = rawValue.toLowerCase();
if (cleanValue === "loose") {
return "loose";
}
if (cleanValue === "strict") {
return "strict";
}
throw new Error(`${argumentName}: invalid parameter - you provided "${rawValue}". Try "loose" or "strict" instead.`);
}
export function optionalInt(argumentName: string, rawValue: string): number | undefined {
if (rawValue.length === 0) {
return undefined;
}
const valueAsNumber = parseFloat(rawValue);
if (Number.isInteger(valueAsNumber)) {
return valueAsNumber;
}
throw new Error(`${argumentName}: invalid parameter - you provided "${rawValue}". Try a whole number (no decimals) instead like 1234`);
}
export function optionalStringArray(argumentName: string, rawValue: string[]): string[] | undefined {
if (rawValue.length === 0) {
return undefined;
}
if (typeof rawValue === "string") {
throw new Error(`${argumentName}: invalid parameter - you provided "${rawValue}". This option expects an list in the EXACT format described in the readme`);
}
return rawValue;
}

View File

@ -1,17 +0,0 @@
{
"compilerOptions": {
"moduleResolution": "Node",
"target": "ES2019", /* 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": "./dist", /* 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'. */
"noEmit": true
},
"exclude": [
"node_modules",
"**/.test.ts"
]
}