diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 00000000..7898fbf8
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,3 @@
+{
+ "extends": "eslint-config-discourse"
+}
diff --git a/.github/workflows/plugin-linting.yml b/.github/workflows/plugin-linting.yml
new file mode 100644
index 00000000..a121658d
--- /dev/null
+++ b/.github/workflows/plugin-linting.yml
@@ -0,0 +1,53 @@
+name: Linting
+
+on:
+ push:
+ branches:
+ - master
+ - main
+ pull_request:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v1
+ with:
+ node-version: 12
+
+ - name: Set up ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: 2.7
+
+ - name: Setup bundler
+ run: gem install bundler -v 2.1.4 --no-doc
+
+ - name: Setup gems
+ run: bundle install --jobs 4
+
+ - name: Yarn install
+ run: yarn install --dev
+
+ - name: ESLint
+ run: yarn eslint --ext .js,.js.es6 --no-error-on-unmatched-pattern {test,assets}/javascripts
+
+ - name: Prettier
+ run: |
+ yarn prettier -v
+ if [ -d "assets" ]; then \
+ yarn prettier --list-different "assets/**/*.{scss,js,es6}" ; \
+ fi
+ if [ -d "test" ]; then \
+ yarn prettier --list-different "test/**/*.{js,es6}" ; \
+ fi
+
+ - name: Ember template lint
+ run: yarn ember-template-lint assets/javascripts
+
+ - name: Rubocop
+ run: bundle exec rubocop .
\ No newline at end of file
diff --git a/.github/workflows/plugin-tests.yml b/.github/workflows/plugin-tests.yml
new file mode 100644
index 00000000..ce6112af
--- /dev/null
+++ b/.github/workflows/plugin-tests.yml
@@ -0,0 +1,137 @@
+name: Plugin Tests
+
+on:
+ push:
+ branches:
+ - master
+ - main
+ pull_request:
+
+jobs:
+ build:
+ name: ${{ matrix.build_type }}
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+
+ env:
+ DISCOURSE_HOSTNAME: www.example.com
+ RUBY_GLOBAL_METHOD_CACHE_SIZE: 131072
+ RAILS_ENV: test
+ PGHOST: localhost
+ PGUSER: discourse
+ PGPASSWORD: discourse
+
+ strategy:
+ fail-fast: false
+
+ matrix:
+ build_type: ["backend", "frontend"]
+ ruby: ["2.7"]
+ postgres: ["12"]
+ redis: ["4.x"]
+
+ services:
+ postgres:
+ image: postgres:${{ matrix.postgres }}
+ ports:
+ - 5432:5432
+ env:
+ POSTGRES_USER: discourse
+ POSTGRES_PASSWORD: discourse
+ 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@v2
+ with:
+ repository: discourse/discourse
+ fetch-depth: 1
+
+ - name: Install plugin
+ uses: actions/checkout@v2
+ with:
+ path: plugins/${{ github.event.repository.name }}
+ fetch-depth: 1
+
+ - name: Check spec existence
+ id: check_spec
+ uses: andstor/file-existence-action@v1
+ with:
+ files: "plugins/${{ github.event.repository.name }}/spec"
+
+ - name: Check qunit existence
+ id: check_qunit
+ uses: andstor/file-existence-action@v1
+ with:
+ files: "plugins/${{ github.event.repository.name }}/test/javascripts"
+
+ - name: Setup Git
+ run: |
+ git config --global user.email "ci@ci.invalid"
+ git config --global user.name "Discourse CI"
+
+ - name: Setup packages
+ run: |
+ sudo apt-get update
+ 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: Update imagemagick
+ if: matrix.build_type == 'backend'
+ run: |
+ wget https://raw.githubusercontent.com/discourse/discourse_docker/master/image/base/install-imagemagick
+ chmod +x install-imagemagick
+ sudo ./install-imagemagick
+
+ - name: Setup redis
+ uses: shogo82148/actions-setup-redis@v1
+ with:
+ redis-version: ${{ matrix.redis }}
+
+ - name: Setup ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: ${{ matrix.ruby }}
+ bundler-cache: true
+
+ - name: Lint English locale
+ if: matrix.build_type == 'backend'
+ run: bundle exec ruby script/i18n_lint.rb "plugins/${{ github.event.repository.name }}/locales/{client,server}.en.yml"
+
+ - name: Get yarn cache directory
+ id: yarn-cache-dir
+ run: echo "::set-output name=dir::$(yarn cache dir)"
+
+ - name: Yarn cache
+ uses: actions/cache@v2
+ 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: Migrate database
+ run: |
+ bin/rake db:create
+ bin/rake db:migrate
+
+ - name: Plugin RSpec
+ if: matrix.build_type == 'backend' && steps.check_spec.outputs.files_exists == 'true'
+ run: bin/rake plugin:spec[${{ github.event.repository.name }}]
+
+ - name: Plugin QUnit
+ if: matrix.build_type == 'frontend' && steps.check_qunit.outputs.files_exists == 'true'
+ run: bundle exec rake plugin:qunit['${{ github.event.repository.name }}','1200000']
+ timeout-minutes: 30
+
+ - name: Simplecov Report
+ if: matrix.build_type == 'backend'
+ run: COVERAGE=1 bin/rake plugin:spec[${{ github.event.repository.name }}]
diff --git a/.gitignore b/.gitignore
index 98902d6e..11ce0a3c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,7 @@
coverage/*
!coverage/.last_run.json
gems/
+.bundle/
+auto_generated
+.DS_Store
+node_modules/
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 00000000..0967ef42
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1 @@
+{}
diff --git a/.rubocop.yml b/.rubocop.yml
new file mode 100644
index 00000000..d46296cf
--- /dev/null
+++ b/.rubocop.yml
@@ -0,0 +1,2 @@
+inherit_gem:
+ rubocop-discourse: default.yml
diff --git a/.template-lintrc.js b/.template-lintrc.js
new file mode 100644
index 00000000..a558b8e3
--- /dev/null
+++ b/.template-lintrc.js
@@ -0,0 +1,4 @@
+module.exports = {
+ plugins: ["ember-template-lint-plugin-discourse"],
+ extends: "discourse:recommended",
+};
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 00000000..7da32ec0
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+source 'https://rubygems.org'
+
+group :development do
+ gem 'rubocop-discourse'
+end
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 00000000..2416ce66
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,38 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ ast (2.4.2)
+ parallel (1.20.1)
+ parser (3.0.1.0)
+ ast (~> 2.4.1)
+ rainbow (3.0.0)
+ regexp_parser (2.1.1)
+ rexml (3.2.5)
+ rubocop (1.12.1)
+ parallel (~> 1.10)
+ parser (>= 3.0.0.0)
+ rainbow (>= 2.2.2, < 4.0)
+ regexp_parser (>= 1.8, < 3.0)
+ rexml
+ rubocop-ast (>= 1.2.0, < 2.0)
+ ruby-progressbar (~> 1.7)
+ unicode-display_width (>= 1.4.0, < 3.0)
+ rubocop-ast (1.4.1)
+ parser (>= 2.7.1.5)
+ rubocop-discourse (2.4.1)
+ rubocop (>= 1.1.0)
+ rubocop-rspec (>= 2.0.0)
+ rubocop-rspec (2.2.0)
+ rubocop (~> 1.0)
+ rubocop-ast (>= 1.1.0)
+ ruby-progressbar (1.11.0)
+ unicode-display_width (2.0.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ rubocop-discourse
+
+BUNDLED WITH
+ 2.2.16
diff --git a/assets/javascripts/discourse/connectors/admin-menu/wizards-nav-button.hbs b/assets/javascripts/discourse/connectors/admin-menu/wizards-nav-button.hbs
index 5398e27d..f76722fc 100644
--- a/assets/javascripts/discourse/connectors/admin-menu/wizards-nav-button.hbs
+++ b/assets/javascripts/discourse/connectors/admin-menu/wizards-nav-button.hbs
@@ -1,3 +1,3 @@
{{#if currentUser.admin}}
- {{nav-item route='adminWizards' label='admin.wizard.nav_label'}}
+ {{nav-item route="adminWizards" label="admin.wizard.nav_label"}}
{{/if}}
diff --git a/assets/javascripts/discourse/connectors/top-notices/prompt-completion.hbs b/assets/javascripts/discourse/connectors/top-notices/prompt-completion.hbs
index 503ee113..70c0b7c4 100644
--- a/assets/javascripts/discourse/connectors/top-notices/prompt-completion.hbs
+++ b/assets/javascripts/discourse/connectors/top-notices/prompt-completion.hbs
@@ -1,7 +1,7 @@
{{#each site.complete_custom_wizard as |wizard|}}
-
-
-
{{i18n 'wizard.complete_custom' name=wizard.name}}
+
-{{/each}}
\ No newline at end of file
+{{/each}}
diff --git a/assets/javascripts/discourse/templates/admin-wizards-api-show.hbs b/assets/javascripts/discourse/templates/admin-wizards-api-show.hbs
index 465e11aa..4d3def3d 100644
--- a/assets/javascripts/discourse/templates/admin-wizards-api-show.hbs
+++ b/assets/javascripts/discourse/templates/admin-wizards-api-show.hbs
@@ -1,5 +1,5 @@