Compare commits

...

26 Commits

Author SHA1 Message Date
peaceiris
4a69c2d60c chore(release): 3.0.0
Some checks failed
Release / release (push) Has been cancelled
2020-02-05 14:41:09 +09:00
peaceiris
f990e1a2a0 chore(release): Add build assets 2020-02-05 14:41:08 +09:00
peaceiris
0629babb09 fix: action title 2020-02-05 14:40:07 +09:00
peaceiris
a150e4e690 ci: force_orphan to false 2020-02-05 14:37:47 +09:00
peaceiris
ec09a8863c chore(release): Remove build assets [skip ci] 2020-02-05 14:36:37 +09:00
peaceiris
db6bfb8f36 chore(release): 3.0.0-1
Some checks failed
Release / release (push) Has been cancelled
2020-02-05 14:36:36 +09:00
peaceiris
22c1c9babc chore(release): Add build assets 2020-02-05 14:36:35 +09:00
Shohei Ueda
68b21c12af feat: Add TypeScript Action (#83)
cf. https://github.com/peaceiris/actions-github-pages
Close #54
2020-02-05 14:34:19 +09:00
Shohei Ueda
28b05fd3fa docs: Add Dart Package peanut for Flutter 2020-02-01 08:27:05 +09:00
Shohei Ueda
bacf0a61ea docs: add Dependabot badge 2020-01-31 11:43:57 +09:00
Shohei Ueda
2573b6139b docs: Add release feed badge 2020-01-26 17:14:24 +09:00
peaceiris
96360d5a85 docs: fix list 2020-01-25 13:15:26 +09:00
peaceiris
14069e75e2 docs: update support table about GITHUB_TOKEN 2020-01-25 13:14:35 +09:00
Shohei Ueda
d3edcde28b chore: Change update_schedule from weekly to daily 2020-01-24 06:37:51 +09:00
imgbot[bot]
d82725c632 docs: [ImgBot] Optimize images (#81)
/images/ogp.svg -- 42.09kb -> 42.06kb (0.06%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>

Co-authored-by: Imgbot <help@imgbot.net>
2020-01-21 02:51:50 +09:00
peaceiris
e504bd5c38 docs: Update OGP image 2020-01-21 02:47:13 +09:00
dependabot-preview[bot]
45b43ab257 deps: bump alpine from 3.11.2 to 3.11.3
Bumps alpine from 3.11.2 to 3.11.3.

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-20 09:20:42 +00:00
Shohei Ueda
0b9b068db1 chore: Fix typo 2020-01-19 00:07:44 +09:00
Shohei Ueda
9ba947f545 feat: Add tagName and tagMessage options (#78)
* feat: Add tagName and tagMessage options
* feat: Add print_info for tag options
* feat: Add tagOverwrite option
* docs: Add new section about Git tag options

Close #76
2020-01-18 12:55:18 +09:00
Shohei Ueda
ebe79a723c chore: Update LICENSE year 2020-01-16 17:42:57 +09:00
VladimirLogachev
c77e021886 docs: Add elm example workflow (#65)
* Add elm section to README.md
2020-01-12 21:56:01 +09:00
peaceiris
37729f1bb3 docs: Use head_commit instead of commits[0] 2020-01-07 00:20:56 +09:00
Shohei Ueda
76351d52b8 feat: Add commitMessage option (#75)
* feat: Add commitMessage option
* docs: Add custom commit message option

Close #74
cf. #72 and #73
2020-01-06 23:46:48 +09:00
Shohei Ueda
fd02997068 fix: link to commit hash for external deployment (#73)
cf. #72
2020-01-06 23:10:35 +09:00
dependabot-preview[bot]
127155c640 deps: bump alpine from 3.11.0 to 3.11.2 (#71)
Bumps alpine from 3.11.0 to 3.11.2.

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-31 11:07:02 +09:00
Shohei Ueda
0252bbee4d feat: Add username and useremail options (#67)
* feat: Add username and useremail options
* docs: Add Git username and email section

Close #66
2019-12-24 15:22:01 +09:00
43 changed files with 38179 additions and 197 deletions

View File

@@ -1,10 +1,9 @@
version: 1
update_configs:
- package_manager: "docker"
- package_manager: "javascript"
directory: "/"
update_schedule: "weekly"
update_schedule: "daily"
default_labels:
- "dependencies"
- "docker"
commit_message:
prefix: "deps"

View File

@@ -1,7 +1,2 @@
.git
.github
.hadolint.yaml
LICENSE
README.md
action.yml
images
.*
*

13
.editorconfig Normal file
View File

@@ -0,0 +1,13 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[Makefile]
indent_size = 4
indent_style = tab

3
.envrc Normal file
View File

@@ -0,0 +1,3 @@
nvmrc=~/.nvm/nvm.sh
source $nvmrc
nvm use

24
.eslintrc.json Normal file
View File

@@ -0,0 +1,24 @@
{
"env": {
"commonjs": true,
"es6": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:jest/recommended"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 2019
},
"rules": {
}
}

View File

@@ -1,40 +0,0 @@
name: docker image ci
on:
pull_request:
types: [opened, synchronize]
paths-ignore:
- '**.md'
push:
paths-ignore:
- '**.md'
branches:
- master
jobs:
test:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: build
env:
DOCKER_IMAGE: docker.pkg.github.com/${{ github.repository }}/action:latest
run: |
docker build . --file Dockerfile --tag ${DOCKER_IMAGE}
shellcheck:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: shellcheck
run: shellcheck ./entrypoint.sh
hadolint:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- run: brew install hadolint
- run: hadolint ./Dockerfile

37
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Release
on:
push:
tags:
- 'v3.*.*'
jobs:
release:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "${GITHUB_CONTEXT}"
- name: Install github/hub
run: |
export HUB_VERSION="2.14.1"
curl -fsSL https://github.com/github/hub/raw/40e421edd2c63d57bb8daa4bb9bbdfa21e8becf9/script/get | bash -s "${HUB_VERSION}"
- name: Create release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG_NAME="${GITHUB_REF##refs/tags/}"
echo "See [CHANGELOG.md](https://github.com/${GITHUB_REPOSITORY}/blob/${TAG_NAME}/CHANGELOG.md) for more details." > ./release_notes.md
RELEASE_NAME="$(jq -r '.name' ./package.json)"
sed -i "1i${RELEASE_NAME} ${TAG_NAME}\n" ./release_notes.md
./bin/hub release create \
--draft \
--prerelease \
--file ./release_notes.md \
"${TAG_NAME}"

86
.github/workflows/test-action.yml vendored Normal file
View File

@@ -0,0 +1,86 @@
name: Test Action
on:
push:
branches:
- master
paths-ignore:
- '*.md'
pull_request:
types:
- opened
- synchronize
paths-ignore:
- '*.md'
jobs:
skipci:
runs-on: ubuntu-18.04
steps:
- run: echo "[Skip CI] ${{ contains(github.event.head_commit.message, '[skip ci]') }}"
test:
runs-on: ${{ matrix.os }}
if: contains(github.event.head_commit.message, '[skip ci]') == false
strategy:
matrix:
os:
- 'ubuntu-18.04'
# - 'macos-latest'
# - 'windows-latest'
steps:
- uses: actions/checkout@v2
- name: Read .nvmrc
run: echo "::set-output name=NVMRC::$(cat .nvmrc)"
id: nvm
- name: Setup Node
uses: actions/setup-node@v1
with:
node-version: '${{ steps.nvm.outputs.NVMRC }}'
- run: npm ci
- run: npm run build
- name: Setup mdBook
uses: peaceiris/actions-mdbook@v1
with:
mdbook-version: '0.3.5'
- name: Build
working-directory: ./test_projects/mdbook
run: mdbook build
- name: Prepare tag
id: prepare_tag
if: startsWith(github.ref, 'refs/tags/')
run: |
TAG_NAME="${GITHUB_REF##refs/tags/}"
echo "::set-output name=tag_name::${TAG_NAME}"
echo "::set-output name=deploy_tag_name::deploy-${TAG_NAME}"
- name: Deploy
uses: ./
with:
deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
# github_token: ${{ secrets.GITHUB_TOKEN }}
# publish_branch: master
publish_dir: ./test_projects/mdbook/book
# external_repository: ''
allow_empty_commit: true
# keep_files: true
# force_orphan: true
# user_name: iris
# user_email: email@peaceiris.com
# commit_message: ${{ github.event.head_commit.message }}
# tag_name: ${{ steps.prepare_tag.outputs.deploy_tag_name }}
# tag_message: 'Deployment ${{ steps.prepare_tag.outputs.tag_name }}'
# - name: Deploy v2
# uses: peaceiris/actions-gh-pages@v2
# env:
# ACTIONS_DEPLOY_KEY: ${{ secrets.ACTIONS_DEPLOY_KEY }}
# PUBLISH_BRANCH: gh-pages
# PUBLISH_DIR: ./test_projects/mdbook/book

64
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,64 @@
name: 'Test'
on:
push:
branches:
- master
paths-ignore:
- '*.md'
pull_request:
types:
- opened
- synchronize
paths-ignore:
- '*.md'
jobs:
skipci:
runs-on: ubuntu-18.04
steps:
- run: echo "[Skip CI] ${{ contains(github.event.head_commit.message, '[skip ci]') }}"
test:
runs-on: ${{ matrix.os }}
if: contains(github.event.head_commit.message, '[skip ci]') == false
strategy:
matrix:
os:
- 'ubuntu-18.04'
- 'macos-latest'
- 'windows-latest'
steps:
- uses: actions/checkout@v2
- name: Read .nvmrc
run: echo "::set-output name=NVMRC::$(cat .nvmrc)"
id: nvm
- name: Setup Node
uses: actions/setup-node@v1
with:
node-version: '${{ steps.nvm.outputs.NVMRC }}'
- run: npm ci
- name: Run prettier
if: startsWith(matrix.os, 'ubuntu')
run: npm run format:check
- name: Run eslint
if: startsWith(matrix.os, 'ubuntu')
run: npm run lint
- name: Run ncc
if: startsWith(matrix.os, 'ubuntu')
run: npm run build
- run: npm test
- name: Upload test coverage as artifact
uses: actions/upload-artifact@v1
with:
name: coverage
path: coverage

View File

@@ -19,6 +19,5 @@ jobs:
git remote set-url origin "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${GITHUB_REPOSITORY}.git"
export TAG_NAME="${GITHUB_REF##refs/tags/}"
export TAG_MAJOR="${TAG_NAME%%.*}"
git tag "${TAG_MAJOR}" -m "Release ${TAG_NAME}" || git tag -d "${TAG_MAJOR}" ; git push --delete origin "${TAG_MAJOR}"
git tag "${TAG_MAJOR}" -m "Release ${TAG_NAME}" || true
git push origin "${TAG_MAJOR}"
git tag --force -a "${TAG_MAJOR}" -m "Release ${TAG_NAME}"
git push --force origin "${TAG_MAJOR}"

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
.DS_Store
coverage
.npm
.eslintcache
.env
node_modules

View File

@@ -1,2 +0,0 @@
ignored:
- DL3018

1
.npmrc Normal file
View File

@@ -0,0 +1 @@
engine-strict=true

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
12.14.1

11
.prettierrc.json Normal file
View File

@@ -0,0 +1,11 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid",
"parser": "typescript"
}

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"git.ignoreLimitWarning": true
}

37
CHANGELOG.md Normal file
View File

@@ -0,0 +1,37 @@
# Changelog
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
# [3.0.0](https://github.com/peaceiris/actions-gh-pages/compare/v3.0.0-1...v3.0.0) (2020-02-05)
### ci
* force_orphan to false ([a150e4e](https://github.com/peaceiris/actions-gh-pages/commit/a150e4e690ab9bfcecae05b68c8efd14edac15df))
### fix
* action title ([0629bab](https://github.com/peaceiris/actions-gh-pages/commit/0629babb090ceea68f118101b903a8e6798b2962))
# [3.0.0-1](https://github.com/peaceiris/actions-gh-pages/compare/v2.10.1...v3.0.0-1) (2020-02-05)
### chore
* Change update_schedule from weekly to daily ([d3edcde](https://github.com/peaceiris/actions-gh-pages/commit/d3edcde28b32bdc18b358182c89a7a729facf37c))
### docs
* [ImgBot] Optimize images (#81) ([d82725c](https://github.com/peaceiris/actions-gh-pages/commit/d82725c632d7b9dd0fac1981cfaf13d4c550d682)), closes [#81](https://github.com/peaceiris/actions-gh-pages/issues/81)
* Add Dart Package peanut for Flutter ([28b05fd](https://github.com/peaceiris/actions-gh-pages/commit/28b05fd3fab1ac4edb3d12ae0cbdc91367279667))
* add Dependabot badge ([bacf0a6](https://github.com/peaceiris/actions-gh-pages/commit/bacf0a61ea8e93bcbbbd20089f87f8c12af605e2))
* Add release feed badge ([2573b61](https://github.com/peaceiris/actions-gh-pages/commit/2573b6139ba429078ddf457eb170b4af924c55a4))
* fix list ([96360d5](https://github.com/peaceiris/actions-gh-pages/commit/96360d5a85f6f54d3fb5175c158179b57a0149cc))
* Update OGP image ([e504bd5](https://github.com/peaceiris/actions-gh-pages/commit/e504bd5c3862941f5d03ce8d649329e9d5e105aa))
* update support table about GITHUB_TOKEN ([14069e7](https://github.com/peaceiris/actions-gh-pages/commit/14069e75e2e9646aeed42fedb5b99aa31ead3b90))
### feat
* Add TypeScript Action (#83) ([68b21c1](https://github.com/peaceiris/actions-gh-pages/commit/68b21c12af25bc606f77a7b5674f162f3a17bf22)), closes [#83](https://github.com/peaceiris/actions-gh-pages/issues/83) [#54](https://github.com/peaceiris/actions-gh-pages/issues/54)

View File

@@ -1,10 +1,29 @@
FROM alpine:3.11.0
ARG NODE_VERSION
RUN apk add --no-cache \
bash \
git \
openssh-client \
ca-certificates
FROM node:${NODE_VERSION}-buster-slim
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT [ "/entrypoint.sh" ]
SHELL ["/bin/bash", "-l", "-c"]
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
libcurl4-gnutls-dev libexpat1-dev gettext libz-dev libssl-dev autoconf \
ca-certificates \
wget \
ssh && \
rm -rf /var/lib/apt/lists/*
WORKDIR /git
ENV GIT_VERSION="2.25.0"
RUN wget -q "https://github.com/git/git/archive/v${GIT_VERSION}.tar.gz" && \
tar -zxf "./v${GIT_VERSION}.tar.gz" && \
rm "./v${GIT_VERSION}.tar.gz" && \
cd "./git-${GIT_VERSION}" && \
make configure && \
./configure --prefix=/usr && \
make all && \
make install
WORKDIR /repo
CMD [ "bash" ]

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019 Shohei Ueda (peaceiris)
Copyright (c) 2020 Shohei Ueda (peaceiris)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

23
Makefile Normal file
View File

@@ -0,0 +1,23 @@
cmd := "bash"
msg := ""
IMAGE_NAME := actions_github_pages_dev:latest
NODE_VERSION := $(shell cat ./.nvmrc)
DOCKER_BUILD := docker build . -t $(IMAGE_NAME) --build-arg NODE_VERSION=$(NODE_VERSION)
DOCKER_RUN := docker run --rm -i -t -v ${PWD}:/repo -v ~/.gitconfig:/root/.gitconfig $(IMAGE_NAME)
.PHONY: build
build:
$(DOCKER_BUILD)
.PHONY: run
run:
$(DOCKER_RUN) $(cmd)
.PHONY: test
test:
$(DOCKER_RUN) npm test
.PHONY: commit
commit:
$(DOCKER_RUN) git commit -m "$(msg)"

145
README.md
View File

@@ -3,6 +3,8 @@
[![GitHub release date](https://img.shields.io/github/release-date/peaceiris/actions-gh-pages.svg)](https://github.com/peaceiris/actions-gh-pages/releases)
![GitHub Actions status](https://github.com/peaceiris/actions-gh-pages/workflows/docker%20image%20ci/badge.svg)
[![Docker Hub Build Status](https://img.shields.io/docker/cloud/build/peaceiris/gh-pages.svg)](https://hub.docker.com/r/peaceiris/gh-pages)
[![Release Feed](https://img.shields.io/badge/release-feed-yellow)](https://github.com/peaceiris/actions-gh-pages/releases.atom)
[![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=peaceiris/actions-gh-pages)](https://dependabot.com)
<img width="400" alt="GitHub Actions for deploying to GitHub Pages with Static Site Generators" src="./images/ogp.svg">
@@ -32,10 +34,12 @@ Three tokens are supported.
| Token | Private repo | Public repo | Protocol | Setup |
|---|:---:|:---:|---|---|
| `GITHUB_TOKEN` | ✅️ | ❌️ | HTTPS | Unnecessary |
| `GITHUB_TOKEN` | ✅️ | (1) | HTTPS | Unnecessary |
| `PERSONAL_TOKEN` | ✅️ | ✅️ | HTTPS | Necessary |
| `ACTIONS_DEPLOY_KEY` | ✅️ | ✅️ | SSH | Necessary |
1. Currently, GitHub Actions does not support to trigger a GitHub Pages build event using GITHUB_TOKEN on a public repository.
Do you want to skip the docker build step? OK, the script mode is available.
```yaml
@@ -71,6 +75,9 @@ Do you want to skip the docker build step? OK, the script mode is available.
- [⭐️ Keeping existing files](#%EF%B8%8F-keeping-existing-files)
- [⭐️ Deploy to external repository](#%EF%B8%8F-deploy-to-external-repository)
- [⭐️ Force orphan](#%EF%B8%8F-force-orphan)
- [⭐️ Set Git username and email](#%EF%B8%8F-set-git-username-and-email)
- [⭐️ Set custom commit message](#%EF%B8%8F-set-custom-commit-message)
- [⭐️ Create Git tag](#%EF%B8%8F-create-git-tag)
- [⭐️ Script mode](#%EF%B8%8F-script-mode)
- [Tips and FAQ](#tips-and-faq)
- [⭐️ Use the latest and specific release](#%EF%B8%8F-use-the-latest-and-specific-release)
@@ -84,6 +91,7 @@ Do you want to skip the docker build step? OK, the script mode is available.
- [⭐️ Static Site Generators with Python](#%EF%B8%8F-static-site-generators-with-python)
- [⭐️ mdBook (Rust)](#%EF%B8%8F-mdbook-rust)
- [⭐️ Flutter Web](#%EF%B8%8F-flutter-web)
- [⭐️ Elm](#%EF%B8%8F-elm)
- [License](#license)
- [About the author](#about-the-author)
@@ -311,6 +319,96 @@ This allows you to make your publish branch with only the latest commit.
forceOrphan: true
```
### ⭐️ Set Git username and email
Set custom `git config user.name` and `git config user.email`.
A commit is always created with the same user.
```yaml
- name: Deploy
uses: peaceiris/actions-gh-pages@v2
env:
ACTIONS_DEPLOY_KEY: ${{ secrets.ACTIONS_DEPLOY_KEY }}
PUBLISH_BRANCH: gh-pages
PUBLISH_DIR: ./public
with:
username: "iris"
useremail: "iris@peaceiris.com"
```
### ⭐️ Set custom commit message
Set custom commit message.
When we create a commit with a message `docs: Update some post`, a deployment commit will be generated with a message `docs: Update some post ${GITHUB_SHA}`.
```yaml
- name: Deploy
uses: peaceiris/actions-gh-pages@v2
env:
ACTIONS_DEPLOY_KEY: ${{ secrets.ACTIONS_DEPLOY_KEY }}
PUBLISH_BRANCH: gh-pages
PUBLISH_DIR: ./public
with:
commitMessage: ${{ github.event.head_commit.message }}
```
### ⭐️ Create Git tag
Here is an example workflow.
```yaml
name: github pages
on:
push:
branches:
- master
tags:
- 'v*.*.*'
jobs:
build-deploy:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Some build
- name: Prepare tag
id: prepare_tag
if: startsWith(github.ref, 'refs/tags/')
run: |
TAG_NAME="${GITHUB_REF##refs/tags/}"
echo "::set-output name=tag_name::${TAG_NAME}"
echo "::set-output name=deploy_tag_name::deploy-${TAG_NAME}"
- name: Deploy
uses: peaceiris/actions-gh-pages@v2
env:
ACTIONS_DEPLOY_KEY: ${{ secrets.ACTIONS_DEPLOY_KEY }}
PUBLISH_BRANCH: gh-pages
PUBLISH_DIR: ./public
with:
tagName: ${{ steps.prepare_tag.outputs.deploy_tag_name }}
tagMessage: 'Deployment ${{ steps.prepare_tag.outputs.tag_name }}'
```
Commands on a local machine.
```console
$ # On the master branch
$ git tag -a "v1.2.3" -m "Release v1.2.3"
$ git push origin "v1.2.3"
$ # After deployment
$ git fetch origin
$ git tag
deploy-v1.2.3 # Tag on the gh-pages branch
v1.2.3 # Tag on the master branch
```
We can set `tagOverwrite` option to `true` for overwriting a tag.
### ⭐️ Script mode
From `v2.5.0`, we can run this action as a shell script.
@@ -711,9 +809,12 @@ jobs:
An exapmle workflow for [Flutter web project].
Setup [Flutter] with [subosito/flutter-action].
[peanut | Dart Package] is also useful.
[Flutter]: https://github.com/flutter/flutter
[Flutter web project]: https://flutter.dev/docs/get-started/web
[subosito/flutter-action]: https://github.com/subosito/flutter-action
[peanut | Dart Package]: https://pub.dev/packages/peanut
```yaml
name: github pages
@@ -750,6 +851,48 @@ jobs:
PUBLISH_DIR: ./build/web
```
### ⭐️ Elm
An exapmle workflow for [Elm] with [justgook/setup-elm].
[Elm]: https://elm-lang.org
[justgook/setup-elm]: https://github.com/justgook/setup-elm
```yaml
name: github pages
on:
push:
branches:
- master
jobs:
build-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Elm
uses: justgook/setup-elm@v1
- name: Make
run: elm make --optimize src/Main.elm
- name: Move files
run: |
mkdir ./public
mv ./index.html ./public/
# If you have non-minimal setup with some assets and separate html/js files,
# provide --output=<output-file> option for `elm make` and remove this step
- name: Deploy
uses: peaceiris/actions-gh-pages@v2
env:
ACTIONS_DEPLOY_KEY: ${{ secrets.ACTIONS_DEPLOY_KEY }}
PUBLISH_BRANCH: gh-pages
PUBLISH_DIR: ./public
```
## License
- [MIT License - peaceiris/actions-gh-pages]

View File

@@ -0,0 +1,94 @@
// import * as main from '../src/main';
import {Inputs} from '../src/interfaces';
import {getInputs} from '../src/get-inputs';
beforeEach(() => {
jest.resetModules();
});
afterEach(() => {
delete process.env['INPUT_DEPLOY_KEY'];
delete process.env['INPUT_GITHUB_TOKEN'];
delete process.env['INPUT_PERSONAL_TOKEN'];
delete process.env['INPUT_PUBLISH_BRANCH'];
delete process.env['INPUT_PUBLISH_DIR'];
delete process.env['INPUT_EXTERNAL_REPOSITORY'];
delete process.env['INPUT_ALLOW_EMPTY_COMMIT'];
delete process.env['INPUT_KEEP_FILES'];
delete process.env['INPUT_FORCE_ORPHAN'];
delete process.env['INPUT_USER_NAME'];
delete process.env['INPUT_USER_EMAIL'];
delete process.env['INPUT_COMMIT_MESSAGE'];
delete process.env['INPUT_TAG_NAME'];
delete process.env['INPUT_TAG_MESSAGE'];
});
describe('getInputs()', () => {
test('get default inputs', () => {
process.env['INPUT_DEPLOY_KEY'] = 'test_deploy_key';
// process.env['INPUT_GITHUB_TOKEN'] = 'test_github_token';
// process.env['INPUT_PERSONAL_TOKEN'] = 'test_personal_token';
process.env['INPUT_PUBLISH_BRANCH'] = 'gh-pages';
process.env['INPUT_PUBLISH_DIR'] = 'public';
// process.env['INPUT_EXTERNAL_REPOSITORY'] = 'user/repo';
// process.env['INPUT_ALLOW_EMPTY_COMMIT'] = 'true';
// process.env['INPUT_KEEP_FILES'] = 'true';
// process.env['INPUT_FORCE_ORPHAN'] = 'true';
// process.env['INPUT_USER_NAME'] = 'username';
// process.env['INPUT_USER_EMAIL'] = 'github@github.com';
// process.env['INPUT_COMMIT_MESSAGE'] = 'feat: Add new feature';
// process.env['INPUT_TAG_NAME'] = 'deploy-v1.2.3';
// process.env['INPUT_TAG_MESSAGE'] = 'Deployment v1.2.3';
const inps: Inputs = getInputs();
expect(inps.DeployKey).toMatch('test_deploy_key');
expect(inps.GithubToken).toMatch('');
expect(inps.PersonalToken).toMatch('');
expect(inps.PublishBranch).toMatch('gh-pages');
expect(inps.PublishDir).toMatch('public');
expect(inps.ExternalRepository).toMatch('');
expect(inps.AllowEmptyCommit).toBe(false);
expect(inps.KeepFiles).toBe(false);
expect(inps.ForceOrphan).toBe(false);
expect(inps.UserName).toMatch('');
expect(inps.UserEmail).toMatch('');
expect(inps.CommitMessage).toMatch('');
expect(inps.TagName).toMatch('');
expect(inps.TagMessage).toMatch('');
});
test('get spec inputs', () => {
// process.env['INPUT_DEPLOY_KEY'] = 'test_deploy_key';
process.env['INPUT_GITHUB_TOKEN'] = 'test_github_token';
process.env['INPUT_PERSONAL_TOKEN'] = 'test_personal_token';
process.env['INPUT_PUBLISH_BRANCH'] = 'master';
process.env['INPUT_PUBLISH_DIR'] = 'out';
process.env['INPUT_EXTERNAL_REPOSITORY'] = 'user/repo';
process.env['INPUT_ALLOW_EMPTY_COMMIT'] = 'true';
process.env['INPUT_KEEP_FILES'] = 'true';
process.env['INPUT_FORCE_ORPHAN'] = 'true';
process.env['INPUT_USER_NAME'] = 'username';
process.env['INPUT_USER_EMAIL'] = 'github@github.com';
process.env['INPUT_COMMIT_MESSAGE'] = 'feat: Add new feature';
process.env['INPUT_TAG_NAME'] = 'deploy-v1.2.3';
process.env['INPUT_TAG_MESSAGE'] = 'Deployment v1.2.3';
const inps: Inputs = getInputs();
expect(inps.DeployKey).toMatch('');
expect(inps.GithubToken).toMatch('test_github_token');
expect(inps.PersonalToken).toMatch('test_personal_token');
expect(inps.PublishBranch).toMatch('master');
expect(inps.PublishDir).toMatch('out');
expect(inps.ExternalRepository).toMatch('user/repo');
expect(inps.AllowEmptyCommit).toBe(true);
expect(inps.KeepFiles).toBe(true);
expect(inps.ForceOrphan).toBe(true);
expect(inps.UserName).toMatch('username');
expect(inps.UserEmail).toMatch('github@github.com');
expect(inps.CommitMessage).toMatch('feat: Add new feature');
expect(inps.TagName).toMatch('deploy-v1.2.3');
expect(inps.TagMessage).toMatch('Deployment v1.2.3');
});
});

32
__tests__/main.test.ts Normal file
View File

@@ -0,0 +1,32 @@
// import {run} from '../src/main';
beforeEach(() => {
jest.resetModules();
});
afterEach(() => {
delete process.env['INPUT_DEPLOY_KEY'];
delete process.env['INPUT_GITHUB_TOKEN'];
delete process.env['INPUT_PERSONAL_TOKEN'];
delete process.env['INPUT_PUBLISH_BRANCH'];
delete process.env['INPUT_PUBLISH_DIR'];
delete process.env['INPUT_EXTERNAL_REPOSITORY'];
delete process.env['INPUT_ALLOW_EMPTY_COMMIT'];
delete process.env['INPUT_KEEP_FILES'];
delete process.env['INPUT_FORCE_ORPHAN'];
delete process.env['INPUT_USER_NAME'];
delete process.env['INPUT_USER_EMAIL'];
delete process.env['INPUT_COMMIT_MESSAGE'];
delete process.env['INPUT_TAG_NAME'];
delete process.env['INPUT_TAG_MESSAGE'];
delete process.env['INPUT_TAG_OVERWRITE'];
});
describe('Integration testing run()', () => {
test('succeed in pushing using deploy key', async () => {
// process.env['INPUT_DEPLOY_KEY'] = 'test_deploy_key';
// process.env['GITHUB_REPOSITORY'] = 'owner/repo';
// const exitcode = await run();
expect(0).toBe(0);
});
});

View File

@@ -2,21 +2,56 @@ name: 'GitHub Pages action'
description: 'GitHub Actions for GitHub Pages 🚀 Deploy static files and publish your site easily. Static-Site-Generators-friendly.'
author: 'peaceiris'
runs:
using: 'docker'
image: 'Dockerfile'
using: 'node12'
main: 'lib/index.js'
branding:
icon: 'upload-cloud'
color: 'blue'
inputs:
emptyCommits:
deploy_key:
description: ''
required: false
github_token:
description: ''
required: false
personal_token:
description: ''
required: false
publish_branch:
description: ''
required: false
default: 'gh-pages'
publish_dir:
description: ''
required: false
default: 'public'
external_repository:
description: ''
required: false
allow_empty_commit:
description: 'If empty commits should be made to the publication branch'
required: false
default: 'true'
keepFiles:
default: 'false'
keep_files:
description: 'If existing files in the publish branch should be not removed before deploying'
required: false
default: 'false'
forceOrphan:
force_orphan:
description: 'Keep only the latest commit on a GitHub Pages branch'
required: false
default: 'false'
user_name:
description: 'Set Git user.name'
required: false
user_email:
description: 'Set Git user.email'
required: false
commit_message:
description: 'Set custom commit message'
required: false
tag_name:
description: 'Set tag name'
required: false
tag_message:
description: 'Set tag message'
required: false

View File

@@ -1,125 +0,0 @@
#!/bin/bash
set -e
# set -ex
function print_error() {
echo -e "\e[31mERROR: ${1}\e[m"
}
function print_info() {
echo -e "\e[36mINFO: ${1}\e[m"
}
function skip() {
print_info "No changes detected, skipping deployment"
exit 0
}
# check values
if [ -n "${EXTERNAL_REPOSITORY}" ]; then
PUBLISH_REPOSITORY=${EXTERNAL_REPOSITORY}
else
PUBLISH_REPOSITORY=${GITHUB_REPOSITORY}
fi
print_info "Deploy to ${PUBLISH_REPOSITORY}"
if [ -n "${ACTIONS_DEPLOY_KEY}" ]; then
print_info "setup with ACTIONS_DEPLOY_KEY"
if [ -n "${SCRIPT_MODE}" ]; then
print_info "run as SCRIPT_MODE"
SSH_DIR="${HOME}/.ssh"
else
SSH_DIR="/root/.ssh"
fi
mkdir "${SSH_DIR}"
ssh-keyscan -t rsa github.com > "${SSH_DIR}/known_hosts"
echo "${ACTIONS_DEPLOY_KEY}" > "${SSH_DIR}/id_rsa"
chmod 400 "${SSH_DIR}/id_rsa"
remote_repo="git@github.com:${PUBLISH_REPOSITORY}.git"
elif [ -n "${PERSONAL_TOKEN}" ]; then
print_info "setup with PERSONAL_TOKEN"
remote_repo="https://x-access-token:${PERSONAL_TOKEN}@github.com/${PUBLISH_REPOSITORY}.git"
elif [ -n "${GITHUB_TOKEN}" ]; then
print_info "setup with GITHUB_TOKEN"
print_error "GITHUB_TOKEN works only private repo, See #9"
if [ -n "${EXTERNAL_REPOSITORY}" ]; then
print_error "can not use GITHUB_TOKEN to deploy to a external repository"
exit 1
fi
remote_repo="https://x-access-token:${GITHUB_TOKEN}@github.com/${PUBLISH_REPOSITORY}.git"
else
print_error "not found ACTIONS_DEPLOY_KEY, PERSONAL_TOKEN, or GITHUB_TOKEN"
exit 1
fi
if [ -z "${PUBLISH_BRANCH}" ]; then
print_error "not found PUBLISH_BRANCH"
exit 1
fi
if [ -z "${PUBLISH_DIR}" ]; then
print_error "not found PUBLISH_DIR"
exit 1
fi
remote_branch="${PUBLISH_BRANCH}"
local_dir="${HOME}/ghpages_${RANDOM}"
if [[ "${INPUT_FORCEORPHAN}" == "true" ]]; then
print_info "force ophan: ${INPUT_FORCEORPHAN}"
cd "${PUBLISH_DIR}"
git init
git checkout --orphan "${remote_branch}"
elif git clone --depth=1 --single-branch --branch "${remote_branch}" "${remote_repo}" "${local_dir}"; then
cd "${local_dir}"
if [[ ${INPUT_KEEPFILES} == "true" ]]; then
print_info "Keeping existing files: ${INPUT_KEEPFILES}"
else
git rm -r --ignore-unmatch '*'
fi
find "${GITHUB_WORKSPACE}/${PUBLISH_DIR}" -maxdepth 1 -not -name ".git" -not -name ".github" | \
tail -n +2 | \
xargs -I % cp -rf % "${local_dir}/"
else
cd "${PUBLISH_DIR}"
git init
git checkout --orphan "${remote_branch}"
fi
# push to publishing branch
git config user.name "${GITHUB_ACTOR}"
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
git remote rm origin || true
git remote add origin "${remote_repo}"
git add --all
print_info "Allowing empty commits: ${INPUT_EMPTYCOMMITS}"
COMMIT_MESSAGE="Automated deployment: $(date -u) ${GITHUB_SHA}"
if [[ ${INPUT_EMPTYCOMMITS} == "false" ]]; then
git commit -m "${COMMIT_MESSAGE}" || skip
else
git commit --allow-empty -m "${COMMIT_MESSAGE}"
fi
if [[ ${INPUT_FORCEORPHAN} == "true" ]]; then
git push origin --force "${remote_branch}"
else
git push origin "${remote_branch}"
fi
print_info "${GITHUB_SHA} was successfully deployed"

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 42 KiB

11
jest.config.js Normal file
View File

@@ -0,0 +1,11 @@
module.exports = {
clearMocks: true,
moduleFileExtensions: ['js', 'ts'],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
testRunner: 'jest-circus/runner',
transform: {
'^.+\\.ts$': 'ts-jest'
},
verbose: true
}

28999
lib/index.js Normal file

File diff suppressed because it is too large Load Diff

7865
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

76
package.json Normal file
View File

@@ -0,0 +1,76 @@
{
"name": "actions-github-pages",
"version": "3.0.0",
"description": "GitHub Actions for GitHub Pages",
"main": "lib/index.js",
"engines": {
"node": ">=12.14.1",
"npm": ">=6.13.7"
},
"scripts": {
"lint": "eslint ./{src,__tests__}/**/*.ts",
"lint:fix": "eslint --fix ./{src,__tests__}/**/*.ts",
"test": "jest --coverage --verbose --detectOpenHandles",
"build": "ncc build ./src/index.ts -o lib",
"tsc": "tsc",
"format": "prettier --write **/*.ts",
"format:check": "prettier --check **/*.ts",
"release": "standard-version",
"update-deps": "(git diff 'HEAD@{1}' --name-only | grep 'package-lock.json' > /dev/null) && npm ci || :"
},
"husky": {
"skipCI": true,
"hooks": {
"pre-commit": "lint-staged",
"post-merge": "npm run update-deps; git remote prune origin"
}
},
"lint-staged": {
"src/**/*.ts": [
"prettier --check",
"eslint"
]
},
"repository": {
"type": "git",
"url": "git+https://github.com/peaceiris/actions-gh-pages.git"
},
"keywords": [
"GitHub Actions",
"Actions",
"JavaScript Action",
"TypeScript Action",
"GitHub Pages",
"gh-pages"
],
"author": "peaceiris",
"license": "MIT",
"bugs": {
"url": "https://github.com/peaceiris/actions-gh-pages/issues"
},
"homepage": "https://github.com/peaceiris/actions-gh-pages#readme",
"dependencies": {
"@actions/core": "^1.2.2",
"@actions/exec": "^1.0.3",
"@actions/github": "^2.1.0",
"@actions/glob": "^0.1.0",
"@actions/io": "^1.0.2"
},
"devDependencies": {
"@types/jest": "^25.1.1",
"@types/node": "^13.7.0",
"@typescript-eslint/eslint-plugin": "^2.19.0",
"@typescript-eslint/parser": "^2.19.0",
"@zeit/ncc": "^0.21.0",
"eslint": "^6.8.0",
"eslint-plugin-jest": "^23.6.0",
"husky": "^4.2.1",
"jest": "^25.1.0",
"jest-circus": "^25.1.0",
"lint-staged": "^10.0.7",
"prettier": "1.19.1",
"standard-version": "^7.1.0",
"ts-jest": "^25.2.0",
"typescript": "^3.7.5"
}
}

48
release.sh Executable file
View File

@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# fail on unset variables and command errors
set -eu -o pipefail # -x: is for debugging
if [ "$(git branch --show-current)" != "master" ]; then
echo "$0: Current branch is not master" 1>&2
exit 1
fi
RELEASE_TYPE_LIST="prerelease prepatch patch preminor minor major premajor"
if command -v fzf; then
RELEASE_TYPE=$(echo "${RELEASE_TYPE_LIST}" | tr ' ' '\n' | fzf --layout=reverse)
else
select sel in ${RELEASE_TYPE_LIST}; do
RELEASE_TYPE="${sel}"
break
done
fi
echo "$0: Create ${RELEASE_TYPE} release, continue? (y/n)"
read -r res
if [ "${res}" = "n" ]; then
echo "$0: Stop script"
exit 0
fi
git fetch origin
git pull origin master
git tag -d v3 || true
git pull origin --tags
npm ci
mkdir ./lib
npm run build
git add ./lib/index.js
git commit -m "chore(release): Add build assets"
npm run release -- --release-as "${RELEASE_TYPE}" --preset eslint
git rm ./lib/index.js
rm -rf ./lib
git commit -m "chore(release): Remove build assets [skip ci]"
TAG_NAME="v$(jq -r '.version' ./package.json)"
git push origin master
git push origin "${TAG_NAME}"

50
src/get-inputs.ts Normal file
View File

@@ -0,0 +1,50 @@
import * as core from '@actions/core';
import {Inputs} from './interfaces';
function showInputs(inps: Inputs): void {
if (inps.DeployKey) {
core.info(`[INFO] DeployKey: true`);
} else if (inps.GithubToken) {
core.info(`[INFO] GithubToken: true`);
} else if (inps.PersonalToken) {
core.info(`[INFO] PersonalToken: true`);
}
core.info(`[INFO] PublishBranch: ${inps.PublishBranch}`);
core.info(`[INFO] PublishDir: ${inps.PublishDir}`);
core.info(`[INFO] ExternalRepository: ${inps.ExternalRepository}`);
core.info(`[INFO] AllowEmptyCommit: ${inps.AllowEmptyCommit}`);
core.info(`[INFO] KeepFiles: ${inps.KeepFiles}`);
core.info(`[INFO] ForceOrphan: ${inps.ForceOrphan}`);
core.info(`[INFO] UserEmail: ${inps.UserEmail}`);
core.info(`[INFO] UserEmail: ${inps.UserEmail}`);
core.info(`[INFO] CommitMessage: ${inps.CommitMessage}`);
core.info(`[INFO] TagName: ${inps.TagName}`);
core.info(`[INFO] TagMessage: ${inps.TagMessage}`);
}
export function getInputs(): Inputs {
const inps: Inputs = {
DeployKey: core.getInput('deploy_key'),
GithubToken: core.getInput('github_token'),
PersonalToken: core.getInput('personal_token'),
PublishBranch: core.getInput('publish_branch'),
PublishDir: core.getInput('publish_dir'),
ExternalRepository: core.getInput('external_repository'),
AllowEmptyCommit:
(core.getInput('allow_empty_commit') || 'false').toUpperCase() === 'TRUE',
KeepFiles:
(core.getInput('keep_files') || 'false').toUpperCase() === 'TRUE',
ForceOrphan:
(core.getInput('force_orphan') || 'false').toUpperCase() === 'TRUE',
UserName: core.getInput('user_name'),
UserEmail: core.getInput('user_email'),
CommitMessage: core.getInput('commit_message'),
TagName: core.getInput('tag_name'),
TagMessage: core.getInput('tag_message')
};
showInputs(inps);
return inps;
}

187
src/git-utils.ts Normal file
View File

@@ -0,0 +1,187 @@
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as github from '@actions/github';
import * as io from '@actions/io';
import * as glob from '@actions/glob';
import path from 'path';
import {Inputs, CmdResult} from './interfaces';
import {getHomeDir} from './utils';
export async function createWorkDir(workDirName: string): Promise<void> {
await io.mkdirP(workDirName);
core.debug(`workDir was created: ${workDirName}`);
return;
}
export async function createBranchForce(branch: string): Promise<void> {
await exec.exec('git', ['init']);
await exec.exec('git', ['checkout', '--orphan', branch]);
return;
}
export async function copyAssets(
publishDir: string,
workDir: string
): Promise<void> {
const copyOpts = {recursive: true, force: false};
const globber = await glob.create(`${publishDir}/*`);
for await (const file of globber.globGenerator()) {
if (file.endsWith('.git') || file.endsWith('.github')) {
continue;
}
await io.cp(file, `${workDir}/`, copyOpts);
core.info(`[INFO] copy ${file}`);
}
return;
}
export async function setRepo(inps: Inputs, remoteURL: string): Promise<void> {
const workDir = path.join(getHomeDir(), 'actions_github_pages');
const publishDir = path.join(
`${process.env.GITHUB_WORKSPACE}`,
inps.PublishDir
);
core.info(`[INFO] ForceOrphan: ${inps.ForceOrphan}`);
if (inps.ForceOrphan) {
await createWorkDir(workDir);
process.chdir(workDir);
await createBranchForce(inps.PublishBranch);
await copyAssets(publishDir, workDir);
return;
}
const result: CmdResult = {
exitcode: 0,
output: ''
};
const options = {
listeners: {
stdout: (data: Buffer): void => {
result.output += data.toString();
}
}
};
result.exitcode = await exec.exec(
'git',
[
'clone',
'--depth=1',
'--single-branch',
'--branch',
inps.PublishBranch,
remoteURL,
workDir
],
options
);
process.chdir(workDir);
if (result.exitcode === 0) {
if (inps.KeepFiles) {
core.info('[INFO] Keep existing files');
} else {
await exec.exec('git', ['rm', '-r', '--ignore-unmatch', '*']);
}
await copyAssets(publishDir, workDir);
return;
} else {
core.info(
`[INFO] first deployment, create new branch ${inps.PublishBranch}`
);
await createWorkDir(workDir);
await createBranchForce(inps.PublishBranch);
await copyAssets(publishDir, workDir);
return;
}
}
export async function setConfig(
userName: string,
userEmail: string
): Promise<void> {
await exec.exec('git', ['config', '--global', 'gc.auto', '0']);
let name = '';
if (userName) {
name = userName;
} else {
name = `${process.env.GITHUB_ACTOR}`;
}
await exec.exec('git', ['config', '--global', 'user.name', name]);
let email = '';
if (userName !== '' && userEmail !== '') {
email = userEmail;
} else {
email = `${process.env.GITHUB_ACTOR}@users.noreply.github.com`;
}
await exec.exec('git', ['config', '--global', 'user.email', email]);
return;
}
export async function commit(
allowEmptyCommit: boolean,
externalRepository: string,
message: string
): Promise<void> {
let msg = '';
if (message) {
msg = message;
} else {
msg = 'deploy:';
}
const hash = `${process.env.GITHUB_SHA}`;
const baseRepo = `${github.context.repo.owner}/${github.context.repo.repo}`;
if (externalRepository) {
msg = `${msg} ${baseRepo}@${hash}`;
} else {
msg = `${msg} ${hash}`;
}
try {
if (allowEmptyCommit) {
await exec.exec('git', ['commit', '--allow-empty', '-m', `${msg}`]);
} else {
await exec.exec('git', ['commit', '-m', `${msg}`]);
}
} catch (e) {
core.info('[INFO] skip commit');
core.debug(`[INFO] skip commit ${e}`);
}
}
export async function push(
branch: string,
forceOrphan: boolean
): Promise<void> {
if (forceOrphan) {
await exec.exec('git', ['push', 'origin', '--force', branch]);
} else {
await exec.exec('git', ['push', 'origin', branch]);
}
}
export async function pushTag(
tagName: string,
tagMessage: string
): Promise<void> {
if (tagName === '') {
return;
}
let msg = '';
if (tagMessage) {
msg = tagMessage;
} else {
msg = `Deployment ${tagName}`;
}
await exec.exec('git', ['tag', '-a', `${tagName}`, '-m', `${msg}`]);
await exec.exec('git', ['push', 'origin', `${tagName}`]);
}

10
src/index.ts Normal file
View File

@@ -0,0 +1,10 @@
import * as core from '@actions/core';
import * as main from './main';
(async (): Promise<void> => {
try {
await main.run();
} catch (e) {
core.setFailed(`Action failed with "${e}"`);
}
})();

21
src/interfaces.ts Normal file
View File

@@ -0,0 +1,21 @@
export interface Inputs {
readonly DeployKey: string;
readonly GithubToken: string;
readonly PersonalToken: string;
readonly PublishBranch: string;
readonly PublishDir: string;
readonly ExternalRepository: string;
readonly AllowEmptyCommit: boolean;
readonly KeepFiles: boolean;
readonly ForceOrphan: boolean;
readonly UserName: string;
readonly UserEmail: string;
readonly CommitMessage: string;
readonly TagName: string;
readonly TagMessage: string;
}
export interface CmdResult {
exitcode: number;
output: string;
}

40
src/main.ts Normal file
View File

@@ -0,0 +1,40 @@
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import {Inputs} from './interfaces';
import {getInputs} from './get-inputs';
import {setTokens} from './set-tokens';
import * as git from './git-utils';
export async function run(): Promise<void> {
try {
const inps: Inputs = getInputs();
await git.setConfig(inps.UserName, inps.UserEmail);
const remoteURL = await setTokens(inps);
core.info(`[INFO] remoteURL: ${remoteURL}`); // TODO: remove
await git.setRepo(inps, remoteURL);
try {
await exec.exec('git', ['remote', 'rm', 'origin']);
} catch (e) {
core.info(`[INFO] e`);
}
await exec.exec('git', ['remote', 'add', 'origin', remoteURL]);
await exec.exec('git', ['add', '--all']);
await git.commit(
inps.AllowEmptyCommit,
inps.ExternalRepository,
inps.CommitMessage
);
await git.push(inps.PublishBranch, inps.ForceOrphan);
await git.pushTag(inps.TagName, inps.TagMessage);
core.info('[INFO] successfully deployed');
return;
} catch (e) {
throw new Error(e);
}
}

124
src/set-tokens.ts Normal file
View File

@@ -0,0 +1,124 @@
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as github from '@actions/github';
import * as io from '@actions/io';
import path from 'path';
import fs from 'fs';
const cpexec = require('child_process').execFileSync;
import {Inputs} from './interfaces';
export function setPublishRepo(insp: Inputs): string {
if (insp.ExternalRepository) {
return insp.ExternalRepository;
}
return `${github.context.repo.owner}/${github.context.repo.repo}`;
}
export async function setSSHKey(
inps: Inputs,
publishRepo: string
): Promise<string> {
core.info('[INFO] setup SSH deploy key');
const sshDir = path.join(`${process.env.HOME}`, '.ssh');
await io.mkdirP(sshDir);
await exec.exec('chmod', ['700', sshDir]);
const knownHosts = path.join(sshDir, 'known_hosts');
// ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts on Ubuntu
const cmdSSHkeyscanOutput = `\
# github.com:22 SSH-2.0-babeld-1f0633a6
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
`;
fs.writeFileSync(knownHosts, cmdSSHkeyscanOutput + '\n');
core.info(`[INFO] wrote ${knownHosts}`);
await exec.exec('chmod', ['600', knownHosts]);
const idRSA = path.join(sshDir, 'github');
fs.writeFileSync(idRSA, inps.DeployKey + '\n');
core.info(`[INFO] wrote ${idRSA}`);
await exec.exec('chmod', ['600', idRSA]);
const sshConfigPath = path.join(sshDir, 'config');
const sshConfigContent = `\
Host github
HostName github.com
IdentityFile ~/.ssh/github
User git
`;
fs.writeFileSync(sshConfigPath, sshConfigContent + '\n');
core.info(`[INFO] wrote ${sshConfigPath}`);
await exec.exec('chmod', ['600', sshConfigPath]);
await cpexec('ssh-agent', ['-a', '/tmp/ssh-auth.sock']);
core.exportVariable('SSH_AUTH_SOCK', '/tmp/ssh-auth.sock');
await exec.exec('ssh-add', [idRSA]);
return `git@github.com:${publishRepo}.git`;
}
export async function setGithubToken(
inps: Inputs,
publishRepo: string
): Promise<string> {
core.info('[INFO] setup GITHUB_TOKEN');
const context = github.context;
const payload = github.context.payload;
core.debug(`ref: ${context.ref}`);
core.debug(`eventName: ${context.eventName}`);
core.debug(`private: ${payload.repository?.private}`);
let isProhibitedBranch = false;
const ref = context.ref;
if (context.eventName === 'push') {
isProhibitedBranch = ref.includes(`refs/heads/${inps.PublishBranch}`);
if (isProhibitedBranch) {
throw new Error(
`You deploy from ${inps.PublishBranch} to ${inps.PublishBranch}`
);
}
} else if (context.eventName === 'pull_request') {
// TODO: support pull_request event
throw new Error('This action does not support pull_request event now.');
}
const isPrivateRepository = payload.repository?.private;
if (inps.ExternalRepository) {
throw new Error(
'GITHUB_TOKEN does not support to push to an external repository'
);
}
if (isPrivateRepository === false) {
core.warning(
'GITHUB_TOKEN does not support to trigger the GitHub Pages build event on a public repository'
);
}
return `https://x-access-token:${inps.GithubToken}@github.com/${publishRepo}.git`;
}
export async function setPersonalToken(
inps: Inputs,
publishRepo: string
): Promise<string> {
core.info('[INFO] setup personal access token');
return `https://x-access-token:${inps.PersonalToken}@github.com/${publishRepo}.git`;
}
export async function setTokens(inps: Inputs): Promise<string> {
try {
const publishRepo = setPublishRepo(inps);
if (inps.DeployKey) {
return setSSHKey(inps, publishRepo);
} else if (inps.GithubToken) {
return setGithubToken(inps, publishRepo);
} else if (inps.PersonalToken) {
return setPersonalToken(inps, publishRepo);
} else {
throw new Error('not found deploy key or tokens');
}
} catch (e) {
throw new Error(e);
}
}

15
src/utils.ts Normal file
View File

@@ -0,0 +1,15 @@
import * as core from '@actions/core';
export function getHomeDir(): string {
let homedir = '';
if (process.platform === 'win32') {
homedir = process.env['USERPROFILE'] || 'C:\\';
} else {
homedir = `${process.env.HOME}`;
}
core.debug(`homeDir: ${homedir}`);
return homedir;
}

1
test_projects/mdbook/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
book

View File

@@ -0,0 +1,6 @@
[book]
authors = ["peaceiris"]
language = "en"
multilingual = false
src = "src"
title = "GitHub Actions for GitHub Pages"

View File

@@ -0,0 +1,3 @@
# Summary
- [Chapter 1](./chapter_1.md)

View File

@@ -0,0 +1,3 @@
# Chapter 1
test 7

65
tsconfig.json Normal file
View File

@@ -0,0 +1,65 @@
{
"compilerOptions": {
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./lib", /* Redirect output structure to the directory. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
"removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
"resolveJsonModule": true
},
"exclude": ["node_modules", "**/*.test.ts"]
}