mirror of
https://github.com/JamesIves/github-pages-deploy-action.git
synced 2023-12-15 20:03:39 +08:00
Merge branch 'dev' into releases/v3
This commit is contained in:
commit
147848b4e0
11
.github/workflows/build.yml
vendored
11
.github/workflows/build.yml
vendored
@ -1,7 +1,14 @@
|
||||
name: unit-tests
|
||||
on: [pull_request, push]
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
- releases/v3
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
jobs:
|
||||
unit-test:
|
||||
unit-tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
95
.github/workflows/integration.yml
vendored
95
.github/workflows/integration.yml
vendored
@ -2,17 +2,108 @@ name: integration-tests
|
||||
on:
|
||||
schedule:
|
||||
- cron: 10 15 * * 0-6
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- releases/v3
|
||||
- releases/v3-test
|
||||
|
||||
jobs:
|
||||
integration-test:
|
||||
# Deploys using checkout@v1 with an ACCESS_TOKEN.
|
||||
integration-checkout-v1:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3-test
|
||||
with:
|
||||
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
BRANCH: gh-pages
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
TARGET_FOLDER: montezuma
|
||||
|
||||
# Deploys using checkout@v2 with a GITHUB_TOKEN.
|
||||
integration-checkout-v2:
|
||||
needs: integration-checkout-v1
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3-test
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BRANCH: gh-pages
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
TARGET_FOLDER: montezuma2
|
||||
|
||||
|
||||
# Deploys using a container that requires you to install rsync.
|
||||
integration-container:
|
||||
needs: integration-checkout-v2
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ruby:2.6
|
||||
env:
|
||||
LANG: C.UTF-8
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install rsync
|
||||
run: |
|
||||
apt-get update && apt-get install -y rsync
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3-test
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BRANCH: gh-pages
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
TARGET_FOLDER: montezuma2
|
||||
|
||||
# Deploys using the CLEAN option.
|
||||
integration-clean:
|
||||
needs: [integration-checkout-v1, integration-checkout-v2, integration-container]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3-test
|
||||
with:
|
||||
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
BRANCH: gh-pages
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
CLEAN: true
|
||||
|
||||
# Deploys to a branch that doesn't exist.
|
||||
integration-branch-creation:
|
||||
needs: [integration-checkout-v1, integration-checkout-v2]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3-test
|
||||
with:
|
||||
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
BRANCH: integration-test-delete-test
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
CLEAN: true
|
||||
|
||||
- name: Cleanup Generated Branch
|
||||
uses: dawidd6/action-delete-branch@v2.0.1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branches: integration-test-delete-test
|
19
README.md
19
README.md
@ -1,9 +1,11 @@
|
||||
# GitHub Pages Deploy Action :rocket:
|
||||
|
||||
[![Build Status](https://github.com/JamesIves/github-pages-deploy-action/workflows/unit-tests/badge.svg)](https://github.com/JamesIves/github-pages-deploy-action/actions) [![Actions Status](https://github.com/JamesIves/github-pages-deploy-action/workflows/integration-tests/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)](https://github.com/JamesIves/github-pages-deploy-action/releases)
|
||||
[![Build Status](https://github.com/JamesIves/github-pages-deploy-action/workflows/unit-tests/badge.svg)](https://github.com/JamesIves/github-pages-deploy-action/actions) [![Actions Status](https://github.com/JamesIves/github-pages-deploy-action/workflows/integration-tests/badge.svg)](https://github.com/JamesIves/github-pages-deploy-action/actions) [![View Action](https://img.shields.io/badge/action-marketplace-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)](https://github.com/JamesIves/github-pages-deploy-action/releases)
|
||||
|
||||
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`.
|
||||
|
||||
![Example Screenshot](screenshot.png)
|
||||
|
||||
## 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@v1` step before this workflow runs in order for the deployment to work.
|
||||
|
||||
@ -94,6 +96,19 @@ jobs:
|
||||
</p>
|
||||
</details>
|
||||
|
||||
#### Using a Container 📦
|
||||
|
||||
If you use a [container](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#jobsjob_idcontainer) in your workflow you may need to run an additional step to install `rsync` as this action depends on it. You can view an example of this below.
|
||||
|
||||
```yml
|
||||
- name: Install rsync
|
||||
run: |
|
||||
apt-get update && apt-get install -y rsync
|
||||
|
||||
- name: Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3
|
||||
```
|
||||
|
||||
## Configuration 📁
|
||||
|
||||
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).
|
||||
@ -116,5 +131,3 @@ With the action correctly configured you should see the workflow trigger the dep
|
||||
### 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)
|
||||
|
23
__tests__/execute.test.ts
Normal file
23
__tests__/execute.test.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import {execute} from '../src/execute';
|
||||
import {exec} from '@actions/exec';
|
||||
|
||||
jest.mock('@actions/exec', () => ({
|
||||
exec: jest.fn()
|
||||
}))
|
||||
|
||||
describe('execute', () => {
|
||||
describe('execute', () => {
|
||||
it('should be called with the correct arguments', async() => {
|
||||
await execute('echo Montezuma', './')
|
||||
|
||||
expect(exec).toBeCalledWith(
|
||||
"echo Montezuma", [], {
|
||||
cwd: "./",
|
||||
listeners: {
|
||||
stdout: expect.any(Function)
|
||||
}
|
||||
}
|
||||
)
|
||||
});
|
||||
})
|
||||
})
|
@ -5,11 +5,11 @@ process.env["GITHUB_SHA"] = "123";
|
||||
import _ from "lodash";
|
||||
import { action } from "../src/constants";
|
||||
import { deploy, generateBranch, init, switchToBaseBranch } from "../src/git";
|
||||
import { execute } from "../src/util";
|
||||
import { execute } from "../src/execute";
|
||||
|
||||
const originalAction = _.cloneDeep(action);
|
||||
|
||||
jest.mock("../src/util", () => ({
|
||||
jest.mock("../src/execute", () => ({
|
||||
execute: jest.fn()
|
||||
}));
|
||||
|
||||
@ -30,7 +30,7 @@ describe("git", () => {
|
||||
});
|
||||
|
||||
const call = await init();
|
||||
expect(execute).toBeCalledTimes(3);
|
||||
expect(execute).toBeCalledTimes(4);
|
||||
expect(call).toBe("Initialization step complete...");
|
||||
});
|
||||
|
||||
@ -46,7 +46,7 @@ describe("git", () => {
|
||||
|
||||
const call = await init();
|
||||
|
||||
expect(execute).toBeCalledTimes(3);
|
||||
expect(execute).toBeCalledTimes(4);
|
||||
expect(call).toBe("Initialization step complete...");
|
||||
});
|
||||
|
||||
@ -109,7 +109,7 @@ describe("git", () => {
|
||||
|
||||
const call = await init();
|
||||
|
||||
expect(execute).toBeCalledTimes(3);
|
||||
expect(execute).toBeCalledTimes(4);
|
||||
expect(call).toBe("Initialization step complete...");
|
||||
});
|
||||
});
|
||||
|
@ -1,23 +1,21 @@
|
||||
import {execute} from '../src/util';
|
||||
import {exec} from '@actions/exec';
|
||||
import {isNullOrUndefined} from '../src/util';
|
||||
|
||||
jest.mock('@actions/exec', () => ({
|
||||
exec: jest.fn()
|
||||
}))
|
||||
|
||||
describe('util', () => {
|
||||
describe('execute', () => {
|
||||
it('should be called with the correct arguements', async() => {
|
||||
await execute('echo Montezuma', './')
|
||||
describe('isNullOrUndefined', () => {
|
||||
it('should return true if the value is null', async() => {
|
||||
const value = null;
|
||||
expect(isNullOrUndefined(value)).toBeTruthy()
|
||||
});
|
||||
|
||||
expect(exec).toBeCalledWith(
|
||||
"echo Montezuma", [], {
|
||||
cwd: "./",
|
||||
listeners: {
|
||||
stdout: expect.any(Function)
|
||||
}
|
||||
}
|
||||
)
|
||||
it('should return true if the value is undefined', async() => {
|
||||
const value = undefined;
|
||||
expect(isNullOrUndefined(value)).toBeTruthy()
|
||||
});
|
||||
|
||||
it('should return false if the value is defined', async() => {
|
||||
const value = 'montezuma';
|
||||
expect(isNullOrUndefined(value)).toBeFalsy()
|
||||
});
|
||||
})
|
||||
})
|
33
lib/execute.js
Normal file
33
lib/execute.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;
|
47
lib/git.js
47
lib/git.js
@ -17,6 +17,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const core = __importStar(require("@actions/core"));
|
||||
const execute_1 = require("./execute");
|
||||
const util_1 = require("./util");
|
||||
const constants_1 = require("./constants");
|
||||
/** Generates the branch if it doesn't exist on the remote.
|
||||
@ -25,15 +26,17 @@ const constants_1 = require("./constants");
|
||||
function init() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
if (!constants_1.action.accessToken && !constants_1.action.gitHubToken) {
|
||||
if (util_1.isNullOrUndefined(constants_1.action.accessToken) &&
|
||||
util_1.isNullOrUndefined(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.name}`, constants_1.workspace);
|
||||
yield util_1.execute(`git config user.email ${constants_1.action.email}`, constants_1.workspace);
|
||||
yield execute_1.execute(`git init`, constants_1.workspace);
|
||||
yield execute_1.execute(`git config user.name ${constants_1.action.name}`, constants_1.workspace);
|
||||
yield execute_1.execute(`git config user.email ${constants_1.action.email}`, constants_1.workspace);
|
||||
yield execute_1.execute(`git fetch`, constants_1.workspace);
|
||||
}
|
||||
catch (error) {
|
||||
core.setFailed(`There was an error initializing the repository: ${error}`);
|
||||
@ -49,9 +52,7 @@ exports.init = init;
|
||||
*/
|
||||
function switchToBaseBranch() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield util_1.execute(constants_1.action.baseBranch
|
||||
? `git switch ${constants_1.action.baseBranch}`
|
||||
: `git checkout --progress --force ${constants_1.action.defaultBranch}`, constants_1.workspace);
|
||||
yield execute_1.execute(`git checkout --progress --force ${constants_1.action.baseBranch ? constants_1.action.baseBranch : constants_1.action.defaultBranch}`, constants_1.workspace);
|
||||
return Promise.resolve("Switched to the base branch...");
|
||||
});
|
||||
}
|
||||
@ -64,11 +65,11 @@ function generateBranch() {
|
||||
try {
|
||||
console.log(`Creating ${constants_1.action.branch} branch... 🔧`);
|
||||
yield switchToBaseBranch();
|
||||
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);
|
||||
yield util_1.execute(`git fetch`, constants_1.workspace);
|
||||
yield execute_1.execute(`git checkout --orphan ${constants_1.action.branch}`, constants_1.workspace);
|
||||
yield execute_1.execute(`git reset --hard`, constants_1.workspace);
|
||||
yield execute_1.execute(`git commit --allow-empty -m "Initial ${constants_1.action.branch} commit."`, constants_1.workspace);
|
||||
yield execute_1.execute(`git push ${constants_1.repositoryPath} ${constants_1.action.branch}`, constants_1.workspace);
|
||||
yield execute_1.execute(`git fetch`, constants_1.workspace);
|
||||
}
|
||||
catch (error) {
|
||||
core.setFailed(`There was an error creating the deployment branch: ${error} ❌`);
|
||||
@ -90,15 +91,15 @@ function deploy() {
|
||||
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);
|
||||
const branchExists = yield execute_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 switchToBaseBranch();
|
||||
yield util_1.execute(`git fetch ${constants_1.repositoryPath}`, constants_1.workspace);
|
||||
yield util_1.execute(`git worktree add --checkout ${temporaryDeploymentDirectory} origin/${constants_1.action.branch}`, constants_1.workspace);
|
||||
yield execute_1.execute(`git fetch ${constants_1.repositoryPath}`, constants_1.workspace);
|
||||
yield execute_1.execute(`git worktree add --checkout ${temporaryDeploymentDirectory} origin/${constants_1.action.branch}`, constants_1.workspace);
|
||||
// Ensures that items that need to be excluded from the clean job get parsed.
|
||||
let excludes = "";
|
||||
if (constants_1.action.clean && constants_1.action.cleanExclude) {
|
||||
@ -114,25 +115,25 @@ function deploy() {
|
||||
Pushes all of the build files into the deployment directory.
|
||||
Allows the user to specify the root if '.' is provided.
|
||||
rysync is used to prevent file duplication. */
|
||||
yield util_1.execute(`rsync -q -av --progress ${constants_1.action.build}/. ${constants_1.action.targetFolder
|
||||
yield execute_1.execute(`rsync -q -av --progress ${constants_1.action.build}/. ${constants_1.action.targetFolder
|
||||
? `${temporaryDeploymentDirectory}/${constants_1.action.targetFolder}`
|
||||
: temporaryDeploymentDirectory} ${constants_1.action.clean
|
||||
? `--delete ${excludes} --exclude CNAME --exclude .nojekyll`
|
||||
: ""} --exclude .git --exclude .github ${constants_1.action.build === constants_1.root ? `--exclude ${temporaryDeploymentDirectory}` : ""}`, constants_1.workspace);
|
||||
const hasFilesToCommit = yield util_1.execute(`git status --porcelain`, temporaryDeploymentDirectory);
|
||||
const hasFilesToCommit = yield execute_1.execute(`git status --porcelain`, temporaryDeploymentDirectory);
|
||||
if (!hasFilesToCommit && !constants_1.isTest) {
|
||||
console.log("There is nothing to commit. Exiting... ✅");
|
||||
return Promise.resolve();
|
||||
}
|
||||
// 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);
|
||||
yield execute_1.execute(`git add --all .`, temporaryDeploymentDirectory);
|
||||
yield execute_1.execute(`git checkout -b ${temporaryDeploymentBranch}`, temporaryDeploymentDirectory);
|
||||
yield execute_1.execute(`git commit -m "Deploying to ${constants_1.action.branch} from ${constants_1.action.baseBranch} ${process.env.GITHUB_SHA}" --quiet`, temporaryDeploymentDirectory);
|
||||
yield execute_1.execute(`git push --force ${constants_1.repositoryPath} ${temporaryDeploymentBranch}:${constants_1.action.branch}`, temporaryDeploymentDirectory);
|
||||
// Cleans up temporary files/folders and restores the git state.
|
||||
console.log("Running post deployment cleanup jobs... 🔧");
|
||||
yield util_1.execute(`rm -rf ${temporaryDeploymentDirectory}`, constants_1.workspace);
|
||||
yield util_1.execute(`git checkout --progress --force ${constants_1.action.defaultBranch}`, constants_1.workspace);
|
||||
yield execute_1.execute(`rm -rf ${temporaryDeploymentDirectory}`, constants_1.workspace);
|
||||
yield execute_1.execute(`git checkout --progress --force ${constants_1.action.defaultBranch}`, constants_1.workspace);
|
||||
return Promise.resolve("Commit step complete...");
|
||||
});
|
||||
}
|
||||
|
43
lib/src/constants.js
Normal file
43
lib/src/constants.js
Normal file
@ -0,0 +1,43 @@
|
||||
"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 = ".";
|
||||
exports.isTest = process.env.UNIT_TEST;
|
||||
// Required action data.
|
||||
exports.action = {
|
||||
build: exports.folder,
|
||||
gitHubRepository: repository && repository.full_name
|
||||
? repository.full_name
|
||||
: process.env.GITHUB_REPOSITORY,
|
||||
gitHubToken: core.getInput("GITHUB_TOKEN"),
|
||||
accessToken: core.getInput("ACCESS_TOKEN"),
|
||||
branch: core.getInput("BRANCH"),
|
||||
targetFolder: core.getInput("TARGET_FOLDER"),
|
||||
baseBranch: core.getInput("BASE_BRANCH"),
|
||||
defaultBranch: process.env.GITHUB_SHA ? process.env.GITHUB_SHA : "master",
|
||||
name: pusher && pusher.name
|
||||
? pusher.name
|
||||
: process.env.GITHUB_ACTOR
|
||||
? process.env.GITHUB_ACTOR
|
||||
: "GitHub Pages Deploy Action",
|
||||
email: pusher && pusher.email
|
||||
? pusher.email
|
||||
: `${process.env.GITHUB_ACTOR ||
|
||||
"github-pages-deploy-action"}@users.noreply.github.com`,
|
||||
clean: core.getInput("CLEAN"),
|
||||
cleanExclude: core.getInput("CLEAN_EXCLUDE")
|
||||
};
|
||||
// Repository path used for commits/pushes.
|
||||
exports.repositoryPath = `https://${exports.action.accessToken ||
|
||||
`x-access-token:${exports.action.gitHubToken}`}@github.com/${exports.action.gitHubRepository}.git`;
|
33
lib/src/execute.js
Normal file
33
lib/src/execute.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;
|
143
lib/src/git.js
Normal file
143
lib/src/git.js
Normal file
@ -0,0 +1,143 @@
|
||||
"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 execute_1 = require("./execute");
|
||||
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 (util_1.isNullOrUndefined(constants_1.action.accessToken) &&
|
||||
util_1.isNullOrUndefined(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("./")) {
|
||||
console.log("2");
|
||||
return core.setFailed(`The deployment folder cannot be prefixed with '/' or './'. Instead reference the folder name directly.`);
|
||||
}
|
||||
yield execute_1.execute(`git init`, constants_1.workspace);
|
||||
yield execute_1.execute(`git config user.name ${constants_1.action.name}`, constants_1.workspace);
|
||||
yield execute_1.execute(`git config user.email ${constants_1.action.email}`, constants_1.workspace);
|
||||
yield execute_1.execute(`git fetch`, 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;
|
||||
/** Switches to the base branch.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
function switchToBaseBranch() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield execute_1.execute(constants_1.action.baseBranch
|
||||
? `git switch ${constants_1.action.baseBranch}`
|
||||
: `git checkout --progress --force ${constants_1.action.defaultBranch}`, constants_1.workspace);
|
||||
return Promise.resolve("Switched to the base branch...");
|
||||
});
|
||||
}
|
||||
exports.switchToBaseBranch = switchToBaseBranch;
|
||||
/** 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 switchToBaseBranch();
|
||||
yield execute_1.execute(`git switch --orphan ${constants_1.action.branch}`, constants_1.workspace);
|
||||
yield execute_1.execute(`git reset --hard`, constants_1.workspace);
|
||||
yield execute_1.execute(`git commit --allow-empty -m "Initial ${constants_1.action.branch} commit."`, constants_1.workspace);
|
||||
yield execute_1.execute(`git push ${constants_1.repositoryPath} ${constants_1.action.branch}`, constants_1.workspace);
|
||||
yield execute_1.execute(`git fetch`, 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 execute_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 switchToBaseBranch();
|
||||
yield execute_1.execute(`git fetch ${constants_1.repositoryPath}`, constants_1.workspace);
|
||||
yield execute_1.execute(`git worktree add --checkout ${temporaryDeploymentDirectory} origin/${constants_1.action.branch}`, constants_1.workspace);
|
||||
// Ensures that items that need to be excluded from the clean job get parsed.
|
||||
let excludes = "";
|
||||
if (constants_1.action.clean && constants_1.action.cleanExclude) {
|
||||
try {
|
||||
const excludedItems = JSON.parse(constants_1.action.cleanExclude);
|
||||
excludedItems.forEach((item) => (excludes += `--exclude ${item} `));
|
||||
}
|
||||
catch (_a) {
|
||||
console.log("There was an error parsing your CLEAN_EXCLUDE items. Please refer to the README for more details. ❌");
|
||||
}
|
||||
}
|
||||
/*
|
||||
Pushes all of the build files into the deployment directory.
|
||||
Allows the user to specify the root if '.' is provided.
|
||||
rysync is used to prevent file duplication. */
|
||||
yield execute_1.execute(`rsync -q -av --progress ${constants_1.action.build}/. ${constants_1.action.targetFolder
|
||||
? `${temporaryDeploymentDirectory}/${constants_1.action.targetFolder}`
|
||||
: temporaryDeploymentDirectory} ${constants_1.action.clean
|
||||
? `--delete ${excludes} --exclude CNAME --exclude .nojekyll`
|
||||
: ""} --exclude .git --exclude .github ${constants_1.action.build === constants_1.root ? `--exclude ${temporaryDeploymentDirectory}` : ""}`, constants_1.workspace);
|
||||
const hasFilesToCommit = yield execute_1.execute(`git status --porcelain`, temporaryDeploymentDirectory);
|
||||
if (!hasFilesToCommit && !constants_1.isTest) {
|
||||
console.log("There is nothing to commit. Exiting... ✅");
|
||||
return Promise.resolve();
|
||||
}
|
||||
// Commits to GitHub.
|
||||
yield execute_1.execute(`git add --all .`, temporaryDeploymentDirectory);
|
||||
yield execute_1.execute(`git switch -c ${temporaryDeploymentBranch}`, temporaryDeploymentDirectory);
|
||||
yield execute_1.execute(`git commit -m "Deploying to ${constants_1.action.branch} from ${constants_1.action.baseBranch} ${process.env.GITHUB_SHA}" --quiet`, temporaryDeploymentDirectory);
|
||||
yield execute_1.execute(`git push --force ${constants_1.repositoryPath} ${temporaryDeploymentBranch}:${constants_1.action.branch}`, temporaryDeploymentDirectory);
|
||||
// Cleans up temporary files/folders and restores the git state.
|
||||
console.log("Running post deployment cleanup jobs... 🔧");
|
||||
yield execute_1.execute(`rm -rf ${temporaryDeploymentDirectory}`, constants_1.workspace);
|
||||
yield execute_1.execute(`git checkout --progress --force ${constants_1.action.defaultBranch}`, constants_1.workspace);
|
||||
return Promise.resolve("Commit step complete...");
|
||||
});
|
||||
}
|
||||
exports.deploy = deploy;
|
36
lib/src/main.js
Normal file
36
lib/src/main.js
Normal file
@ -0,0 +1,36 @@
|
||||
"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) {
|
||||
console.log("The deployment encountered an error. ❌");
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
finally {
|
||||
console.log("Completed Deployment ✅");
|
||||
}
|
||||
});
|
||||
})();
|
10
lib/src/util.js
Normal file
10
lib/src/util.js
Normal file
@ -0,0 +1,10 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/** Utility function that checks to see if a value is undefined or not.
|
||||
* @param {*} value = The value to check.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isNullOrUndefined(value) {
|
||||
return typeof value === "undefined" || value === null || value === "";
|
||||
}
|
||||
exports.isNullOrUndefined = isNullOrUndefined;
|
35
lib/util.js
35
lib/util.js
@ -1,33 +1,10 @@
|
||||
"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.
|
||||
/** Utility function that checks to see if a value is undefined or not.
|
||||
* @param {*} value = The value to check.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
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);
|
||||
});
|
||||
function isNullOrUndefined(value) {
|
||||
return typeof value === "undefined" || value === null || value === "";
|
||||
}
|
||||
exports.execute = execute;
|
||||
exports.isNullOrUndefined = isNullOrUndefined;
|
||||
|
BIN
screenshot.png
BIN
screenshot.png
Binary file not shown.
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 45 KiB |
22
src/execute.ts
Normal file
22
src/execute.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);
|
||||
}
|
21
src/git.ts
21
src/git.ts
@ -1,5 +1,6 @@
|
||||
import * as core from "@actions/core";
|
||||
import { execute } from "./util";
|
||||
import { execute } from "./execute";
|
||||
import { isNullOrUndefined } from "./util";
|
||||
import { workspace, action, root, repositoryPath, isTest } from "./constants";
|
||||
|
||||
/** Generates the branch if it doesn't exist on the remote.
|
||||
@ -7,7 +8,10 @@ import { workspace, action, root, repositoryPath, isTest } from "./constants";
|
||||
*/
|
||||
export async function init(): Promise<any> {
|
||||
try {
|
||||
if (!action.accessToken && !action.gitHubToken) {
|
||||
if (
|
||||
isNullOrUndefined(action.accessToken) &&
|
||||
isNullOrUndefined(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."
|
||||
);
|
||||
@ -22,6 +26,7 @@ export async function init(): Promise<any> {
|
||||
await execute(`git init`, workspace);
|
||||
await execute(`git config user.name ${action.name}`, workspace);
|
||||
await execute(`git config user.email ${action.email}`, workspace);
|
||||
await execute(`git fetch`, workspace);
|
||||
} catch (error) {
|
||||
core.setFailed(`There was an error initializing the repository: ${error}`);
|
||||
} finally {
|
||||
@ -32,11 +37,11 @@ export async function init(): Promise<any> {
|
||||
/** Switches to the base branch.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export async function switchToBaseBranch() {
|
||||
export async function switchToBaseBranch(): Promise<any> {
|
||||
await execute(
|
||||
action.baseBranch
|
||||
? `git switch ${action.baseBranch}`
|
||||
: `git checkout --progress --force ${action.defaultBranch}`,
|
||||
`git checkout --progress --force ${
|
||||
action.baseBranch ? action.baseBranch : action.defaultBranch
|
||||
}`,
|
||||
workspace
|
||||
);
|
||||
|
||||
@ -50,7 +55,7 @@ export async function generateBranch(): Promise<any> {
|
||||
try {
|
||||
console.log(`Creating ${action.branch} branch... 🔧`);
|
||||
await switchToBaseBranch();
|
||||
await execute(`git switch --orphan ${action.branch}`, workspace);
|
||||
await execute(`git checkout --orphan ${action.branch}`, workspace);
|
||||
await execute(`git reset --hard`, workspace);
|
||||
await execute(
|
||||
`git commit --allow-empty -m "Initial ${action.branch} commit."`,
|
||||
@ -141,7 +146,7 @@ export async function deploy(): Promise<any> {
|
||||
// Commits to GitHub.
|
||||
await execute(`git add --all .`, temporaryDeploymentDirectory);
|
||||
await execute(
|
||||
`git switch -c ${temporaryDeploymentBranch}`,
|
||||
`git checkout -b ${temporaryDeploymentBranch}`,
|
||||
temporaryDeploymentDirectory
|
||||
);
|
||||
await execute(
|
||||
|
25
src/util.ts
25
src/util.ts
@ -1,22 +1,7 @@
|
||||
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.
|
||||
/** Utility function that checks to see if a value is undefined or not.
|
||||
* @param {*} value = The value to check.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
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);
|
||||
export function isNullOrUndefined(value: any): boolean {
|
||||
return typeof value === "undefined" || value === null || value === "";
|
||||
}
|
||||
|
16
yarn.lock
16
yarn.lock
@ -3,18 +3,18 @@
|
||||
|
||||
|
||||
"@actions/core@^1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.2.0.tgz#aa5f52b26c362c821d41557e599371a42f6c0b3d"
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.2.1.tgz#867e92da94d80f743e6e0503c668af832465080a"
|
||||
|
||||
"@actions/exec@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@actions/exec/-/exec-1.0.2.tgz#80ae9c2ea0bf5d0046a9f73d2a1b15bddfff0311"
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@actions/exec/-/exec-1.0.3.tgz#b967f8700d6ff011dcc91243b58bafc1bb9ab95f"
|
||||
dependencies:
|
||||
"@actions/io" "^1.0.1"
|
||||
|
||||
"@actions/github@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@actions/github/-/github-2.0.0.tgz#5b066b1a8747bbf48d47a058d9c241a2e37d5ee7"
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@actions/github/-/github-2.0.1.tgz#2870f56c28f042effc04e9ebf0df1f1af23715f7"
|
||||
dependencies:
|
||||
"@octokit/graphql" "^4.3.1"
|
||||
"@octokit/rest" "^16.15.0"
|
||||
@ -395,8 +395,8 @@
|
||||
jest-diff "^24.3.0"
|
||||
|
||||
"@types/node@>= 8", "@types/node@^13.1.2":
|
||||
version "13.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.4.tgz#4cfd90175a200ee9b02bd6b1cd19bc349741607e"
|
||||
version "13.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.6.tgz#076028d0b0400be8105b89a0a55550c86684ffec"
|
||||
|
||||
"@types/stack-utils@^1.0.1":
|
||||
version "1.0.1"
|
||||
|
Loading…
Reference in New Issue
Block a user