├── .github ├── dependabot.yml └── workflows │ ├── jekyll-deploy.yml │ └── jekyll-test.yml ├── README.md ├── action.yml ├── deployer ├── Dockerfile └── entrypoint.rb └── tests ├── .gitignore ├── 404.html ├── CNAME ├── Gemfile ├── Gemfile.lock ├── _config.yml ├── _posts └── 2020-08-26-welcome-to-jekyll.markdown ├── about.markdown └── index.markdown /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: bundler 4 | directory: "/tests" 5 | schedule: 6 | interval: weekly 7 | open-pull-requests-limit: 10 8 | -------------------------------------------------------------------------------- /.github/workflows/jekyll-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Jekyll Deploy 2 | 3 | # Controls when the action will run. Triggers the workflow on push or pull request 4 | # events but only for the master branch 5 | on: 6 | push: 7 | branches: 8 | # deploy on updates on main 9 | - main 10 | schedule: 11 | # redeploy every morning to update unpublished pages 12 | - cron: "0 2 * * *" 13 | 14 | jobs: 15 | deploy: 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - name: Cache gems 22 | uses: actions/cache@v1 23 | with: 24 | path: tests/vendor/gems 25 | key: ${{ runner.os }}-build-${{ hashFiles('**/Gemfile.lock') }} 26 | restore-keys: | 27 | ${{ runner.os }}-build- 28 | ${{ runner.os }}- 29 | 30 | - name: Build & Deploy to GitHub Pages 31 | uses: DavidS/jekyll-deploy@main 32 | with: 33 | source-dir: tests 34 | target-branch: deploy 35 | env: 36 | JEKYLL_ENV: production 37 | GH_PAGES_TOKEN: ${{ secrets.GH_PAGES_TOKEN }} 38 | -------------------------------------------------------------------------------- /.github/workflows/jekyll-test.yml: -------------------------------------------------------------------------------- 1 | name: Jekyll Test 2 | 3 | on: [ pull_request ] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | 12 | - name: Cache gems 13 | uses: actions/cache@v1 14 | with: 15 | path: tests/vendor/gems 16 | key: ${{ runner.os }}-build-${{ hashFiles('**/Gemfile.lock') }} 17 | restore-keys: | 18 | ${{ runner.os }}-build- 19 | ${{ runner.os }}- 20 | 21 | - name: Test using current SHA 22 | uses: ./ 23 | with: 24 | source-dir: tests 25 | build-only: true 26 | env: 27 | JEKYLL_ENV: production 28 | 29 | - name: Test deploy using current SHA 30 | uses: ./ 31 | with: 32 | source-dir: tests 33 | target-branch: deploy 34 | env: 35 | JEKYLL_ENV: production 36 | GH_PAGES_TOKEN: ${{ secrets.GH_PAGES_TOKEN }} 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jekyll-deploy 2 | 3 | Builds and deploys a jekyll page to GitHub pages. 4 | 5 | Features: 6 | * build and test modes 7 | * record the site's source commit using a merge commit 8 | * build from any subdirectory in your repository 9 | * specify a target branch 10 | 11 | ## Usage 12 | 13 | To deploy every update to the `main` branch and regenerate the site once a day: 14 | 15 | ```yaml 16 | name: Jekyll Deploy 17 | 18 | on: 19 | push: 20 | branches: 21 | # deploy on updates on main 22 | - main 23 | schedule: 24 | # redeploy every morning to update unpublished pages 25 | - cron: "0 2 * * *" 26 | 27 | jobs: 28 | deploy: 29 | runs-on: ubuntu-latest 30 | 31 | steps: 32 | - uses: actions/checkout@v2 33 | 34 | - name: Cache gems 35 | uses: actions/cache@v1 36 | with: 37 | path: vendor/gems 38 | key: ${{ runner.os }}-build-${{ hashFiles('**/Gemfile.lock') }} 39 | restore-keys: | 40 | ${{ runner.os }}-build- 41 | ${{ runner.os }}- 42 | 43 | - name: Build & Deploy to GitHub Pages 44 | uses: DavidS/jekyll-deploy@main 45 | env: 46 | JEKYLL_ENV: production 47 | GH_PAGES_TOKEN: ${{ secrets.GH_PAGES_TOKEN }} 48 | ``` 49 | 50 | To check PRs, set `build-only: true`: 51 | 52 | ```yaml 53 | name: Jekyll Test 54 | 55 | on: [ pull_request ] 56 | 57 | jobs: 58 | test: 59 | runs-on: ubuntu-latest 60 | 61 | steps: 62 | - uses: actions/checkout@v2 63 | 64 | - name: Cache gems 65 | uses: actions/cache@v1 66 | with: 67 | path: vendor/gems 68 | key: ${{ runner.os }}-build-${{ hashFiles('**/Gemfile.lock') }} 69 | restore-keys: | 70 | ${{ runner.os }}-build- 71 | ${{ runner.os }}- 72 | 73 | - name: Test 74 | uses: DavidS/jekyll-deploy@ 75 | with: 76 | build-only: true 77 | env: 78 | JEKYLL_ENV: production 79 | GH_PAGES_TOKEN: ${{ secrets.GH_PAGES_TOKEN }} 80 | ``` 81 | 82 | The `GH_PAGES_TOKEN` needs the `public_repo` scope to be able to trigger deployments on a public repo or the full `repo` scope to deploy a private repository. Please note that this is circumventing GitHub's protection for infinitely recursive Actions invocations, so proceed with caution! 83 | 84 | ## Specifying a source directory 85 | 86 | If your site's source is not at the root of the repository, you can use the `source-dir` input to tell this action where the source can be found. For example, if your site is in a `docs/jekyll` subdirectory: 87 | 88 | ```yaml 89 | - name: Build & Deploy to custom branch 90 | uses: DavidS/jekyll-deploy@ 91 | with: 92 | source-dir: docs/jekyll 93 | env: 94 | JEKYLL_ENV: production 95 | GH_PAGES_TOKEN: ${{ secrets.GH_PAGES_TOKEN }} 96 | ``` 97 | 98 | 99 | ## Specifying a target branch 100 | 101 | By default, this action deploys the compiled output to `gh-pages`, GitHub's default. If you want to use a different branch, you can use the `target-branch` input to do so. For example, to deploy to `docs`: 102 | 103 | ```yaml 104 | - name: Build & Deploy to custom branch 105 | uses: DavidS/jekyll-deploy@main 106 | with: 107 | target-branch: docs 108 | env: 109 | JEKYLL_ENV: production 110 | GH_PAGES_TOKEN: ${{ secrets.GH_PAGES_TOKEN }} 111 | ``` 112 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: jekyll-deploy 2 | description: "Builds and deploys a jekyll page to GitHub pages" 3 | branding: 4 | icon: "chevrons-right" 5 | color: "gray-dark" 6 | runs: 7 | using: "docker" 8 | image: "deployer/Dockerfile" 9 | inputs: 10 | build-only: 11 | description: Set to "true" to only build, but not deploy. This is useful for PR testing. 12 | required: false 13 | default: "false" 14 | adjust-last-modified: 15 | description: By default this action clamps last-modified times to the date of the last commit modifying it. This reduces the amount of churn of updating timestamps in the rendered files. Set this to "false" to use the build time instead. 16 | required: false 17 | default: "true" 18 | source-dir: 19 | description: Specify a subdirectory containing the jekyll site, relative to the root of the repository. If this is not specified, the site is expected to be in the root of the repository. 20 | required: false 21 | default: . 22 | target-branch: 23 | description: Specify the branch to deploy the site to. By default, this is "gh-pages", GitHub's default branch for doc sites. 24 | required: false 25 | default: "gh-pages" 26 | -------------------------------------------------------------------------------- /deployer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:2.6 2 | LABEL "com.github.actions.name"="Jekyll Deploy" 3 | LABEL "com.github.actions.description"="Builds and deploys a jekyll page to GitHub pages" 4 | LABEL "com.github.actions.icon"="chevrons-right" 5 | LABEL "com.github.actions.color"="gray-dark" 6 | 7 | RUN gem install bundler -v 2.1.4 \ 8 | && apt update \ 9 | && apt install -y git-restore-mtime \ 10 | && apt clean \ 11 | && rm -rf /var/lib/apt/lists/* 12 | 13 | ADD entrypoint.rb /entrypoint.rb 14 | ENTRYPOINT ["/entrypoint.rb"] 15 | -------------------------------------------------------------------------------- /deployer/entrypoint.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require 'English' 5 | require 'fileutils' 6 | 7 | def system_or_fail(*cmd) 8 | puts "executing #{cmd.inspect}" 9 | if system(*cmd) 10 | puts "executed #{cmd.inspect} successfully" 11 | else 12 | puts "execution failed with '#{$CHILD_STATUS}'" 13 | exit $CHILD_STATUS.exitstatus 14 | end 15 | end 16 | 17 | basedir = Dir.pwd 18 | 19 | if ENV['INPUT_ADJUST-LAST-MODIFIED'] == "true" 20 | # help jekyll with stable last modified times to avoid churning timestamps 21 | puts "Adjusting mtime/last modified times" 22 | system_or_fail('git', 'restore-mtime', '--merge', ENV['INPUT_SOURCE-DIR']) 23 | else 24 | puts "Adjusting mtime/last modified times disabled in config" 25 | end 26 | 27 | Dir.chdir(ENV['INPUT_SOURCE-DIR']) 28 | sourcedir = Dir.pwd 29 | 30 | system_or_fail('bundle', 'config', 'set', 'path', 'vendor/gems') 31 | system_or_fail('bundle', 'config', 'set', 'deployment', 'true') 32 | system_or_fail('bundle', 'install', '--jobs=4', '--retry=3') 33 | 34 | if ENV['INPUT_BUILD-ONLY'] == "true" 35 | system_or_fail('bundle', 'exec', 'jekyll', 'build', '--future', '--verbose', '--trace') 36 | exit 37 | else 38 | system_or_fail('bundle', 'exec', 'jekyll', 'build', '--verbose', '--trace') 39 | end 40 | 41 | Dir.chdir('_site') 42 | File.open('.nojekyll', 'w') { |f| f.puts 'Skip Jekyll' } 43 | 44 | system_or_fail('git', 'init', '.') 45 | FileUtils.cp(File.join(basedir, '/.git/config'), '.git/config') 46 | system_or_fail('git', 'config', 'user.name', ENV['GITHUB_ACTOR']) 47 | system_or_fail('git', 'config', 'user.email', "#{ENV['GITHUB_ACTOR']}@users.noreply.github.com") 48 | system_or_fail('git', 'fetch', '--no-tags', '--no-recurse-submodules', 'origin', "+#{ENV['GITHUB_SHA']}:refs/remotes/origin/source") 49 | if %x(git ls-remote --heads origin) =~ %r{\trefs/heads/#{ENV['INPUT_TARGET-BRANCH']}\n} 50 | puts "Found target branch '#{ENV['INPUT_TARGET-BRANCH']}', using that as base" 51 | system_or_fail('git', 'fetch', '--no-tags', '--no-recurse-submodules', 'origin', "+#{ENV['INPUT_TARGET-BRANCH']}:refs/remotes/origin/#{ENV['INPUT_TARGET-BRANCH']}") 52 | system_or_fail('git', 'reset', '--soft', "origin/#{ENV['INPUT_TARGET-BRANCH']}") 53 | else 54 | puts "Didn't find target branch '#{ENV['INPUT_TARGET-BRANCH']}', using the source as a base" 55 | system_or_fail('git', 'reset', '--soft', "origin/source") 56 | end 57 | 58 | if File.exist?(File.join(sourcedir, 'CNAME')) && !File.exist?('CNAME') 59 | puts "Rendering github's CNAME file" 60 | FileUtils.cp(File.join(sourcedir, 'CNAME'), 'CNAME') 61 | end 62 | 63 | system_or_fail('git', 'add', '-A', '.') 64 | system_or_fail('git', 'commit', '-m', 'Update github pages') 65 | system_or_fail('git', 'merge', '-s', 'ours', 'origin/source') 66 | system_or_fail('git', 'push', 'origin', "HEAD:#{ENV['INPUT_TARGET-BRANCH']}") 67 | 68 | puts "triggering a github pages deploy" 69 | 70 | require 'net/http' 71 | result = Net::HTTP.post( 72 | URI("https://api.github.com/repos/#{ENV['GITHUB_REPOSITORY']}/pages/builds"), 73 | "", 74 | "Content-Type" => "application/json", 75 | "Authorization" => "token #{ENV['GH_PAGES_TOKEN']}", 76 | ) 77 | 78 | puts result.body 79 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | .sass-cache 3 | .jekyll-cache 4 | .jekyll-metadata 5 | vendor 6 | -------------------------------------------------------------------------------- /tests/404.html: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: /404.html 3 | layout: default 4 | --- 5 | 6 | 19 | 20 |
Page not found :(
24 |The requested page could not be found.
25 |