Compare commits

31 Commits

Author SHA1 Message Date
Sam Kirkland
bb9b486951 Update Dockerfile
Patch v3.1.1 to resolve wrong git-ftp version being used
2022-12-15 09:35:45 -06:00
Sam Kirkland
559ddbb4df Update Dockerfile 2021-08-16 11:53:47 -05:00
SamKirkland
da0d77ff39 v3.1.1
Bug fix: argument escaping for spaces within passwords
2020-05-17 17:28:14 -05:00
SamKirkland
1af692f7d5 Updating linux testing instructions 2020-05-17 17:25:20 -05:00
SamKirkland
ae5262e007 using act for local debugging
Added act library for local debugging
Attempting to use exec argument escaping
2020-05-17 16:57:25 -05:00
Sam Kirkland
b698c49eac Merge pull request #72 from Helias/patch-1
Add Linux istructions
2020-05-07 00:25:44 -05:00
Stefano Borzì
ccf756b42e Add Linux istructions 2020-05-06 18:21:47 +02:00
SamKirkland
f68449776c v3.1.0
Official release of known-hosts
2020-05-05 00:58:08 -05:00
SamKirkland
a54cf4c5e3 Closes #60
Due to node issue using exit code 0 for exceptions thrown in async methods.
Fixed by moving getUserArguments inside try block.
2020-05-02 02:14:10 -05:00
SamKirkland
c42c8e46fb Updating ReadMe FAQ Section 2020-05-02 00:24:55 -05:00
SamKirkland
c926b9df00 Library & test updates
- Updated NPM packages
- Updated tests to point to correct branch (oops)
2020-05-01 23:07:16 -05:00
Sam Kirkland
3f7edaa478 Merge pull request #58 from SamKirkland/dependabot/npm_and_yarn/acorn-5.7.4
Bump acorn from 5.7.3 to 5.7.4
2020-04-04 15:50:05 -05:00
dependabot[bot]
e39df43686 Bump acorn from 5.7.3 to 5.7.4
Bumps [acorn](https://github.com/acornjs/acorn) from 5.7.3 to 5.7.4.
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/5.7.3...5.7.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-04-04 20:46:45 +00:00
Sam Kirkland
586c7242ef Merge pull request #55 from apokalyptik/master
known_hosts support
2020-04-04 15:45:04 -05:00
Sam Kirkland
97865be6a0 Update README.md
Removed incorrect information about known_hosts expiring
2020-04-04 15:43:55 -05:00
Sam Kirkland
b890f82a46 Update README.md
I tested this out on my host, added commands for windows 10 and moved the docs around a bit
2020-04-02 00:47:59 -05:00
apokalyptik
c9f0bcd878 Update README.md 2020-03-31 10:10:56 -07:00
apokalyptik
481f9001ff work on formatting 2020-03-31 10:10:10 -07:00
Demitrious Kelly
4938a6057e README update, and rebuild of index.js 2020-03-31 10:00:49 -07:00
Sam Kirkland
af948b8060 Update main.ts
Code Cleanup changes:
- Pulled out this PR into a new function `configureHost`
- Placed args.knownHosts empty at the top of the function, this is known as "fail fast" and helps make the code more readable. Instead of wrapping our code in if/else blocks.
- Converted fs.writeFile to a awaitable function to make it more readable
- Pulled out sshFolder into a const
- Removed `console.log('Wrote ' + process.env['HOME'] + '/.ssh/known_hosts');` logging. Probably not needed because we log ` Configured known_hosts` just 2 lines later
- Small formatting changes

Bug fixes:
- Converted fs.writeFile to a awaitable function, previously the code continued to execute so this could open up a race condition. Also it's more readable :)
 - Race condition example: Previously we asked node to write the file `known_hosts` but we never verified the IO operation completed before modifying the files permission, or deploying the site. If this IO operation wasn't immediate the next function would throw or the deploy would error out.
- Any exception within the new method was swallowed because we had a catch without a throw. In this case let's end the program run instead of attempting to deploy
-
2020-03-30 23:20:38 -05:00
Demitrious Kelly
db3b78d8e7 more spaghetti at the wall [2] 2020-03-25 15:28:33 -07:00
Demitrious Kelly
034d210969 more spaghetti at the wall 2020-03-25 15:15:12 -07:00
Demitrious Kelly
2863e02eda home? 2020-03-25 15:03:56 -07:00
Demitrious Kelly
9315d47124 attempt to create known_hosts 2020-03-25 14:52:17 -07:00
Sam Kirkland
98039f1fbe Added notes about git-ftp-include 2020-02-20 13:16:57 -06:00
SamKirkland
4895f6f251 v3.0.0
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
2020-02-18 00:34:10 -06:00
Sam Kirkland
e62d32ee89 Update issue templates 2020-02-11 19:26:23 -06:00
Sam Kirkland
5aed021d1b Merge pull request #17 from mikeybinnswebdesign/patch-3
Add temporary workaround to ARGS list
2019-11-09 22:20:22 -06:00
Sam Kirkland
bfc3d99cdc Merge pull request #20 from fabiankaegy/patch-1
remove `(currently only for beta testers)`
2019-11-09 22:19:55 -06:00
Fabian Kägy
319b6d2cd8 remove (currently only for beta testers)
As GitHub actions is no longer in Beta I removed the line of it only being available for beta testers
2019-11-10 01:15:05 +01:00
Mikey Binns
fd3d225df7 Add temporary workaround to ARGS list
I found the temporary workaround you mentioned in this issue to be very beneficial, so I am proposing that it be added to the table of flags. I do also see the argument for not including it though, so this is more to open the discussion.
2019-10-10 09:24:55 +01:00
21 changed files with 7269 additions and 188 deletions

23
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,23 @@
---
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:
# !!!!!!! TODO Fill Out !!!!!!!
```
**My Action Log**
```
# Paste Log here
```

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@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 }}

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@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

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 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 apt-get update
RUN apt-get install -y git
RUN apt-get install -y git-ftp
RUN apt-get install -y nodejs
RUN apk update
RUN apk add openssh sshpass lftp
COPY dist/index.js /deploy.js
RUN chmod +x deploy.js
COPY entrypoint.sh /entrypoint.sh
RUN chmod 777 entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
ENTRYPOINT ["node", "../../deploy.js"]

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
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
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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
SOFTWARE.
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

475
README.md
View File

@@ -1,10 +1,16 @@
# 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)
![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
Place the following in `Your_Project/.github/workflows/main.yml`
```yml
on: push
name: Publish Website
@@ -13,65 +19,259 @@ jobs:
name: FTP-Deploy-Action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/checkout@v2.1.0
with:
fetch-depth: 2
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@2.0.0
env:
FTP_SERVER: ftp.samkirkland.com
FTP_USERNAME: myFtpUserName
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
ARGS: --delete
# --delete arg will delete files on the server if you've deleted them in git
uses: SamKirkland/FTP-Deploy-Action@3.1.1
with:
ftp-server: ftp://ftp.samkirkland.com/
ftp-username: myFtpUserName
ftp-password: ${{ secrets.FTP_PASSWORD }}
```
---
### Setup Steps
1. Select the repository you want to add the action to
2. Select the actions tab `(currently only for beta testers)`
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 above code into your 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`
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`
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 recommend you store your `ftp-password` as a secret.
| 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_USERNAME` | Yes | git-action@samkirkland.com | N/A | FTP account username |
| `FTP_PASSWORD` | Yes | CrazyUniquePassword&%123 | N/A | FTP account password |
| `METHOD` | No | ftp | ftp | Protocol used to deploy (ftp or sftp) |
| `PORT` | No | 21 | ftp=21, sftp=22 | The port used to connect to server |
| `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. |
| 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) |
#### 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.
#### 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:
Below is an incomplete list of commonly used args:
| Argument | Description |
|------------------------|------------------------------------------------------------------------------------------------------|
| `--verbose` | Outputs which files are being modified, useful for debugging |
| `--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` |
| `--delete-excluded` | Deletes any items you've marked as excluded if they exist on the server |
| `--no-empty-dirs` | Don't create empty directories |
| `--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) |
| `--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.
```yml
on: push
name: Publish 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: 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 }}
```
### 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
## 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
### 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
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 }}
git-ftp-args: --insecure # if your certificate is setup correctly this can be removed (see known-hosts argument)
```
### 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
@@ -80,8 +280,10 @@ jobs:
name: FTP-Deploy-Action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/checkout@v2.1.0
with:
fetch-depth: 2
- name: Use Node.js 12.x
uses: actions/setup-node@v1
with:
@@ -96,36 +298,12 @@ jobs:
run: ls
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@2.0.0
env:
FTP_SERVER: ftp.samkirkland.com
FTP_USERNAME: myFTPUsername
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
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
uses: SamKirkland/FTP-Deploy-Action@3.1.1
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
```
### Log only dry run: Use this mode for testing
@@ -138,53 +316,126 @@ jobs:
name: FTP-Deploy-Action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/checkout@v2.1.0
with:
fetch-depth: 2
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action@2.0.0
env:
FTP_SERVER: ftp.samkirkland.com
FTP_USERNAME: myFTPUsername
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
ARGS: --delete --dry-run
uses: SamKirkland/FTP-Deploy-Action@3.1.1
with:
ftp-server: ftp://ftp.samkirkland.com/
ftp-username: myFTPUsername
ftp-password: ${{ secrets.FTP_PASSWORD }}
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
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 to exclude .git files from the publish
* **Fix:** Add `--exclude-glob=.git*/** --exclude-glob=.git**` to your ARGS
* 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
* Note: This will exclude all folders and files that start with `.git` no matter the folder they're in
<details>
<summary>How to exclude .git files from the publish</summary>
#### 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"]
}
See the [`.git-ftp-ignore`](#ignore-specific-files-when-deploying) example section
</details>
<details>
<summary>All files are being uploaded instead of just different files</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
</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
name: Publish Website
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
runs-on: ubuntu-latest
timeout-minutes: 15 # time out after 15 minutes (default is 360 minutes)
steps:
....
```
</details>
### 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`
---
## 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>
##### Instructions for debugging on linux
- Please submit a PR for linux instructions :)
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>
#### ToDo
- More examples
<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
#### 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!

View File

@@ -1,46 +1,27 @@
name: 'FTP Deploy'
description: 'Syncs files via FTP/SFTP to a remote server'
author: 'Sam Kirkland'
inputs:
ftp_server:
description: 'FTP server name (you may need to specify a port)'
ftp-server:
description: 'Deployment destination server & path. Formatted as protocol://domain.com:port/full/destination/path/'
required: true
ftp_username:
ftp-username:
description: 'FTP account username'
required: true
ftp_password:
ftp-password:
description: 'FTP account password'
required: true
method:
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:
local-dir:
description: 'The local folder to copy, defaults to root project folder'
default: ./
required: false
default: ""
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)'
git-ftp-args:
description: 'Passes through options into git-ftp'
default:
required: false
default: ""
ARGS:
description: 'Passes through options into lftp'
required: false
default: ""
runs:
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.ftp_server }}
- ${{ inputs.ftp_username }}
- ${{ inputs.ftp_password }}
- ${{ inputs.method }}
- ${{ inputs.port }}
- ${{ inputs.local_dir }}
- ${{ inputs.remote_dir }}
branding:
icon: 'upload-cloud'
icon: 'upload-cloud'
color: 'orange'

View File

@@ -0,0 +1,18 @@
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

1689
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

4761
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

39
package.json Normal file
View File

@@ -0,0 +1,39 @@
{
"name": "typescript-action",
"version": "1.0.0",
"private": true,
"description": "TypeScript template 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"
},
"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.4",
"@actions/exec": "1.0.4"
},
"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"
}
}

91
src/main.ts Normal file
View File

@@ -0,0 +1,91 @@
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import fs from 'fs';
import { promisify } from 'util';
import { IActionArguments } from './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"), "")
};
}
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) {
core.setFailed(error.message);
}
}

31
src/types.ts Normal file
View File

@@ -0,0 +1,31 @@
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
}

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@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 |