Skip to content

Commit 58cf6a4

Browse files
committed
add workflow that also supports pnpm
1 parent 0a60109 commit 58cf6a4

File tree

1 file changed

+348
-0
lines changed

1 file changed

+348
-0
lines changed
Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
name: Discourse Plugin with pnpm and yarn
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
repository:
7+
type: string
8+
required: false
9+
name:
10+
type: string
11+
required: false
12+
core_ref:
13+
type: string
14+
required: false
15+
secrets:
16+
ssh_private_key:
17+
description: "Optional SSH private key to be used when cloning additional plugin repos"
18+
required: false
19+
20+
concurrency:
21+
group: discourse-plugin-${{ format('{0}-{1}-{2}', github.head_ref || github.run_number, github.job, inputs.core_ref) }}
22+
cancel-in-progress: true
23+
24+
jobs:
25+
linting:
26+
runs-on: ubuntu-latest
27+
28+
steps:
29+
- uses: actions/checkout@v4
30+
with:
31+
repository: ${{ inputs.repository }}
32+
33+
- name: Determine JS package manager
34+
id: js-pkg-manager
35+
run: |
36+
if [ -f yarn.lock ]; then
37+
echo "Using Yarn"
38+
echo "manager=yarn" >> $GITHUB_OUTPUT
39+
else
40+
echo "Using pnpm"
41+
echo "manager=pnpm" >> $GITHUB_OUTPUT
42+
fi
43+
44+
- name: Install package manager
45+
run: npm install -g ${{ steps.js-pkg-manager.outputs.manager }}
46+
47+
- name: Set up Node.js
48+
uses: actions/setup-node@v4
49+
with:
50+
node-version: 20
51+
cache: ${{ steps.js-pkg-manager.outputs.manager }}
52+
53+
- name: Install JS dependencies
54+
run: ${{ steps.js-pkg-manager.outputs.manager }} install --frozen-lockfile
55+
56+
- name: Set up ruby
57+
uses: ruby/setup-ruby@v1
58+
with:
59+
ruby-version: "3.2"
60+
bundler-cache: true
61+
62+
- name: ESLint
63+
if: ${{ !cancelled() }}
64+
run: |
65+
if test -f .prettierrc.cjs; then
66+
${{ steps.js-pkg-manager.outputs.manager }} eslint --ext .js,.gjs,.js.es6 --no-error-on-unmatched-pattern {test,assets,admin/assets}/javascripts
67+
else
68+
${{ steps.js-pkg-manager.outputs.manager }} eslint --ext .js,.js.es6 --no-error-on-unmatched-pattern {test,assets,admin/assets}/javascripts
69+
fi
70+
71+
- name: Prettier
72+
if: ${{ !cancelled() }}
73+
shell: bash
74+
run: |
75+
${{ steps.js-pkg-manager.outputs.manager }} prettier -v
76+
if [ -n "$(find assets -type f \( -name "*.scss" -or -name "*.js" -or -name "*.gjs" -or -name "*.es6" -or -name "*.hbs" \) 2>/dev/null)" ]; then
77+
${{ steps.js-pkg-manager.outputs.manager }} prettier --list-different "assets/**/*.{scss,js,gjs,es6,hbs}"
78+
fi
79+
if [ -n "$(find admin/assets -type f \( -name "*.scss" -or -name "*.js" -or -name "*.gjs" -or -name "*.es6" -or -name "*.hbs" \) 2>/dev/null)" ]; then
80+
${{ steps.js-pkg-manager.outputs.manager }} prettier --list-different "admin/assets/**/*.{scss,js,gjs,es6,hbs}"
81+
fi
82+
if [ 0 -lt $(find test -type f \( -name "*.js" -or -name "*.gjs" -or -name "*.es6" \) 2> /dev/null | wc -l) ]; then
83+
${{ steps.js-pkg-manager.outputs.manager }} prettier --list-different "test/**/*.{js,gjs,es6}"
84+
fi
85+
86+
- name: Ember template lint
87+
if: ${{ !cancelled() }}
88+
run: ${{ steps.js-pkg-manager.outputs.manager }} ember-template-lint --no-error-on-unmatched-pattern assets/javascripts
89+
90+
# Separated due to https://github.com/ember-template-lint/ember-template-lint/issues/2758
91+
- name: Ember template lint (admin)
92+
if: ${{ !cancelled() }}
93+
run: ${{ steps.js-pkg-manager.outputs.manager }} ember-template-lint --no-error-on-unmatched-pattern admin/assets/javascripts
94+
95+
- name: Rubocop
96+
if: ${{ !cancelled() }}
97+
run: bundle exec rubocop .
98+
99+
- name: Syntax Tree
100+
if: ${{ !cancelled() }}
101+
run: |
102+
if test -f .streerc; then
103+
bundle exec stree check Gemfile $(git ls-files '*.rb') $(git ls-files '*.rake') $(git ls-files '*.thor')
104+
else
105+
echo "Stree config not detected for this repository. Skipping."
106+
fi
107+
108+
check_for_tests:
109+
runs-on: ubuntu-latest
110+
outputs:
111+
matrix: ${{ steps.check_tests.outputs.matrix }}
112+
has_specs: ${{ steps.check_tests.outputs.has_specs }}
113+
has_compatibility_file: ${{ steps.check_tests.outputs.has_compatibility_file }}
114+
115+
steps:
116+
- name: Checkout repo
117+
uses: actions/checkout@v4
118+
with:
119+
repository: ${{ inputs.repository }}
120+
path: tmp/plugin
121+
fetch-depth: 1
122+
123+
- name: Check For Test Types
124+
id: check_tests
125+
shell: ruby {0}
126+
working-directory: tmp/plugin
127+
run: |
128+
require 'json'
129+
130+
matrix = []
131+
132+
matrix << 'frontend' if Dir.glob("test/javascripts/**/*.{js,es6,gjs}").any?
133+
matrix << 'backend'
134+
matrix << 'system' if Dir.glob("spec/system/**/*.rb").any?
135+
136+
puts "Running jobs: #{matrix.inspect}"
137+
138+
File.write(ENV["GITHUB_OUTPUT"], "has_specs=true\n", mode: 'a+') if Dir.glob("spec/**/*.rb").reject { _1.start_with?("spec/system") }.any?
139+
File.write(ENV["GITHUB_OUTPUT"], "has_compatibility_file=true\n", mode: 'a+') if File.exist?(".discourse-compatibility")
140+
141+
File.write(ENV["GITHUB_OUTPUT"], "matrix=#{matrix.to_json}\n", mode: 'a+')
142+
143+
tests:
144+
name: ${{ matrix.build_type || '' }}_tests
145+
runs-on: ubuntu-latest
146+
container: discourse/discourse_test:slim${{ (matrix.build_type == 'frontend' || matrix.build_type == 'system') && '-browsers' || '' }}
147+
timeout-minutes: 30
148+
needs: check_for_tests
149+
150+
env:
151+
DISCOURSE_HOSTNAME: www.example.com
152+
RUBY_GLOBAL_METHOD_CACHE_SIZE: 131072
153+
RAILS_ENV: test
154+
PGUSER: discourse
155+
PGPASSWORD: discourse
156+
PLUGIN_NAME: ${{ inputs.name || github.event.repository.name }}
157+
CHEAP_SOURCE_MAPS: "1"
158+
159+
strategy:
160+
fail-fast: false
161+
162+
matrix:
163+
build_type: ${{ fromJSON(needs.check_for_tests.outputs.matrix) }}
164+
165+
steps:
166+
- name: Set working directory owner
167+
run: chown root:root .
168+
169+
- uses: actions/checkout@v4
170+
with:
171+
repository: discourse/discourse
172+
fetch-depth: 1
173+
ref: ${{ inputs.core_ref }}
174+
175+
- name: Install plugin
176+
uses: actions/checkout@v4
177+
with:
178+
repository: ${{ inputs.repository }}
179+
path: plugins/${{ env.PLUGIN_NAME }}
180+
fetch-depth: 1
181+
182+
- name: Setup Git
183+
run: |
184+
git config --global user.email "ci@ci.invalid"
185+
git config --global user.name "Discourse CI"
186+
187+
- name: Clone additional plugins
188+
uses: discourse/.github/actions/clone-additional-plugins@v1
189+
with:
190+
ssh_private_key: ${{ secrets.ssh_private_key }}
191+
about_json_path: plugins/${{ env.PLUGIN_NAME }}/about.json
192+
193+
- name: Start redis
194+
run: |
195+
redis-server /etc/redis/redis.conf &
196+
197+
- name: Start Postgres
198+
run: |
199+
chown -R postgres /var/run/postgresql
200+
sudo -E -u postgres script/start_test_db.rb
201+
sudo -u postgres psql -c "CREATE ROLE $PGUSER LOGIN SUPERUSER PASSWORD '$PGPASSWORD';"
202+
203+
- name: Container envs
204+
id: container-envs
205+
run: |
206+
echo "ruby_version=$RUBY_VERSION" >> $GITHUB_OUTPUT
207+
echo "debian_release=$DEBIAN_RELEASE" >> $GITHUB_OUTPUT
208+
shell: bash
209+
210+
- name: Bundler cache
211+
uses: actions/cache@v4
212+
with:
213+
path: vendor/bundle
214+
key: ${{ runner.os }}-${{ steps.container-envs.outputs.ruby_version }}-${{ steps.container-envs.outputs.debian_release }}-gem-${{ hashFiles('**/Gemfile.lock') }}
215+
restore-keys: |
216+
${{ runner.os }}-${{ steps.container-envs.outputs.ruby_version }}-${{ steps.container-envs.outputs.debian_release }}-gem-
217+
218+
- name: Setup gems
219+
run: |
220+
gem install bundler --conservative -v $(awk '/BUNDLED WITH/ { getline; gsub(/ /,""); print $0 }' Gemfile.lock)
221+
bundle config --local path vendor/bundle
222+
bundle config --local deployment true
223+
bundle config --local without development
224+
bundle install --jobs 4
225+
bundle clean
226+
227+
- name: Lint English locale
228+
if: matrix.build_type == 'backend'
229+
run: bundle exec ruby script/i18n_lint.rb "plugins/${{ env.PLUGIN_NAME }}/locales/{client,server}.en.yml"
230+
231+
- name: Get yarn cache directory
232+
id: yarn-cache-dir
233+
run: if [ -f yarn.lock ]; then echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT; fi
234+
235+
- name: Yarn cache
236+
uses: actions/cache@v4
237+
id: yarn-cache
238+
if: ${{ steps.yarn-cache-dir.outputs.dir }}
239+
with:
240+
path: ${{ steps.yarn-cache-dir.outputs.dir }}
241+
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
242+
restore-keys: |
243+
${{ runner.os }}-yarn-
244+
245+
- name: Install JS Dependencies
246+
run: if [ -f yarn.lock ]; then yarn install --frozen-lockfile; else pnpm install --frozen-lockfile; fi
247+
248+
- name: Fetch app state cache
249+
uses: actions/cache@v4
250+
id: app-cache
251+
with:
252+
path: tmp/app-cache
253+
key: >-
254+
${{ hashFiles('.github/workflows/tests.yml') }}-
255+
${{ hashFiles('db/**/*', 'plugins/**/db/**/*') }}-
256+
257+
- name: Restore database from cache
258+
if: steps.app-cache.outputs.cache-hit == 'true'
259+
run: |
260+
if test -f script/silence_successful_output; then
261+
script/silence_successful_output psql -f tmp/app-cache/cache.sql postgres
262+
else
263+
psql -f tmp/app-cache/cache.sql postgres
264+
fi
265+
266+
- name: Restore uploads from cache
267+
if: steps.app-cache.outputs.cache-hit == 'true'
268+
run: rm -rf public/uploads && cp -r tmp/app-cache/uploads public/uploads
269+
270+
- name: Create and migrate database
271+
if: steps.app-cache.outputs.cache-hit != 'true'
272+
run: |
273+
bin/rake db:create
274+
if test -f script/silence_successful_output; then
275+
script/silence_successful_output bin/rake db:migrate
276+
else
277+
bin/rake db:migrate
278+
fi
279+
280+
- name: Dump database for cache
281+
if: steps.app-cache.outputs.cache-hit != 'true'
282+
run: mkdir -p tmp/app-cache && pg_dumpall > tmp/app-cache/cache.sql
283+
284+
- name: Dump uploads for cache
285+
if: steps.app-cache.outputs.cache-hit != 'true'
286+
run: rm -rf tmp/app-cache/uploads && cp -r public/uploads tmp/app-cache/uploads
287+
288+
- name: Check Zeitwerk eager_load
289+
if: matrix.build_type == 'backend'
290+
env:
291+
LOAD_PLUGINS: 1
292+
run: |
293+
if ! bin/rails zeitwerk:check --trace; then
294+
echo
295+
echo "---------------------------------------------"
296+
echo
297+
echo "::error::'bin/rails zeitwerk:check' failed - the app will fail to boot with 'eager_load=true' (e.g. in production)."
298+
echo "To reproduce locally, run 'bin/rails zeitwerk:check'."
299+
echo "Alternatively, you can run your local server/tests with the 'DISCOURSE_ZEITWERK_EAGER_LOAD=1' environment variable."
300+
echo
301+
exit 1
302+
fi
303+
304+
- name: Check Zeitwerk reloading
305+
if: matrix.build_type == 'backend'
306+
env:
307+
LOAD_PLUGINS: 1
308+
run: |
309+
if ! bin/rails runner 'Rails.application.reloader.reload!'; then
310+
echo
311+
echo "---------------------------------------------"
312+
echo
313+
echo "::error::Zeitwerk reload failed - the app will not be able to reload properly in development."
314+
echo "To reproduce locally, run \`bin/rails runner 'Rails.application.reloader.reload!'\`."
315+
echo
316+
exit 1
317+
fi
318+
319+
- name: Validate discourse-compatibility
320+
if: matrix.build_type == 'backend' && needs.check_for_tests.outputs.has_compatibility_file && !inputs.core_ref
321+
run: bin/rake "compatibility:validate[plugins/${{ env.PLUGIN_NAME }}/.discourse-compatibility]"
322+
323+
- name: Plugin RSpec
324+
if: matrix.build_type == 'backend' && needs.check_for_tests.outputs.has_specs
325+
run: bin/rake plugin:spec[${{ env.PLUGIN_NAME }}]
326+
327+
- name: Plugin QUnit
328+
if: matrix.build_type == 'frontend'
329+
run: QUNIT_EMBER_CLI=1 bundle exec rake plugin:qunit['${{ env.PLUGIN_NAME }}','1200000']
330+
timeout-minutes: 10
331+
332+
- name: Ember Build for System Tests
333+
if: matrix.build_type == 'system'
334+
run: bin/ember-cli --build
335+
336+
- name: Plugin System Tests
337+
if: matrix.build_type == 'system'
338+
env:
339+
LOAD_PLUGINS: 1
340+
CAPYBARA_DEFAULT_MAX_WAIT_TIME: 10
341+
run: bin/system_rspec plugins/${{ env.PLUGIN_NAME }}/spec/system
342+
343+
- name: Upload failed system test screenshots
344+
uses: actions/upload-artifact@v3
345+
if: matrix.build_type == 'system' && failure()
346+
with:
347+
name: failed-system-test-screenshots
348+
path: tmp/capybara/*.png

0 commit comments

Comments
 (0)