Merge branch 'dev' into releases/v3

This commit is contained in:
JamesIves 2020-03-31 08:38:33 -04:00
commit df5a466cbc
22 changed files with 812 additions and 771 deletions

View File

@ -35,7 +35,6 @@
"@typescript-eslint/no-misused-new": "error", "@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error", "@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "warn", "@typescript-eslint/no-non-null-assertion": "warn",
"@typescript-eslint/no-object-literal-type-assertion": "error",
"@typescript-eslint/no-unnecessary-qualifier": "error", "@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error", "@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-useless-constructor": "error", "@typescript-eslint/no-useless-constructor": "error",
@ -43,7 +42,6 @@
"@typescript-eslint/prefer-for-of": "warn", "@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-function-type": "warn", "@typescript-eslint/prefer-function-type": "warn",
"@typescript-eslint/prefer-includes": "error", "@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-interface": "error",
"@typescript-eslint/prefer-string-starts-ends-with": "error", "@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/promise-function-async": "error", "@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-array-sort-compare": "error", "@typescript-eslint/require-array-sort-compare": "error",

View File

@ -19,6 +19,7 @@ jobs:
- name: Install and Test - name: Install and Test
run: | run: |
npm install npm install
npm run-script lint
npm run-script test npm run-script test
- name: Uploade CodeCov Report - name: Uploade CodeCov Report

View File

@ -126,7 +126,7 @@ jobs:
BASE_BRANCH: dev BASE_BRANCH: dev
TARGET_FOLDER: montezuma4 TARGET_FOLDER: montezuma4
# Deploys using the CLEAN option. # Deploys using the CLEAN and SINGLE_COMMIT option.
integration-clean: integration-clean:
needs: [integration-checkout-v1, integration-checkout-v2, integration-container, integration-ssh, integration-env] needs: [integration-checkout-v1, integration-checkout-v2, integration-container, integration-ssh, integration-env]
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -144,8 +144,9 @@ jobs:
FOLDER: integration FOLDER: integration
BASE_BRANCH: dev BASE_BRANCH: dev
CLEAN: true CLEAN: true
SINGLE_COMMIT: true
# Deploys to a branch that doesn't exist. # Deploys to a branch that doesn't exist with SINGLE_COMMIT toggled.
integration-branch-creation: integration-branch-creation:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@ -162,6 +163,7 @@ jobs:
FOLDER: integration FOLDER: integration
BASE_BRANCH: dev BASE_BRANCH: dev
CLEAN: true CLEAN: true
SINGLE_COMMIT: true
- name: Cleanup Generated Branch - name: Cleanup Generated Branch
uses: dawidd6/action-delete-branch@v2.0.1 uses: dawidd6/action-delete-branch@v2.0.1

View File

@ -127,7 +127,7 @@ jobs:
BASE_BRANCH: dev BASE_BRANCH: dev
TARGET_FOLDER: montezuma4 TARGET_FOLDER: montezuma4
# Deploys using the CLEAN option. # Deploys using the CLEAN option with SINGLE_COMMIT toggled.
integration-clean: integration-clean:
needs: [integration-checkout-v1, integration-checkout-v2, integration-container, integration-ssh, integration-env] needs: [integration-checkout-v1, integration-checkout-v2, integration-container, integration-ssh, integration-env]
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -145,8 +145,9 @@ jobs:
FOLDER: integration FOLDER: integration
BASE_BRANCH: dev BASE_BRANCH: dev
CLEAN: true CLEAN: true
SINGLE_COMMIT: true
# Deploys to a branch that doesn't exist. # Deploys to a branch that doesn't exist with SINGLE_COMMIT.
integration-branch-creation: integration-branch-creation:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@ -163,6 +164,7 @@ jobs:
FOLDER: integration FOLDER: integration
BASE_BRANCH: dev BASE_BRANCH: dev
CLEAN: true CLEAN: true
SINGLE_COMMIT: true
- name: Cleanup Generated Branch - name: Cleanup Generated Branch
uses: dawidd6/action-delete-branch@v2.0.1 uses: dawidd6/action-delete-branch@v2.0.1

View File

@ -5,7 +5,7 @@ on:
types: [created] types: [created]
jobs: jobs:
publish-npm: publish-npm-js:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -26,3 +26,25 @@ jobs:
- run: npm publish - run: npm publish
env: env:
NODE_AUTH_TOKEN: ${{ secrets.npm_token }} NODE_AUTH_TOKEN: ${{ secrets.npm_token }}
publish-npm-github:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
ref: dev
- uses: actions/setup-node@v1
with:
node-version: 12
registry-url: 'https://npm.pkg.github.com'
- name: Configure git
run: |
git config user.email "iam@jamesiv.es"
git config user.name "James Ives"
- run: npm install
- run: npm run-script build
- run: npm version patch -m "Release %s"
- run: npm ci
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,10 +1,42 @@
# GitHub Pages Deploy Action :rocket: <p align="center">
<a href="https://github.com/marketplace/actions/deploy-to-github-pages">
<img width="150px" src="./assets/icon.png">
</a>
</p>
[![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) [![Codecov Coverage](https://codecov.io/gh/JamesIves/github-pages-deploy-action/branch/dev/graph/badge.svg)](https://codecov.io/gh/JamesIves/github-pages-deploy-action/branch/dev) <h1 align="center">
GitHub Pages Deploy Action :rocket:
</h1>
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`. <p align="center">
<a href="https://github.com/JamesIves/github-pages-deploy-action/actions">
<img src="https://github.com/JamesIves/github-pages-deploy-action/workflows/unit-tests/badge.svg">
</a>
![Example Screen shot](screenshot.png) <a href="https://github.com/JamesIves/github-pages-deploy-action/actions">
<img src="https://github.com/JamesIves/github-pages-deploy-action/workflows/integration-tests/badge.svg">
</a>
<a href="https://github.com/marketplace/actions/deploy-to-github-pages">
<img src="https://img.shields.io/badge/action-marketplace-blue.svg?logo=github&color=orange">
</a>
<a href="https://github.com/JamesIves/github-pages-deploy-action/releases">
<img src="https://img.shields.io/github/v/release/JamesIves/github-pages-deploy-action.svg?logo=github">
</a>
<a href="https://codecov.io/gh/JamesIves/github-pages-deploy-action/branch/dev">
<img src="https://codecov.io/gh/JamesIves/github-pages-deploy-action/branch/dev/graph/badge.svg">
</a>
</p>
<p align="center">
This <a href="https://github.com/features/actions">GitHub Action</a> will deploy your project to <a href="https://pages.github.com/">GitHub Pages</a>. It can be configured to upload your production-ready code into any branch you'd like, including <b>gh-pages</b> and <b>docs</b>.
</p>
<p align="center">
<img src="./assets/screenshot.png">
</p>
## Getting Started :airplane: ## Getting Started :airplane:
@ -24,7 +56,12 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Build and Deploy 🚀 - name: Install and Build 🔧 # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built.
run: |
npm install
npm run build
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@releases/v3 uses: JamesIves/github-pages-deploy-action@releases/v3
with: with:
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }} ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
@ -78,7 +115,7 @@ For more information regarding the [action interface please click here](https://
## Configuration 📁 ## 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). 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/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets).
#### Required Setup #### Required Setup
@ -101,16 +138,16 @@ In addition to the deployment options you must also configure the following.
| Key | Value Information | Type | Required | | Key | Value Information | Type | Required |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -------- | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -------- |
| `GIT_CONFIG_NAME` | Allows you to customize the name that is attached to the GitHub config which is used when pushing the deployment commits. If this is not included it will use the name in the GitHub context, followed by the name of the action. | `with` | **No** | | `GIT_CONFIG_NAME` | Allows you to customize the name that is attached to the git config which is used when pushing the deployment commits. If this is not included it will use the name in the GitHub context, followed by the name of the action. | `with` | **No** |
| `GIT_CONFIG_EMAIL` | Allows you to customize the email that is attached to the GitHub config which is used when pushing the deployment commits. If this is not included it will use the email in the GitHub context, followed by a generic noreply GitHub email. | `with` | **No** | | `GIT_CONFIG_EMAIL` | Allows you to customize the email that is attached to the git config which is used when pushing the deployment commits. If this is not included it will use the email in the GitHub context, followed by a generic noreply GitHub email. | `with` | **No** |
| `REPOSITORY_NAME` | Allows you to speicfy a different repository path so long as you have permissions to push to it. This should be formatted like so: `JamesIves/github-pages-deploy-action`. | `with` | **No** | | `REPOSITORY_NAME` | Allows you to speicfy a different repository path so long as you have permissions to push to it. This should be formatted like so: `JamesIves/github-pages-deploy-action`. | `with` | **No** |
| `TARGET_FOLDER` | If you'd like to push the contents of the deployment folder into a specific directory on the deployment branch you can specify it here. | `with` | **No** | | `TARGET_FOLDER` | If you'd like to push the contents of the deployment folder into a specific directory on the deployment branch you can specify it here. | `with` | **No** |
| `BASE_BRANCH` | The base branch of your repository which you'd like to checkout prior to deploying. This defaults to the current commit [SHA](http://en.wikipedia.org/wiki/SHA-1) that triggered the build followed by `master` if it doesn't exist. This is useful for making deployments from another branch, and also may be necessary when using a scheduled job. | `with` | **No** | | `BASE_BRANCH` | The base branch of your repository which you'd like to checkout prior to deploying. This defaults to the current commit [SHA](http://en.wikipedia.org/wiki/SHA-1) that triggered the build followed by `master` if it doesn't exist. This is useful for making deployments from another branch, and also may be necessary when using a scheduled job. | `with` | **No** |
| `COMMIT_MESSAGE` | If you need to customize the commit message for an integration you can do so. | `with` | **No** | | `COMMIT_MESSAGE` | If you need to customize the commit message for an integration you can do so. | `with` | **No** |
| `CLEAN` | If your project generates hashed files on build you can use this option to automatically delete them from the deployment branch with each deploy. This option can be toggled on by setting it to `true`. | `with` | **No** | | `CLEAN` | If your project generates hashed files on build you can use this option to automatically delete them from the deployment branch with each deploy. This option can be toggled on by setting it to `true`. | `with` | **No** |
| `CLEAN_EXCLUDE` | If you need to use `CLEAN` but you'd like to preserve certain files or folders you can use this option. This should be formatted as an array but stored as a string. For example: `'["filename.js", "folder"]'` | `with` | **No** | | `CLEAN_EXCLUDE` | If you need to use `CLEAN` but you'd like to preserve certain files or folders you can use this option. This should be formatted as an array but stored as a string. For example: `'["filename.js", "folder"]'` | `with` | **No** |
| `SINGLE_COMMIT` | This option can be toggled to `true` if you'd prefer to have a single commit on the deployment branch instead of maintaining the full history. Using this option will also cause any existing history to be wiped from the deployment branch. | `with` | **No** |
| `WORKSPACE` | This should point to where your project lives on the virtual machine. The GitHub Actions environment will set this for you. It is only neccersary to set this variable if you're using the node module. | `with` | **No** | | `WORKSPACE` | This should point to where your project lives on the virtual machine. The GitHub Actions environment will set this for you. It is only neccersary to set this variable if you're using the node module. | `with` | **No** |
| `DEBUG` | By default the git commands are hidden from the log. If you'd like to turn them on you can toggle this to `true`. **If you're using this action in your own project as a node module via yarn or npm you may expose your secrets if you toggle this on in a production environment**. | `with` | **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.
@ -126,15 +163,15 @@ ssh-keygen -t rsa -b 4096 -C "youremailhere@example.com" -N ""
Once you've generated the key pair you must add the contents of the public key within your repositories [deploy keys menu](https://developer.github.com/v3/guides/managing-deploy-keys/). You can find this option by going to `Settings > Deploy Keys`, you can name the public key whatever you want, but you **do** need to give it write access. Afterwards add the contents of the private key to the `Settings > Secrets` menu as `DEPLOY_KEY`. Once you've generated the key pair you must add the contents of the public key within your repositories [deploy keys menu](https://developer.github.com/v3/guides/managing-deploy-keys/). You can find this option by going to `Settings > Deploy Keys`, you can name the public key whatever you want, but you **do** need to give it write access. Afterwards add the contents of the private key to the `Settings > Secrets` menu as `DEPLOY_KEY`.
With this configured you must add the `ssh-agent` step to your workflow and set `SSH` to `true` within the deploy action. With this configured you must add the `ssh-agent` step to your workflow and set `SSH` to `true` within the deploy action. There are several SSH actions available on the [GitHub marketplace](https://github.com/marketplace?type=actions) for you to choose from.
```yml ```yml
- name: Install SSH Client - name: Install SSH Client 🔑
uses: webfactory/ssh-agent@v0.2.0 uses: webfactory/ssh-agent@v0.2.0
with: with:
ssh-private-key: ${{ secrets.DEPLOY_KEY }} ssh-private-key: ${{ secrets.DEPLOY_KEY }}
- name: Build and Deploy 🚀 - name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@releases/v3 uses: JamesIves/github-pages-deploy-action@releases/v3
with: with:
SSH: true SSH: true
@ -160,17 +197,17 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Install - name: Install and Build 🔧 # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built.
run: | run: |
npm install npm install
npm run-script build npm run build
- name: Install SSH Client 🔑 - name: Install SSH Client 🔑
uses: webfactory/ssh-agent@v0.2.0 # This step installs the ssh client into the workflow run. There's many options available for this on the action marketplace. uses: webfactory/ssh-agent@v0.2.0 # This step installs the ssh client into the workflow run. There's many options available for this on the action marketplace.
with: with:
ssh-private-key: ${{ secrets.DEPLOY_KEY }} ssh-private-key: ${{ secrets.DEPLOY_KEY }}
- name: Build and Deploy Repo 🚀 - name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@releases/v3-test uses: JamesIves/github-pages-deploy-action@releases/v3-test
with: with:
BASE_BRANCH: master BASE_BRANCH: master
@ -212,12 +249,12 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Install # The project is built using npm and placed in the 'build' folder. - name: Install and Build 🔧 # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built.
run: | run: |
npm install npm install
npm run-script build npm run build
- name: Upload Artifacts # The project is then uploaded as an artifact named 'site'. - name: Upload Artifacts 🔺 # The project is then uploaded as an artifact named 'site'.
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
with: with:
name: site name: site
@ -232,12 +269,12 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Download Artifacts # The built project is downloaded into the 'site' folder. - name: Download Artifacts 🔻 # The built project is downloaded into the 'site' folder.
uses: actions/download-artifact@v1 uses: actions/download-artifact@v1
with: with:
name: site name: site
- name: Build and Deploy 🚀 - name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@releases/v3 uses: JamesIves/github-pages-deploy-action@releases/v3
with: with:
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }} ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
@ -255,11 +292,11 @@ jobs:
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. 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 ```yml
- name: Install rsync - name: Install rsync 📚
run: | run: |
apt-get update && apt-get install -y rsync apt-get update && apt-get install -y rsync
- name: Deploy - name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@releases/v3 uses: JamesIves/github-pages-deploy-action@releases/v3
``` ```
@ -267,4 +304,10 @@ If you use a [container](https://help.github.com/en/actions/automating-your-work
### Additional Build Files 📁 ### 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. 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.
---
### Debugging 🐝
By default the git commands are hidden from the logs. If you'd like to turn them on you can set the `ACTIONS_STEP_DEBUG` environment variable to true within the [Settings/Secrets](https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets) menu. If you're using this action in your own project as a node module via yarn or npm **you may expose your secrets if you toggle this on in a production environment**. You can learn more about debugging GitHub actions [here](https://github.com/actions/toolkit/blob/master/docs/action-debugging.md).

View File

@ -1 +1 @@
process.env.UNIT_TEST = "true" process.env.UNIT_TEST = 'true'

View File

@ -7,7 +7,7 @@ jest.mock('@actions/exec', () => ({
describe('execute', () => { describe('execute', () => {
it('should be called with the correct arguments', async () => { it('should be called with the correct arguments', async () => {
await stdout('hello') stdout('hello')
await execute('echo Montezuma', './') await execute('echo Montezuma', './')
expect(exec).toBeCalledWith('echo Montezuma', [], { expect(exec).toBeCalledWith('echo Montezuma', [], {
@ -20,9 +20,9 @@ describe('execute', () => {
}) })
it('should not silence the input when INPUT_DEBUG is defined', async () => { it('should not silence the input when INPUT_DEBUG is defined', async () => {
process.env['DEBUG_DEPLOY_ACTION'] = 'yes' process.env['RUNNER_DEBUG'] = '1'
await stdout('hello') stdout('hello')
await execute('echo Montezuma', './') await execute('echo Montezuma', './')
expect(exec).toBeCalledWith('echo Montezuma', [], { expect(exec).toBeCalledWith('echo Montezuma', [], {

View File

@ -5,13 +5,14 @@ process.env['GITHUB_SHA'] = '123'
import {action} from '../src/constants' import {action} from '../src/constants'
import {deploy, generateBranch, init, switchToBaseBranch} from '../src/git' import {deploy, generateBranch, init, switchToBaseBranch} from '../src/git'
import {execute} from '../src/execute' import {execute} from '../src/execute'
import {setFailed} from '@actions/core'
const originalAction = JSON.stringify(action) const originalAction = JSON.stringify(action)
jest.mock('@actions/core', () => ({ jest.mock('@actions/core', () => ({
setFailed: jest.fn(), setFailed: jest.fn(),
getInput: jest.fn() getInput: jest.fn(),
isDebug: jest.fn(),
info: jest.fn()
})) }))
jest.mock('../src/execute', () => ({ jest.mock('../src/execute', () => ({
@ -318,6 +319,24 @@ describe('git', () => {
expect(execute).toBeCalledTimes(12) expect(execute).toBeCalledTimes(12)
}) })
it('should execute commands with single commit toggled', async () => {
Object.assign(action, {
folder: 'build',
branch: 'branch',
gitHubToken: '123',
singleCommit: true,
pusher: {
name: 'asd',
email: 'as@cat'
}
})
await deploy(action)
// Includes the call to generateBranch
expect(execute).toBeCalledTimes(18)
})
it('should execute commands with clean options, ommits sha commit message', async () => { it('should execute commands with clean options, ommits sha commit message', async () => {
process.env.GITHUB_SHA = '' process.env.GITHUB_SHA = ''
Object.assign(action, { Object.assign(action, {

View File

@ -18,7 +18,9 @@ jest.mock('../src/execute', () => ({
jest.mock('@actions/core', () => ({ jest.mock('@actions/core', () => ({
setFailed: jest.fn(), setFailed: jest.fn(),
getInput: jest.fn(), getInput: jest.fn(),
exportVariable: jest.fn() exportVariable: jest.fn(),
isDebug: jest.fn(),
info: jest.fn()
})) }))
describe('main', () => { describe('main', () => {

View File

@ -159,7 +159,7 @@ describe('util', () => {
gitHubToken: 'anothersecret123333' gitHubToken: 'anothersecret123333'
} }
process.env['INPUT_DEBUG'] = 'true' process.env['RUNNER_DEBUG'] = '1'
const string = `This is an error message! It contains ${action.accessToken} and ${action.gitHubToken} and ${action.repositoryPath}` const string = `This is an error message! It contains ${action.accessToken} and ${action.gitHubToken} and ${action.repositoryPath}`
expect(suppressSensitiveInformation(string, action)).toBe( expect(suppressSensitiveInformation(string, action)).toBe(

View File

@ -64,6 +64,6 @@ inputs:
description: "This should point to where your project lives on the virtual machine. The GitHub Actions environment will set this for you. It is only neccersary to set this variable if you're using the node module." description: "This should point to where your project lives on the virtual machine. The GitHub Actions environment will set this for you. It is only neccersary to set this variable if you're using the node module."
required: false required: false
DEBUG: SINGLE_COMMIT:
description: "By default the git commands are hidden from the log. If you'd like to turn them on you can toggle this to true." description: "This option can be used if you'd prefer to have a single commit on the deployment branch instead of maintaining the full history."
required: false required: false

BIN
assets/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -8,7 +8,7 @@ module.exports = {
'^.+\\.ts$': 'ts-jest' '^.+\\.ts$': 'ts-jest'
}, },
verbose: true, verbose: true,
setupFiles: ["<rootDir>/__tests__/env.js"], setupFiles: ['<rootDir>/__tests__/env.js'],
collectCoverage: true, collectCoverage: true,
collectCoverageFrom: ['src/*.ts','!src/constants.ts'] collectCoverageFrom: ['src/*.ts', '!src/constants.ts']
} }

View File

@ -2,7 +2,7 @@
"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.",
"author": "James Ives <iam@jamesiv.es>", "author": "James Ives <iam@jamesiv.es>",
"version": "3.4.0", "version": "3.4.2",
"license": "MIT", "license": "MIT",
"main": "lib/lib.js", "main": "lib/lib.js",
"types": "lib/lib.d.ts", "types": "lib/lib.d.ts",
@ -33,20 +33,20 @@
"deployment" "deployment"
], ],
"dependencies": { "dependencies": {
"@actions/core": "^1.2.0", "@actions/core": "1.2.3",
"@actions/exec": "^1.0.2", "@actions/exec": "1.0.3",
"@actions/github": "^2.0.0" "@actions/github": "2.1.1"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^25.1.0", "@types/jest": "25.1.4",
"@types/node": "^13.1.2", "@types/node": "13.9.5",
"jest": "^25.1.0", "jest": "25.2.4",
"jest-circus": "^25.1.0", "jest-circus": "25.2.4",
"prettier": "^1.19.1", "prettier": "2.0.2",
"ts-jest": "^25.0.0", "ts-jest": "25.3.0",
"eslint": "^5.16.0", "eslint": "6.8.0",
"eslint-plugin-github": "^2.0.0", "eslint-plugin-github": "3.4.1",
"eslint-plugin-jest": "^22.21.0", "eslint-plugin-jest": "23.8.2",
"typescript": "^3.7.4" "typescript": "3.8.3"
} }
} }

View File

@ -13,13 +13,11 @@ export interface ActionInterface {
/** The branch that the action should deploy to. */ /** The branch that the action should deploy to. */
branch: string branch: string
/** If your project generates hashed files on build you can use this option to automatically delete them from the deployment branch with each deploy. This option can be toggled on by setting it to true. */ /** If your project generates hashed files on build you can use this option to automatically delete them from the deployment branch with each deploy. This option can be toggled on by setting it to true. */
clean?: string | boolean clean?: boolean | null
/** If you need to use CLEAN but you'd like to preserve certain files or folders you can use this option. */ /** If you need to use CLEAN but you'd like to preserve certain files or folders you can use this option. */
cleanExclude?: string | string[] cleanExclude?: string | string[]
/** If you need to customize the commit message for an integration you can do so. */ /** If you need to customize the commit message for an integration you can do so. */
commitMessage?: string commitMessage?: string
/** Unhides the Git commands from the function terminal. */
debug?: boolean | string
/** The default branch of the deployment. Similar to baseBranch if you're using this action as a module. */ /** The default branch of the deployment. Similar to baseBranch if you're using this action as a module. */
defaultBranch?: string defaultBranch?: string
/** The git config email. */ /** The git config email. */
@ -29,17 +27,19 @@ export interface ActionInterface {
/** GitHub deployment token. */ /** GitHub deployment token. */
gitHubToken?: string | null gitHubToken?: string | null
/** Determines if the action is running in test mode or not. */ /** Determines if the action is running in test mode or not. */
isTest?: string | undefined | null isTest?: boolean | null
/** The git config name. */ /** The git config name. */
name?: string name?: string
/** The repository path, for example JamesIves/github-pages-deploy-action */ /** The repository path, for example JamesIves/github-pages-deploy-action. */
repositoryName?: string repositoryName?: string
/** The fully qualified repositpory path, this gets auto generated if repositoryName is provided. */ /** The fully qualified repositpory path, this gets auto generated if repositoryName is provided. */
repositoryPath?: string repositoryPath?: string
/** The root directory where your project lives. */ /** The root directory where your project lives. */
root?: string root?: string
/** Wipes the commit history from the deployment branch in favor of a single commit. */
singleCommit?: boolean | null
/** Set to true if you're using an ssh client in your build step. */ /** Set to true if you're using an ssh client in your build step. */
ssh?: string | boolean | null ssh?: boolean | null
/** If you'd like to push the contents of the deployment folder into a specific directory on the deployment branch you can specify it here. */ /** If you'd like to push the contents of the deployment folder into a specific directory on the deployment branch you can specify it here. */
targetFolder?: string targetFolder?: string
/** The token type, ie ssh/github token/access token, this gets automatically generated. */ /** The token type, ie ssh/github token/access token, this gets automatically generated. */
@ -55,18 +55,21 @@ export const action: ActionInterface = {
folder: getInput('FOLDER'), folder: getInput('FOLDER'),
branch: getInput('BRANCH'), branch: getInput('BRANCH'),
commitMessage: getInput('COMMIT_MESSAGE'), commitMessage: getInput('COMMIT_MESSAGE'),
clean: getInput('CLEAN'), clean: !isNullOrUndefined(getInput('CLEAN'))
? getInput('CLEAN').toLowerCase() === 'true'
: false,
cleanExclude: getInput('CLEAN_EXCLUDE'), cleanExclude: getInput('CLEAN_EXCLUDE'),
debug: getInput('DEBUG'),
defaultBranch: process.env.GITHUB_SHA ? process.env.GITHUB_SHA : 'master', defaultBranch: process.env.GITHUB_SHA ? process.env.GITHUB_SHA : 'master',
isTest: process.env.UNIT_TEST, isTest: process.env.UNIT_TEST
ssh: getInput('SSH'), ? process.env.UNIT_TEST.toLowerCase() === 'true'
: false,
email: !isNullOrUndefined(getInput('GIT_CONFIG_EMAIL')) email: !isNullOrUndefined(getInput('GIT_CONFIG_EMAIL'))
? getInput('GIT_CONFIG_EMAIL') ? getInput('GIT_CONFIG_EMAIL')
: pusher && pusher.email : pusher && pusher.email
? pusher.email ? pusher.email
: `${process.env.GITHUB_ACTOR || : `${
'github-pages-deploy-action'}@users.noreply.github.com`, process.env.GITHUB_ACTOR || 'github-pages-deploy-action'
}@users.noreply.github.com`,
gitHubToken: getInput('GITHUB_TOKEN'), gitHubToken: getInput('GITHUB_TOKEN'),
name: !isNullOrUndefined(getInput('GIT_CONFIG_NAME')) name: !isNullOrUndefined(getInput('GIT_CONFIG_NAME'))
? getInput('GIT_CONFIG_NAME') ? getInput('GIT_CONFIG_NAME')
@ -81,6 +84,12 @@ export const action: ActionInterface = {
? repository.full_name ? repository.full_name
: process.env.GITHUB_REPOSITORY, : process.env.GITHUB_REPOSITORY,
root: '.', root: '.',
singleCommit: !isNullOrUndefined(getInput('SINGLE_COMMIT'))
? getInput('SINGLE_COMMIT').toLowerCase() === 'true'
: false,
ssh: !isNullOrUndefined(getInput('SSH'))
? getInput('SSH').toLowerCase() === 'true'
: false,
targetFolder: getInput('TARGET_FOLDER'), targetFolder: getInput('TARGET_FOLDER'),
workspace: process.env.GITHUB_WORKSPACE || '' workspace: process.env.GITHUB_WORKSPACE || ''
} }

View File

@ -1,19 +1,20 @@
import {isDebug} from '@actions/core'
import {exec} from '@actions/exec' import {exec} from '@actions/exec'
let output: string let output: string
/** Wrapper around the GitHub toolkit exec command which returns the output. /** Wrapper around the GitHub toolkit exec command which returns the output.
* Also allows you to easily toggle the current working directory. * Also allows you to easily toggle the current working directory.
* @param cmd = The command to execute. *
* @param cwd - The current working directory. * @param {string} cmd - The command to execute.
* @returns - The output from the command. * @param {string} cwd - The current working directory.
*/ */
export async function execute(cmd: string, cwd: string): Promise<any> { export async function execute(cmd: string, cwd: string): Promise<any> {
output = '' output = ''
await exec(cmd, [], { await exec(cmd, [], {
// Silences the input unless the INPUT_DEBUG flag is set. // Silences the input unless the INPUT_DEBUG flag is set.
silent: process.env.DEBUG_DEPLOY_ACTION ? false : true, silent: isDebug() ? false : true,
cwd, cwd,
listeners: { listeners: {
stdout stdout

View File

@ -1,3 +1,4 @@
import {info} from '@actions/core'
import {ActionInterface} from './constants' import {ActionInterface} from './constants'
import {execute} from './execute' import {execute} from './execute'
import { import {
@ -11,8 +12,8 @@ export async function init(action: ActionInterface): Promise<void | Error> {
try { try {
hasRequiredParameters(action) hasRequiredParameters(action)
console.log(`Deploying using ${action.tokenType}... 🔑`) info(`Deploying using ${action.tokenType} 🔑`)
console.log('Configuring git...') info('Configuring git…')
await execute(`git init`, action.workspace) await execute(`git init`, action.workspace)
await execute(`git config user.name "${action.name}"`, action.workspace) await execute(`git config user.name "${action.name}"`, action.workspace)
@ -24,7 +25,7 @@ export async function init(action: ActionInterface): Promise<void | Error> {
) )
await execute(`git fetch`, action.workspace) await execute(`git fetch`, action.workspace)
console.log('Git configured... 🔧') info('Git configured… 🔧')
} catch (error) { } catch (error) {
throw new Error( throw new Error(
`There was an error initializing the repository: ${suppressSensitiveInformation( `There was an error initializing the repository: ${suppressSensitiveInformation(
@ -63,13 +64,13 @@ export async function generateBranch(action: ActionInterface): Promise<void> {
try { try {
hasRequiredParameters(action) hasRequiredParameters(action)
console.log(`Creating the ${action.branch} branch...`) info(`Creating the ${action.branch} branch`)
await switchToBaseBranch(action) await switchToBaseBranch(action)
await execute(`git checkout --orphan ${action.branch}`, action.workspace) await execute(`git checkout --orphan ${action.branch}`, action.workspace)
await execute(`git reset --hard`, action.workspace) await execute(`git reset --hard`, action.workspace)
await execute( await execute(
`git commit --allow-empty -m "Initial ${action.branch} commit."`, `git commit --allow-empty -m "Initial ${action.branch} commit"`,
action.workspace action.workspace
) )
await execute( await execute(
@ -78,7 +79,7 @@ export async function generateBranch(action: ActionInterface): Promise<void> {
) )
await execute(`git fetch`, action.workspace) await execute(`git fetch`, action.workspace)
console.log(`Created the ${action.branch} branch... 🔧`) info(`Created the ${action.branch} branch 🔧`)
} catch (error) { } catch (error) {
throw new Error( throw new Error(
`There was an error creating the deployment branch: ${suppressSensitiveInformation( `There was an error creating the deployment branch: ${suppressSensitiveInformation(
@ -93,11 +94,18 @@ export async function generateBranch(action: ActionInterface): Promise<void> {
export async function deploy(action: ActionInterface): Promise<void> { export async function deploy(action: ActionInterface): Promise<void> {
const temporaryDeploymentDirectory = 'gh-action-temp-deployment-folder' const temporaryDeploymentDirectory = 'gh-action-temp-deployment-folder'
const temporaryDeploymentBranch = 'gh-action-temp-deployment-branch' const temporaryDeploymentBranch = 'gh-action-temp-deployment-branch'
console.log('Starting to commit changes...')
info('Starting to commit changes…')
try { try {
hasRequiredParameters(action) hasRequiredParameters(action)
const commitMessage = `${
!isNullOrUndefined(action.commitMessage)
? action.commitMessage
: `Deploying to ${action.branch} from ${action.baseBranch}`
} ${process.env.GITHUB_SHA ? `@ ${process.env.GITHUB_SHA}` : ''} 🚀`
/* /*
Checks to see if the remote exists prior to deploying. Checks to see if the remote exists prior to deploying.
If the branch doesn't exist it gets created here as an orphan. If the branch doesn't exist it gets created here as an orphan.
@ -132,7 +140,7 @@ export async function deploy(action: ActionInterface): Promise<void> {
excludes += `--exclude ${item} ` excludes += `--exclude ${item} `
} }
} catch { } catch {
console.log( info(
'There was an error parsing your CLEAN_EXCLUDE items. Please refer to the README for more details. ❌' 'There was an error parsing your CLEAN_EXCLUDE items. Please refer to the README for more details. ❌'
) )
} }
@ -165,7 +173,7 @@ export async function deploy(action: ActionInterface): Promise<void> {
) )
if (!hasFilesToCommit && !action.isTest) { if (!hasFilesToCommit && !action.isTest) {
console.log('There is nothing to commit. Exiting early... 📭') info('There is nothing to commit. Exiting early… 📭')
return return
} }
@ -179,13 +187,7 @@ export async function deploy(action: ActionInterface): Promise<void> {
`${action.workspace}/${temporaryDeploymentDirectory}` `${action.workspace}/${temporaryDeploymentDirectory}`
) )
await execute( await execute(
`git commit -m "${ `git commit -m "${commitMessage}" --quiet`,
!isNullOrUndefined(action.commitMessage)
? action.commitMessage
: `Deploying to ${action.branch} from ${action.baseBranch}`
} ${
process.env.GITHUB_SHA ? `- ${process.env.GITHUB_SHA}` : ''
} 🚀" --quiet`,
`${action.workspace}/${temporaryDeploymentDirectory}` `${action.workspace}/${temporaryDeploymentDirectory}`
) )
await execute( await execute(
@ -193,10 +195,37 @@ export async function deploy(action: ActionInterface): Promise<void> {
`${action.workspace}/${temporaryDeploymentDirectory}` `${action.workspace}/${temporaryDeploymentDirectory}`
) )
console.log(`Changes committed to the ${action.branch} branch... 📦`) info(`Changes committed to the ${action.branch} branch 📦`)
// Cleans up temporary files/folders and restores the git state. // Cleans up temporary files/folders and restores the git state.
console.log('Running post deployment cleanup jobs...') info('Running post deployment cleanup jobs…')
if (action.singleCommit) {
await execute(`git fetch ${action.repositoryPath}`, action.workspace)
await execute(
`git checkout --orphan ${action.branch}-temp`,
`${action.workspace}/${temporaryDeploymentDirectory}`
)
await execute(
`git add --all .`,
`${action.workspace}/${temporaryDeploymentDirectory}`
)
await execute(
`git commit -m "${commitMessage}" --quiet`,
`${action.workspace}/${temporaryDeploymentDirectory}`
)
await execute(
`git branch -M ${action.branch}-temp ${action.branch}`,
`${action.workspace}/${temporaryDeploymentDirectory}`
)
await execute(
`git push origin ${action.branch} --force`,
`${action.workspace}/${temporaryDeploymentDirectory}`
)
info('Cleared git history… 🚿')
}
await execute( await execute(
`git checkout --progress --force ${action.defaultBranch}`, `git checkout --progress --force ${action.defaultBranch}`,
action.workspace action.workspace

View File

@ -1,16 +1,19 @@
import {exportVariable, setFailed} from '@actions/core' import {info, setFailed} from '@actions/core'
import {action, ActionInterface} from './constants' import {action, ActionInterface} from './constants'
import {deploy, generateBranch, init} from './git' import {deploy, generateBranch, init} from './git'
import {generateRepositoryPath, generateTokenType} from './util' import {generateRepositoryPath, generateTokenType} from './util'
/** Initializes and runs the action. */ /** Initializes and runs the action.
*
* @param {object} configuration - The action configuration.
*/
export default async function run( export default async function run(
configuration: ActionInterface configuration: ActionInterface
): Promise<void> { ): Promise<void> {
let errorState = false let errorState = false
try { try {
console.log('Checking configuration and starting deployment...🚦') info('Checking configuration and starting deployment… 🚦')
const settings = { const settings = {
...action, ...action,
@ -21,18 +24,13 @@ export default async function run(
settings.repositoryPath = generateRepositoryPath(settings) settings.repositoryPath = generateRepositoryPath(settings)
settings.tokenType = generateTokenType(settings) settings.tokenType = generateTokenType(settings)
if (settings.debug) {
// Sets the debug flag if passed as an arguement.
exportVariable('DEBUG_DEPLOY_ACTION', 'debug')
}
await init(settings) await init(settings)
await deploy(settings) await deploy(settings)
} catch (error) { } catch (error) {
errorState = true errorState = true
setFailed(error.message) setFailed(error.message)
} finally { } finally {
console.log( info(
`${ `${
errorState errorState
? 'Deployment Failed ❌' ? 'Deployment Failed ❌'

View File

@ -1,4 +1,4 @@
import {getInput} from '@actions/core' import {isDebug} from '@actions/core'
import {ActionInterface} from './constants' import {ActionInterface} from './constants'
/* Utility function that checks to see if a value is undefined or not. */ /* Utility function that checks to see if a value is undefined or not. */
@ -19,10 +19,9 @@ export const generateTokenType = (action: ActionInterface): string =>
export const generateRepositoryPath = (action: ActionInterface): string => export const generateRepositoryPath = (action: ActionInterface): string =>
action.ssh action.ssh
? `git@github.com:${action.repositoryName}` ? `git@github.com:${action.repositoryName}`
: `https://${action.accessToken || : `https://${
`x-access-token:${action.gitHubToken}`}@github.com/${ action.accessToken || `x-access-token:${action.gitHubToken}`
action.repositoryName }@github.com/${action.repositoryName}.git`
}.git`
/* Checks for the required tokens and formatting. Throws an error if any case is matched. */ /* Checks for the required tokens and formatting. Throws an error if any case is matched. */
export const hasRequiredParameters = (action: ActionInterface): void => { export const hasRequiredParameters = (action: ActionInterface): void => {
@ -59,7 +58,7 @@ export const suppressSensitiveInformation = (
): string => { ): string => {
let value = str let value = str
if (getInput('DEBUG')) { if (isDebug()) {
// Data is unmasked in debug mode. // Data is unmasked in debug mode.
return value return value
} }

1244
yarn.lock

File diff suppressed because it is too large Load Diff