├── .gitignore ├── docker ├── database.yml ├── docker-compose.yml ├── Dockerfile └── entrypoint.sh ├── README.md ├── LICENSE └── action.yml /.gitignore: -------------------------------------------------------------------------------- 1 | # OS metadata 2 | .DS_Store 3 | Thumbs.db -------------------------------------------------------------------------------- /docker/database.yml: -------------------------------------------------------------------------------- 1 | test: 2 | url: <%= ENV['DATABASE_URL'].sub(/\/app$/, "/app#{ENV['TEST_ENV_NUMBER']}") %> 3 | -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.7" 2 | 3 | networks: 4 | testing: 5 | 6 | services: 7 | ci: 8 | build: 9 | context: ./ 10 | dockerfile: Dockerfile 11 | args: 12 | PLUGIN_NAME: ${PLUGIN_NAME} 13 | OPENPROJECT_BRANCH: ${OPENPROJECT_BRANCH:-v12.0.2} 14 | environment: 15 | RSPEC_RETRY_RETRY_COUNT: "${CI_RETRY_COUNT:-3}" 16 | JOBS: "${CI_JOBS:-8}" 17 | tmpfs: 18 | - "/tmp" 19 | volumes: 20 | - "${PLUGIN_PATH}:/home/dev/plugin" 21 | - "${CI_CACHE_PATH:-/tmp}/op-bundle:/usr/local/bundle" 22 | - "${CI_CACHE_PATH:-/tmp}/op-node:/home/dev/openproject/frontend/node_modules" 23 | networks: 24 | - testing 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenProject Plugin CI 2 | 3 | This action works with your custom plugin to automate testing for angular unit, rspec unit, and rspec features. 4 | 5 | ## Usage 6 | 7 | In your workflow file, add a step with the following: 8 | 9 | ```yml 10 | uses: bitcrowd/openproject-plugin_test_action@v1 11 | with: 12 | # Name of the plugin to test as listed in the Gemfile.plugins 13 | pluginName: "" 14 | # Version of OpenProject to test against. Must be a branch or tag name from https://github.com/opf/openproject. 15 | # Default: v12.0.2 16 | openprojectVersion: "" 17 | # The test steps to use. Must be given in the order outlined in the default value but you can leave out some tests if you want. 18 | # Default: run-angular-unit run-rspec-unit run-rspec-features 19 | testSteps: "" 20 | ``` 21 | 22 | An example can be found at [bitcrowd/openproject-proto_plugin](https://github.com/bitcrowd/openproject-proto_plugin.) 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 bitcrowd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: "openproject-plugin_test" 2 | description: "Test your OpenProject plugin" 3 | author: "bitcrowd" 4 | inputs: 5 | pluginName: 6 | required: true 7 | description: "Name of the plugin to test as listed in the Gemfile.plugins" 8 | openprojectVersion: 9 | required: false 10 | description: "Version of OpenProject to test against. Must be a branch or tag name from https://github.com/opf/openproject" 11 | default: "v12.0.2" 12 | testSteps: 13 | required: false 14 | description: "The test steps to use. Must be given in the order outlined in the default value but you can leave out some tests if you want." 15 | default: "run-angular-unit run-rspec-unit run-rspec-features" 16 | runs: 17 | using: "composite" 18 | steps: 19 | - name: build 20 | env: 21 | PLUGIN_NAME: ${{ inputs.pluginName }} 22 | PLUGIN_PATH: ${{ github.workspace }} 23 | OPENPROJECT_BRANCH: ${{ inputs.openprojectVersion }} 24 | LOCAL_DEV_CHECK: "1" 25 | CI_RETRY_COUNT: "3" 26 | CI_CACHE_PATH: "/tmp/cache" 27 | CI_JOBS: "8" 28 | shell: "bash" 29 | run: | 30 | docker-compose -f ${{ github.action_path }}/docker/docker-compose.yml build --pull ci 31 | - name: test 32 | env: 33 | PLUGIN_NAME: ${{ inputs.pluginName }} 34 | PLUGIN_PATH: ${{ github.workspace }} 35 | OPENPROJECT_BRANCH: ${{ inputs.openprojectVersion }} 36 | LOCAL_DEV_CHECK: "1" 37 | CI_RETRY_COUNT: "3" 38 | CI_CACHE_PATH: "/tmp/cache" 39 | CI_JOBS: "8" 40 | shell: "bash" 41 | run: | 42 | docker-compose -f ${{ github.action_path }}/docker/docker-compose.yml run ci setup-tests ${{ inputs.testSteps }} 43 | - name: cleanup 44 | env: 45 | PLUGIN_NAME: ${{ inputs.pluginName }} 46 | PLUGIN_PATH: ${{ github.workspace }} 47 | OPENPROJECT_BRANCH: ${{ inputs.openprojectVersion }} 48 | LOCAL_DEV_CHECK: "1" 49 | CI_RETRY_COUNT: "3" 50 | CI_CACHE_PATH: "/tmp/cache" 51 | CI_JOBS: "8" 52 | shell: "bash" 53 | run: | 54 | docker-compose -f ${{ github.action_path }}/docker/docker-compose.yml down --remove-orphans -t 10 55 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:2.7.4-buster 2 | LABEL org.openproject.image.authors="operations@openproject.com" 3 | 4 | ARG OPENPROJECT_BRANCH=v12.0.1 5 | ARG PLUGIN_NAME 6 | 7 | ENV NODE_VERSION="14.17.0" 8 | ENV CHROME_SOURCE_URL="https://dl.google.com/dl/linux/direct/google-chrome-stable_current_amd64.deb https://openproject-public.s3.eu-central-1.amazonaws.com/binaries/google-chrome-stable_current_amd64.deb" 9 | ENV USER=dev 10 | 11 | RUN useradd -d /home/$USER -m $USER -s /bin/bash 12 | WORKDIR /home/$USER 13 | 14 | RUN curl -s https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz | tar xzf - -C /usr/local --strip-components=1 15 | 16 | RUN wget --quiet -O- https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - 17 | RUN echo "deb http://apt.postgresql.org/pub/repos/apt buster-pgdg main" > /etc/apt/sources.list.d/pgdg.list 18 | 19 | RUN apt-get update -qq && \ 20 | DEBIAN_FRONTEND=noninteractive apt-get install -y \ 21 | postgresql-9.6 postgresql-client-9.6 postgresql-13 postgresql-client-13 time pandoc imagemagick libpq-dev default-jre-headless firefox-esr git 22 | 23 | # Try Downloading binary from fallback source if first one fails 24 | RUN for url in $CHROME_SOURCE_URL; do \ 25 | file_name="/tmp/`basename $url`"; \ 26 | wget --no-verbose -O $file_name $url && \ 27 | apt install -y $file_name && rm -f $file_name && \ 28 | break; \ 29 | done 30 | 31 | ENV CI=true 32 | ENV RAILS_ENV=test 33 | ENV BUNDLER_VERSION="2.1.4" 34 | ENV BUNDLE_WITHOUT="development:production:docker" 35 | ENV OPENPROJECT_DISABLE_DEV_ASSET_PROXY=1 36 | ENV CAPYBARA_DYNAMIC_BIND_IP=1 37 | ENV CAPYBARA_DOWNLOADED_FILE_DIR=/tmp 38 | # disable deprecations and other warnings in output 39 | ENV RUBYOPT="-W0" 40 | ENV DATABASE_URL=postgres://app:p4ssw0rd@127.0.0.1/app 41 | ENV PGVERSION=9.6 42 | 43 | RUN gem install bundler --version "$BUNDLER_VERSION" --no-document 44 | 45 | RUN git clone --depth 1 --branch "$OPENPROJECT_BRANCH" https://github.com/opf/openproject.git /home/$USER/openproject 46 | 47 | # Plugin specific 48 | RUN echo "group :opf_plugins do\n\tgem '$PLUGIN_NAME', path: '~/plugin'\nend" > /home/$USER/openproject/Gemfile.plugins 49 | VOLUME [ "/usr/local/bundle", "/home/$USER/plugin", "/home/$USER/openproject/tmp" ] 50 | 51 | RUN chown -hR $USER /home/$USER 52 | 53 | WORKDIR /home/$USER/openproject 54 | 55 | COPY ./entrypoint.sh /usr/sbin/entrypoint.sh 56 | ENTRYPOINT [ "/usr/sbin/entrypoint.sh" ] 57 | CMD ["setup-tests", "bash"] 58 | 59 | # ruby servers 60 | EXPOSE 3000-3016 61 | # billy proxy servers 62 | EXPOSE 4000-4016 63 | 64 | 65 | ## --- END CI environment --- 66 | -------------------------------------------------------------------------------- /docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | PLUGIN_FOLDER_NAME="openproject-proto_plugin" 5 | export PGBIN="/usr/lib/postgresql/$PGVERSION/bin" 6 | export JOBS="${CI_JOBS:=$(nproc)}" 7 | # for parallel rspec 8 | export PARALLEL_TEST_PROCESSORS=$JOBS 9 | 10 | # if from within docker 11 | if [ $(id -u) -eq 0 ]; then 12 | if [ ! -d "/tmp/nulldb" ]; then 13 | su - postgres -c "$PGBIN/initdb -E UTF8 -D /tmp/nulldb" 14 | su - postgres -c "$PGBIN/pg_ctl -D /tmp/nulldb -l /dev/null -w start" 15 | echo "create database app; create user app with superuser encrypted password 'p4ssw0rd'; grant all privileges on database app to app;" | su - postgres -c $PGBIN/psql 16 | fi 17 | 18 | mkdir -p /usr/local/bundle 19 | mkdir -p /home/$USER/openproject/frontend/node_modules 20 | mkdir -p /home/$USER/openproject/tmp 21 | chown $USER:$USER /usr/local/bundle 22 | chown -R $USER:$USER /home/$USER/openproject/frontend/node_modules 23 | chown $USER:$USER /home/$USER/openproject/tmp 24 | fi 25 | 26 | 27 | execute() { 28 | if [ $(id -u) -eq 0 ]; then 29 | su $USER -c "$@" 30 | else 31 | bash -c "$@" 32 | fi 33 | } 34 | 35 | cleanup() { 36 | rm -rf tmp/cache/parallel* 37 | } 38 | 39 | if [ "$1" == "setup-tests" ]; then 40 | echo "Preparing environment for running tests..." 41 | shift 42 | 43 | execute "mkdir -p tmp" 44 | execute "cp docker/ci/database.yml config/" 45 | 46 | for i in $(seq 0 $JOBS); do 47 | folder="$CAPYBARA_DOWNLOADED_FILE_DIR/$i" 48 | echo "Creating folder $folder..." 49 | rm -rf "$folder" 50 | mkdir -p "$folder" 51 | chmod 1777 "$folder" 52 | done 53 | 54 | chown -hR dev /usr/local/bundle 55 | execute "time bundle install -j$JOBS" 56 | chown -hR dev /usr/local/bundle 57 | execute "TEST_ENV_NUMBER=0 time bundle exec rake db:create db:migrate db:schema:dump webdrivers:chromedriver:update webdrivers:geckodriver:update openproject:plugins:register_frontend" 58 | execute "time bundle exec rake parallel:create parallel:load_schema" 59 | fi 60 | 61 | if [ "$1" == "run-angular-unit" ]; then 62 | shift 63 | if ! execute "cd frontend && npm install && npm run test -- --include=src/app/features/plugins/linked/${PLUGIN_FOLDER_NAME}"; then 64 | cleanup 65 | exit 1 66 | else 67 | cleanup 68 | exit 0 69 | fi 70 | fi 71 | 72 | if [ "$1" == "run-rspec-unit" ]; then 73 | shift 74 | if ! execute "time bundle exec rspec --exclude-pattern '../plugin/spec/features/**/*' --pattern '../plugin/spec/**/*_spec.rb'"; then 75 | execute "cat tmp/parallel_summary.log" 76 | cleanup 77 | exit 1 78 | else 79 | cleanup 80 | exit 0 81 | fi 82 | fi 83 | 84 | if [ "$1" == "run-rspec-features" ]; then 85 | shift 86 | execute "cd frontend; npm install ; cd -" 87 | execute "bundle exec rake assets:precompile" 88 | execute "cp -rp config/frontend_assets.manifest.json public/assets/frontend_assets.manifest.json" 89 | 90 | if ! execute "time bundle exec rspec --pattern '../plugin/spec/features/**/*_spec.rb'" ; then 91 | execute "cat tmp/parallel_summary.log" 92 | cleanup 93 | exit 1 94 | else 95 | cleanup 96 | exit 0 97 | fi 98 | fi 99 | 100 | if [ ! -z "$1" ] ; then 101 | exec "$@" 102 | fi 103 | --------------------------------------------------------------------------------