mirror of
https://github.com/JamesIves/github-pages-deploy-action.git
synced 2023-12-15 20:03:39 +08:00
[Release] Version 4 (#589)
* Stop checking out workspace (#515)
* Stop checking out base branch before deployment, drop option.
* Don't check out default branch, as we don't check out base branch, drop option.
* Don't stash/unstash as we don't update the workdir, drop preserve option.
* Don't init the workspace
* Only fetch the remote branch if it exists, only with depth 1.
* Rely on previous checkouts to have handled lfs files correctly, drop option.
* Update README, action.yml, integration tests
* Set up eslint for test files. (#517)
* Add DRY_RUN option, passing --dry-run to git push. (#526)
See #499 for the proposal.
* Simplifies Token Setup (#530)
* Token simplification
* Access Token / Github Token -> Token
* Oops
* Typos
* Update README.md
* Update README.md
* Update action.yml
Co-authored-by: Axel Hecht <axel@pike.org>
* Update README.md
Co-authored-by: Axel Hecht <axel@pike.org>
* Update README.md
Co-authored-by: Axel Hecht <axel@pike.org>
* Adjust codeql action to latest recommendations (#540)
Also, add the dev and release branches, and drop master.
* Add workflow to update build and node_modules on release branches (#541)
* Stores username/email in secrets
* Removing stale bot integration
* Test current code base as an integration test for PRs and pushes (#505)
* Add a build step to create lib and node_modules artifact
* Run integration test with built dist and current SHA as base
For pull requests, the github.sha is the sha of the merge to the
target branch, not the head of the PR. Special case that.
* Use v2 checkout, and DRY_RUN for the integration test.
I also made the branches more generic, as there are now more of them.
* Fix #536, don't push at all on dryRun
Also add tests for dryRun and singleCommit and generateBranch
code flows.
* Try to fix dryRun on new remote branches, refactor fetch
* Try to fix dryRun, only fetch if origin branch exists
* Refactor worktree setup to include branch generation and setup for singleCommit
This is a continuation of the no-checkout work, and sadly suggested pretty
intensive changes.
* Set up git config to fix tests, also make debugging easier
* Add matrix for existing and non-existing branch
* Add matrix for singleCommit and not
* Drop GITHUB_TOKEN, add DRY_RUN to action.yml
* When deploying existing branch, add a modifcation and deploy again
* Force branch checkout to work in redeployment scenarios
* Make singleCommit easier to see in job descriptions
* Review comments
* Add a test-only property to action to test code paths with remote branch.
* Introduce TestFlag enum to signal different test scenarios to unit tests
* Fix util.test.ts
* Update worktree.ts
* Fix a few nits in tests and automation. Don't try to wordcount ls-rem… (#546)
* Fix a few nits in tests and automation. Don't try to wordcount ls-remote.
Nits in tests are around undoing changes made to the environment,
and to not modify the checkout.
* Describe suite with empty SHA
* Lowercase Inputs (#547)
* Lowercases inputs
* Adjusts workflow tests and deployment_status
* Use multi-line string for clean-exclude patterns. (#553)
As this change is subtle, I'm taking the opportunity to change
the underscore for the hyphen, which makes it less likely that
users of this action will just pass in an old json array.
* Hyphenate inputs and outputs, add step output, fix #558 (#559)
* Hyphenate inputs and outputs, add step output, fix #558
I've also tried to make the clean docs a bit clearer, and consistent
about clean being on my default. Still not totally happy with the intro
of the docs there, though.
* Add testing of step outputs to build integration tests
* Security Docs
* Integration tests
* Revert "Integration tests"
This reverts commit 639ff537d5
.
* Native SSH Key Support (#569)
* SSH Key Support 🔑
* Update ssh.ts
* Update src/ssh.ts
Co-authored-by: Axel Hecht <axel@pike.org>
* README fixes/etc
* Unit Tests & README
* ssh key
* Update README.md
* Update ssh.test.ts
* Update ssh.test.ts
* Update ssh.test.ts
* Update ssh.test.ts
* Update ssh.test.ts
* Update ssh.test.ts
* Update integration.yml
Co-authored-by: Axel Hecht <axel@pike.org>
* Deployment Issues (#583)
* Update git.ts
* Tests
* Update git.ts
* Formatting
* Update src/git.ts
Co-authored-by: Axel Hecht <axel@pike.org>
* TestFlag
* Logging
* Update git.ts
Co-authored-by: Axel Hecht <axel@pike.org>
* Codespace Support (#584)
* Add files via upload
* Update README.md
* Add files via upload
* Update README.md
* Update README.md
* Update README.md
* Update README.md
* Update README.md
* SSH Issues (#588)
* Unsets Persisted Credentials (#587)
* Persist
* Config Setup/Tests
* Assets
* Update git.ts
* Spacing
* Update integration.yml
* Update README.md
Co-authored-by: Axel Hecht <axel@pike.org>
This commit is contained in:
parent
023cc8dca5
commit
442182742b
2
.devcontainer/Dockerfile
Normal file
2
.devcontainer/Dockerfile
Normal file
@ -0,0 +1,2 @@
|
||||
ARG VARIANT=12
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:${VARIANT}
|
7
.devcontainer/base.Dockerfile
Normal file
7
.devcontainer/base.Dockerfile
Normal file
@ -0,0 +1,7 @@
|
||||
ARG VARIANT=12-buster
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:dev-${VARIANT}
|
||||
|
||||
# Install tslint, typescript. eslint is installed by javascript image
|
||||
ARG NODE_MODULES="tslint-to-eslint-config typescript"
|
||||
RUN su node -c "umask 0002 && npm install -g ${NODE_MODULES}" \
|
||||
&& npm cache clean --force > /dev/null 2>&1
|
18
.devcontainer/devcontainer.json
Normal file
18
.devcontainer/devcontainer.json
Normal file
@ -0,0 +1,18 @@
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/master/containers/typescript-node
|
||||
{
|
||||
"name": "Node.js & TypeScript",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
// Update 'VARIANT' to pick a Node version: 10, 12, 14
|
||||
"args": {
|
||||
"VARIANT": "14"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"terminal.integrated.shell.linux": "/bin/bash"
|
||||
},
|
||||
"extensions": [
|
||||
"dbaeumer.vscode-eslint"
|
||||
],
|
||||
"remoteUser": "node"
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 9,
|
||||
"sourceType": "module",
|
||||
"project": "./tsconfig.json"
|
||||
"project": "./tsconfig.lint.json"
|
||||
},
|
||||
"globals": {
|
||||
"fetch": true
|
||||
@ -55,8 +55,9 @@
|
||||
"@typescript-eslint/type-annotation-spacing": "error",
|
||||
"@typescript-eslint/unbound-method": "error",
|
||||
"no-console": "off",
|
||||
"no-shadow": ["error", { "builtinGlobals": false, "hoist": "all", "allow": ["Status"] }]
|
||||
},
|
||||
"no-shadow": "off", // replaced by ts-eslint rule below
|
||||
"@typescript-eslint/no-shadow": "error"
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true,
|
||||
|
14
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
14
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
@ -8,14 +8,20 @@ labels:
|
||||
|
||||
<!-- Please check the Q&A before posting an issue: https://github.com/JamesIves/github-pages-deploy-action/discussions?discussions_q=category%3AQ%26A -->
|
||||
|
||||
**Describe the bug**
|
||||
### Describe the bug
|
||||
<!-- Please provide a clear and concise description of what the bug is. -->
|
||||
|
||||
**Reproduce**
|
||||
---
|
||||
|
||||
### Reproduction Steps
|
||||
<!-- Steps to reproduce the behavior. -->
|
||||
|
||||
**Logs**
|
||||
---
|
||||
|
||||
### Logs
|
||||
<!-- Please provide your deployment logs and a link or sample to/of your workflow. If the error message isn't revealing the problem please set ACTIONS_STEP_DEBUG to true in your repository's secrets menu and run the workflow again. -->
|
||||
|
||||
**Additional Comments**
|
||||
---
|
||||
|
||||
### Additional Comments
|
||||
<!--Add any other context about the problem here. -->
|
||||
|
16
.github/PULL_REQUEST_TEMPLATE.md
vendored
16
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,8 +1,12 @@
|
||||
**Description**
|
||||
> Provide a description of what your changes do.
|
||||
### Description
|
||||
<!-- Provide a description of what your changes do. -->
|
||||
|
||||
**Testing Instructions**
|
||||
> Give us step by step instructions on how to test your changes.
|
||||
---
|
||||
|
||||
**Additional Notes**
|
||||
> Anything else that will help us test the pull request.
|
||||
### Testing Instructions
|
||||
<!-- Give us step by step instructions on how to test your changes. -->
|
||||
|
||||
---
|
||||
|
||||
### Additional Notes
|
||||
<!-- Anything else that will help us test the pull request. -->
|
17
.github/stale.yml
vendored
17
.github/stale.yml
vendored
@ -1,17 +0,0 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 60
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- pinned
|
||||
- security
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: wontfix
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
106
.github/workflows/build.yml
vendored
106
.github/workflows/build.yml
vendored
@ -2,11 +2,11 @@ name: unit-tests
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
- releases/v3
|
||||
- 'dev*'
|
||||
- 'releases/v*'
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- 'dev*'
|
||||
tags-ignore:
|
||||
- '*.*'
|
||||
jobs:
|
||||
@ -14,11 +14,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/setup-node@v1.4.4
|
||||
with:
|
||||
node-version: '10.15.1'
|
||||
node-version: 'v12.18.4'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: Install Yarn
|
||||
@ -34,3 +34,99 @@ jobs:
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/setup-node@v1.4.4
|
||||
with:
|
||||
node-version: 'v12.18.4'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: Install Yarn
|
||||
run: npm install -g yarn
|
||||
|
||||
- name: Build lib
|
||||
run: |
|
||||
yarn install
|
||||
yarn build
|
||||
|
||||
- name: Rebuild production node_modules
|
||||
run: |
|
||||
yarn install --production
|
||||
ls node_modules
|
||||
|
||||
- name: artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: dist
|
||||
path: |
|
||||
lib
|
||||
node_modules
|
||||
|
||||
integration:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
strategy:
|
||||
matrix:
|
||||
branch: ["gh-pages", "no-pages"]
|
||||
commit: ["singleCommit", "add commits"]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: actions/setup-node@v1.4.4
|
||||
with:
|
||||
node-version: 'v12.18.4'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: dist
|
||||
|
||||
- name: Deploy
|
||||
id: unmodified
|
||||
uses: ./
|
||||
with:
|
||||
folder: integration
|
||||
branch: ${{ matrix.branch }}
|
||||
single-commit: ${{ matrix.commit == 'singleCommit' }}
|
||||
dry-run: true
|
||||
|
||||
# Usually, this should be skipped, but if the upstream gh-pages
|
||||
# branch doesn't match ours, it should still be a success.
|
||||
- name: Check step output
|
||||
run: |
|
||||
[[ \
|
||||
${{steps.unmodified.outputs.deployment-status}} = skipped || \
|
||||
${{steps.unmodified.outputs.deployment-status}} = success \
|
||||
]]
|
||||
|
||||
- name: Tweak content to publish to existing branch
|
||||
if: ${{ matrix.branch == 'gh-pages' }}
|
||||
run: |
|
||||
echo "<!-- just sayin -->" >> integration/index.html
|
||||
|
||||
- name: Deploy with modifications to existing branch
|
||||
id: modified
|
||||
uses: ./
|
||||
if: ${{ matrix.branch == 'gh-pages' }}
|
||||
with:
|
||||
folder: integration
|
||||
branch: ${{ matrix.branch }}
|
||||
single-commit: ${{ matrix.commit == 'singleCommit' }}
|
||||
dry-run: true
|
||||
|
||||
# The modified deployment should be a success, and not skipped.
|
||||
- name: Check step output
|
||||
if: ${{ matrix.branch == 'gh-pages' }}
|
||||
run: |
|
||||
[[ \
|
||||
${{steps.modified.outputs.deployment-status}} = success \
|
||||
]]
|
||||
|
19
.github/workflows/codeql-analysis.yml
vendored
19
.github/workflows/codeql-analysis.yml
vendored
@ -1,11 +1,15 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [dev, master, releases/v2, releases/v3]
|
||||
branches:
|
||||
- dev
|
||||
- 'dev-v*'
|
||||
- 'releases/v*'
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [dev]
|
||||
branches:
|
||||
- dev
|
||||
- 'dev-v*'
|
||||
schedule:
|
||||
- cron: '0 9 * * 4'
|
||||
|
||||
@ -17,15 +21,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
203
.github/workflows/integration-beta.yml
vendored
203
.github/workflows/integration-beta.yml
vendored
@ -1,203 +0,0 @@
|
||||
name: integration-tests-beta
|
||||
on:
|
||||
schedule:
|
||||
- cron: 30 15 * * 0-6
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- releases/v3-test
|
||||
|
||||
jobs:
|
||||
# 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-test
|
||||
with:
|
||||
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
BRANCH: gh-pages-test
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
TARGET_FOLDER: cat/montezuma
|
||||
GIT_CONFIG_NAME: Montezuma
|
||||
GIT_CONFIG_EMAIL: montezuma@jamesiv.es
|
||||
|
||||
- name: Cleanup Generated Branch
|
||||
uses: dawidd6/action-delete-branch@v2.0.1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branches: gh-pages-test
|
||||
|
||||
|
||||
# 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
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3-test
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BRANCH: gh-pages-test
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
TARGET_FOLDER: cat/montezuma2
|
||||
|
||||
- name: Cleanup Generated Branch
|
||||
uses: dawidd6/action-delete-branch@v2.0.1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branches: gh-pages-test
|
||||
|
||||
|
||||
# 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
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- 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-test
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
TARGET_FOLDER: cat/montezuma2
|
||||
|
||||
- name: Cleanup Generated Branch
|
||||
uses: dawidd6/action-delete-branch@v2.0.1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branches: gh-pages-test
|
||||
|
||||
|
||||
# Deploys using an SSH key.
|
||||
integration-ssh:
|
||||
needs: integration-container
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install SSH Client
|
||||
uses: webfactory/ssh-agent@v0.4.1
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3-test
|
||||
with:
|
||||
SSH: true
|
||||
BRANCH: gh-pages-test
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
TARGET_FOLDER: cat/montezuma3
|
||||
|
||||
- name: Cleanup Generated Branch
|
||||
uses: dawidd6/action-delete-branch@v2.0.1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branches: gh-pages-test
|
||||
|
||||
|
||||
# Deploys using a custom env.
|
||||
integration-env:
|
||||
needs: integration-ssh
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-node@v1.4.4
|
||||
with:
|
||||
node-version: '10.x'
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install SSH Client
|
||||
uses: webfactory/ssh-agent@v0.4.1
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3-test
|
||||
with:
|
||||
SSH: true
|
||||
BRANCH: gh-pages-test
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
TARGET_FOLDER: cat/montezuma4
|
||||
|
||||
- name: Cleanup Generated Branch
|
||||
uses: dawidd6/action-delete-branch@v2.0.1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branches: gh-pages-test
|
||||
|
||||
|
||||
# Deploys using the CLEAN option toggled.
|
||||
integration-clean:
|
||||
needs: [integration-checkout-v1, integration-checkout-v2, integration-container, integration-ssh, integration-env]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3-test
|
||||
with:
|
||||
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
BRANCH: gh-pages-test
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
CLEAN: true
|
||||
|
||||
# Deploys to a branch that doesn't exist with SINGLE_COMMIT.
|
||||
integration-branch-creation:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3-test
|
||||
with:
|
||||
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
BRANCH: integration-test-delete-beta
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
SINGLE_COMMIT: true
|
||||
|
||||
- name: Cleanup Generated Branch
|
||||
uses: dawidd6/action-delete-branch@v2.0.1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branches: integration-test-delete-beta
|
127
.github/workflows/integration.yml
vendored
127
.github/workflows/integration.yml
vendored
@ -7,7 +7,7 @@ on:
|
||||
- '*.*'
|
||||
branches:
|
||||
- dev
|
||||
- releases/v3
|
||||
- releases/v4
|
||||
|
||||
jobs:
|
||||
# Deploys using checkout@v1 with an ACCESS_TOKEN.
|
||||
@ -18,15 +18,14 @@ jobs:
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v4
|
||||
with:
|
||||
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
BRANCH: gh-pages
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
TARGET_FOLDER: cat/montezuma
|
||||
GIT_CONFIG_NAME: Montezuma
|
||||
GIT_CONFIG_EMAIL: montezuma@jamesiv.es
|
||||
token: ${{ secrets.ACCESS_TOKEN }}
|
||||
branch: gh-pages
|
||||
folder: integration
|
||||
target-folder: cat/montezuma
|
||||
git-config-name: Montezuma
|
||||
git-config-email: montezuma@jamesiv.es
|
||||
|
||||
- name: Cleanup Generated Branch
|
||||
uses: dawidd6/action-delete-branch@v2.0.1
|
||||
@ -45,13 +44,11 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v4
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BRANCH: gh-pages
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
TARGET_FOLDER: cat/montezuma2
|
||||
branch: gh-pages
|
||||
folder: integration
|
||||
target-folder: cat/montezuma2
|
||||
|
||||
- name: Cleanup Generated Branch
|
||||
uses: dawidd6/action-delete-branch@v2.0.1
|
||||
@ -79,13 +76,11 @@ jobs:
|
||||
apt-get update && apt-get install -y rsync
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v4
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BRANCH: gh-pages
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
TARGET_FOLDER: cat/montezuma2
|
||||
branch: gh-pages
|
||||
folder: integration
|
||||
target-folder: cat/montezuma2
|
||||
|
||||
- name: Cleanup Generated Branch
|
||||
uses: dawidd6/action-delete-branch@v2.0.1
|
||||
@ -95,6 +90,47 @@ jobs:
|
||||
|
||||
# Deploys using an SSH key.
|
||||
integration-ssh:
|
||||
needs: integration-container
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v4
|
||||
with:
|
||||
ssh-key: ${{ secrets.DEPLOY_KEY }}
|
||||
branch: gh-pages
|
||||
folder: integration
|
||||
target-folder: cat/montezuma3
|
||||
|
||||
- name: Cleanup Generated Branch
|
||||
uses: dawidd6/action-delete-branch@v2.0.1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branches: gh-pages
|
||||
|
||||
# Deploys cross repo with an access token.
|
||||
integration-cross-repo-push:
|
||||
needs: integration-container
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v4
|
||||
with:
|
||||
repository-name: MontezumaIves/lab
|
||||
token: ${{ secrets.CROSS_REPO_PUSH_TOKEN }}
|
||||
branch: gh-pages
|
||||
folder: integration
|
||||
single-commit: true
|
||||
|
||||
# Deploys using an SSH key.
|
||||
integration-ssh-third-party-client:
|
||||
needs: integration-container
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@ -109,13 +145,12 @@ jobs:
|
||||
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v4
|
||||
with:
|
||||
SSH: true
|
||||
BRANCH: gh-pages
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
TARGET_FOLDER: cat/montezuma3
|
||||
ssh: true
|
||||
branch: gh-pages
|
||||
folder: integration
|
||||
target-folder: cat/montezuma4
|
||||
|
||||
- name: Cleanup Generated Branch
|
||||
uses: dawidd6/action-delete-branch@v2.0.1
|
||||
@ -137,19 +172,13 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install SSH Client
|
||||
uses: webfactory/ssh-agent@v0.4.1
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v4
|
||||
with:
|
||||
SSH: true
|
||||
BRANCH: gh-pages
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
TARGET_FOLDER: cat/montezuma4
|
||||
ssh-key: ${{ secrets.DEPLOY_KEY }}
|
||||
branch: gh-pages
|
||||
folder: integration
|
||||
target-folder: cat/montezuma4
|
||||
|
||||
- name: Cleanup Generated Branch
|
||||
uses: dawidd6/action-delete-branch@v2.0.1
|
||||
@ -168,13 +197,12 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v4
|
||||
with:
|
||||
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
BRANCH: gh-pages
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
CLEAN: true
|
||||
token: ${{ secrets.ACCESS_TOKEN }}
|
||||
branch: gh-pages
|
||||
folder: integration
|
||||
clean: true
|
||||
|
||||
# Deploys to a branch that doesn't exist with SINGLE_COMMIT.
|
||||
integration-branch-creation:
|
||||
@ -187,13 +215,12 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Build and Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v4
|
||||
with:
|
||||
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
BRANCH: integration-test-delete-prod
|
||||
FOLDER: integration
|
||||
BASE_BRANCH: dev
|
||||
SINGLE_COMMIT: true
|
||||
token: ${{ secrets.ACCESS_TOKEN }}
|
||||
branch: integration-test-delete-prod
|
||||
folder: integration
|
||||
single-commit: true
|
||||
|
||||
- name: Cleanup Generated Branch
|
||||
uses: dawidd6/action-delete-branch@v2.0.1
|
||||
|
50
.github/workflows/production.yml
vendored
Normal file
50
.github/workflows/production.yml
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
name: Deploy Production Dependencies and Code
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- 'releases/v*'
|
||||
tags-ignore:
|
||||
- '*.*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build production
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/setup-node@v1.4.4
|
||||
with:
|
||||
node-version: 'v12.18.4'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: Install Yarn
|
||||
run: npm install -g yarn
|
||||
|
||||
- name: Clobber lib
|
||||
run: rm -rf lib
|
||||
|
||||
- name: Set up .gitignore
|
||||
run: |
|
||||
sed -i -e's/^lib/# lib/' -e's/^node_module/# node_modules/' .gitignore
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
yarn install
|
||||
yarn build
|
||||
|
||||
- name: Install Production node_modules
|
||||
run: |
|
||||
yarn install --production
|
||||
|
||||
- name: Commit and Push
|
||||
# Keep the run green if the commit fails for the lack of changes
|
||||
continue-on-error: True
|
||||
run: |
|
||||
git config user.email "${{ secrets.GIT_CONFIG_EMAIL }}"
|
||||
git config user.name "${{ secrets.GIT_CONFIG_NAME }}"
|
||||
git add .
|
||||
git commit -m "Deploy Production Code for Commit ${{ github.sha }} 🚀"
|
||||
git push
|
180
README.md
180
README.md
@ -1,6 +1,6 @@
|
||||
<p align="center">
|
||||
<a href="https://github.com/marketplace/actions/deploy-to-github-pages">
|
||||
<img width="150px" src="https://github.com/JamesIves/github-pages-deploy-action/raw/dev/assets/icon.png">
|
||||
<img alt="" width="300px" src="https://github.com/JamesIves/github-pages-deploy-action/raw/dev-v4/assets/icon.png">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@ -10,23 +10,23 @@
|
||||
|
||||
<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">
|
||||
<img src="https://github.com/JamesIves/github-pages-deploy-action/workflows/unit-tests/badge.svg" alt="Unit test status badge">
|
||||
</a>
|
||||
|
||||
<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">
|
||||
<img src="https://github.com/JamesIves/github-pages-deploy-action/workflows/integration-tests/badge.svg" alt="Integration test status badge">
|
||||
</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">
|
||||
<img src="https://codecov.io/gh/JamesIves/github-pages-deploy-action/branch/dev/graph/badge.svg" alt="Code coverage status badge">
|
||||
</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">
|
||||
<img src="https://img.shields.io/github/v/release/JamesIves/github-pages-deploy-action.svg?logo=github" alt="Release version badge">
|
||||
</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">
|
||||
<img src="https://img.shields.io/badge/action-marketplace-blue.svg?logo=github&color=orange" alt="Github marketplace badge">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://github.com/JamesIves/github-pages-deploy-action/raw/dev/assets/screenshot.png">
|
||||
<img src="https://github.com/JamesIves/github-pages-deploy-action/raw/dev-v4/assets/screenshot.png">
|
||||
</p>
|
||||
|
||||
## Getting Started :airplane:
|
||||
@ -52,9 +52,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout 🛎️
|
||||
uses: actions/checkout@v2.3.1 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly.
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v2.3.1
|
||||
|
||||
- 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: |
|
||||
@ -62,12 +60,10 @@ jobs:
|
||||
npm run build
|
||||
|
||||
- name: Deploy 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@3.7.1
|
||||
uses: JamesIves/github-pages-deploy-action@4.0.0
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BRANCH: gh-pages # The branch the action should deploy to.
|
||||
FOLDER: build # The folder the action should deploy.
|
||||
CLEAN: true # Automatically remove deleted files from the deploy branch
|
||||
branch: gh-pages # The branch the action should deploy to.
|
||||
folder: build # The folder the action should deploy.
|
||||
```
|
||||
|
||||
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.
|
||||
@ -105,7 +101,7 @@ Calling the functions directly will require you to pass in an object containing
|
||||
import run from "github-pages-deploy-action";
|
||||
|
||||
run({
|
||||
accessToken: process.env["ACCESS_TOKEN"],
|
||||
token: process.env["ACCESS_TOKEN"],
|
||||
branch: "gh-pages",
|
||||
folder: "build",
|
||||
repositoryName: "JamesIves/github-pages-deploy-action",
|
||||
@ -122,44 +118,41 @@ The `with` portion of the workflow **must** be configured before the action will
|
||||
|
||||
#### Required Setup
|
||||
|
||||
One of the following deployment options must be configured.
|
||||
|
||||
| Key | Value Information | Type | Required |
|
||||
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | -------- |
|
||||
| `GITHUB_TOKEN` | In order for GitHub to trigger the rebuild of your page you must provide the action with the repository's provided GitHub token. This can be referenced in the workflow `yml` file by using `${{ secrets.GITHUB_TOKEN }}`. If you experience any issues with your changes not being reflected after the deployment it may be neccersary to use either the `SSH` or `ACCESS_TOKEN` options. | `secrets / with` | **Yes** |
|
||||
| `SSH` | You can configure the action to deploy using SSH by setting this option to `true`. For more information on how to add your ssh key pair please refer to the [Using a Deploy Key section of this README](https://github.com/JamesIves/github-pages-deploy-action/tree/dev#using-an-ssh-deploy-key-). | `with` | **Yes** |
|
||||
| `ACCESS_TOKEN` | Depending on the repository's 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 / with` | **Yes** |
|
||||
|
||||
In addition to the deployment options you must also configure the following.
|
||||
The following options must be configured in order to make a deployment.
|
||||
|
||||
| Key | Value Information | Type | Required |
|
||||
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -------- |
|
||||
| `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. If you wish to deploy the root directory you can place a `.` here. You can also utilize absolute file paths by appending `~` to your folder path. | `with` | **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. If you wish to deploy the root directory you can place a `.` here. You can also utilize absolute file paths by appending `~` to your folder path. | `with` | **Yes** |
|
||||
|
||||
By default the action does not need any token configuration and uses the provided repository scoped GitHub token to make the deployment. If you require more customization you can modify the deployment type using the following options.
|
||||
|
||||
| Key | Value Information | Type | Required |
|
||||
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | -------- |
|
||||
| `token` | This option defaults to the repository scoped GitHub Token. However if you need more permissions for things such as deploying to another repository, you can add a Personal Access Token (PAT) here. This should be stored in the `secrets / with` menu **as a secret**. We reccomend using a service account with the least permissions neccersary and recommend when generating a new PAT that you select the least permission scopes neccersary. [Learn more about creating and using encrypted secrets here.](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets) | `with` | **No** |
|
||||
| `ssh-key` | You can configure the action to deploy using SSH by setting this option to a private SSH key stored **as a secret**. It can also be set to `true` to use an existing SSH client configuration. For more detailed information on how to add your public/private ssh key pair please refer to the [Using a Deploy Key section of this README](https://github.com/JamesIves/github-pages-deploy-action/tree/dev#using-an-ssh-deploy-key-). | `with` | **No** |
|
||||
|
||||
#### Optional Choices
|
||||
|
||||
| Key | Value Information | Type | Required |
|
||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -------- |
|
||||
| `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 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 specify 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`. You'll need to use an `ACCESS_TOKEN` for this configuration option to work properly. | `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** |
|
||||
| `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 is turned on by default, and can be toggled off by setting it to `false`. | `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** |
|
||||
| `LFS` | If toggled all files will be migrated from [Git LFS](https://git-lfs.github.com/) so they can be comitted to the deployment branch. | `with` | **No** |
|
||||
| `PRESERVE` | Preserves and restores the workspace prior to deployment. This option is useful if you're modifying files in the worktree that aren't comitted to Git. | `with` | **No** |
|
||||
| `SILENT` | Silences the action output preventing it from displaying git messages. | `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 necessary to set this variable if you're using the node module. | `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 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 specify 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`. You'll need to use a PAT in the `token` input for this configuration option to work properly. | `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** |
|
||||
| `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 target folder on the deployment branch with each deploy. This option is turned on by default, and can be toggled off by setting it to `false`. | `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 contain each pattern as a single line in a multiline string. | `with` | **No** |
|
||||
| `dry-run` | Do not actually push back, but use `--dry-run` on `git push` invocations insead. | `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** |
|
||||
| `silent` | Silences the action output preventing it from displaying git messages. | `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 necessary to set this variable if you're using the node module. | `with` | **No** |
|
||||
|
||||
With the action correctly configured you should see the workflow trigger the deployment under the configured conditions.
|
||||
|
||||
#### Deployment Status
|
||||
|
||||
The action will export an environment variable called `DEPLOYMENT_STATUS` that you can use in your workflow to determine if the deployment was successful or not. You can find an explanation of each status type below.
|
||||
The action will export an environment variable called `deployment_status` that you can use in your workflow to determine if the deployment was successful or not. You can find an explanation of each status type below.
|
||||
|
||||
| Status | Description |
|
||||
| ------------- |-------------|
|
||||
@ -167,6 +160,8 @@ The action will export an environment variable called `DEPLOYMENT_STATUS` that y
|
||||
| `failed` | The `failed` status indicates that the action encountered an error while trying to deploy. |
|
||||
| `skipped` | The `skipped` status indicates that the action exited early as there was nothing new to deploy. |
|
||||
|
||||
This value is also set as a step output as `deployment-status`.
|
||||
|
||||
---
|
||||
|
||||
### Using an SSH Deploy Key 🔑
|
||||
@ -179,20 +174,15 @@ ssh-keygen -t rsa -m pem -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 repository's [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. There are several SSH actions available on the [GitHub marketplace](https://github.com/marketplace?type=actions) for you to choose from.
|
||||
With this configured you can then set the `ssh-key` part of the action to your private key stored as a secret.
|
||||
|
||||
```yml
|
||||
- name: Install SSH Client 🔑
|
||||
uses: webfactory/ssh-agent@v0.4.1
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
|
||||
|
||||
- name: Deploy 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@3.7.1
|
||||
uses: JamesIves/github-pages-deploy-action@4.0.0
|
||||
with:
|
||||
SSH: true
|
||||
BRANCH: gh-pages
|
||||
FOLDER: site
|
||||
branch: gh-pages
|
||||
folder: site
|
||||
ssh-key: ${{ secrets.DEPLOY_KEY }}
|
||||
```
|
||||
|
||||
<details><summary>You can view a full example of this here.</summary>
|
||||
@ -209,33 +199,30 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout 🛎️
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v2.3.1
|
||||
|
||||
- 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: Install SSH Client 🔑
|
||||
uses: webfactory/ssh-agent@v0.4.1 # This step installs the ssh client into the workflow run. There's many options available for this on the action marketplace.
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
|
||||
|
||||
- name: Deploy 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@3.7.1
|
||||
uses: JamesIves/github-pages-deploy-action@4.0.0
|
||||
with:
|
||||
BASE_BRANCH: master
|
||||
BRANCH: gh-pages
|
||||
FOLDER: build
|
||||
CLEAN: true
|
||||
SSH: true # SSH must be set to true so the deploy action knows which protocol to deploy with.
|
||||
branch: gh-pages
|
||||
folder: build
|
||||
clean: true
|
||||
clean-exclude: |
|
||||
special-file.txt
|
||||
some/*.txt
|
||||
ssh-key: ${{ secrets.DEPLOY_KEY }}
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
Alternatively if you've already configured the SSH client within a previous step you can set the `ssh-key` option to `true` to allow it to deploy using an existing SSH client. Instead of adjusting the client configuration it will simply switch to using GitHub's SSH endpoints.
|
||||
|
||||
---
|
||||
|
||||
### Operating System Support 💿
|
||||
@ -261,9 +248,7 @@ jobs:
|
||||
runs-on: windows-latest # The first job utilizes windows-latest
|
||||
steps:
|
||||
- name: Checkout 🛎️
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v2.3.1
|
||||
|
||||
- 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: |
|
||||
@ -281,9 +266,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout 🛎️
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v2.3.1
|
||||
|
||||
- name: Download Artifacts 🔻 # The built project is downloaded into the 'site' folder.
|
||||
uses: actions/download-artifact@v1
|
||||
@ -291,11 +274,11 @@ jobs:
|
||||
name: site
|
||||
|
||||
- name: Deploy 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@3.7.1
|
||||
uses: JamesIves/github-pages-deploy-action@4.0.0
|
||||
with:
|
||||
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
BRANCH: gh-pages
|
||||
FOLDER: "site" # The deployment folder should match the name of the artifact. Even though our project builds into the 'build' folder the artifact name of 'site' must be placed here.
|
||||
token: ${{ secrets.ACCESS_TOKEN }}
|
||||
branch: gh-pages
|
||||
folder: "site" # The deployment folder should match the name of the artifact. Even though our project builds into the 'build' folder the artifact name of 'site' must be placed here.
|
||||
```
|
||||
|
||||
</p>
|
||||
@ -313,27 +296,56 @@ If you use a [container](https://help.github.com/en/actions/automating-your-work
|
||||
apt-get update && apt-get install -y rsync
|
||||
|
||||
- name: Deploy 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@3.7.1
|
||||
uses: JamesIves/github-pages-deploy-action@4.0.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Additional Build Files 📁
|
||||
|
||||
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. Additionally you can include these files in your deployment folder to update them.
|
||||
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, additionally you can include these files in your deployment folder to update them. If you need to add additional files to the deployment that should be ignored by the build clean-up steps you can utilize the `clean-exclude` option.
|
||||
|
||||
|
||||
<details><summary>Click here to view an exmaple of this.</summary>
|
||||
<p>
|
||||
|
||||
```yml
|
||||
name: Build and Deploy
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout 🛎️
|
||||
uses: actions/checkout@v2.3.1
|
||||
|
||||
- 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@4.0.0
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: build
|
||||
clean: true
|
||||
clean-exclude: |
|
||||
special-file.txt
|
||||
some/*.txt
|
||||
```
|
||||
</p>
|
||||
</details>
|
||||
|
||||
If you wish to remove these files you must go into the deployment branch directly to remove them. This is to prevent accidental changes in your deployment script from creating breaking changes.
|
||||
|
||||
---
|
||||
|
||||
### Debugging 🐝
|
||||
|
||||
If you'd like to enable action debugging 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).
|
||||
|
||||
---
|
||||
|
||||
## Support 💖
|
||||
|
||||
This project would not be possible without all of our fantastic [contributors](https://github.com/JamesIves/github-pages-deploy-action/graphs/contributors).
|
||||
This project would not be possible without all of our fantastic [contributors](https://github.com/JamesIves/github-pages-deploy-action/graphs/contributors). The project logo was created by [Paganini](https://twitter.com/paganiniart).
|
||||
|
||||
If you'd like to support the maintenance and upkeep of this project you can [donate via GitHub Sponsors](https://github.com/sponsors/JamesIves). This project is distributed under the [MIT](https://github.com/JamesIves/github-pages-deploy-action/blob/dev/LICENSE) license.
|
||||
|
@ -2,12 +2,12 @@
|
||||
|
||||
## Supported Versions
|
||||
|
||||
The current versions are actively maintained and will receieve frequent updates and security patches.
|
||||
The current version is actively maintained and will receive frequent updates and security patches.
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 3.0.x | :white_check_mark: |
|
||||
| < 2.0 | :x: |
|
||||
| 4.0.x | :white_check_mark: |
|
||||
| < 3.0 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
@ -1,2 +1 @@
|
||||
process.env.UNIT_TEST = 'true'
|
||||
process.env.ACTIONS_STEP_DEBUG = 'false'
|
||||
process.env.ACTIONS_STEP_DEBUG = 'false'
|
||||
|
@ -1,18 +1,24 @@
|
||||
/* eslint-disable import/first */
|
||||
// Initial env variable setup for tests.
|
||||
process.env['INPUT_FOLDER'] = 'build'
|
||||
process.env['GITHUB_SHA'] = '123'
|
||||
|
||||
import {mkdirP, rmRF} from '@actions/io'
|
||||
import {action, Status} from '../src/constants'
|
||||
import {action, Status, TestFlag} from '../src/constants'
|
||||
import {execute} from '../src/execute'
|
||||
import {deploy, generateBranch, init, switchToBaseBranch} from '../src/git'
|
||||
import {deploy, init} from '../src/git'
|
||||
import fs from 'fs'
|
||||
|
||||
const originalAction = JSON.stringify(action)
|
||||
|
||||
jest.mock('fs', () => ({
|
||||
existsSync: jest.fn()
|
||||
}))
|
||||
|
||||
jest.mock('@actions/core', () => ({
|
||||
setFailed: jest.fn(),
|
||||
getInput: jest.fn(),
|
||||
setOutput: jest.fn(),
|
||||
isDebug: jest.fn(),
|
||||
info: jest.fn()
|
||||
}))
|
||||
@ -23,6 +29,7 @@ jest.mock('@actions/io', () => ({
|
||||
}))
|
||||
|
||||
jest.mock('../src/execute', () => ({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
__esModule: true,
|
||||
execute: jest.fn()
|
||||
}))
|
||||
@ -33,23 +40,22 @@ describe('git', () => {
|
||||
})
|
||||
|
||||
describe('init', () => {
|
||||
it('should stash changes if preserve is true', async () => {
|
||||
it('should execute commands', async () => {
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
repositoryPath: 'JamesIves/github-pages-deploy-action',
|
||||
accessToken: '123',
|
||||
token: '123',
|
||||
branch: 'branch',
|
||||
folder: '.',
|
||||
preserve: true,
|
||||
isTest: true,
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
}
|
||||
},
|
||||
isTest: TestFlag.HAS_CHANGED_FILES
|
||||
})
|
||||
|
||||
await init(action)
|
||||
expect(execute).toBeCalledTimes(7)
|
||||
expect(execute).toBeCalledTimes(5)
|
||||
})
|
||||
|
||||
it('should catch when a function throws an error', async () => {
|
||||
@ -60,15 +66,14 @@ describe('git', () => {
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
repositoryPath: 'JamesIves/github-pages-deploy-action',
|
||||
accessToken: '123',
|
||||
token: '123',
|
||||
branch: 'branch',
|
||||
folder: '.',
|
||||
preserve: true,
|
||||
isTest: true,
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
}
|
||||
},
|
||||
isTest: TestFlag.HAS_CHANGED_FILES
|
||||
})
|
||||
|
||||
try {
|
||||
@ -79,109 +84,64 @@ describe('git', () => {
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('generateBranch', () => {
|
||||
it('should execute six commands', async () => {
|
||||
it('should correctly continue when it cannot unset a git config value', async () => {
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
accessToken: '123',
|
||||
repositoryPath: 'JamesIves/github-pages-deploy-action',
|
||||
token: '123',
|
||||
branch: 'branch',
|
||||
folder: '.',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
}
|
||||
},
|
||||
isTest: TestFlag.UNABLE_TO_UNSET_GIT_CONFIG
|
||||
})
|
||||
|
||||
await generateBranch(action)
|
||||
expect(execute).toBeCalledTimes(6)
|
||||
await init(action)
|
||||
expect(execute).toBeCalledTimes(5)
|
||||
})
|
||||
|
||||
it('should catch when a function throws an error', async () => {
|
||||
;(execute as jest.Mock).mockImplementationOnce(() => {
|
||||
throw new Error('Mocked throw')
|
||||
})
|
||||
it('should not unset git config if a user is using ssh', async () => {
|
||||
// Sets and unsets the CI condition.
|
||||
process.env.CI = 'true'
|
||||
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
accessToken: '123',
|
||||
repositoryPath: 'JamesIves/github-pages-deploy-action',
|
||||
sshKey: true,
|
||||
branch: 'branch',
|
||||
folder: '.',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
}
|
||||
},
|
||||
isTest: false
|
||||
})
|
||||
|
||||
try {
|
||||
await generateBranch(action)
|
||||
} catch (error) {
|
||||
expect(error.message).toBe(
|
||||
'There was an error creating the deployment branch: There was an error switching to the base branch: Mocked throw ❌ ❌'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
await init(action)
|
||||
expect(execute).toBeCalledTimes(4)
|
||||
|
||||
describe('switchToBaseBranch', () => {
|
||||
it('should execute one command', async () => {
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
accessToken: '123',
|
||||
branch: 'branch',
|
||||
folder: '.',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
}
|
||||
})
|
||||
|
||||
await switchToBaseBranch(action)
|
||||
expect(execute).toBeCalledTimes(1)
|
||||
process.env.CI = undefined
|
||||
})
|
||||
|
||||
it('should execute one command if using custom baseBranch', async () => {
|
||||
it('should correctly continue when it cannot remove origin', async () => {
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
baseBranch: '123',
|
||||
accessToken: '123',
|
||||
repositoryPath: 'JamesIves/github-pages-deploy-action',
|
||||
token: '123',
|
||||
branch: 'branch',
|
||||
folder: '.',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
}
|
||||
},
|
||||
isTest: TestFlag.UNABLE_TO_REMOVE_ORIGIN
|
||||
})
|
||||
|
||||
await switchToBaseBranch(action)
|
||||
expect(execute).toBeCalledTimes(1)
|
||||
})
|
||||
|
||||
it('should catch when a function throws an error', async () => {
|
||||
;(execute as jest.Mock).mockImplementationOnce(() => {
|
||||
throw new Error('Mocked throw')
|
||||
})
|
||||
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
baseBranch: '123',
|
||||
accessToken: '123',
|
||||
branch: 'branch',
|
||||
folder: '.',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
await switchToBaseBranch(action)
|
||||
} catch (error) {
|
||||
expect(error.message).toBe(
|
||||
'There was an error switching to the base branch: Mocked throw ❌'
|
||||
)
|
||||
}
|
||||
await init(action)
|
||||
expect(execute).toBeCalledTimes(5)
|
||||
})
|
||||
})
|
||||
|
||||
@ -191,73 +151,41 @@ describe('git', () => {
|
||||
silent: false,
|
||||
folder: 'assets',
|
||||
branch: 'branch',
|
||||
gitHubToken: '123',
|
||||
lfs: true,
|
||||
token: '123',
|
||||
repositoryName: 'JamesIves/montezuma',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
}
|
||||
},
|
||||
isTest: TestFlag.HAS_CHANGED_FILES
|
||||
})
|
||||
|
||||
const response = await deploy(action)
|
||||
|
||||
// Includes the call to generateBranch
|
||||
expect(execute).toBeCalledTimes(13)
|
||||
// Includes the call to generateWorktree
|
||||
expect(execute).toBeCalledTimes(11)
|
||||
expect(rmRF).toBeCalledTimes(1)
|
||||
expect(response).toBe(Status.SUCCESS)
|
||||
})
|
||||
|
||||
it('should execute stash apply commands if preserve is true', async () => {
|
||||
it('should not push when asked to dryRun', async () => {
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
dryRun: true,
|
||||
folder: 'assets',
|
||||
folderPath: 'assets',
|
||||
branch: 'branch',
|
||||
gitHubToken: '123',
|
||||
lfs: true,
|
||||
preserve: true,
|
||||
isTest: true,
|
||||
token: '123',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
}
|
||||
},
|
||||
isTest: TestFlag.HAS_CHANGED_FILES
|
||||
})
|
||||
|
||||
const response = await deploy(action)
|
||||
|
||||
// Includes the call to generateBranch
|
||||
expect(execute).toBeCalledTimes(14)
|
||||
expect(rmRF).toBeCalledTimes(1)
|
||||
expect(response).toBe(Status.SUCCESS)
|
||||
})
|
||||
|
||||
it('should appropriately move along if git stash errors', async () => {
|
||||
;(execute as jest.Mock).mockImplementation(cmd => {
|
||||
if (cmd === 'git stash apply') {
|
||||
// Mocks the case where git stash apply errors.
|
||||
throw new Error()
|
||||
}
|
||||
})
|
||||
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
folder: 'assets',
|
||||
folderPath: 'assets',
|
||||
branch: 'branch',
|
||||
gitHubToken: '123',
|
||||
lfs: true,
|
||||
preserve: true,
|
||||
isTest: true,
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
}
|
||||
})
|
||||
|
||||
const response = await deploy(action)
|
||||
|
||||
// Includes the call to generateBranch
|
||||
expect(execute).toBeCalledTimes(14)
|
||||
// Includes the call to generateWorktree
|
||||
expect(execute).toBeCalledTimes(10)
|
||||
expect(rmRF).toBeCalledTimes(1)
|
||||
expect(response).toBe(Status.SUCCESS)
|
||||
})
|
||||
@ -268,110 +196,171 @@ describe('git', () => {
|
||||
folder: 'other',
|
||||
folderPath: 'other',
|
||||
branch: 'branch',
|
||||
gitHubToken: '123',
|
||||
token: '123',
|
||||
singleCommit: true,
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
},
|
||||
clean: true
|
||||
clean: true,
|
||||
isTest: TestFlag.HAS_CHANGED_FILES
|
||||
})
|
||||
|
||||
await deploy(action)
|
||||
|
||||
// Includes the call to generateBranch
|
||||
expect(execute).toBeCalledTimes(18)
|
||||
// Includes the call to generateWorktree
|
||||
expect(execute).toBeCalledTimes(10)
|
||||
expect(rmRF).toBeCalledTimes(1)
|
||||
})
|
||||
|
||||
it('should not ignore CNAME or nojekyll if they exist in the deployment folder', async () => {
|
||||
it('should execute commands with single commit toggled and existing branch', async () => {
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
folder: 'assets',
|
||||
folderPath: 'assets',
|
||||
folder: 'other',
|
||||
folderPath: 'other',
|
||||
branch: 'branch',
|
||||
gitHubToken: '123',
|
||||
token: '123',
|
||||
singleCommit: true,
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
},
|
||||
clean: true
|
||||
clean: true,
|
||||
isTest: TestFlag.HAS_CHANGED_FILES | TestFlag.HAS_REMOTE_BRANCH
|
||||
})
|
||||
|
||||
fs.createWriteStream('assets/.nojekyll')
|
||||
fs.createWriteStream('assets/CNAME')
|
||||
await deploy(action)
|
||||
|
||||
const response = await deploy(action)
|
||||
|
||||
// Includes the call to generateBranch
|
||||
expect(execute).toBeCalledTimes(12)
|
||||
// Includes the call to generateWorktree
|
||||
expect(execute).toBeCalledTimes(9)
|
||||
expect(rmRF).toBeCalledTimes(1)
|
||||
expect(response).toBe(Status.SUCCESS)
|
||||
})
|
||||
|
||||
it('should execute commands with clean options, ommits sha commit message', async () => {
|
||||
process.env.GITHUB_SHA = ''
|
||||
it('should execute commands with single commit and dryRun toggled', async () => {
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
folder: 'other',
|
||||
folderPath: 'other',
|
||||
branch: 'branch',
|
||||
gitHubToken: '123',
|
||||
singleCommit: true,
|
||||
dryRun: true,
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
},
|
||||
clean: true,
|
||||
cleanExclude: '["cat", "montezuma"]',
|
||||
workspace: 'other'
|
||||
isTest: TestFlag.HAS_CHANGED_FILES
|
||||
})
|
||||
|
||||
await deploy(action)
|
||||
|
||||
// Includes the call to generateBranch
|
||||
expect(execute).toBeCalledTimes(12)
|
||||
// Includes the call to generateWorktree
|
||||
expect(execute).toBeCalledTimes(9)
|
||||
expect(rmRF).toBeCalledTimes(1)
|
||||
})
|
||||
|
||||
it('should execute commands with clean options stored as an array instead', async () => {
|
||||
it('should not ignore CNAME or nojekyll if they exist in the deployment folder', async () => {
|
||||
;(fs.existsSync as jest.Mock)
|
||||
.mockImplementationOnce(() => {
|
||||
return true
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
return true
|
||||
})
|
||||
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
folder: 'assets',
|
||||
folderPath: 'assets',
|
||||
branch: 'branch',
|
||||
gitHubToken: '123',
|
||||
token: '123',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
},
|
||||
clean: true,
|
||||
cleanExclude: ['cat', 'montezuma']
|
||||
isTest: TestFlag.HAS_CHANGED_FILES
|
||||
})
|
||||
|
||||
const response = await deploy(action)
|
||||
|
||||
// Includes the call to generateWorktree
|
||||
expect(execute).toBeCalledTimes(11)
|
||||
expect(rmRF).toBeCalledTimes(1)
|
||||
expect(fs.existsSync).toBeCalledTimes(2)
|
||||
expect(response).toBe(Status.SUCCESS)
|
||||
})
|
||||
|
||||
describe('with empty GITHUB_SHA', () => {
|
||||
const oldSha = process.env.GITHUB_SHA
|
||||
afterAll(() => {
|
||||
process.env.GITHUB_SHA = oldSha
|
||||
})
|
||||
it('should execute commands with clean options', async () => {
|
||||
process.env.GITHUB_SHA = ''
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
folder: 'other',
|
||||
folderPath: 'other',
|
||||
branch: 'branch',
|
||||
token: '123',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
},
|
||||
clean: true,
|
||||
workspace: 'other',
|
||||
isTest: TestFlag.NONE
|
||||
})
|
||||
|
||||
await deploy(action)
|
||||
|
||||
// Includes the call to generateWorktree
|
||||
expect(execute).toBeCalledTimes(8)
|
||||
expect(rmRF).toBeCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
it('should execute commands with clean options stored as an array', async () => {
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
folder: 'assets',
|
||||
folderPath: 'assets',
|
||||
branch: 'branch',
|
||||
token: '123',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
},
|
||||
clean: true,
|
||||
cleanExclude: ['cat', 'montezuma'],
|
||||
isTest: TestFlag.NONE
|
||||
})
|
||||
|
||||
await deploy(action)
|
||||
|
||||
// Includes the call to generateBranch
|
||||
expect(execute).toBeCalledTimes(12)
|
||||
// Includes the call to generateWorktree
|
||||
expect(execute).toBeCalledTimes(8)
|
||||
expect(rmRF).toBeCalledTimes(1)
|
||||
})
|
||||
|
||||
it('should gracefully handle incorrectly formatted clean exclude items', async () => {
|
||||
it('should gracefully handle target folder', async () => {
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
folder: '.',
|
||||
branch: 'branch',
|
||||
gitHubToken: '123',
|
||||
token: '123',
|
||||
pusher: {},
|
||||
clean: true,
|
||||
targetFolder: 'new_folder',
|
||||
commitMessage: 'Hello!',
|
||||
isTest: true,
|
||||
cleanExclude: '["cat, "montezuma"]' // There is a syntax errror in the string.
|
||||
isTest: TestFlag.NONE
|
||||
})
|
||||
|
||||
await deploy(action)
|
||||
|
||||
expect(execute).toBeCalledTimes(12)
|
||||
expect(execute).toBeCalledTimes(8)
|
||||
expect(rmRF).toBeCalledTimes(1)
|
||||
expect(mkdirP).toBeCalledTimes(1)
|
||||
})
|
||||
@ -381,16 +370,16 @@ describe('git', () => {
|
||||
silent: false,
|
||||
folder: 'assets',
|
||||
branch: 'branch',
|
||||
gitHubToken: '123',
|
||||
token: '123',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
},
|
||||
isTest: false // Setting this env variable to false means there will never be anything to commit and the action will exit early.
|
||||
isTest: TestFlag.NONE // Setting this flag to None means there will never be anything to commit and the action will exit early.
|
||||
})
|
||||
|
||||
const response = await deploy(action)
|
||||
expect(execute).toBeCalledTimes(13)
|
||||
expect(execute).toBeCalledTimes(8)
|
||||
expect(rmRF).toBeCalledTimes(1)
|
||||
expect(response).toBe(Status.SKIPPED)
|
||||
})
|
||||
@ -404,12 +393,12 @@ describe('git', () => {
|
||||
silent: false,
|
||||
folder: 'assets',
|
||||
branch: 'branch',
|
||||
gitHubToken: '123',
|
||||
lfs: true,
|
||||
token: '123',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
}
|
||||
},
|
||||
isTest: TestFlag.HAS_CHANGED_FILES
|
||||
})
|
||||
|
||||
try {
|
||||
|
@ -1,10 +1,11 @@
|
||||
/* eslint-disable import/first */
|
||||
// Initial env variable setup for tests.
|
||||
process.env['INPUT_FOLDER'] = 'build'
|
||||
process.env['GITHUB_SHA'] = '123'
|
||||
process.env['INPUT_DEBUG'] = 'debug'
|
||||
|
||||
import '../src/main'
|
||||
import {action} from '../src/constants'
|
||||
import {action, TestFlag} from '../src/constants'
|
||||
import run from '../src/lib'
|
||||
import {execute} from '../src/execute'
|
||||
import {rmRF} from '@actions/io'
|
||||
@ -23,6 +24,7 @@ jest.mock('@actions/io', () => ({
|
||||
jest.mock('@actions/core', () => ({
|
||||
setFailed: jest.fn(),
|
||||
getInput: jest.fn(),
|
||||
setOutput: jest.fn(),
|
||||
exportVariable: jest.fn(),
|
||||
isDebug: jest.fn(),
|
||||
info: jest.fn()
|
||||
@ -38,16 +40,16 @@ describe('main', () => {
|
||||
repositoryPath: 'JamesIves/github-pages-deploy-action',
|
||||
folder: 'assets',
|
||||
branch: 'branch',
|
||||
gitHubToken: '123',
|
||||
token: '123',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
},
|
||||
isTest: false,
|
||||
isTest: TestFlag.NONE,
|
||||
debug: true
|
||||
})
|
||||
await run(action)
|
||||
expect(execute).toBeCalledTimes(19)
|
||||
expect(execute).toBeCalledTimes(13)
|
||||
expect(rmRF).toBeCalledTimes(1)
|
||||
expect(exportVariable).toBeCalledTimes(1)
|
||||
})
|
||||
@ -57,14 +59,16 @@ describe('main', () => {
|
||||
repositoryPath: 'JamesIves/github-pages-deploy-action',
|
||||
folder: 'assets',
|
||||
branch: 'branch',
|
||||
gitHubToken: '123',
|
||||
token: '123',
|
||||
sshKey: true,
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
}
|
||||
},
|
||||
isTest: TestFlag.HAS_CHANGED_FILES
|
||||
})
|
||||
await run(action)
|
||||
expect(execute).toBeCalledTimes(18)
|
||||
expect(execute).toBeCalledTimes(16)
|
||||
expect(rmRF).toBeCalledTimes(1)
|
||||
expect(exportVariable).toBeCalledTimes(1)
|
||||
})
|
||||
@ -73,15 +77,13 @@ describe('main', () => {
|
||||
Object.assign(action, {
|
||||
folder: 'assets',
|
||||
branch: 'branch',
|
||||
baseBranch: 'master',
|
||||
gitHubToken: null,
|
||||
ssh: null,
|
||||
accessToken: null,
|
||||
token: null,
|
||||
sshKey: null,
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
},
|
||||
isTest: true
|
||||
isTest: TestFlag.HAS_CHANGED_FILES
|
||||
})
|
||||
await run(action)
|
||||
expect(execute).toBeCalledTimes(0)
|
||||
|
137
__tests__/ssh.test.ts
Normal file
137
__tests__/ssh.test.ts
Normal file
@ -0,0 +1,137 @@
|
||||
import {exportVariable} from '@actions/core'
|
||||
import {mkdirP} from '@actions/io'
|
||||
import child_process, {execFileSync, execSync} from 'child_process'
|
||||
import {appendFileSync} from 'fs'
|
||||
import {action, TestFlag} from '../src/constants'
|
||||
import {execute} from '../src/execute'
|
||||
import {configureSSH} from '../src/ssh'
|
||||
|
||||
const originalAction = JSON.stringify(action)
|
||||
|
||||
jest.mock('fs', () => ({
|
||||
appendFileSync: jest.fn(),
|
||||
existsSync: jest.fn()
|
||||
}))
|
||||
|
||||
jest.mock('child_process', () => ({
|
||||
execFileSync: jest.fn(),
|
||||
execSync: jest.fn()
|
||||
}))
|
||||
|
||||
jest.mock('@actions/io', () => ({
|
||||
rmRF: jest.fn(),
|
||||
mkdirP: jest.fn()
|
||||
}))
|
||||
|
||||
jest.mock('@actions/core', () => ({
|
||||
setFailed: jest.fn(),
|
||||
getInput: jest.fn(),
|
||||
setOutput: jest.fn(),
|
||||
isDebug: jest.fn(),
|
||||
info: jest.fn(),
|
||||
exportVariable: jest.fn()
|
||||
}))
|
||||
|
||||
jest.mock('../src/execute', () => ({
|
||||
execute: jest.fn()
|
||||
}))
|
||||
|
||||
describe('configureSSH', () => {
|
||||
afterEach(() => {
|
||||
Object.assign(action, JSON.parse(originalAction))
|
||||
})
|
||||
|
||||
it('should skip client configuration if sshKey is set to true', async () => {
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
folder: 'assets',
|
||||
branch: 'branch',
|
||||
sshKey: true,
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
},
|
||||
isTest: TestFlag.HAS_CHANGED_FILES
|
||||
})
|
||||
|
||||
await configureSSH(action)
|
||||
|
||||
expect(execute).toBeCalledTimes(0)
|
||||
expect(mkdirP).toBeCalledTimes(0)
|
||||
expect(appendFileSync).toBeCalledTimes(0)
|
||||
})
|
||||
|
||||
it('should configure the ssh client if a key is defined', async () => {
|
||||
;(child_process.execFileSync as jest.Mock).mockImplementationOnce(() => {
|
||||
return 'SSH_AUTH_SOCK=/some/random/folder/agent.123; export SSH_AUTH_SOCK;\nSSH_AGENT_PID=123; export SSH_AGENT_PID;'
|
||||
})
|
||||
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
folder: 'assets',
|
||||
branch: 'branch',
|
||||
sshKey: '?=-----BEGIN 123 456\n 789',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
},
|
||||
isTest: TestFlag.HAS_CHANGED_FILES
|
||||
})
|
||||
|
||||
await configureSSH(action)
|
||||
|
||||
expect(execFileSync).toBeCalledTimes(1)
|
||||
expect(exportVariable).toBeCalledTimes(2)
|
||||
expect(execSync).toBeCalledTimes(3)
|
||||
})
|
||||
|
||||
it('should not export variables if the return from ssh-agent is skewed', async () => {
|
||||
;(child_process.execFileSync as jest.Mock).mockImplementationOnce(() => {
|
||||
return 'useless nonsense here;'
|
||||
})
|
||||
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
folder: 'assets',
|
||||
branch: 'branch',
|
||||
sshKey: '?=-----BEGIN 123 456\n 789',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
},
|
||||
isTest: TestFlag.HAS_CHANGED_FILES
|
||||
})
|
||||
|
||||
await configureSSH(action)
|
||||
|
||||
expect(execFileSync).toBeCalledTimes(1)
|
||||
expect(exportVariable).toBeCalledTimes(0)
|
||||
expect(execSync).toBeCalledTimes(3)
|
||||
})
|
||||
|
||||
it('should throw if something errors', async () => {
|
||||
;(child_process.execFileSync as jest.Mock).mockImplementationOnce(() => {
|
||||
throw new Error('Mocked throw')
|
||||
})
|
||||
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
folder: 'assets',
|
||||
branch: 'branch',
|
||||
sshKey: 'real_key',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
},
|
||||
isTest: TestFlag.HAS_CHANGED_FILES
|
||||
})
|
||||
|
||||
try {
|
||||
await configureSSH(action)
|
||||
} catch (error) {
|
||||
expect(error.message).toBe(
|
||||
'The ssh client configuration encountered an error: Mocked throw ❌'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
@ -1,4 +1,4 @@
|
||||
import {ActionInterface} from '../src/constants'
|
||||
import {ActionInterface, TestFlag} from '../src/constants'
|
||||
import {
|
||||
isNullOrUndefined,
|
||||
generateTokenType,
|
||||
@ -37,38 +37,25 @@ describe('util', () => {
|
||||
branch: '123',
|
||||
workspace: 'src/',
|
||||
folder: 'build',
|
||||
gitHubToken: null,
|
||||
accessToken: null,
|
||||
ssh: true,
|
||||
silent: false
|
||||
token: null,
|
||||
sshKey: 'real_token',
|
||||
silent: false,
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
expect(generateTokenType(action)).toEqual('SSH Deploy Key')
|
||||
})
|
||||
|
||||
it('should return access token if access token is provided', async () => {
|
||||
it('should return deploy token if token is provided', async () => {
|
||||
const action = {
|
||||
branch: '123',
|
||||
workspace: 'src/',
|
||||
folder: 'build',
|
||||
gitHubToken: null,
|
||||
accessToken: '123',
|
||||
ssh: null,
|
||||
silent: false
|
||||
token: '123',
|
||||
sshKey: null,
|
||||
silent: false,
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
expect(generateTokenType(action)).toEqual('Access Token')
|
||||
})
|
||||
|
||||
it('should return github token if github token is provided', async () => {
|
||||
const action = {
|
||||
branch: '123',
|
||||
workspace: 'src/',
|
||||
folder: 'build',
|
||||
gitHubToken: '123',
|
||||
accessToken: null,
|
||||
ssh: null,
|
||||
silent: false
|
||||
}
|
||||
expect(generateTokenType(action)).toEqual('GitHub Token')
|
||||
expect(generateTokenType(action)).toEqual('Deploy Token')
|
||||
})
|
||||
|
||||
it('should return ... if no token is provided', async () => {
|
||||
@ -76,10 +63,10 @@ describe('util', () => {
|
||||
branch: '123',
|
||||
workspace: 'src/',
|
||||
folder: 'build',
|
||||
gitHubToken: null,
|
||||
accessToken: null,
|
||||
ssh: null,
|
||||
silent: false
|
||||
token: null,
|
||||
sshKey: null,
|
||||
silent: false,
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
expect(generateTokenType(action)).toEqual('…')
|
||||
})
|
||||
@ -92,42 +79,26 @@ describe('util', () => {
|
||||
branch: '123',
|
||||
workspace: 'src/',
|
||||
folder: 'build',
|
||||
gitHubToken: null,
|
||||
accessToken: null,
|
||||
ssh: true,
|
||||
silent: false
|
||||
token: null,
|
||||
sshKey: 'real_token',
|
||||
silent: false,
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
expect(generateRepositoryPath(action)).toEqual(
|
||||
'git@github.com:JamesIves/github-pages-deploy-action'
|
||||
)
|
||||
})
|
||||
|
||||
it('should return https if access token is provided', async () => {
|
||||
it('should return https with x-access-token if deploy token is provided', async () => {
|
||||
const action = {
|
||||
repositoryName: 'JamesIves/github-pages-deploy-action',
|
||||
branch: '123',
|
||||
workspace: 'src/',
|
||||
folder: 'build',
|
||||
gitHubToken: null,
|
||||
accessToken: '123',
|
||||
ssh: null,
|
||||
silent: false
|
||||
}
|
||||
expect(generateRepositoryPath(action)).toEqual(
|
||||
'https://123@github.com/JamesIves/github-pages-deploy-action.git'
|
||||
)
|
||||
})
|
||||
|
||||
it('should return https with x-access-token if github token is provided', async () => {
|
||||
const action = {
|
||||
repositoryName: 'JamesIves/github-pages-deploy-action',
|
||||
branch: '123',
|
||||
workspace: 'src/',
|
||||
folder: 'build',
|
||||
gitHubToken: '123',
|
||||
accessToken: null,
|
||||
ssh: null,
|
||||
silent: false
|
||||
token: '123',
|
||||
sshKey: null,
|
||||
silent: false,
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
expect(generateRepositoryPath(action)).toEqual(
|
||||
'https://x-access-token:123@github.com/JamesIves/github-pages-deploy-action.git'
|
||||
@ -143,14 +114,14 @@ describe('util', () => {
|
||||
branch: '123',
|
||||
workspace: 'src/',
|
||||
folder: 'build',
|
||||
accessToken: 'supersecret999%%%',
|
||||
gitHubToken: 'anothersecret123333',
|
||||
silent: false
|
||||
token: 'anothersecret123333',
|
||||
silent: false,
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
|
||||
const string = `This is an error message! It contains ${action.accessToken} and ${action.gitHubToken} and ${action.repositoryPath} and ${action.accessToken} again!`
|
||||
const string = `This is an error message! It contains ${action.token} and ${action.repositoryPath} and ${action.token} again!`
|
||||
expect(suppressSensitiveInformation(string, action)).toBe(
|
||||
'This is an error message! It contains *** and *** and *** and *** again!'
|
||||
'This is an error message! It contains *** and *** and *** again!'
|
||||
)
|
||||
})
|
||||
|
||||
@ -162,16 +133,16 @@ describe('util', () => {
|
||||
branch: '123',
|
||||
workspace: 'src/',
|
||||
folder: 'build',
|
||||
accessToken: 'supersecret999%%%',
|
||||
gitHubToken: 'anothersecret123333',
|
||||
silent: false
|
||||
token: 'anothersecret123333',
|
||||
silent: false,
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
|
||||
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.token} and ${action.repositoryPath}`
|
||||
expect(suppressSensitiveInformation(string, action)).toBe(
|
||||
'This is an error message! It contains supersecret999%%% and anothersecret123333 and https://x-access-token:supersecret999%%%@github.com/anothersecret123333'
|
||||
'This is an error message! It contains anothersecret123333 and https://x-access-token:supersecret999%%%@github.com/anothersecret123333'
|
||||
)
|
||||
})
|
||||
})
|
||||
@ -183,10 +154,10 @@ describe('util', () => {
|
||||
branch: '123',
|
||||
workspace: 'src/',
|
||||
folder: 'build',
|
||||
gitHubToken: null,
|
||||
accessToken: null,
|
||||
ssh: null,
|
||||
silent: false
|
||||
token: null,
|
||||
sshKey: null,
|
||||
silent: false,
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
expect(generateFolderPath(action)).toEqual('src/build')
|
||||
})
|
||||
@ -196,10 +167,10 @@ describe('util', () => {
|
||||
branch: '123',
|
||||
workspace: 'src/',
|
||||
folder: '/home/user/repo/build',
|
||||
gitHubToken: null,
|
||||
accessToken: null,
|
||||
ssh: null,
|
||||
silent: false
|
||||
token: null,
|
||||
sshKey: null,
|
||||
silent: false,
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
expect(generateFolderPath(action)).toEqual('/home/user/repo/build')
|
||||
})
|
||||
@ -209,10 +180,10 @@ describe('util', () => {
|
||||
branch: '123',
|
||||
workspace: 'src/',
|
||||
folder: './build',
|
||||
gitHubToken: null,
|
||||
accessToken: null,
|
||||
ssh: null,
|
||||
silent: false
|
||||
token: null,
|
||||
sshKey: null,
|
||||
silent: false,
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
expect(generateFolderPath(action)).toEqual('src/build')
|
||||
})
|
||||
@ -222,10 +193,10 @@ describe('util', () => {
|
||||
branch: '123',
|
||||
workspace: 'src/',
|
||||
folder: '~/repo/build',
|
||||
gitHubToken: null,
|
||||
accessToken: null,
|
||||
ssh: null,
|
||||
silent: false
|
||||
token: null,
|
||||
sshKey: null,
|
||||
silent: false,
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
process.env.HOME = '/home/user'
|
||||
expect(generateFolderPath(action)).toEqual('/home/user/repo/build')
|
||||
@ -239,7 +210,8 @@ describe('util', () => {
|
||||
repositoryPath: undefined,
|
||||
branch: 'branch',
|
||||
folder: 'build',
|
||||
workspace: 'src/'
|
||||
workspace: 'src/',
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
|
||||
try {
|
||||
@ -251,14 +223,15 @@ describe('util', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('should fail if access token is defined but it is an empty string', () => {
|
||||
it('should fail if token is defined but it is an empty string', () => {
|
||||
const action = {
|
||||
silent: false,
|
||||
repositoryPath: undefined,
|
||||
accessToken: '',
|
||||
token: '',
|
||||
branch: 'branch',
|
||||
folder: 'build',
|
||||
workspace: 'src/'
|
||||
workspace: 'src/',
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
|
||||
try {
|
||||
@ -274,10 +247,11 @@ describe('util', () => {
|
||||
const action = {
|
||||
silent: false,
|
||||
repositoryPath: undefined,
|
||||
accessToken: '123',
|
||||
token: '123',
|
||||
branch: '',
|
||||
folder: 'build',
|
||||
workspace: 'src/'
|
||||
workspace: 'src/',
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
|
||||
try {
|
||||
@ -291,10 +265,11 @@ describe('util', () => {
|
||||
const action = {
|
||||
silent: false,
|
||||
repositoryPath: undefined,
|
||||
gitHubToken: '123',
|
||||
token: '123',
|
||||
branch: 'branch',
|
||||
folder: '',
|
||||
workspace: 'src/'
|
||||
workspace: 'src/',
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
|
||||
try {
|
||||
@ -310,10 +285,11 @@ describe('util', () => {
|
||||
const action: ActionInterface = {
|
||||
silent: false,
|
||||
repositoryPath: undefined,
|
||||
gitHubToken: '123',
|
||||
token: '123',
|
||||
branch: 'branch',
|
||||
folder: 'notARealFolder',
|
||||
workspace: '.'
|
||||
workspace: '.',
|
||||
isTest: TestFlag.NONE
|
||||
}
|
||||
|
||||
try {
|
||||
|
35
__tests__/worktree.error.test.ts
Normal file
35
__tests__/worktree.error.test.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import {TestFlag} from '../src/constants'
|
||||
import {execute} from '../src/execute'
|
||||
import {generateWorktree} from '../src/worktree'
|
||||
|
||||
jest.mock('../src/execute', () => ({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
__esModule: true,
|
||||
execute: jest.fn()
|
||||
}))
|
||||
|
||||
describe('generateWorktree', () => {
|
||||
it('should catch when a function throws an error', async () => {
|
||||
;(execute as jest.Mock).mockImplementationOnce(() => {
|
||||
throw new Error('Mocked throw')
|
||||
})
|
||||
try {
|
||||
await generateWorktree(
|
||||
{
|
||||
workspace: 'somewhere',
|
||||
singleCommit: false,
|
||||
branch: 'gh-pages',
|
||||
folder: '',
|
||||
silent: true,
|
||||
isTest: TestFlag.HAS_CHANGED_FILES
|
||||
},
|
||||
'worktree',
|
||||
true
|
||||
)
|
||||
} catch (error) {
|
||||
expect(error.message).toBe(
|
||||
'There was an error creating the worktree: Mocked throw ❌'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
195
__tests__/worktree.test.ts
Normal file
195
__tests__/worktree.test.ts
Normal file
@ -0,0 +1,195 @@
|
||||
import {rmRF} from '@actions/io'
|
||||
import {TestFlag} from '../src/constants'
|
||||
import {generateWorktree} from '../src/worktree'
|
||||
import {execute} from '../src/execute'
|
||||
import fs from 'fs'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
|
||||
jest.mock('@actions/core', () => ({
|
||||
setFailed: jest.fn(),
|
||||
getInput: jest.fn(),
|
||||
isDebug: jest.fn(),
|
||||
info: jest.fn()
|
||||
}))
|
||||
|
||||
/*
|
||||
Test generateWorktree against a known git repository.
|
||||
The upstream repository `origin` is set up once for the test suite,
|
||||
and for each test run, a new clone is created.
|
||||
|
||||
See workstree.error.test.ts for testing mocked errors from git.*/
|
||||
|
||||
describe('generateWorktree', () => {
|
||||
let tempdir: string | null = null
|
||||
let clonedir: string | null = null
|
||||
beforeAll(async () => {
|
||||
// Set up origin repository
|
||||
const silent = true
|
||||
tempdir = fs.mkdtempSync(path.join(os.tmpdir(), 'gh-deploy-'))
|
||||
const origin = path.join(tempdir, 'origin')
|
||||
await execute('git init origin', tempdir, silent)
|
||||
await execute('git config user.email "you@example.com"', origin, silent)
|
||||
await execute('git config user.name "Jane Doe"', origin, silent)
|
||||
await execute('git checkout -b main', origin, silent)
|
||||
fs.writeFileSync(path.join(origin, 'f1'), 'hello world\n')
|
||||
await execute('git add .', origin, silent)
|
||||
await execute('git commit -mc0', origin, silent)
|
||||
fs.writeFileSync(path.join(origin, 'f1'), 'hello world\nand planets\n')
|
||||
await execute('git add .', origin, silent)
|
||||
await execute('git commit -mc1', origin, silent)
|
||||
await execute('git checkout --orphan gh-pages', origin, silent)
|
||||
await execute('git reset --hard', origin, silent)
|
||||
await fs.promises.writeFile(path.join(origin, 'gh1'), 'pages content\n')
|
||||
await execute('git add .', origin, silent)
|
||||
await execute('git commit -mgh0', origin, silent)
|
||||
await fs.promises.writeFile(
|
||||
path.join(origin, 'gh1'),
|
||||
'pages content\ngoes on\n'
|
||||
)
|
||||
await execute('git add .', origin, silent)
|
||||
await execute('git commit -mgh1', origin, silent)
|
||||
})
|
||||
beforeEach(async () => {
|
||||
// Clone origin to our workspace for each test
|
||||
const silent = true
|
||||
clonedir = path.join(tempdir as string, 'clone')
|
||||
await execute('git init clone', tempdir as string, silent)
|
||||
await execute('git config user.email "you@example.com"', clonedir, silent)
|
||||
await execute('git config user.name "Jane Doe"', clonedir, silent)
|
||||
await execute(
|
||||
`git remote add origin ${path.join(tempdir as string, 'origin')}`,
|
||||
clonedir,
|
||||
silent
|
||||
)
|
||||
await execute('git fetch --depth=1 origin main', clonedir, silent)
|
||||
await execute('git checkout main', clonedir, silent)
|
||||
})
|
||||
afterEach(async () => {
|
||||
// Tear down workspace
|
||||
await rmRF(clonedir as string)
|
||||
})
|
||||
afterAll(async () => {
|
||||
// Tear down origin repository
|
||||
if (tempdir) {
|
||||
await rmRF(tempdir)
|
||||
// console.log(tempdir)
|
||||
}
|
||||
})
|
||||
describe('with existing branch and new commits', () => {
|
||||
it('should check out the latest commit', async () => {
|
||||
const workspace = clonedir as string
|
||||
await generateWorktree(
|
||||
{
|
||||
workspace,
|
||||
singleCommit: false,
|
||||
branch: 'gh-pages',
|
||||
folder: '',
|
||||
silent: true,
|
||||
isTest: TestFlag.NONE
|
||||
},
|
||||
'worktree',
|
||||
true
|
||||
)
|
||||
const dirEntries = await fs.promises.readdir(
|
||||
path.join(workspace, 'worktree')
|
||||
)
|
||||
expect(dirEntries.sort((a, b) => a.localeCompare(b))).toEqual([
|
||||
'.git',
|
||||
'gh1'
|
||||
])
|
||||
const commitMessages = await execute(
|
||||
'git log --format=%s',
|
||||
path.join(workspace, 'worktree'),
|
||||
true
|
||||
)
|
||||
expect(commitMessages).toBe('gh1')
|
||||
})
|
||||
})
|
||||
describe('with missing branch and new commits', () => {
|
||||
it('should create initial commit', async () => {
|
||||
const workspace = clonedir as string
|
||||
await generateWorktree(
|
||||
{
|
||||
workspace,
|
||||
singleCommit: false,
|
||||
branch: 'no-pages',
|
||||
folder: '',
|
||||
silent: true,
|
||||
isTest: TestFlag.NONE
|
||||
},
|
||||
'worktree',
|
||||
false
|
||||
)
|
||||
const dirEntries = await fs.promises.readdir(
|
||||
path.join(workspace, 'worktree')
|
||||
)
|
||||
expect(dirEntries).toEqual(['.git'])
|
||||
const commitMessages = await execute(
|
||||
'git log --format=%s',
|
||||
path.join(workspace, 'worktree'),
|
||||
true
|
||||
)
|
||||
expect(commitMessages).toBe('Initial no-pages commit')
|
||||
})
|
||||
})
|
||||
describe('with existing branch and singleCommit', () => {
|
||||
it('should check out the latest commit', async () => {
|
||||
const workspace = clonedir as string
|
||||
await generateWorktree(
|
||||
{
|
||||
workspace,
|
||||
singleCommit: true,
|
||||
branch: 'gh-pages',
|
||||
folder: '',
|
||||
silent: true,
|
||||
isTest: TestFlag.NONE
|
||||
},
|
||||
'worktree',
|
||||
true
|
||||
)
|
||||
const dirEntries = await fs.promises.readdir(
|
||||
path.join(workspace, 'worktree')
|
||||
)
|
||||
expect(dirEntries.sort((a, b) => a.localeCompare(b))).toEqual([
|
||||
'.git',
|
||||
'gh1'
|
||||
])
|
||||
expect(async () => {
|
||||
await execute(
|
||||
'git log --format=%s',
|
||||
path.join(workspace, 'worktree'),
|
||||
true
|
||||
)
|
||||
}).rejects.toThrow()
|
||||
})
|
||||
})
|
||||
describe('with missing branch and singleCommit', () => {
|
||||
it('should create initial commit', async () => {
|
||||
const workspace = clonedir as string
|
||||
await generateWorktree(
|
||||
{
|
||||
workspace,
|
||||
singleCommit: true,
|
||||
branch: 'no-pages',
|
||||
folder: '',
|
||||
silent: true,
|
||||
isTest: TestFlag.NONE
|
||||
},
|
||||
'worktree',
|
||||
false
|
||||
)
|
||||
const dirEntries = await fs.promises.readdir(
|
||||
path.join(workspace, 'worktree')
|
||||
)
|
||||
expect(dirEntries).toEqual(['.git'])
|
||||
expect(async () => {
|
||||
await execute(
|
||||
'git log --format=%s',
|
||||
path.join(workspace, 'worktree'),
|
||||
true
|
||||
)
|
||||
}).rejects.toThrow()
|
||||
})
|
||||
})
|
||||
})
|
73
action.yml
73
action.yml
@ -8,79 +8,82 @@ branding:
|
||||
icon: 'git-commit'
|
||||
color: 'orange'
|
||||
inputs:
|
||||
SSH:
|
||||
description: 'You can configure the action to deploy using SSH by setting this option to true. More more information on how to add your ssh key pair please refer to the Using a Deploy Key section of this README.'
|
||||
ssh-key:
|
||||
description: >
|
||||
This option allows you to define a private SSH key to be used in conjunction with a repository deployment key to deploy using SSH.
|
||||
The private key should be stored in the `secrets / with` menu **as a secret**. The public should be stored in the repositories deployment
|
||||
keys menu and be given write access.
|
||||
|
||||
Alternatively you can set this field to `true` to enable SSH endpoints for deployment without configuring the ssh client. This can be useful if you've
|
||||
already setup the SSH client using another package or action in a previous step.
|
||||
required: false
|
||||
|
||||
ACCESS_TOKEN:
|
||||
description: '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. This should be stored as a secret.'
|
||||
required: false
|
||||
token:
|
||||
description: >
|
||||
This option defaults to the repository scoped GitHub Token.
|
||||
However if you need more permissions for things such as deploying to another repository, you can add a Personal Access Token (PAT) here.
|
||||
This should be stored in the `secrets / with` menu **as a secret**.
|
||||
|
||||
GITHUB_TOKEN:
|
||||
description: 'In order for GitHub to trigger the rebuild of your page you must provide the action with the repositories provided GitHub token.'
|
||||
We recommend using a service account with the least permissions neccersary
|
||||
and when generating a new PAT that you select the least permission scopes required.
|
||||
|
||||
[Learn more about creating and using encrypted secrets here.](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)
|
||||
required: false
|
||||
default: ${{ github.token }}
|
||||
|
||||
BRANCH:
|
||||
branch:
|
||||
description: 'This is the branch you wish to deploy to, for example gh-pages or docs.'
|
||||
required: true
|
||||
|
||||
FOLDER:
|
||||
folder:
|
||||
description: 'The folder in your repository that you want to deploy. If your build script compiles into a directory named build you would put it here. Folder paths cannot have a leading / or ./. If you wish to deploy the root directory you can place a . here.'
|
||||
required: true
|
||||
|
||||
TARGET_FOLDER:
|
||||
target-folder:
|
||||
description: 'If you would like to push the contents of the deployment folder into a specific directory on the deployment branch you can specify it here.'
|
||||
required: false
|
||||
|
||||
BASE_BRANCH:
|
||||
description: 'The base branch of your repository which you would like to checkout prior to deploying. This defaults to the current commit SHA that triggered the build followed by master if it does not exist. This is useful for making deployments from another branch, and also may be necessary when using a scheduled job.'
|
||||
required: false
|
||||
|
||||
COMMIT_MESSAGE:
|
||||
commit-message:
|
||||
description: 'If you need to customize the commit message for an integration you can do so.'
|
||||
required: false
|
||||
|
||||
CLEAN:
|
||||
description: '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:
|
||||
description: 'If your project generates hashed files on build you can use this option to automatically delete them from the target folder on the deployment branch with each deploy. This option is on by default and can be toggled off by setting it to false.'
|
||||
required: false
|
||||
default: 'true'
|
||||
default: true
|
||||
|
||||
CLEAN_EXCLUDE:
|
||||
description: "If you need to use CLEAN but you would like to preserve certain files or folders you can use this option. This should be formatted as an array but stored as a string."
|
||||
clean-exclude:
|
||||
description: "If you need to use clean but you would like to preserve certain files or folders you can use this option. This should contain each pattern as a single line in a multiline string."
|
||||
required: false
|
||||
|
||||
GIT_CONFIG_NAME:
|
||||
dry-run:
|
||||
description: "Do not actually push back, but use `--dry-run` on `git push` invocations insead."
|
||||
required: false
|
||||
|
||||
git-config-name:
|
||||
description: "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."
|
||||
required: false
|
||||
|
||||
GIT_CONFIG_EMAIL:
|
||||
git-config-email:
|
||||
description: "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."
|
||||
required: false
|
||||
|
||||
REPOSITORY_NAME:
|
||||
repository-name:
|
||||
description: "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"
|
||||
required: false
|
||||
|
||||
WORKSPACE:
|
||||
workspace:
|
||||
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
|
||||
|
||||
SINGLE_COMMIT:
|
||||
single-commit:
|
||||
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
|
||||
|
||||
LFS:
|
||||
description: "Migrates files from Git LFS so they can be comitted to the deployment branch."
|
||||
required: false
|
||||
|
||||
SILENT:
|
||||
silent:
|
||||
description: "Silences the action output preventing it from displaying git messages."
|
||||
required: false
|
||||
|
||||
PRESERVE:
|
||||
description: "Preserves and restores any workspace changes prior to deployment."
|
||||
required: false
|
||||
|
||||
outputs:
|
||||
DEPLOYMENT_STATUS:
|
||||
deployment-status:
|
||||
description: 'The status of the deployment that indicates if the run failed or passed. Possible outputs include: success|failed|skipped'
|
||||
|
BIN
assets/icon.png
BIN
assets/icon.png
Binary file not shown.
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 63 KiB |
Binary file not shown.
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 10 KiB |
@ -9,7 +9,7 @@
|
||||
"scripts": {
|
||||
"build": "rimraf lib && tsc --declaration",
|
||||
"test": "jest",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"lint": "eslint src/**/*.ts __tests__/**/*.ts",
|
||||
"format": "prettier --write './**/*.ts'"
|
||||
},
|
||||
"repository": {
|
||||
|
112
src/constants.ts
112
src/constants.ts
@ -4,38 +4,37 @@ import {isNullOrUndefined} from './util'
|
||||
|
||||
const {pusher, repository} = github.context.payload
|
||||
|
||||
/* Flags to signal different scenarios to test cases */
|
||||
export enum TestFlag {
|
||||
NONE = 0,
|
||||
HAS_CHANGED_FILES = 1 << 1, // Assume changes to commit.
|
||||
HAS_REMOTE_BRANCH = 1 << 2, // Assume remote repository has existing commits.
|
||||
UNABLE_TO_REMOVE_ORIGIN = 1 << 3, // Assume we can't remove origin.
|
||||
UNABLE_TO_UNSET_GIT_CONFIG = 1 << 4 // Assume we can't remove previously set git configs.
|
||||
}
|
||||
|
||||
/* For more information please refer to the README: https://github.com/JamesIves/github-pages-deploy-action */
|
||||
export interface ActionInterface {
|
||||
/** Deployment access token. */
|
||||
accessToken?: string | null
|
||||
/** The base branch that the deploy should be made from. */
|
||||
baseBranch?: string
|
||||
/** The branch that the action should deploy to. */
|
||||
branch: string
|
||||
/** git push with --dry-run */
|
||||
dryRun?: boolean | null
|
||||
/** 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?: boolean | null
|
||||
/** 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[]
|
||||
/** If you need to customize the commit message for an integration you can do so. */
|
||||
commitMessage?: string
|
||||
/** The default branch of the deployment. Similar to baseBranch if you're using this action as a module. */
|
||||
defaultBranch?: string
|
||||
/** The git config email. */
|
||||
email?: string
|
||||
/** The folder to deploy. */
|
||||
folder: string
|
||||
/** The auto generated folder path. */
|
||||
folderPath?: string
|
||||
/** GitHub deployment token. */
|
||||
gitHubToken?: string | null
|
||||
/** Determines if the action is running in test mode or not. */
|
||||
isTest?: boolean | null
|
||||
/** Removes files from LFS if toggled to allow normal deployment. */
|
||||
lfs?: boolean | null
|
||||
/** Determines test scenarios the action is running in. */
|
||||
isTest: TestFlag
|
||||
/** The git config name. */
|
||||
name?: string
|
||||
/** Determines if the workspace should be stashed/restored prior to comitting. */
|
||||
preserve?: boolean | null
|
||||
/** The repository path, for example JamesIves/github-pages-deploy-action. */
|
||||
repositoryName?: string
|
||||
/** The fully qualified repositpory path, this gets auto generated if repositoryName is provided. */
|
||||
@ -44,11 +43,13 @@ export interface ActionInterface {
|
||||
singleCommit?: boolean | null
|
||||
/** Determines if the action should run in silent mode or not. */
|
||||
silent: boolean
|
||||
/** Set to true if you're using an ssh client in your build step. */
|
||||
ssh?: boolean | null
|
||||
/** Defines an SSH private key that can be used during deployment. This can also be set to true to use SSH deployment endpoints if you've already configured the SSH client outside of this package. */
|
||||
sshKey?: string | 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. */
|
||||
targetFolder?: string
|
||||
/** The token type, ie ssh/github token/access token, this gets automatically generated. */
|
||||
/** Deployment token. */
|
||||
token?: string | null
|
||||
/** The token type, ie ssh/token, this gets automatically generated. */
|
||||
tokenType?: string
|
||||
/** The folder where your deployment project lives. */
|
||||
workspace: string
|
||||
@ -56,82 +57,79 @@ export interface ActionInterface {
|
||||
|
||||
/** The minimum required values to run the action as a node module. */
|
||||
export interface NodeActionInterface {
|
||||
/** Deployment access token. */
|
||||
accessToken?: string | null
|
||||
/** The branch that the action should deploy to. */
|
||||
branch: string
|
||||
/** The folder to deploy. */
|
||||
folder: string
|
||||
/** GitHub deployment token. */
|
||||
gitHubToken?: string | null
|
||||
/** The repository path, for example JamesIves/github-pages-deploy-action. */
|
||||
repositoryName: string
|
||||
/** GitHub deployment token. */
|
||||
token?: string | null
|
||||
/** Determines if the action should run in silent mode or not. */
|
||||
silent: boolean
|
||||
/** Set to true if you're using an ssh client in your build step. */
|
||||
ssh?: boolean | null
|
||||
/** Defines an SSH private key that can be used during deployment. This can also be set to true to use SSH deployment endpoints if you've already configured the SSH client outside of this package. */
|
||||
sshKey?: string | boolean | null
|
||||
/** The folder where your deployment project lives. */
|
||||
workspace: string
|
||||
/** Determines test scenarios the action is running in. */
|
||||
isTest: TestFlag
|
||||
}
|
||||
|
||||
/* Required action data that gets initialized when running within the GitHub Actions environment. */
|
||||
export const action: ActionInterface = {
|
||||
accessToken: getInput('ACCESS_TOKEN'),
|
||||
baseBranch: getInput('BASE_BRANCH'),
|
||||
folder: getInput('FOLDER'),
|
||||
branch: getInput('BRANCH'),
|
||||
commitMessage: getInput('COMMIT_MESSAGE'),
|
||||
clean: !isNullOrUndefined(getInput('CLEAN'))
|
||||
? getInput('CLEAN').toLowerCase() === 'true'
|
||||
folder: getInput('folder'),
|
||||
branch: getInput('branch'),
|
||||
commitMessage: getInput('commit-message'),
|
||||
dryRun: !isNullOrUndefined(getInput('dry-run'))
|
||||
? getInput('dry-run').toLowerCase() === 'true'
|
||||
: false,
|
||||
cleanExclude: getInput('CLEAN_EXCLUDE'),
|
||||
defaultBranch: process.env.GITHUB_SHA ? process.env.GITHUB_SHA : 'master',
|
||||
isTest: process.env.UNIT_TEST
|
||||
? process.env.UNIT_TEST.toLowerCase() === 'true'
|
||||
clean: !isNullOrUndefined(getInput('clean'))
|
||||
? getInput('clean').toLowerCase() === 'true'
|
||||
: false,
|
||||
lfs: !isNullOrUndefined(getInput('LFS'))
|
||||
? getInput('LFS').toLowerCase() === 'true'
|
||||
: false,
|
||||
email: !isNullOrUndefined(getInput('GIT_CONFIG_EMAIL'))
|
||||
? getInput('GIT_CONFIG_EMAIL')
|
||||
cleanExclude: (getInput('clean-exclude') || '')
|
||||
.split('\n')
|
||||
.filter(l => l !== ''),
|
||||
isTest: TestFlag.NONE,
|
||||
email: !isNullOrUndefined(getInput('git-config-email'))
|
||||
? getInput('git-config-email')
|
||||
: pusher && pusher.email
|
||||
? pusher.email
|
||||
: `${
|
||||
process.env.GITHUB_ACTOR || 'github-pages-deploy-action'
|
||||
}@users.noreply.github.com`,
|
||||
gitHubToken: getInput('GITHUB_TOKEN'),
|
||||
name: !isNullOrUndefined(getInput('GIT_CONFIG_NAME'))
|
||||
? getInput('GIT_CONFIG_NAME')
|
||||
name: !isNullOrUndefined(getInput('git-config-name'))
|
||||
? getInput('git-config-name')
|
||||
: pusher && pusher.name
|
||||
? pusher.name
|
||||
: process.env.GITHUB_ACTOR
|
||||
? process.env.GITHUB_ACTOR
|
||||
: 'GitHub Pages Deploy Action',
|
||||
preserve: !isNullOrUndefined(getInput('PRESERVE'))
|
||||
? getInput('PRESERVE').toLowerCase() === 'true'
|
||||
: false,
|
||||
repositoryName: !isNullOrUndefined(getInput('REPOSITORY_NAME'))
|
||||
? getInput('REPOSITORY_NAME')
|
||||
repositoryName: !isNullOrUndefined(getInput('repository-name'))
|
||||
? getInput('repository-name')
|
||||
: repository && repository.full_name
|
||||
? repository.full_name
|
||||
: process.env.GITHUB_REPOSITORY,
|
||||
singleCommit: !isNullOrUndefined(getInput('SINGLE_COMMIT'))
|
||||
? getInput('SINGLE_COMMIT').toLowerCase() === 'true'
|
||||
token: getInput('token'),
|
||||
singleCommit: !isNullOrUndefined(getInput('single-commit'))
|
||||
? getInput('single-commit').toLowerCase() === 'true'
|
||||
: false,
|
||||
silent: !isNullOrUndefined(getInput('SILENT'))
|
||||
? getInput('SILENT').toLowerCase() === 'true'
|
||||
silent: !isNullOrUndefined(getInput('silent'))
|
||||
? getInput('silent').toLowerCase() === 'true'
|
||||
: false,
|
||||
ssh: !isNullOrUndefined(getInput('SSH'))
|
||||
? getInput('SSH').toLowerCase() === 'true'
|
||||
: false,
|
||||
targetFolder: getInput('TARGET_FOLDER'),
|
||||
sshKey: isNullOrUndefined(getInput('ssh-key'))
|
||||
? false
|
||||
: !isNullOrUndefined(getInput('ssh-key')) &&
|
||||
getInput('ssh-key').toLowerCase() === 'true'
|
||||
? true
|
||||
: getInput('ssh-key'),
|
||||
targetFolder: getInput('target-folder'),
|
||||
workspace: process.env.GITHUB_WORKSPACE || ''
|
||||
}
|
||||
|
||||
/** Types for the required action parameters. */
|
||||
export type RequiredActionParameters = Pick<
|
||||
ActionInterface,
|
||||
'accessToken' | 'gitHubToken' | 'ssh' | 'branch' | 'folder'
|
||||
'token' | 'sshKey' | 'branch' | 'folder' | 'isTest'
|
||||
>
|
||||
|
||||
/** Status codes for the action. */
|
||||
|
237
src/git.ts
237
src/git.ts
@ -1,8 +1,9 @@
|
||||
import {info} from '@actions/core'
|
||||
import {mkdirP, rmRF} from '@actions/io'
|
||||
import fs from 'fs'
|
||||
import {ActionInterface, Status} from './constants'
|
||||
import {ActionInterface, Status, TestFlag} from './constants'
|
||||
import {execute} from './execute'
|
||||
import {generateWorktree} from './worktree'
|
||||
import {isNullOrUndefined, suppressSensitiveInformation} from './util'
|
||||
|
||||
/* Initializes git in the workspace. */
|
||||
@ -11,7 +12,6 @@ export async function init(action: ActionInterface): Promise<void | Error> {
|
||||
info(`Deploying using ${action.tokenType}… 🔑`)
|
||||
info('Configuring git…')
|
||||
|
||||
await execute(`git init`, action.workspace, action.silent)
|
||||
await execute(
|
||||
`git config user.name "${action.name}"`,
|
||||
action.workspace,
|
||||
@ -23,10 +23,31 @@ export async function init(action: ActionInterface): Promise<void | Error> {
|
||||
action.silent
|
||||
)
|
||||
|
||||
try {
|
||||
if ((process.env.CI && !action.sshKey) || action.isTest) {
|
||||
/* Ensures that previously set Git configs do not interfere with the deployment.
|
||||
Only runs in the GitHub Actions CI environment if a user is not using an SSH key.
|
||||
*/
|
||||
await execute(
|
||||
`git config --local --unset-all http.https://github.com/.extraheader`,
|
||||
action.workspace,
|
||||
action.silent
|
||||
)
|
||||
}
|
||||
|
||||
if (action.isTest === TestFlag.UNABLE_TO_UNSET_GIT_CONFIG) {
|
||||
throw new Error()
|
||||
}
|
||||
} catch {
|
||||
info(
|
||||
'Unable to unset previous git config authentication as it may not exist, continuing…'
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
await execute(`git remote rm origin`, action.workspace, action.silent)
|
||||
|
||||
if (action.isTest) {
|
||||
if (action.isTest === TestFlag.UNABLE_TO_REMOVE_ORIGIN) {
|
||||
throw new Error()
|
||||
}
|
||||
} catch {
|
||||
@ -38,18 +59,6 @@ export async function init(action: ActionInterface): Promise<void | Error> {
|
||||
action.workspace,
|
||||
action.silent
|
||||
)
|
||||
|
||||
if (action.preserve) {
|
||||
info(`Stashing workspace changes… ⬆️`)
|
||||
await execute(`git stash`, action.workspace, action.silent)
|
||||
}
|
||||
|
||||
await execute(
|
||||
`git fetch --no-recurse-submodules`,
|
||||
action.workspace,
|
||||
action.silent
|
||||
)
|
||||
|
||||
info('Git configured… 🔧')
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
@ -61,63 +70,6 @@ export async function init(action: ActionInterface): Promise<void | Error> {
|
||||
}
|
||||
}
|
||||
|
||||
/* Switches to the base branch. */
|
||||
export async function switchToBaseBranch(
|
||||
action: ActionInterface
|
||||
): Promise<void> {
|
||||
try {
|
||||
await execute(
|
||||
`git checkout --progress --force ${
|
||||
action.baseBranch ? action.baseBranch : action.defaultBranch
|
||||
}`,
|
||||
action.workspace,
|
||||
action.silent
|
||||
)
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`There was an error switching to the base branch: ${suppressSensitiveInformation(
|
||||
error.message,
|
||||
action
|
||||
)} ❌`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/* Generates the branch if it doesn't exist on the remote. */
|
||||
export async function generateBranch(action: ActionInterface): Promise<void> {
|
||||
try {
|
||||
info(`Creating the ${action.branch} branch…`)
|
||||
|
||||
await switchToBaseBranch(action)
|
||||
await execute(
|
||||
`git checkout --orphan ${action.branch}`,
|
||||
action.workspace,
|
||||
action.silent
|
||||
)
|
||||
await execute(`git reset --hard`, action.workspace, action.silent)
|
||||
await execute(
|
||||
`git commit --no-verify --allow-empty -m "Initial ${action.branch} commit"`,
|
||||
action.workspace,
|
||||
action.silent
|
||||
)
|
||||
await execute(
|
||||
`git push --force ${action.repositoryPath} ${action.branch}`,
|
||||
action.workspace,
|
||||
action.silent
|
||||
)
|
||||
await execute(`git fetch`, action.workspace, action.silent)
|
||||
|
||||
info(`Created the ${action.branch} branch… 🔧`)
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`There was an error creating the deployment branch: ${suppressSensitiveInformation(
|
||||
error.message,
|
||||
action
|
||||
)} ❌`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/* Runs the necessary steps to make the deployment. */
|
||||
export async function deploy(action: ActionInterface): Promise<Status> {
|
||||
const temporaryDeploymentDirectory =
|
||||
@ -131,75 +83,28 @@ export async function deploy(action: ActionInterface): Promise<Status> {
|
||||
try {
|
||||
const commitMessage = !isNullOrUndefined(action.commitMessage)
|
||||
? (action.commitMessage as string)
|
||||
: `Deploying to ${action.branch} from ${action.baseBranch} ${
|
||||
process.env.GITHUB_SHA ? `@ ${process.env.GITHUB_SHA}` : ''
|
||||
: `Deploying to ${action.branch}${
|
||||
process.env.GITHUB_SHA
|
||||
? ` from @ ${process.env.GITHUB_REPOSITORY}@${process.env.GITHUB_SHA}`
|
||||
: ''
|
||||
} 🚀`
|
||||
|
||||
/*
|
||||
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 ${action.repositoryPath} ${action.branch} | wc -l`,
|
||||
action.workspace,
|
||||
action.silent
|
||||
)
|
||||
|
||||
if (!branchExists && !action.isTest) {
|
||||
await generateBranch(action)
|
||||
}
|
||||
|
||||
// Checks out the base branch to begin the deployment process.
|
||||
await switchToBaseBranch(action)
|
||||
|
||||
await execute(
|
||||
`git fetch ${action.repositoryPath}`,
|
||||
action.workspace,
|
||||
action.silent
|
||||
)
|
||||
|
||||
if (action.lfs) {
|
||||
// Migrates data from LFS so it can be comitted the "normal" way.
|
||||
info(`Migrating from Git LFS… ⚓`)
|
||||
await execute(
|
||||
`git lfs migrate export --include="*" --yes`,
|
||||
// Checks to see if the remote exists prior to deploying.
|
||||
const branchExists =
|
||||
action.isTest & TestFlag.HAS_REMOTE_BRANCH ||
|
||||
(await execute(
|
||||
`git ls-remote --heads ${action.repositoryPath} ${action.branch}`,
|
||||
action.workspace,
|
||||
action.silent
|
||||
)
|
||||
}
|
||||
))
|
||||
|
||||
if (action.preserve) {
|
||||
info(`Applying stashed workspace changes… ⬆️`)
|
||||
|
||||
try {
|
||||
await execute(`git stash apply`, action.workspace, action.silent)
|
||||
} catch {
|
||||
info('Unable to apply from stash, continuing…')
|
||||
}
|
||||
}
|
||||
|
||||
await execute(
|
||||
`git worktree add --checkout ${temporaryDeploymentDirectory} origin/${action.branch}`,
|
||||
action.workspace,
|
||||
action.silent
|
||||
)
|
||||
await generateWorktree(action, temporaryDeploymentDirectory, branchExists)
|
||||
|
||||
// Ensures that items that need to be excluded from the clean job get parsed.
|
||||
let excludes = ''
|
||||
if (action.clean && action.cleanExclude) {
|
||||
try {
|
||||
const excludedItems =
|
||||
typeof action.cleanExclude === 'string'
|
||||
? JSON.parse(action.cleanExclude)
|
||||
: action.cleanExclude
|
||||
|
||||
for (const item of excludedItems) {
|
||||
excludes += `--exclude ${item} `
|
||||
}
|
||||
} catch {
|
||||
info(
|
||||
'There was an error parsing your CLEAN_EXCLUDE items. Please refer to the README for more details. ❌'
|
||||
)
|
||||
for (const item of action.cleanExclude) {
|
||||
excludes += `--exclude ${item} `
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,13 +143,24 @@ export async function deploy(action: ActionInterface): Promise<Status> {
|
||||
action.silent
|
||||
)
|
||||
|
||||
const hasFilesToCommit = await execute(
|
||||
`git status --porcelain`,
|
||||
`${action.workspace}/${temporaryDeploymentDirectory}`,
|
||||
action.silent
|
||||
)
|
||||
// Use git status to check if we have something to commit.
|
||||
// Special case is singleCommit with existing history, when
|
||||
// we're really interested if the diff against the upstream branch
|
||||
// changed.
|
||||
const checkGitStatus =
|
||||
branchExists && action.singleCommit
|
||||
? `git diff origin/${action.branch}`
|
||||
: `git status --porcelain`
|
||||
info(`Checking if there are files to commit…`)
|
||||
const hasFilesToCommit =
|
||||
action.isTest & TestFlag.HAS_CHANGED_FILES ||
|
||||
(await execute(
|
||||
checkGitStatus,
|
||||
`${action.workspace}/${temporaryDeploymentDirectory}`,
|
||||
true // This output is always silenced due to the large output it creates.
|
||||
))
|
||||
|
||||
if (!hasFilesToCommit && !action.isTest) {
|
||||
if (!hasFilesToCommit) {
|
||||
return Status.SKIPPED
|
||||
}
|
||||
|
||||
@ -264,54 +180,15 @@ export async function deploy(action: ActionInterface): Promise<Status> {
|
||||
`${action.workspace}/${temporaryDeploymentDirectory}`,
|
||||
action.silent
|
||||
)
|
||||
await execute(
|
||||
`git push --force ${action.repositoryPath} ${temporaryDeploymentBranch}:${action.branch}`,
|
||||
`${action.workspace}/${temporaryDeploymentDirectory}`,
|
||||
action.silent
|
||||
)
|
||||
|
||||
info(`Changes committed to the ${action.branch} branch… 📦`)
|
||||
|
||||
if (action.singleCommit) {
|
||||
if (!action.dryRun) {
|
||||
await execute(
|
||||
`git fetch ${action.repositoryPath}`,
|
||||
action.workspace,
|
||||
action.silent
|
||||
)
|
||||
await execute(
|
||||
`git checkout --orphan ${action.branch}-temp`,
|
||||
`git push --force ${action.repositoryPath} ${temporaryDeploymentBranch}:${action.branch}`,
|
||||
`${action.workspace}/${temporaryDeploymentDirectory}`,
|
||||
action.silent
|
||||
)
|
||||
await execute(
|
||||
`git add --all .`,
|
||||
`${action.workspace}/${temporaryDeploymentDirectory}`,
|
||||
action.silent
|
||||
)
|
||||
await execute(
|
||||
`git commit -m "${commitMessage}" --quiet --no-verify`,
|
||||
`${action.workspace}/${temporaryDeploymentDirectory}`,
|
||||
action.silent
|
||||
)
|
||||
await execute(
|
||||
`git branch -M ${action.branch}-temp ${action.branch}`,
|
||||
`${action.workspace}/${temporaryDeploymentDirectory}`,
|
||||
action.silent
|
||||
)
|
||||
await execute(
|
||||
`git push origin ${action.branch} --force`,
|
||||
`${action.workspace}/${temporaryDeploymentDirectory}`,
|
||||
action.silent
|
||||
)
|
||||
|
||||
info('Cleared git history… 🚿')
|
||||
}
|
||||
|
||||
await execute(
|
||||
`git checkout --progress --force ${action.defaultBranch}`,
|
||||
action.workspace,
|
||||
action.silent
|
||||
)
|
||||
info(`Changes committed to the ${action.branch} branch… 📦`)
|
||||
|
||||
return Status.SUCCESS
|
||||
} catch (error) {
|
||||
|
14
src/lib.ts
14
src/lib.ts
@ -1,9 +1,10 @@
|
||||
import {exportVariable, info, setFailed} from '@actions/core'
|
||||
import {ActionInterface, Status, NodeActionInterface} from './constants'
|
||||
import {exportVariable, info, setFailed, setOutput} from '@actions/core'
|
||||
import {ActionInterface, NodeActionInterface, Status} from './constants'
|
||||
import {deploy, init} from './git'
|
||||
import {configureSSH} from './ssh'
|
||||
import {
|
||||
generateFolderPath,
|
||||
checkParameters,
|
||||
generateFolderPath,
|
||||
generateRepositoryPath,
|
||||
generateTokenType
|
||||
} from './util'
|
||||
@ -43,6 +44,10 @@ export default async function run(
|
||||
settings.repositoryPath = generateRepositoryPath(settings)
|
||||
settings.tokenType = generateTokenType(settings)
|
||||
|
||||
if (settings.sshKey) {
|
||||
await configureSSH(settings)
|
||||
}
|
||||
|
||||
await init(settings)
|
||||
status = await deploy(settings)
|
||||
} catch (error) {
|
||||
@ -59,6 +64,7 @@ export default async function run(
|
||||
}`
|
||||
)
|
||||
|
||||
exportVariable('DEPLOYMENT_STATUS', status)
|
||||
exportVariable('deployment_status', status)
|
||||
setOutput('deployment-status', status)
|
||||
}
|
||||
}
|
||||
|
57
src/ssh.ts
Normal file
57
src/ssh.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import {exportVariable, info} from '@actions/core'
|
||||
import {mkdirP} from '@actions/io'
|
||||
import {execFileSync, execSync} from 'child_process'
|
||||
import {appendFileSync} from 'fs'
|
||||
import {ActionInterface} from './constants'
|
||||
import {suppressSensitiveInformation} from './util'
|
||||
|
||||
export async function configureSSH(action: ActionInterface): Promise<void> {
|
||||
try {
|
||||
if (typeof action.sshKey === 'string') {
|
||||
const sshDirectory = `${process.env['HOME']}/.ssh`
|
||||
const sshKnownHostsDirectory = `${sshDirectory}/known_hosts`
|
||||
|
||||
// SSH fingerprints provided by GitHub: https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/githubs-ssh-key-fingerprints
|
||||
const sshGitHubKnownHostRsa =
|
||||
'\ngithub.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==\n'
|
||||
const sshGitHubKnownHostDss =
|
||||
'\ngithub.com ssh-dss AAAAB3NzaC1kc3MAAACBANGFW2P9xlGU3zWrymJgI/lKo//ZW2WfVtmbsUZJ5uyKArtlQOT2+WRhcg4979aFxgKdcsqAYW3/LS1T2km3jYW/vr4Uzn+dXWODVk5VlUiZ1HFOHf6s6ITcZvjvdbp6ZbpM+DuJT7Bw+h5Fx8Qt8I16oCZYmAPJRtu46o9C2zk1AAAAFQC4gdFGcSbp5Gr0Wd5Ay/jtcldMewAAAIATTgn4sY4Nem/FQE+XJlyUQptPWMem5fwOcWtSXiTKaaN0lkk2p2snz+EJvAGXGq9dTSWHyLJSM2W6ZdQDqWJ1k+cL8CARAqL+UMwF84CR0m3hj+wtVGD/J4G5kW2DBAf4/bqzP4469lT+dF2FRQ2L9JKXrCWcnhMtJUvua8dvnwAAAIB6C4nQfAA7x8oLta6tT+oCk2WQcydNsyugE8vLrHlogoWEicla6cWPk7oXSspbzUcfkjN3Qa6e74PhRkc7JdSdAlFzU3m7LMkXo1MHgkqNX8glxWNVqBSc0YRdbFdTkL0C6gtpklilhvuHQCdbgB3LBAikcRkDp+FCVkUgPC/7Rw==\n'
|
||||
|
||||
info(`Configuring SSH client… 🔑`)
|
||||
|
||||
await mkdirP(sshDirectory)
|
||||
|
||||
appendFileSync(sshKnownHostsDirectory, sshGitHubKnownHostRsa)
|
||||
appendFileSync(sshKnownHostsDirectory, sshGitHubKnownHostDss)
|
||||
|
||||
// Initializes SSH agent.
|
||||
const agentOutput = execFileSync('ssh-agent').toString().split('\n')
|
||||
|
||||
agentOutput.map(line => {
|
||||
const exportableVariables = /^(SSH_AUTH_SOCK|SSH_AGENT_PID)=(.*); export \1/.exec(
|
||||
line
|
||||
)
|
||||
|
||||
if (exportableVariables && exportableVariables.length) {
|
||||
exportVariable(exportableVariables[1], exportableVariables[2])
|
||||
}
|
||||
})
|
||||
|
||||
// Adds the SSH key to the agent.
|
||||
action.sshKey.split(/(?=-----BEGIN)/).map(async line => {
|
||||
execSync('ssh-add -', {input: `${line.trim()}\n`})
|
||||
})
|
||||
|
||||
execSync('ssh-add -l')
|
||||
} else {
|
||||
info(`Skipping SSH client configuration… ⌚`)
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`The ssh client configuration encountered an error: ${suppressSensitiveInformation(
|
||||
error.message,
|
||||
action
|
||||
)} ❌`
|
||||
)
|
||||
}
|
||||
}
|
28
src/util.ts
28
src/util.ts
@ -1,6 +1,6 @@
|
||||
import {isDebug} from '@actions/core'
|
||||
import {existsSync} from 'fs'
|
||||
import path from 'path'
|
||||
import {isDebug} from '@actions/core'
|
||||
import {ActionInterface, RequiredActionParameters} from './constants'
|
||||
|
||||
/* Replaces all instances of a match in a string. */
|
||||
@ -13,21 +13,15 @@ export const isNullOrUndefined = (value: any): boolean =>
|
||||
|
||||
/* Generates a token type used for the action. */
|
||||
export const generateTokenType = (action: ActionInterface): string =>
|
||||
action.ssh
|
||||
? 'SSH Deploy Key'
|
||||
: action.accessToken
|
||||
? 'Access Token'
|
||||
: action.gitHubToken
|
||||
? 'GitHub Token'
|
||||
: '…'
|
||||
action.sshKey ? 'SSH Deploy Key' : action.token ? 'Deploy Token' : '…'
|
||||
|
||||
/* Generates a the repository path used to make the commits. */
|
||||
export const generateRepositoryPath = (action: ActionInterface): string =>
|
||||
action.ssh
|
||||
action.sshKey
|
||||
? `git@github.com:${action.repositoryName}`
|
||||
: `https://${
|
||||
action.accessToken || `x-access-token:${action.gitHubToken}`
|
||||
}@github.com/${action.repositoryName}.git`
|
||||
: `https://${`x-access-token:${action.token}`}@github.com/${
|
||||
action.repositoryName
|
||||
}.git`
|
||||
|
||||
/* Genetate absolute folder path by the provided folder name */
|
||||
export const generateFolderPath = (action: ActionInterface): string => {
|
||||
@ -52,7 +46,7 @@ const hasRequiredParameters = <K extends keyof RequiredActionParameters>(
|
||||
|
||||
/* Verifies the action has the required parameters to run, otherwise throw an error. */
|
||||
export const checkParameters = (action: ActionInterface): void => {
|
||||
if (!hasRequiredParameters(action, ['accessToken', 'gitHubToken', 'ssh'])) {
|
||||
if (!hasRequiredParameters(action, ['token', 'sshKey'])) {
|
||||
throw new Error(
|
||||
'No deployment token/method was provided. You must provide the action with either a Personal Access Token or the GitHub Token secret in order to deploy. If you wish to use an ssh deploy token then you must set SSH to true.'
|
||||
)
|
||||
@ -85,11 +79,9 @@ export const suppressSensitiveInformation = (
|
||||
return value
|
||||
}
|
||||
|
||||
const orderedByLength = ([
|
||||
action.accessToken,
|
||||
action.gitHubToken,
|
||||
action.repositoryPath
|
||||
].filter(Boolean) as string[]).sort((a, b) => b.length - a.length)
|
||||
const orderedByLength = ([action.token, action.repositoryPath].filter(
|
||||
Boolean
|
||||
) as string[]).sort((a, b) => b.length - a.length)
|
||||
|
||||
for (const find of orderedByLength) {
|
||||
value = replaceAll(value, find, '***')
|
||||
|
85
src/worktree.ts
Normal file
85
src/worktree.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import {info} from '@actions/core'
|
||||
import {ActionInterface} from './constants'
|
||||
import {execute} from './execute'
|
||||
import {suppressSensitiveInformation} from './util'
|
||||
|
||||
export class GitCheckout {
|
||||
orphan = false
|
||||
commitish?: string | null = null
|
||||
branch: string
|
||||
constructor(branch: string) {
|
||||
this.branch = branch
|
||||
}
|
||||
toString(): string {
|
||||
return [
|
||||
'git',
|
||||
'checkout',
|
||||
this.orphan ? '--orphan' : '-B',
|
||||
this.branch,
|
||||
this.commitish || ''
|
||||
].join(' ')
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate the worktree and set initial content if it exists */
|
||||
export async function generateWorktree(
|
||||
action: ActionInterface,
|
||||
worktreedir: string,
|
||||
branchExists: boolean
|
||||
): Promise<void> {
|
||||
try {
|
||||
info('Creating worktree…')
|
||||
|
||||
if (branchExists) {
|
||||
await execute(
|
||||
`git fetch --no-recurse-submodules --depth=1 origin ${action.branch}`,
|
||||
action.workspace,
|
||||
action.silent
|
||||
)
|
||||
}
|
||||
|
||||
await execute(
|
||||
`git worktree add --no-checkout --detach ${worktreedir}`,
|
||||
action.workspace,
|
||||
action.silent
|
||||
)
|
||||
const checkout = new GitCheckout(action.branch)
|
||||
if (branchExists) {
|
||||
// There's existing data on the branch to check out
|
||||
checkout.commitish = `origin/${action.branch}`
|
||||
}
|
||||
if (!branchExists || action.singleCommit) {
|
||||
// Create a new history if we don't have the branch, or if we want to reset it
|
||||
checkout.orphan = true
|
||||
}
|
||||
await execute(
|
||||
checkout.toString(),
|
||||
`${action.workspace}/${worktreedir}`,
|
||||
action.silent
|
||||
)
|
||||
if (!branchExists) {
|
||||
info(`Created the ${action.branch} branch… 🔧`)
|
||||
// Our index is in HEAD state, reset
|
||||
await execute(
|
||||
'git reset --hard',
|
||||
`${action.workspace}/${worktreedir}`,
|
||||
action.silent
|
||||
)
|
||||
if (!action.singleCommit) {
|
||||
// New history isn't singleCommit, create empty initial commit
|
||||
await execute(
|
||||
`git commit --no-verify --allow-empty -m "Initial ${action.branch} commit"`,
|
||||
`${action.workspace}/${worktreedir}`,
|
||||
action.silent
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`There was an error creating the worktree: ${suppressSensitiveInformation(
|
||||
error.message,
|
||||
action
|
||||
)} ❌`
|
||||
)
|
||||
}
|
||||
}
|
7
tsconfig.lint.json
Normal file
7
tsconfig.lint.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "."
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
Loading…
Reference in New Issue
Block a user