mirror of
https://github.com/JamesIves/github-pages-deploy-action.git
synced 2023-12-15 20:03:39 +08:00
Version 3 (#44)
* Version 3 Beta * README Updates * More readme updates * lock * Restoring license/contrib * One set of tests * linting * More tests * Finish up unit tests * Update action.yml * Update main.yml * Update README.md * Update README.md * README Changes * Update README.md * Unit testing job * Some more stuff * More cleanup * Update README.md * Unrequired * Update CONTRIBUTING.md * no guess * Using Git Switch as opposed to checkout * Force Commit * Remove git * Some more simplification * Update git.ts * changes * Options * w * Debugging * More debugging * More debugging * Debugging * Debugging * Debugging * Debugging * Debugging * Debugging * Debugging * Debugging * Debugging * Debugging * Debugging * Debugging * Debugging * Debug * Debugging * Another 1 * Update git.ts * Fixes root deployment * Quiet Mode * Quiet * Excluding .github * Update README.md
This commit is contained in:
parent
ab80c0965e
commit
4b2f84d384
16
.github/workflows/build.yml
vendored
Normal file
16
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
name: unit
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
jobs:
|
||||||
|
unit-test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@master
|
||||||
|
|
||||||
|
- name: Install and Test
|
||||||
|
run: |
|
||||||
|
npm install
|
||||||
|
npm run-script test
|
@ -14,5 +14,4 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||||
BRANCH: gh-pages
|
BRANCH: gh-pages
|
||||||
FOLDER: 'test/build'
|
FOLDER: 'integration'
|
||||||
BUILD_SCRIPT: npm run-script integrationTest
|
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,4 +5,5 @@
|
|||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
test/build
|
|
||||||
|
node_modules
|
@ -1,10 +1,28 @@
|
|||||||
# Contributing
|
# Contributing
|
||||||
|
|
||||||
When contributing to this repository, please first discuss the change you wish to make via issue,
|
When contributing to this repository, please first discuss the change you wish to make via issue,
|
||||||
email, or any other method with the owners of this repository before making a change.
|
email, or any other method with the owners of this repository before making a change.
|
||||||
|
|
||||||
## Pull Request Best Practices
|
## Pull Request Best Practices
|
||||||
|
|
||||||
1. Ensure that you've tested your feature/change yourself. As the primary focus of this project is deployment, providing a link to a deployed repository using your branch is preferred. You can reference the forked action using your GitHub username, for example `yourname/github-pages-deplpy-action@master`.
|
1. Ensure that you've tested your feature/change yourself. As the primary focus of this project is deployment, providing a link to a deployed repository using your branch is preferred. You can reference the forked action using your GitHub username, for example `yourname/github-pages-deplpy-action@master`.
|
||||||
2. Make sure you update the README if you've made a change that requires documentation.
|
2. Make sure you update the README if you've made a change that requires documentation.
|
||||||
3. When making a pull request, highlight any areas that may cause a breaking change so the maintainer can update the version number accordingly on the GitHub marketplace.
|
3. When making a pull request, highlight any areas that may cause a breaking change so the maintainer can update the version number accordingly on the GitHub marketplace.
|
||||||
|
|
||||||
|
# Deploying
|
||||||
|
|
||||||
|
In order to deploy and test your own fork of this action, you must commit the required `node_modules` dependencies.
|
||||||
|
|
||||||
|
To do this you can follow the instructions below:
|
||||||
|
|
||||||
|
```
|
||||||
|
# comment out in distribution branches
|
||||||
|
# node_modules/
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git checkout -b branchnamehere
|
||||||
|
$ git commit -a -m "prod dependencies"
|
||||||
|
```
|
||||||
|
|
||||||
|
The `node_modules` folder should _not_ be included when making a pull request.
|
13
Dockerfile
13
Dockerfile
@ -1,13 +0,0 @@
|
|||||||
FROM node:10
|
|
||||||
|
|
||||||
LABEL "com.github.actions.name"="Deploy to GitHub Pages"
|
|
||||||
LABEL "com.github.actions.description"="This action will handle the building and deploying process of your project to GitHub Pages."
|
|
||||||
LABEL "com.github.actions.icon"="git-commit"
|
|
||||||
LABEL "com.github.actions.color"="orange"
|
|
||||||
|
|
||||||
LABEL "repository"="http://github.com/JamesIves/gh-pages-github-action"
|
|
||||||
LABEL "homepage"="http://github.com/JamesIves/gh-pages-gh-action"
|
|
||||||
LABEL "maintainer"="James Ives <iam@jamesiv.es>"
|
|
||||||
|
|
||||||
ADD entrypoint.sh /entrypoint.sh
|
|
||||||
ENTRYPOINT ["/entrypoint.sh"]
|
|
2
LICENSE
2
LICENSE
@ -18,4 +18,4 @@ 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 THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
23
README.md
23
README.md
@ -1,8 +1,8 @@
|
|||||||
# GitHub Pages Deploy Action :rocket:
|
# GitHub Pages Deploy Action :rocket:
|
||||||
|
|
||||||
[![Actions Status](https://github.com/JamesIves/github-pages-deploy-action/workflows/integration/badge.svg)](https://github.com/JamesIves/github-pages-deploy-action/actions) [![View Action](https://img.shields.io/badge/view-action-blue.svg)](https://github.com/marketplace/actions/deploy-to-github-pages) [![Issues](https://img.shields.io/github/issues/JamesIves/github-pages-deploy-action.svg)](https://github.com/JamesIves/github-pages-deploy-action/issues)
|
[![Build Status](https://github.com/JamesIves/github-pages-deploy-action/workflows/unit/badge.svg)](https://github.com/JamesIves/github-pages-deploy-action/actions) [![Actions Status](https://github.com/JamesIves/github-pages-deploy-action/workflows/integration/badge.svg)](https://github.com/JamesIves/github-pages-deploy-action/actions) [![View Action](https://img.shields.io/badge/view-action-blue.svg?logo=github&color=orange)](https://github.com/marketplace/actions/deploy-to-github-pages) [![Version](https://img.shields.io/github/v/release/JamesIves/github-pages-deploy-action.svg?logo=github)](hhttps://github.com/JamesIves/github-pages-deploy-action/releases)
|
||||||
|
|
||||||
This [GitHub action](https://github.com/features/actions) will handle the building and deploy process of your project to [GitHub Pages](https://pages.github.com/). It can be configured to upload your production-ready code into any branch you'd like, including `gh-pages` and `docs`. This action is built on [Node](https://nodejs.org/en/), which means that you can call any optional build scripts your project requires prior to deploying.
|
This [GitHub action](https://github.com/features/actions) will handle the deploy process of your project to [GitHub Pages](https://pages.github.com/). It can be configured to upload your production-ready code into any branch you'd like, including `gh-pages` and `docs`.
|
||||||
|
|
||||||
## Getting Started :airplane:
|
## Getting Started :airplane:
|
||||||
You can include the action in your workflow to trigger on any event that [GitHub actions supports](https://help.github.com/en/articles/events-that-trigger-workflows). If the remote branch that you wish to deploy to doesn't already exist the action will create it for you. Your workflow will also need to include the `actions/checkout` step before this workflow runs in order for the deployment to work.
|
You can include the action in your workflow to trigger on any event that [GitHub actions supports](https://help.github.com/en/articles/events-that-trigger-workflows). If the remote branch that you wish to deploy to doesn't already exist the action will create it for you. Your workflow will also need to include the `actions/checkout` step before this workflow runs in order for the deployment to work.
|
||||||
@ -20,13 +20,12 @@ jobs:
|
|||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
- name: Build and Deploy
|
- name: Build and Deploy
|
||||||
uses: JamesIves/github-pages-deploy-action@releases/v2
|
uses: JamesIves/github-pages-deploy-action@releases/v3
|
||||||
env:
|
with:
|
||||||
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||||
BASE_BRANCH: master # The branch the action should deploy from.
|
BASE_BRANCH: master # The branch the action should deploy from.
|
||||||
BRANCH: gh-pages # The branch the action should deploy to.
|
BRANCH: gh-pages # The branch the action should deploy to.
|
||||||
FOLDER: build # The folder the action should deploy.
|
FOLDER: build # The folder the action should deploy.
|
||||||
BUILD_SCRIPT: npm install && npm run-script build # The build script the action should run prior to deploying.
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If you'd like to make it so the workflow only triggers on push events to specific branches then you can modify the `on` section. You'll still need to specify a `BASE_BRANCH` if you're deploying from a branch other than `master`.
|
If you'd like to make it so the workflow only triggers on push events to specific branches then you can modify the `on` section. You'll still need to specify a `BASE_BRANCH` if you're deploying from a branch other than `master`.
|
||||||
@ -40,7 +39,7 @@ on:
|
|||||||
|
|
||||||
## Configuration 📁
|
## Configuration 📁
|
||||||
|
|
||||||
The `env` portion of the workflow **must** be configured before the action will work. You can add these in the `env` section found in the examples above. Any `secrets` must be referenced using the bracket syntax and stored in the GitHub repositories `Settings/Secrets` menu. You can learn more about setting environment variables with GitHub actions [here](https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idstepsenv).
|
The `with` portion of the workflow **must** be configured before the action will work. You can add these in the `with` section found in the examples above. Any `secrets` must be referenced using the bracket syntax and stored in the GitHub repositories `Settings/Secrets` menu. You can learn more about setting environment variables with GitHub actions [here](https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idstepsenv).
|
||||||
|
|
||||||
Below you'll find a description of what each option does.
|
Below you'll find a description of what each option does.
|
||||||
|
|
||||||
@ -48,12 +47,14 @@ Below you'll find a description of what each option does.
|
|||||||
| ------------- | ------------- | ------------- | ------------- |
|
| ------------- | ------------- | ------------- | ------------- |
|
||||||
| `GITHUB_TOKEN` | In order for GitHub to trigger the rebuild of your page you must provide the action with the repositories provided GitHub token. This can be referenced in the workflow `yml` file by using `${{ secrets.GITHUB_TOKEN }}`. Only required if an access token is **not** provided. **Please note there is currently an issue affecting the use of this token, [you can learn more here](https://github.com/JamesIves/github-pages-deploy-action/issues/5)**. | `secrets` | **Yes** |
|
| `GITHUB_TOKEN` | In order for GitHub to trigger the rebuild of your page you must provide the action with the repositories provided GitHub token. This can be referenced in the workflow `yml` file by using `${{ secrets.GITHUB_TOKEN }}`. Only required if an access token is **not** provided. **Please note there is currently an issue affecting the use of this token, [you can learn more here](https://github.com/JamesIves/github-pages-deploy-action/issues/5)**. | `secrets` | **Yes** |
|
||||||
| `ACCESS_TOKEN` | Depending on the repository permissions you may need to provide the action with a GitHub personal access token instead of the provided GitHub token in order to deploy. You can [learn more about how to generate one here](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line). **This should be stored as a secret**. | `secrets` | **No** |
|
| `ACCESS_TOKEN` | Depending on the repository permissions you may need to provide the action with a GitHub personal access token instead of the provided GitHub token in order to deploy. You can [learn more about how to generate one here](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line). **This should be stored as a secret**. | `secrets` | **No** |
|
||||||
| `BRANCH` | This is the branch you wish to deploy to, for example `gh-pages` or `docs`. | `env` | **Yes** |
|
| `BRANCH` | This is the branch you wish to deploy to, for example `gh-pages` or `docs`. | `with` | **Yes** |
|
||||||
| `FOLDER` | The folder in your repository that you want to deploy. If your build script compiles into a directory named `build` you'd put it here. **Folder paths cannot have a leading `/` or `./`**. | `env` | **Yes** |
|
| `FOLDER` | The folder in your repository that you want to deploy. If your build script compiles into a directory named `build` you'd put it here. **Folder paths cannot have a leading `/` or `./`**. | `with` | **Yes** |
|
||||||
| `BASE_BRANCH` | The base branch of your repository which you'd like to checkout prior to deploying. This defaults to `master`. | `env` | **No** |
|
| `BASE_BRANCH` | The base branch of your repository which you'd like to checkout prior to deploying. This defaults to `master`. | `with` | **No** |
|
||||||
| `BUILD_SCRIPT` | If you require a build script to compile your code prior to pushing it you can add the script here. The Docker container which powers the action runs Node which means `npm` commands are valid. If you're using a static site generator such as Jekyll I'd suggest compiling the code prior to pushing it to your base branch. | `env` | **No** |
|
|
||||||
| `CNAME` | If you're using a [custom domain](https://help.github.com/en/articles/using-a-custom-domain-with-github-pages), you will need to add the domain name to the `CNAME` environment variable. If you don't do this GitHub will wipe out your domain configuration after each deploy. This value will look something like this: `jives.dev`. | `env` | **No** |
|
|
||||||
|
|
||||||
With the action correctly configured you should see the workflow trigger the deployment under the configured conditions.
|
With the action correctly configured you should see the workflow trigger the deployment under the configured conditions.
|
||||||
|
|
||||||
|
### Additional Build Files
|
||||||
|
|
||||||
|
This action maintains the full Git history of the deployment branch. Therefore if you're using a custom domain and require a `CNAME` file, or if you require the use of a `.nojekyll` file, you can safely commit these files directly into deployment branch without them being overridden after each deployment.
|
||||||
|
|
||||||
![Example](screenshot.png)
|
![Example](screenshot.png)
|
||||||
|
161
__tests__/git.test.ts
Normal file
161
__tests__/git.test.ts
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
// Initial env variable setup for tests.
|
||||||
|
process.env["INPUT_FOLDER"] = "build";
|
||||||
|
|
||||||
|
import { execute } from "../src/util";
|
||||||
|
import { init, generateBranch, deploy } from "../src/git";
|
||||||
|
import {action} from '../src/constants'
|
||||||
|
import {cp} from '@actions/io';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
const originalAction = _.cloneDeep(action);
|
||||||
|
|
||||||
|
jest.mock("../src/util", () => ({
|
||||||
|
execute: jest.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock("@actions/io", () => ({
|
||||||
|
cp: jest.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("git", () => {
|
||||||
|
afterEach(() => {
|
||||||
|
_.assignIn(action, originalAction);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("init", () => {
|
||||||
|
it("should execute three commands if a GitHub token is provided", async () => {
|
||||||
|
|
||||||
|
|
||||||
|
Object.assign(action, {
|
||||||
|
build: 'build',
|
||||||
|
gitHubToken: '123',
|
||||||
|
pusher: {
|
||||||
|
name: 'asd',
|
||||||
|
email: 'as@cat'
|
||||||
|
}})
|
||||||
|
|
||||||
|
const call = await init();
|
||||||
|
expect(execute).toBeCalledTimes(3);
|
||||||
|
expect(call).toBe('Initialization step complete...')
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should execute three commands if a Access token is provided", async () => {
|
||||||
|
|
||||||
|
Object.assign(action, {
|
||||||
|
build: 'build',
|
||||||
|
accessToken: '123',
|
||||||
|
pusher: {
|
||||||
|
name: 'asd',
|
||||||
|
email: 'as@cat'
|
||||||
|
}})
|
||||||
|
|
||||||
|
const call = await init();
|
||||||
|
|
||||||
|
expect(execute).toBeCalledTimes(3);
|
||||||
|
expect(call).toBe('Initialization step complete...')
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should fail if there is no provided GitHub Token or Access Token", async () => {
|
||||||
|
Object.assign(action, {
|
||||||
|
build: 'build',
|
||||||
|
pusher: {
|
||||||
|
name: 'asd',
|
||||||
|
email: 'as@cat'
|
||||||
|
}})
|
||||||
|
|
||||||
|
const call = await init()
|
||||||
|
|
||||||
|
expect(execute).toBeCalledTimes(0);
|
||||||
|
expect(call).toBe('Initialization step complete...')
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should fail if the build folder begins with a /", async () => {
|
||||||
|
Object.assign(action, {
|
||||||
|
accessToken: '123',
|
||||||
|
build: '/',
|
||||||
|
pusher: {
|
||||||
|
name: 'asd',
|
||||||
|
email: 'as@cat'
|
||||||
|
}})
|
||||||
|
|
||||||
|
const call = await init()
|
||||||
|
|
||||||
|
expect(execute).toBeCalledTimes(0);
|
||||||
|
expect(call).toBe('Initialization step complete...')
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should fail if the build folder begins with a ./", async () => {
|
||||||
|
Object.assign(action, {
|
||||||
|
accessToken: '123',
|
||||||
|
build: './',
|
||||||
|
pusher: {
|
||||||
|
name: 'asd',
|
||||||
|
email: 'as@cat'
|
||||||
|
}})
|
||||||
|
|
||||||
|
const call = await init()
|
||||||
|
|
||||||
|
expect(execute).toBeCalledTimes(0);
|
||||||
|
expect(call).toBe('Initialization step complete...')
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should not fail if root is used", async () => {
|
||||||
|
Object.assign(action, {
|
||||||
|
accessToken: '123',
|
||||||
|
build: '.',
|
||||||
|
pusher: {
|
||||||
|
name: 'asd',
|
||||||
|
email: 'as@cat'
|
||||||
|
}})
|
||||||
|
|
||||||
|
const call = await init()
|
||||||
|
|
||||||
|
expect(execute).toBeCalledTimes(3);
|
||||||
|
expect(call).toBe('Initialization step complete...')
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('generateBranch', () => {
|
||||||
|
it('should execute five commands', async () => {
|
||||||
|
const call = await generateBranch();
|
||||||
|
expect(execute).toBeCalledTimes(6);
|
||||||
|
expect(call).toBe('Deployment branch creation step complete...')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('deploy', () => {
|
||||||
|
it('should execute five commands', async () => {
|
||||||
|
Object.assign(action, {
|
||||||
|
build: 'build',
|
||||||
|
gitHubToken: '123',
|
||||||
|
pusher: {
|
||||||
|
name: 'asd',
|
||||||
|
email: 'as@cat'
|
||||||
|
}})
|
||||||
|
|
||||||
|
const call = await deploy();
|
||||||
|
|
||||||
|
// Includes the call to generateBranch
|
||||||
|
expect(execute).toBeCalledTimes(14);
|
||||||
|
expect(cp).toBeCalledTimes(1)
|
||||||
|
expect(call).toBe('Commit step complete...')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should execute six commands if root is used', async () => {
|
||||||
|
Object.assign(action, {
|
||||||
|
build: '.',
|
||||||
|
gitHubToken: '123',
|
||||||
|
pusher: {
|
||||||
|
name: 'asd',
|
||||||
|
email: 'as@cat'
|
||||||
|
}})
|
||||||
|
|
||||||
|
const call = await deploy();
|
||||||
|
|
||||||
|
// Includes the call to generateBranch
|
||||||
|
expect(execute).toBeCalledTimes(15);
|
||||||
|
expect(cp).toBeCalledTimes(0)
|
||||||
|
expect(call).toBe('Commit step complete...')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
23
__tests__/util.test.ts
Normal file
23
__tests__/util.test.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import {execute} from '../src/util';
|
||||||
|
import {exec} from '@actions/exec';
|
||||||
|
|
||||||
|
jest.mock('@actions/exec', () => ({
|
||||||
|
exec: jest.fn()
|
||||||
|
}))
|
||||||
|
|
||||||
|
describe('util', () => {
|
||||||
|
describe('execute', () => {
|
||||||
|
it('should be called with the correct arguements', async() => {
|
||||||
|
await execute('echo Montezuma', './')
|
||||||
|
|
||||||
|
expect(exec).toBeCalledWith(
|
||||||
|
"echo Montezuma", [], {
|
||||||
|
cwd: "./",
|
||||||
|
listeners: {
|
||||||
|
stdout: expect.any(Function)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
})
|
||||||
|
})
|
@ -1,9 +1,9 @@
|
|||||||
name: 'Deploy to GitHub Pages'
|
name: 'Deploy to GitHub Pages'
|
||||||
description: 'This action will handle the building and deploying process of your project to GitHub Pages.'
|
description: 'This action will handle the deployment process of your project to GitHub Pages.'
|
||||||
author: 'James Ives <iam@jamesiv.es>'
|
author: 'James Ives <iam@jamesiv.es>'
|
||||||
runs:
|
runs:
|
||||||
using: 'docker'
|
using: 'node12'
|
||||||
image: 'Dockerfile'
|
main: 'lib/main.js'
|
||||||
branding:
|
branding:
|
||||||
icon: 'git-commit'
|
icon: 'git-commit'
|
||||||
color: 'orange'
|
color: 'orange'
|
@ -1,92 +0,0 @@
|
|||||||
#!/bin/sh -l
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [ -z "$ACCESS_TOKEN" ] && [ -z "$GITHUB_TOKEN" ]
|
|
||||||
then
|
|
||||||
echo "You must provide the action with either a Personal Access Token or the GitHub Token secret in order to deploy."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$BRANCH" ]
|
|
||||||
then
|
|
||||||
echo "You must provide the action with a branch name it should deploy to, for example gh-pages or docs."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$FOLDER" ]
|
|
||||||
then
|
|
||||||
echo "You must provide the action with the folder name in the repository where your compiled page lives."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$FOLDER" in /*|./*)
|
|
||||||
echo "The deployment folder cannot be prefixed with '/' or './'. Instead reference the folder name directly."
|
|
||||||
exit 1
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Installs Git and jq.
|
|
||||||
apt-get update && \
|
|
||||||
apt-get install -y git && \
|
|
||||||
apt-get install -y jq && \
|
|
||||||
|
|
||||||
# Gets the commit email/name if it exists in the push event payload.
|
|
||||||
COMMIT_EMAIL=`jq '.pusher.email' ${GITHUB_EVENT_PATH}`
|
|
||||||
COMMIT_NAME=`jq '.pusher.name' ${GITHUB_EVENT_PATH}`
|
|
||||||
|
|
||||||
# If the commit email/name is not found in the event payload then it falls back to the actor.
|
|
||||||
if [ -z "$COMMIT_EMAIL" ]
|
|
||||||
then
|
|
||||||
COMMIT_EMAIL="${GITHUB_ACTOR:-github-pages-deploy-action}@users.noreply.github.com"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$COMMIT_NAME" ]
|
|
||||||
then
|
|
||||||
COMMIT_NAME="${GITHUB_ACTOR:-GitHub Pages Deploy Action}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Directs the action to the the Github workspace.
|
|
||||||
cd $GITHUB_WORKSPACE && \
|
|
||||||
|
|
||||||
# Configures Git.
|
|
||||||
git init && \
|
|
||||||
git config --global user.email "${COMMIT_EMAIL}" && \
|
|
||||||
git config --global user.name "${COMMIT_NAME}" && \
|
|
||||||
|
|
||||||
## Initializes the repository path using the access token.
|
|
||||||
REPOSITORY_PATH="https://${ACCESS_TOKEN:-"x-access-token:$GITHUB_TOKEN"}@github.com/${GITHUB_REPOSITORY}.git" && \
|
|
||||||
|
|
||||||
# Checks to see if the remote exists prior to deploying.
|
|
||||||
# If the branch doesn't exist it gets created here as an orphan.
|
|
||||||
if [ "$(git ls-remote --heads "$REPOSITORY_PATH" "$BRANCH" | wc -l)" -eq 0 ];
|
|
||||||
then
|
|
||||||
echo "Creating remote branch ${BRANCH} as it doesn't exist..."
|
|
||||||
git checkout "${BASE_BRANCH:-master}" && \
|
|
||||||
git checkout --orphan $BRANCH && \
|
|
||||||
git rm -rf . && \
|
|
||||||
touch README.md && \
|
|
||||||
git add README.md && \
|
|
||||||
git commit -m "Initial ${BRANCH} commit" && \
|
|
||||||
git push $REPOSITORY_PATH $BRANCH
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Checks out the base branch to begin the deploy process.
|
|
||||||
git checkout "${BASE_BRANCH:-master}" && \
|
|
||||||
|
|
||||||
# Builds the project if a build script is provided.
|
|
||||||
echo "Running build scripts... $BUILD_SCRIPT" && \
|
|
||||||
eval "$BUILD_SCRIPT" && \
|
|
||||||
|
|
||||||
if [ "$CNAME" ]; then
|
|
||||||
echo "Generating a CNAME file in in the $FOLDER directory..."
|
|
||||||
echo $CNAME > $FOLDER/CNAME
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Commits the data to Github.
|
|
||||||
echo "Deploying to GitHub..." && \
|
|
||||||
git add -f $FOLDER && \
|
|
||||||
|
|
||||||
git commit -m "Deploying to ${BRANCH} from ${BASE_BRANCH:-master} ${GITHUB_SHA}" --quiet && \
|
|
||||||
git push $REPOSITORY_PATH `git subtree split --prefix $FOLDER ${BASE_BRANCH:-master}`:$BRANCH --force && \
|
|
||||||
|
|
||||||
echo "Deployment succesful!"
|
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
11
jest.config.js
Normal file
11
jest.config.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module.exports = {
|
||||||
|
clearMocks: true,
|
||||||
|
moduleFileExtensions: ['js', 'ts'],
|
||||||
|
testEnvironment: 'node',
|
||||||
|
testMatch: ['**/*.test.ts'],
|
||||||
|
testRunner: 'jest-circus/runner',
|
||||||
|
transform: {
|
||||||
|
'^.+\\.ts$': 'ts-jest'
|
||||||
|
},
|
||||||
|
verbose: true
|
||||||
|
}
|
28
lib/constants.js
Normal file
28
lib/constants.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||||
|
result["default"] = mod;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const core = __importStar(require("@actions/core"));
|
||||||
|
const github = __importStar(require("@actions/github"));
|
||||||
|
const { pusher, repository } = github.context.payload;
|
||||||
|
exports.workspace = process.env.GITHUB_WORKSPACE;
|
||||||
|
exports.folder = core.getInput("FOLDER", { required: true });
|
||||||
|
exports.root = ".";
|
||||||
|
// Required action data.
|
||||||
|
exports.action = {
|
||||||
|
build: exports.folder,
|
||||||
|
gitHubRepository: repository ? repository.full_name : "",
|
||||||
|
gitHubToken: core.getInput("GITHUB_TOKEN"),
|
||||||
|
accessToken: core.getInput("ACCESS_TOKEN"),
|
||||||
|
branch: core.getInput("BRANCH"),
|
||||||
|
baseBranch: core.getInput("BASE_BRANCH") || "master",
|
||||||
|
pusher
|
||||||
|
};
|
||||||
|
// Repository path used for commits/pushes.
|
||||||
|
exports.repositoryPath = `https://${exports.action.accessToken ||
|
||||||
|
`x-access-token:${exports.action.gitHubToken}`}@github.com/${exports.action.gitHubRepository}.git`;
|
113
lib/git.js
Normal file
113
lib/git.js
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||||
|
result["default"] = mod;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const core = __importStar(require("@actions/core"));
|
||||||
|
const io_1 = require("@actions/io");
|
||||||
|
const util_1 = require("./util");
|
||||||
|
const constants_1 = require("./constants");
|
||||||
|
/** Generates the branch if it doesn't exist on the remote.
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
function init() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
try {
|
||||||
|
if (!constants_1.action.accessToken && !constants_1.action.gitHubToken) {
|
||||||
|
return core.setFailed("You must provide the action with either a Personal Access Token or the GitHub Token secret in order to deploy.");
|
||||||
|
}
|
||||||
|
if (constants_1.action.build.startsWith("/") || constants_1.action.build.startsWith("./")) {
|
||||||
|
return core.setFailed(`The deployment folder cannot be prefixed with '/' or './'. Instead reference the folder name directly.`);
|
||||||
|
}
|
||||||
|
yield util_1.execute(`git init`, constants_1.workspace);
|
||||||
|
yield util_1.execute(`git config user.name ${constants_1.action.pusher.name}`, constants_1.workspace);
|
||||||
|
yield util_1.execute(`git config user.email ${constants_1.action.pusher.email}`, constants_1.workspace);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
core.setFailed(`There was an error initializing the repository: ${error}`);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
return Promise.resolve("Initialization step complete...");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.init = init;
|
||||||
|
/** Generates the branch if it doesn't exist on the remote.
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
function generateBranch() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
try {
|
||||||
|
console.log(`Creating ${constants_1.action.branch} branch...`);
|
||||||
|
yield util_1.execute(`git switch ${constants_1.action.baseBranch || "master"}`, constants_1.workspace);
|
||||||
|
yield util_1.execute(`git switch --orphan ${constants_1.action.branch}`, constants_1.workspace);
|
||||||
|
yield util_1.execute(`git reset --hard`, constants_1.workspace);
|
||||||
|
yield util_1.execute(`git commit --allow-empty -m "Initial ${constants_1.action.branch} commit."`, constants_1.workspace);
|
||||||
|
yield util_1.execute(`git push ${constants_1.repositoryPath} ${constants_1.action.branch}`, constants_1.workspace);
|
||||||
|
// Switches back to the base branch.
|
||||||
|
yield util_1.execute(`git switch ${constants_1.action.baseBranch || "master"}`, constants_1.workspace);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
core.setFailed(`There was an error creating the deployment branch: ${error}`);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
return Promise.resolve("Deployment branch creation step complete...");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.generateBranch = generateBranch;
|
||||||
|
/** Runs the necessary steps to make the deployment.
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
function deploy() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const temporaryDeploymentDirectory = "gh-action-temp-deployment-folder";
|
||||||
|
const temporaryDeploymentBranch = "gh-action-temp-deployment-branch";
|
||||||
|
/*
|
||||||
|
Checks to see if the remote exists prior to deploying.
|
||||||
|
If the branch doesn't exist it gets created here as an orphan.
|
||||||
|
*/
|
||||||
|
const branchExists = yield util_1.execute(`git ls-remote --heads ${constants_1.repositoryPath} ${constants_1.action.branch} | wc -l`, constants_1.workspace);
|
||||||
|
if (!branchExists) {
|
||||||
|
console.log("Deployment branch does not exist. Creating....");
|
||||||
|
yield generateBranch();
|
||||||
|
}
|
||||||
|
// Checks out the base branch to begin the deployment process.
|
||||||
|
yield util_1.execute(`git checkout ${constants_1.action.baseBranch || "master"}`, constants_1.workspace);
|
||||||
|
yield util_1.execute(`git fetch origin`, constants_1.workspace);
|
||||||
|
yield util_1.execute(`git worktree add --checkout ${temporaryDeploymentDirectory} origin/${constants_1.action.branch}`, constants_1.workspace);
|
||||||
|
/*
|
||||||
|
Pushes all of the build files into the deployment directory.
|
||||||
|
Allows the user to specify the root if '.' is provided. */
|
||||||
|
if (constants_1.action.build === constants_1.root) {
|
||||||
|
// rsync is executed here so the .git and temporary deployment directories don't get duplicated.
|
||||||
|
yield util_1.execute(`rsync -q -av --progress ${constants_1.action.build}/. ${temporaryDeploymentDirectory} --exclude .git --exclude .github --exclude ${temporaryDeploymentDirectory}`, constants_1.workspace);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
yield io_1.cp(`${constants_1.action.build}/.`, temporaryDeploymentDirectory, {
|
||||||
|
recursive: true,
|
||||||
|
force: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Commits to GitHub.
|
||||||
|
yield util_1.execute(`git add --all .`, temporaryDeploymentDirectory);
|
||||||
|
yield util_1.execute(`git switch -c ${temporaryDeploymentBranch}`, temporaryDeploymentDirectory);
|
||||||
|
yield util_1.execute(`git commit -m "Deploying to ${constants_1.action.branch} from ${constants_1.action.baseBranch} ${process.env.GITHUB_SHA}" --quiet`, temporaryDeploymentDirectory);
|
||||||
|
yield util_1.execute(`git push --force ${constants_1.repositoryPath} ${temporaryDeploymentBranch}:${constants_1.action.branch}`, temporaryDeploymentDirectory);
|
||||||
|
return Promise.resolve("Commit step complete...");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.deploy = deploy;
|
35
lib/main.js
Normal file
35
lib/main.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||||
|
result["default"] = mod;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const core = __importStar(require("@actions/core"));
|
||||||
|
const git_1 = require("./git");
|
||||||
|
/** Initializes and runs the action. */
|
||||||
|
(function () {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
try {
|
||||||
|
yield git_1.init();
|
||||||
|
yield git_1.deploy();
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
core.setFailed(error.message);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
console.log("Completed Deployment");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
33
lib/util.js
Normal file
33
lib/util.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const exec_1 = require("@actions/exec");
|
||||||
|
/** Wrapper around the GitHub toolkit exec command which returns the output.
|
||||||
|
* Also allows you to easily toggle the current working directory.
|
||||||
|
* @param {String} cmd = The command to execute.
|
||||||
|
* @param {String} cwd - The current working directory.
|
||||||
|
* @returns {Promise} - The output from the command.
|
||||||
|
*/
|
||||||
|
function execute(cmd, cwd) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
let output = "";
|
||||||
|
yield exec_1.exec(cmd, [], {
|
||||||
|
cwd,
|
||||||
|
listeners: {
|
||||||
|
stdout: (data) => {
|
||||||
|
output += data.toString().trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Promise.resolve(output);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.execute = execute;
|
50
package.json
50
package.json
@ -1,9 +1,51 @@
|
|||||||
{
|
{
|
||||||
"name": "github-pages-deploy-action",
|
"name": "github-pages-deploy-action",
|
||||||
"description": "GitHub action for building a project and deploying it to GitHub pages.",
|
"description": "GitHub action for building a project and deploying it to GitHub pages.",
|
||||||
"license": "MIT",
|
"private": true,
|
||||||
"repository": "https://github.com/JamesIves/github-pages-deploy-action",
|
"main": "lib/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"integrationTest": "mkdir test/build && cp test/image.jpg test/build/image.jpg && cp test/index.html test/build/index.html"
|
"build": "tsc",
|
||||||
|
"test": "jest",
|
||||||
|
"lint": "tslint -p tsconfig.json --project '.' || (echo Project needs formatting)",
|
||||||
|
"format": "prettier --write './src/*.ts'"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/JamesIves/github-pages-deploy-action.git"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/JamesIves/github-pages-deploy-action/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/JamesIves/github-pages-deploy-action",
|
||||||
|
"keywords": [
|
||||||
|
"actions",
|
||||||
|
"node",
|
||||||
|
"setup",
|
||||||
|
"build",
|
||||||
|
"deploy",
|
||||||
|
"gh-pages",
|
||||||
|
"pages",
|
||||||
|
"github",
|
||||||
|
"deploy",
|
||||||
|
"deployment"
|
||||||
|
],
|
||||||
|
"author": "James Ives",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/core": "^1.0.0",
|
||||||
|
"@actions/exec": "^1.0.1",
|
||||||
|
"@actions/github": "^1.1.0",
|
||||||
|
"@actions/io": "^1.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/jest": "^24.0.13",
|
||||||
|
"@types/node": "^12.11.0",
|
||||||
|
"jest": "^24.8.0",
|
||||||
|
"jest-circus": "^24.7.1",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
|
"prettier": "^1.18.2",
|
||||||
|
"ts-jest": "^24.0.2",
|
||||||
|
"tslint": "^5.20.0",
|
||||||
|
"typescript": "^3.5.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
25
src/constants.ts
Normal file
25
src/constants.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import * as core from "@actions/core";
|
||||||
|
import * as github from "@actions/github";
|
||||||
|
|
||||||
|
const { pusher, repository } = github.context.payload;
|
||||||
|
|
||||||
|
export const workspace: any = process.env.GITHUB_WORKSPACE;
|
||||||
|
export const folder = core.getInput("FOLDER", { required: true });
|
||||||
|
export const root = ".";
|
||||||
|
|
||||||
|
// Required action data.
|
||||||
|
export const action = {
|
||||||
|
build: folder,
|
||||||
|
gitHubRepository: repository ? repository.full_name : "",
|
||||||
|
gitHubToken: core.getInput("GITHUB_TOKEN"),
|
||||||
|
accessToken: core.getInput("ACCESS_TOKEN"),
|
||||||
|
branch: core.getInput("BRANCH"),
|
||||||
|
baseBranch: core.getInput("BASE_BRANCH") || "master",
|
||||||
|
pusher
|
||||||
|
};
|
||||||
|
|
||||||
|
// Repository path used for commits/pushes.
|
||||||
|
export const repositoryPath = `https://${action.accessToken ||
|
||||||
|
`x-access-token:${action.gitHubToken}`}@github.com/${
|
||||||
|
action.gitHubRepository
|
||||||
|
}.git`;
|
118
src/git.ts
Normal file
118
src/git.ts
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import * as core from "@actions/core";
|
||||||
|
import { cp } from "@actions/io";
|
||||||
|
import { execute } from "./util";
|
||||||
|
import { workspace, action, root, repositoryPath } from "./constants";
|
||||||
|
|
||||||
|
/** Generates the branch if it doesn't exist on the remote.
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
export async function init(): Promise<any> {
|
||||||
|
try {
|
||||||
|
if (!action.accessToken && !action.gitHubToken) {
|
||||||
|
return core.setFailed(
|
||||||
|
"You must provide the action with either a Personal Access Token or the GitHub Token secret in order to deploy."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.build.startsWith("/") || action.build.startsWith("./")) {
|
||||||
|
return core.setFailed(
|
||||||
|
`The deployment folder cannot be prefixed with '/' or './'. Instead reference the folder name directly.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await execute(`git init`, workspace);
|
||||||
|
await execute(`git config user.name ${action.pusher.name}`, workspace);
|
||||||
|
await execute(`git config user.email ${action.pusher.email}`, workspace);
|
||||||
|
} catch (error) {
|
||||||
|
core.setFailed(`There was an error initializing the repository: ${error}`);
|
||||||
|
} finally {
|
||||||
|
return Promise.resolve("Initialization step complete...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Generates the branch if it doesn't exist on the remote.
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
export async function generateBranch(): Promise<any> {
|
||||||
|
try {
|
||||||
|
console.log(`Creating ${action.branch} branch...`);
|
||||||
|
await execute(`git switch ${action.baseBranch || "master"}`, workspace);
|
||||||
|
await execute(`git switch --orphan ${action.branch}`, workspace);
|
||||||
|
await execute(`git reset --hard`, workspace);
|
||||||
|
await execute(
|
||||||
|
`git commit --allow-empty -m "Initial ${action.branch} commit."`,
|
||||||
|
workspace
|
||||||
|
);
|
||||||
|
await execute(`git push ${repositoryPath} ${action.branch}`, workspace);
|
||||||
|
|
||||||
|
// Switches back to the base branch.
|
||||||
|
await execute(`git switch ${action.baseBranch || "master"}`, workspace);
|
||||||
|
} catch (error) {
|
||||||
|
core.setFailed(
|
||||||
|
`There was an error creating the deployment branch: ${error}`
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
return Promise.resolve("Deployment branch creation step complete...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Runs the necessary steps to make the deployment.
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
export async function deploy(): Promise<any> {
|
||||||
|
const temporaryDeploymentDirectory = "gh-action-temp-deployment-folder";
|
||||||
|
const temporaryDeploymentBranch = "gh-action-temp-deployment-branch";
|
||||||
|
/*
|
||||||
|
Checks to see if the remote exists prior to deploying.
|
||||||
|
If the branch doesn't exist it gets created here as an orphan.
|
||||||
|
*/
|
||||||
|
const branchExists = await execute(
|
||||||
|
`git ls-remote --heads ${repositoryPath} ${action.branch} | wc -l`,
|
||||||
|
workspace
|
||||||
|
);
|
||||||
|
if (!branchExists) {
|
||||||
|
console.log("Deployment branch does not exist. Creating....");
|
||||||
|
await generateBranch();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks out the base branch to begin the deployment process.
|
||||||
|
await execute(`git checkout ${action.baseBranch || "master"}`, workspace);
|
||||||
|
await execute(`git fetch origin`, workspace);
|
||||||
|
await execute(
|
||||||
|
`git worktree add --checkout ${temporaryDeploymentDirectory} origin/${action.branch}`,
|
||||||
|
workspace
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Pushes all of the build files into the deployment directory.
|
||||||
|
Allows the user to specify the root if '.' is provided. */
|
||||||
|
if (action.build === root) {
|
||||||
|
// rsync is executed here so the .git and temporary deployment directories don't get duplicated.
|
||||||
|
await execute(
|
||||||
|
`rsync -q -av --progress ${action.build}/. ${temporaryDeploymentDirectory} --exclude .git --exclude .github --exclude ${temporaryDeploymentDirectory}`,
|
||||||
|
workspace
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await cp(`${action.build}/.`, temporaryDeploymentDirectory, {
|
||||||
|
recursive: true,
|
||||||
|
force: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commits to GitHub.
|
||||||
|
await execute(`git add --all .`, temporaryDeploymentDirectory);
|
||||||
|
await execute(
|
||||||
|
`git switch -c ${temporaryDeploymentBranch}`,
|
||||||
|
temporaryDeploymentDirectory
|
||||||
|
);
|
||||||
|
await execute(
|
||||||
|
`git commit -m "Deploying to ${action.branch} from ${action.baseBranch} ${process.env.GITHUB_SHA}" --quiet`,
|
||||||
|
temporaryDeploymentDirectory
|
||||||
|
);
|
||||||
|
await execute(
|
||||||
|
`git push --force ${repositoryPath} ${temporaryDeploymentBranch}:${action.branch}`,
|
||||||
|
temporaryDeploymentDirectory
|
||||||
|
);
|
||||||
|
|
||||||
|
return Promise.resolve("Commit step complete...");
|
||||||
|
}
|
14
src/main.ts
Normal file
14
src/main.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import * as core from "@actions/core";
|
||||||
|
import { init, deploy } from "./git";
|
||||||
|
|
||||||
|
/** Initializes and runs the action. */
|
||||||
|
(async function() {
|
||||||
|
try {
|
||||||
|
await init();
|
||||||
|
await deploy();
|
||||||
|
} catch (error) {
|
||||||
|
core.setFailed(error.message);
|
||||||
|
} finally {
|
||||||
|
console.log("Completed Deployment");
|
||||||
|
}
|
||||||
|
})();
|
22
src/util.ts
Normal file
22
src/util.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { exec } from "@actions/exec";
|
||||||
|
|
||||||
|
/** Wrapper around the GitHub toolkit exec command which returns the output.
|
||||||
|
* Also allows you to easily toggle the current working directory.
|
||||||
|
* @param {String} cmd = The command to execute.
|
||||||
|
* @param {String} cwd - The current working directory.
|
||||||
|
* @returns {Promise} - The output from the command.
|
||||||
|
*/
|
||||||
|
export async function execute(cmd: string, cwd: string): Promise<any> {
|
||||||
|
let output = "";
|
||||||
|
|
||||||
|
await exec(cmd, [], {
|
||||||
|
cwd,
|
||||||
|
listeners: {
|
||||||
|
stdout: (data: Buffer) => {
|
||||||
|
output += data.toString().trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.resolve(output);
|
||||||
|
}
|
63
tsconfig.json
Normal file
63
tsconfig.json
Normal 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"]
|
||||||
|
}
|
37
tslint.json
Normal file
37
tslint.json
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"adjacent-overload-signatures": true,
|
||||||
|
"ban-comma-operator": true,
|
||||||
|
"no-namespace": true,
|
||||||
|
"no-parameter-reassignment": true,
|
||||||
|
"no-reference": true,
|
||||||
|
"no-unnecessary-type-assertion": true,
|
||||||
|
"label-position": true,
|
||||||
|
"no-conditional-assignment": true,
|
||||||
|
"no-construct": true,
|
||||||
|
"no-duplicate-super": true,
|
||||||
|
"no-duplicate-switch-case": true,
|
||||||
|
"no-duplicate-variable": [true, "check-parameters"],
|
||||||
|
"no-shadowed-variable": true,
|
||||||
|
"no-empty": [true, "allow-empty-catch"],
|
||||||
|
"no-floating-promises": false,
|
||||||
|
"no-implicit-dependencies": true,
|
||||||
|
"no-invalid-this": true,
|
||||||
|
"no-string-throw": true,
|
||||||
|
"no-unsafe-finally": true,
|
||||||
|
"no-use-before-declare": true,
|
||||||
|
"no-void-expression": [true, "ignore-arrow-function-shorthand"],
|
||||||
|
"no-duplicate-imports": true,
|
||||||
|
"no-empty-interface": {"severity": "warning"},
|
||||||
|
"no-import-side-effect": {"severity": "warning"},
|
||||||
|
"no-var-keyword": {"severity": "warning"},
|
||||||
|
"triple-equals": {"severity": "warning"},
|
||||||
|
"deprecation": {"severity": "warning"},
|
||||||
|
"prefer-for-of": {"severity": "warning"},
|
||||||
|
"unified-signatures": {"severity": "warning"},
|
||||||
|
"prefer-const": {"severity": "warning"},
|
||||||
|
"trailing-comma": {"severity": "warning"}
|
||||||
|
},
|
||||||
|
|
||||||
|
"defaultSeverity": "error"
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user