This repository provides centralized workflow configurations for Decidim modules that we can use for centralizing the configurations for the workflows and maintain them in a single location.
Each shared action has a dedicated folder in this repository where the actions can be referred from. This repository also contains shared ready-made workflow configurations to be used within the modules for easier management.
The workflows that this repository provides:
build_app.yml- Takes care of building the test application for easier reuse in case the target repository has multiple modules in it.ci_js.yml- Contains the workflow for runningnpm testwithin the module's repository, usually using Jest within the Decidim context.ci_rspec.yml- Contains the workflow for runningrspecwithin the module's repository, using RSpec.lint.yml- Lints the code using different linters, such as Rubocop, ESLint and Stylelint.
The actions that this repository provides:
- Main actions
setup-app- Creates, configures and caches the test application for reuse.test-rspec- Runs the RSpec tests for the module.test-js- Runs the JS tests (generally Jest) for the module.lint- Runs the different linters for the module.
- Support actions
app-cache- Caches and restores the generated test application with a unique cache key.create-app- Creates and sets up the test application for reuse.gem-version- Fetches a gem version from the repository'sGemfile.lockfor configuring the application environment accordingly for different versions.setup-app- Combinesapp-cacheandcreate-appactions by utilizing theapp-cacheaction to check if the application has already been cached and if not, callscreate-appto generate the application which is cached by the other action after creation.setup-ruby-runtime- Sets up the Ruby runtime and dependencies for RSpec tests.
This repository contains both GitHub actions as well as shared workflow configuration files. The actions can be used individually but the shared workflow files allow us to maintain some of the worker and service configurations in a centralized locations. This makes it easy e.g. to update the PostgreSQL versions when needed or add additional services to the list.
The recommended way is to run the workflows using the shared workflow
configuration files located at the .github/workflows directory of this
repository. The following sections give examples on how to configure these
properly for your module repository.
For all configured workflows, the following configurations are common:
onflag - Adds the correct triggers when these workflows are run (e.g. during pushes into specific branches or during pull requests)concurrencyflag - Disables concurrent workflows using theconcurrencyflag. E.g. when you have pull requests open that have actions running on previous commits, this would cancel the previous runs when new commits are pushed to the same branch.
To run the RSpec tests, configure the following workflow file within your module's repository:
.github/workflows/ci_decidim_{MODULE_NAME}.yml
(replace {MODULE_NAME} with the name of your module)
The contents of this file should look as follows:
# Replace the {MODULE_NAME} below with the actual name of the module.
name: "[CI] {MODULE_NAME}"
on:
push:
branches:
- develop
- main
- release/*
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
build_app:
name: Build test application
uses: mainio/gha-decidim-module/.github/workflows/build_app.yml@main
secrets: inherit
main:
needs: build_app
name: Tests
uses: mainio/gha-decidim-module/.github/workflows/ci_rspec.yml@main
secrets: inheritThe jobs of this workflow will handle the following tasks:
build_app- Builds the test application, i.e.spec/decidim_dummy_appand stores it in a cache. Pre-building the app will speed up consequent runs on the same workflow, e.g. if the workflow fails due to a flaky test.main- Loads the cached application and runs therspectests within the repository using that application.
Note
If you have not implemented any Jest tests for the repository, do not add this workflow.
To run the JS tests (i.e. npm test, usually using Jest), configure the
following workflow file within your module's repository:
.github/workflows/ci_decidim_{MODULE_NAME}_js.yml
(replace {MODULE_NAME} with the name of your module)
The contents of this file should look as follows:
# Replace the {MODULE_NAME} below with the actual name of the module.
name: "[CI] {MODULE_NAME} JavaScript"
on:
push:
branches:
- develop
- main
- release/*
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
main:
name: JS tests
uses: mainio/gha-decidim-module/.github/workflows/ci_js.yml@main
secrets: inheritThe main job takes care of installing the NPM dependencies and running
npm test within the repository.
To run the different linters (Rubocop, ESLint and Stylelint), configure the following workflow file within your module's repository:
.github/workflows/lint.yml
The contents of this file should look as follows:
name: "[CI] Lint"
on:
push:
branches:
- develop
- main
- release/*
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
lint:
name: Lint code
uses: mainio/gha-decidim-module/.github/workflows/lint.yml@main
secrets: inherit
with:
eslint: true # Remove this if you do not have ESLint configured in the repository
stylelint: true # Remove this if you do not have Stylelint configured in the repositoryThe lint job takes care of installing the necessary requirements for running
the different linters as well as running the linting tasks. The example
configuration runs all the linters (Rubocop, ESLint and Stylelint) but you can
enable or disable the different linters using these input options:
rubocop(boolean, default:true) - Defines whether Rubocop will be runeslint(boolean, default:false) - Defines whether ESLint will be runstylelint(boolean, default:false) - Defines whether Stylelint will be run
Note
Before enabling ESLint or Stylelint, please make sure that the commands
npm run lint and npm run stylelint are defined and work correctly within
the repository.
If you need more granular control regarding the runner environment and attached services, you can also use the actions directly that are available in the subfolders of this repository. The following sections explain each action in more detail.
Note
This action should be used in conjunction with the test-rspec action for it
to be useful. This only generates the test application which is why it may not
be very useful otherwise.
The setup-app action takes care of generating the test application (i.e.
spec/decidim_dummy_app) and storing it in the GitHub actions cache for quick
usage within your actual jobs. This is a separate action in order to make it
quicker to run the test jobs consequently in case they fail due to a flaky test
or when there are multiple action runs during the same cache window.
To use this action within your workflow, configure the following workflow file within your module's repository:
name: "[CI] Setup test app"
on:
push:
branches:
- develop
- main
- release/*
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
build_app:
name: Build test application
uses: mainio/gha-decidim-module/setup-app@mainThe action provides the following input options:
use-cached-app(boolean, default:true) - Defines whether the generated test application is stored in a cache.- This is required in case you need to use the same application across multiple jobs which is why it is enabled by default.
The test-rspec action runs the RSpec tests within the module's repository.
Prior to using this action, you need to have generated the test application
(see setup-app for more details) in order for the test application to exist.
To use this action within your workflow, configure the following workflow file within your module's repository:
name: "[CI] RSpec"
on:
push:
branches:
- develop
- main
- release/*
pull_request:
env:
CI: "true"
CODECOV: "true"
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
main:
name: Tests
runs-on: ubuntu-latest
timeout-minutes: 60
services:
postgres:
image: postgres:14
ports: ["5432:5432"]
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
POSTGRES_PASSWORD: ${{ env.DATABASE_PASSWORD }}
env:
DATABASE_USERNAME: postgres
DATABASE_PASSWORD: postgres
DATABASE_HOST: localhost
steps:
- uses: mainio/gha-decidim-module/setup-app@main
with:
use-cached-app: false
- uses: mainio/gha-decidim-module/test-rspec@main
with:
use-cached-app: falseThe action provides the following input options:
use-cached-app(boolean, default:true) - Defines whether the generated test application is used to run the specs. If used, please also define thebuild-appaction separately in a separate job.- Note that when this configuration is used, also the database schema will be
loaded prior to running the tests regardless of the
load-schemaconfiguration. If you want to run the full migrations, enable thedb-migrateoption.
- Note that when this configuration is used, also the database schema will be
loaded prior to running the tests regardless of the
load-schema(boolean, default:true) - Defines whether the test database is purged and the database schema is re-loaded before running the tests.- Note that this is skipped in case the
db-migrateoption is enabled.
- Note that this is skipped in case the
db-migrate(boolean, default:false) - Defines whether the full DB migrations are run for the test application instead of loading only the schema generated during thesetup-appphase. This is slower than the default behavior but can be useful if the target module or application has custom migrations that would not be dumped to the Railsdb/schema.rbfile (such as DB rules or triggers).codecov-token(string) - Defines thetokeninput forcodecov/codecov-action. Used for uploading the coverage reports to Codecov.- This is passed through the secrets by the
ci_rspec.ymlworkflow.
- This is passed through the secrets by the
test-folder(string) - An optional folder within the repository where to run the tests at. By default, the tests are run at the root of the repository. This can be useful when the repository contains multiple modules and the tests are separated for each module e.g. through a matrix strategy.
The test-js action runs the JavaScript tests within the module's repository
using npm test.
To use this action within your workflow, configure the following workflow file within your module's repository:
name: "[CI] JS"
on:
push:
branches:
- develop
- main
- release/*
pull_request:
env:
CI: "true"
CODECOV: "true"
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
main:
name: Tests
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: mainio/gha-decidim-module/test-js@mainNote that before configuring this action, you should ensure that you have an NPM
script named test defined in the module's package.json file and running the
command npm run test succeeds without errors.
The lint action configures and runs the linters (Rubocop, ESLint and
Stylelint) for your module's repository. By default, only Rubocop is run but if
you want to enable ESLint and/or Stylelint, you can do so by using the input
options (see below).
To use this action within your workflow, configure the following workflow file within your module's repository:
name: "[CI] Lint"
on:
push:
branches:
- develop
- main
- release/*
pull_request:
env:
CI: "true"
CODECOV: "true"
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
main:
name: Lint
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: mainio/gha-decidim-module/lint@main
with:
eslint: true
stylelint: trueNote that before enabling either the eslint or stylelint options, you should
ensure that you have an NPM scripts named lint and stylelint defined in the
module's package.json file and running the command npm run lint and
npm run stylelint succeed without errors.
The action provides the following input options:
rubocop(boolean, default:true) - Defines whether the Rubocop will be run.eslint(boolean, default:false) - Defines whether ESLint will be run usingnpm run lint.- Before enabling this option, make sure that
npm run lintsucceeds without errors within your module's repository.
- Before enabling this option, make sure that
stylelint(boolean, default:false) - Defines whether Stylelint will be run usingnpm run lint.- Before enabling this option, make sure that
npm run stylelintsucceeds without errors within your module's repository.
- Before enabling this option, make sure that
The following actions are supportive actions that do not need to be directly configured for the repository. These actions are used by the other actions within this repository for convenience.
Generates a unique cache key for the test application by hashing the
Gemfile.lock file(s) and all files under **/db/migrate directories of the
repository. After that, sets up the actions/cache action with generated key
and the correct path to the folder to be cached (the test application folder).
The action provides the following output strings:
key- The generated cache key.cache-hit- A boolean string indicating whether there was a cache hit or not."true"- there was a cache hit"false"- there was no cache hit
This action is a supportive action that should not be used directly in the
repository. Instead, use the setup-app or test-rspec actions utilizing this.
Note
This action is used by the setup-app action that first checks whether the
app has already been cached and whether it requires to be created.
The create-app action takes care of generating the test application (i.e.
spec/decidim_dummy_app). This is a separate action to separate the logic for
generating the whole application from other necessary actions that need to
happen during the application building.
This action is a supportive action that should not be used directly in the
repository. Instead, use the setup-app action if you need to setup and cache
the application for reuse.
Parses the Gemfile.lock at the root of the repository to determine the
installed version of the gem provided with the gem input option.
The action provides the following input options:
gem(string) - Defines the name of the gem to look for fromGemfile.lock.
The action provides the following output strings:
version- The installed version of the provided gem.
This action is a supportive action that does not need to be used directly within the repository. This is used by the other actions for convenience.
Note
This action is automatically used by the the setup-app and test-rspec
actions to setup the Ruby environment and required dependencies for the RSpec
tests. It is not necessary to run this action outside of the test-rspec
action.
The setup-ruby-runtime action takes care of setting up the Ruby environment
and all necessary dependencies for RSpec testing, such as the correct image
processor based on the target application version. This is a separate action to
make the actions using this (setup-app and test-rspec) more maintainable and
less verbose with the dependencies setup.
The action also caches the dependencies for the detected image processor in
order to install it quicker during the application setup at the test-rspec
action. Especially downloading the dependencies for libvips can be slow
sometimes which makes the application setup slower.
This action is a supportive action that should not be used directly in the
repository. Instead, use the setup-app or test-rspec actions utilizing this.
We welcome contributions for these actions and shared workflow configurations but we use them ourselves in all of our modules. Therefore, they may be slightly opinionated towards the needs of the modules we are maintaining, although they are following similar conventions and patterns as the Decidim core.
Before introducing any new features or adding new services to the actions or workflow configurations, please open an issue first and briefly and clearly explain what you would like to change and why. We can then reach a conclusion about the change before breaking all the workflows out there.
In case you are fixing a bug, those contributions are of course always welcome.
This repository is distributed under the GNU AFFERO GENERAL PUBLIC LICENSE.
For further details, see the license.