DEV: introduces Github Actions for CI (#8441)

Co-Authored-By: David Taylor <david@taylorhq.com>
This commit is contained in:
Joffrey JAFFEUX 2019-12-10 14:45:47 +01:00 committed by GitHub
parent dfb9fa3b98
commit bd17a3a8e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 292 additions and 0 deletions

150
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,150 @@
name: CI
on: [push]
jobs:
build:
name: "${{ matrix.target }}-${{ matrix.build_types }}"
runs-on: ${{ matrix.os }}
env:
DISCOURSE_HOSTNAME: www.example.com
RUBY_GLOBAL_METHOD_CACHE_SIZE: 131072
BUILD_TYPE: ${{ matrix.build_types }}
TARGET: ${{ matrix.target }}
RAILS_ENV: test
PGHOST: localhost
PGUSER: discourse
PGPASSWORD: discourse
strategy:
fail-fast: false
matrix:
build_types: [ 'BACKEND', 'FRONTEND', 'LINT' ]
target: [ 'PLUGINS', 'CORE' ]
os: [ ubuntu-latest ]
ruby: [ '2.6.3' ]
postgres: [ '10' ]
redis: [ '4.x' ]
services:
postgres:
image: postgres:${{ matrix.postgres }}
ports:
- 5432:5432
env:
POSTGRES_USER: discourse
POSTGRES_PASSWORD: discourse
POSTGRES_DB: discourse_test
options: >-
--mount type=tmpfs,destination=/var/lib/postgresql/data
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@master
with:
fetch-depth: 1
- name: Setup Git
run: git config --global user.email "ci@ci.invalid" && git config --global user.name "Discourse CI"
- name: Setup packages
if: env.BUILD_TYPE != 'LINT'
run: |
sudo apt-get -yqq install postgresql-client libpq-dev gifsicle jpegoptim optipng jhead && \
wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/master/image/base/install-pngquant | sudo sh
- name: Setup redis
uses: shogo82148/actions-setup-redis@v1
if: env.BUILD_TYPE != 'LINT'
with:
redis-version: ${{ matrix.redis }}
- name: Setup ruby
uses: actions/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
architecture: 'x64'
- name: Setup bundler
run: gem install bundler -v 1.17.3 --no-doc
- name: Bundler cache
uses: actions/cache@v1
id: bundler-cache
with:
path: vendor/bundle
key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gem-
- name: Setup gems
run: bundle install --without development --deployment --jobs 4 --retry 3
- name: Get yarn cache directory
id: yarn-cache-dir
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Yarn cache
uses: actions/cache@v1
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir.outputs.dir }}
key: ${{ runner.os }}-${{ matrix.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ matrix.os }}-yarn-
- name: Yarn install
run: yarn install --dev
- name: "Checkout official plugins"
if: env.TARGET == 'PLUGINS'
run: bin/rake plugin:install_all_official
- name: Create database
if: env.BUILD_TYPE != 'LINT'
run: bin/rake db:create && bin/rake db:migrate
- name: Create parallel databases
if: env.BUILD_TYPE == 'BACKEND' && env.TARGET == 'CORE'
run: bin/rake parallel:create && bin/rake parallel:migrate
- name: Rubocop
if: env.BUILD_TYPE == 'LINT'
run: ruby script/rubocop_github_action.rb
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JOB_NAME: ${{ matrix.target }}-${{ matrix.build_types }} / Rubocop
- name: ESLint
if: env.BUILD_TYPE == 'LINT'
run: yarn eslint app/assets/javascripts test/javascripts && yarn eslint --ext .es6 app/assets/javascripts test/javascripts plugins
- name: Prettier
if: env.BUILD_TYPE == 'LINT'
run: yarn prettier --list-different "app/assets/stylesheets/**/*.scss" "app/assets/javascripts/**/*.es6" "test/javascripts/**/*.es6" "plugins/**/*.scss" "plugins/**/*.es6"
- name: Core RSpec
if: env.BUILD_TYPE == 'BACKEND' && env.TARGET == 'CORE'
run: bin/turbo_rspec && bin/rake plugin:spec
- name: Plugin RSpec
if: env.BUILD_TYPE == 'BACKEND' && env.TARGET == 'PLUGINS'
run: bin/rake plugin:spec
- name: Core QUnit
if: env.BUILD_TYPE == 'FRONTEND' && env.TARGET == 'CORE'
run: bundle exec rake qunit:test['1200000']
- name: Wizard QUnit
if: env.BUILD_TYPE == 'FRONTEND' && env.TARGET == 'CORE'
run: bundle exec rake qunit:test['1200000','/wizard/qunit']
- name: Plugin QUnit # Tests core plugins in TARGET=CORE, and all plugins in TARGET=PLUGINS
if: env.BUILD_TYPE == 'FRONTEND'
run: bundle exec rake plugin:qunit

View File

@ -0,0 +1,142 @@
# frozen_string_literal: true
# Adapted from https://github.com/gimenete/rubocop-action/blob/master/lib/index.rb
require 'net/http'
require 'json'
require 'time'
@GITHUB_SHA = ENV["GITHUB_SHA"]
@GITHUB_EVENT_PATH = ENV["GITHUB_EVENT_PATH"]
@GITHUB_TOKEN = ENV["GITHUB_TOKEN"]
@GITHUB_WORKSPACE = ENV["GITHUB_WORKSPACE"]
@event = JSON.parse(File.read(ENV["GITHUB_EVENT_PATH"]))
@repository = @event["repository"]
@owner = @repository["owner"]["login"]
@repo = @repository["name"]
@check_name = ENV["JOB_NAME"]
@headers = {
"Content-Type": 'application/json',
"Accept": 'application/vnd.github.antiope-preview+json',
"Authorization": "Bearer #{@GITHUB_TOKEN}",
"User-Agent": 'rubocop-action'
}
def create_check
body = {
"name" => @check_name,
"head_sha" => @GITHUB_SHA,
"status" => "in_progress",
"started_at" => Time.now.iso8601
}
http = Net::HTTP.new('api.github.com', 443)
http.use_ssl = true
path = "/repos/#{@owner}/#{@repo}/check-runs"
resp = http.post(path, body.to_json, @headers)
if resp.code.to_i >= 300
raise resp.message
end
data = JSON.parse(resp.body)
data["id"]
end
def update_check(id, conclusion, output)
body = {
"name" => @check_name,
"head_sha" => @GITHUB_SHA,
"status" => 'completed',
"completed_at" => Time.now.iso8601,
"conclusion" => conclusion,
"output" => output
}
http = Net::HTTP.new('api.github.com', 443)
http.use_ssl = true
path = "/repos/#{@owner}/#{@repo}/check-runs/#{id}"
resp = http.patch(path, body.to_json, @headers)
if resp.code.to_i >= 300
raise resp.message
end
end
@annotation_levels = {
"refactor" => 'failure',
"convention" => 'failure',
"warning" => 'warning',
"error" => 'failure',
"fatal" => 'failure'
}
def run_rubocop
annotations = []
errors = nil
Dir.chdir(@GITHUB_WORKSPACE) { # rubocop:disable DiscourseCops/NoChdir because this is not part of the app
errors = JSON.parse(`bundle exec rubocop --parallel --format json .`)
}
conclusion = "success"
count = 0
errors["files"].each do |file|
path = file["path"]
offenses = file["offenses"]
offenses.each do |offense|
severity = offense["severity"]
message = offense["message"]
location = offense["location"]
annotation_level = @annotation_levels[severity]
count = count + 1
if annotation_level == "failure"
conclusion = "failure"
end
annotations.push(
"path" => path,
"start_line" => location["start_line"],
"end_line" => location["start_line"],
"annotation_level": annotation_level,
"message" => message
)
end
end
output = {
"title": @check_name,
"summary": "#{count} offense(s) found",
"annotations" => annotations
}
{ "output" => output, "conclusion" => conclusion }
end
def run
id = create_check()
begin
results = run_rubocop()
conclusion = results["conclusion"]
output = results["output"]
update_check(id, conclusion, output)
if conclusion == "failure"
puts "Rubocop Failed: #{output["summary"]}"
exit 1
end
rescue
update_check(id, "failure", nil)
puts "Rubocop Errored"
exit 1
end
end
run()