diff --git a/.github/jobs/base.sh b/.github/jobs/base.sh new file mode 100755 index 0000000000..b0fdbb65a2 --- /dev/null +++ b/.github/jobs/base.sh @@ -0,0 +1,93 @@ +#!/bin/bash + +set -x + +. .github/jobs/data/gha_ci_bashrc + +lsb_release -a + +cat > ~/.my.cnf < etc/dbpasswords.secret + +# Generate APP_SECRET for symfony +# shellcheck disable=SC2164 +( cd etc ; ./gensymfonysecret > symfony_app.secret ) + +cat > webapp/config/static.yaml <> ~www-data/.netrc +sudo -u www-data bin/dj_setup_database -uroot -pdomjudge bare-install + +# shellcheck disable=SC2154 +if [ -n "${integration:-}" ]; then + # Make sure admin has a team associated to insert submissions as well. + echo "UPDATE user SET teamid=1 WHERE userid=1;" | mysql domjudge +fi + +sudo -u www-data bin/dj_setup_database -uroot -pdomjudge install-examples diff --git a/.github/workflowscripts/baseinstall.sh b/.github/jobs/baseinstall.sh similarity index 97% rename from .github/workflowscripts/baseinstall.sh rename to .github/jobs/baseinstall.sh index 7bd3ab27e7..d444636bcf 100755 --- a/.github/workflowscripts/baseinstall.sh +++ b/.github/jobs/baseinstall.sh @@ -79,7 +79,7 @@ openssl req -nodes -new -x509 -keyout /tmp/server.key -out /tmp/server.crt -subj sudo cp /tmp/server.crt /usr/local/share/ca-certificates/ sudo update-ca-certificates # shellcheck disable=SC2002 -cat "$(pwd)/.github/workflowscripts/nginx_extra" | sudo tee -a /etc/nginx/sites-enabled/domjudge +cat "$(pwd)/.github/jobs/data/nginx_extra" | sudo tee -a /etc/nginx/sites-enabled/domjudge sudo nginx -t section_end diff --git a/.github/jobs/data/gha_ci_bashrc b/.github/jobs/data/gha_ci_bashrc new file mode 100755 index 0000000000..6e6f8556e3 --- /dev/null +++ b/.github/jobs/data/gha_ci_bashrc @@ -0,0 +1,59 @@ +#!/bin/bash + +# Expand aliases for non-interactive shell +shopt -s expand_aliases + +# Fail pipeline when variable is not set or individual command has an non-zero exitcode. +set -euo pipefail + +# Show which commands are being run +set -x + +# Chown the checked out files +sudo chown -R domjudge:domjudge . + +# Shared constants between jobs +export DIR=$(pwd) +export GITSHA=$(git rev-parse HEAD || true) +export PS4='(${BASH_SOURCE}:${LINENO}): - [$?] $ ' +export LOGFILE="/opt/domjudge/domserver/webapp/var/log/prod.log" + +# Functions to annotate the Github actions logs +alias trace_on='set -x' +alias trace_off='{ set +x; } 2>/dev/null' + +section_start_internal () { + echo "::group::$1" + trace_on +} + +section_end_internal () { + echo "::endgroup::" + trace_on +} + +alias section_start='trace_off ; section_start_internal ' +alias section_end='trace_off ; section_end_internal ' + +# Shared storage for all artifacts +export ARTIFACTS="$DIR/artifacts" +mkdir -p "$ARTIFACTS" + +function show_phpinfo() { + phpversion=$1 + section_start phpinfo + update-alternatives --set php /usr/bin/php"${phpversion}" + php -v + php -m + section_end phpinfo +} + +function log_on_err() { + echo -e "\\n\\n=======================================================\\n" + echo "Symfony log:" + if sudo test -f "$LOGFILE" ; then + sudo cat "$LOGFILE" + fi +} + +set -eux diff --git a/.github/workflowscripts/mapi.config b/.github/jobs/data/mapi.config similarity index 100% rename from .github/workflowscripts/mapi.config rename to .github/jobs/data/mapi.config diff --git a/.github/workflowscripts/nginx_extra b/.github/jobs/data/nginx_extra similarity index 100% rename from .github/workflowscripts/nginx_extra rename to .github/jobs/data/nginx_extra diff --git a/.github/workflowscripts/getapi.sh b/.github/jobs/getapi.sh similarity index 100% rename from .github/workflowscripts/getapi.sh rename to .github/jobs/getapi.sh diff --git a/.github/jobs/unit-tests.sh b/.github/jobs/unit-tests.sh new file mode 100755 index 0000000000..ddbc3786d8 --- /dev/null +++ b/.github/jobs/unit-tests.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +. .github/jobs/data/gha_ci_bashrc + +section_start chown_checkout +git config --global --add safe.directory /__w/domjudge/domjudge +section_end chown_checkout + +section_start current_database_domjudge "Currently installed databases (domjudge)" +set +eu +echo "show databases" | mysql -hsqlserveranother -udomjudge -pdomjudge +echo "show databases" | mysql -hsqlserver -udomjudge -pdomjudge +set -eu +section_end current_database_domjudge + +section_start current_database_root "Currently installed databases (root)" +set +eu +echo "show databases" | mysql -hsqlserver -uroot -pdomjudge +set -eu +section_end current_database_root + +export version=$1 +unittest=$2 +[ "$version" = "8.1" ] && CODECOVERAGE=1 || CODECOVERAGE=0 + +show_phpinfo $version + +.github/jobs/base.sh + +# Add team to admin user +echo "INSERT INTO userrole (userid, roleid) VALUES (1, 3);" | mysql domjudge +echo "UPDATE user SET teamid = 1 WHERE userid = 1;" | mysql domjudge + +# Copy the .env.test file, as this is normally not done during +# installation and we need it. +cp webapp/.env.test /opt/domjudge/domserver/webapp/ + +# We also need the composer.json for PHPunit to detect the correct directory. +cp composer.json /opt/domjudge/domserver/ + +cd /opt/domjudge/domserver + +export APP_ENV="test" + +# Run phpunit tests. +pcov="" +phpcov="" +if [ "$CODECOVERAGE" -eq 1 ]; then + phpcov="-dpcov.enabled=1 -dpcov.directory=webapp/src" + pcov="--coverage-html=${PWD}/coverage-html --coverage-clover coverage.xml" +fi +set +e +php $phpcov lib/vendor/bin/phpunit -c webapp/phpunit.xml.dist webapp/tests/$unittest --log-junit ${DIR}/unit-tests.xml --colors=never $pcov > "$ARTIFACTS"/phpunit.out +UNITSUCCESS=$? +set -e +CNT=0 +if [ $CODECOVERAGE -eq 1 ]; then + CNT=$(sed -n '/Generating code coverage report/,$p' "$ARTIFACTS"/phpunit.out | grep -v DoctrineTestBundle | grep -cv ^$) + FILE=deprecation.txt + sed -n '/Generating code coverage report/,$p' "$ARTIFACTS"/phpunit.out > "$DIR/$FILE" + if [ $CNT -le 12 ]; then + STATE=success + else + STATE=failure + fi + ORIGINAL="gitlab.com/DOMjudge" + REPLACETO="domjudge.gitlab.io/-" + # Copied from CCS + #curl https://api.github.com/repos/domjudge/domjudge/statuses/$CI_COMMIT_SHA \ + # -X POST \ + # -H "Authorization: token $GH_BOT_TOKEN_OBSCURED" \ + # -H "Accept: application/vnd.github.v3+json" \ + # -d "{\"state\": \"$STATE\", \"target_url\": \"${CI_JOB_URL/$ORIGINAL/$REPLACETO}/artifacts/$FILE\", \"description\":\"Symfony deprecations\", \"context\": \"Symfony deprecation\"}" +fi +if [ $UNITSUCCESS -ne 0 ]; then + exit $UNITSUCCESS +fi + +if [ $CODECOVERAGE -eq 1 ]; then + section_start uploadcoverage "Upload code coverage" + # Only upload when we got working unit-tests. + set +u # Uses some variables which are not set + # shellcheck disable=SC1090 + . $DIR/.github/jobs/uploadcodecov.sh &>/dev/zero + set -u # Undo set dance + section_end uploadcoverage +fi diff --git a/.github/workflows/check-unit-codecov-update.yml b/.github/workflows/check-unit-codecov-update.yml new file mode 100644 index 0000000000..4ccc26ad4a --- /dev/null +++ b/.github/workflows/check-unit-codecov-update.yml @@ -0,0 +1,21 @@ +name: Unit tests (Codecov script) +on: + push: + branches: + - main + - '[0-9]+.[0-9]+' + pull_request: + branches: + - main + - '[0-9]+.[0-9]+' + +jobs: + check-static-codecov: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Download latest codecov upload script + run: wget https://codecov.io/bash -O newcodecov + - name: Detect changes to manually verify + run: diff newcodecov .github/jobs/uploadcodecov.sh + diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 97ea3c9c6d..9d675a142b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,22 +2,22 @@ name: "CodeQL" on: push: - branches: [ main ] + branches: + - main + - '[0-9]+.[0-9]+' pull_request: - # The branches below must be a subset of the branches above - branches: [ main ] - schedule: - - cron: '16 12 * * 6' + branches: + - main + - '[0-9]+.[0-9]+' jobs: analyze: + # We can not run with our gitlab container + # CodeQL has missing .so files otherwise name: Analyze runs-on: ubuntu-latest env: - COMPILED: | - [ - "cpp" - ] + COMPILED: "cpp" permissions: actions: read contents: read @@ -27,24 +27,16 @@ jobs: fail-fast: false matrix: language: [ 'cpp', 'java', 'javascript', 'python' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://git.io/codeql-language-support steps: - name: Checkout repository uses: actions/checkout@v2 - # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - # Install needed tools, - name: Install required tools if: ${{ contains(env.COMPILED, matrix.language) }} run: | diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 31ed27b285..ff91f2a9be 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -1,20 +1,27 @@ on: - pull_request: + push: + branches: + - main + - '[0-9]+.[0-9]+' + pull_request: + branches: + - main + - '[0-9]+.[0-9]+' name: Spell Check jobs: - codespell: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Rewrite Changelog to find new mistakes - run: awk '1;/Version 7.2.1 - 6 May 2020/{exit}' ChangeLog > latest_Changelog - - name: Get dirs to skip - id: list_to_csv - run: echo "::set-output name=SKIP::$(awk '{print $1}' .github/jobs/data/codespellignorefiles.txt | paste -s -d, -)" - - uses: codespell-project/actions-codespell@master - with: - check_filenames: true - ignore_words_file: .github/jobs/data/codespellignorewords.txt - skip: ${{ steps.list_to_csv.outputs.SKIP }} + codespell: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Rewrite Changelog to find new mistakes + run: awk '1;/Version 7.2.1 - 6 May 2020/{exit}' ChangeLog > latest_Changelog + - name: Get dirs to skip + id: list_to_csv + run: echo "::set-output name=SKIP::$(awk '{print $1}' .github/jobs/data/codespellignorefiles.txt | paste -s -d, -)" + - uses: codespell-project/actions-codespell@master + with: + check_filenames: true + ignore_words_file: .github/jobs/data/codespellignorewords.txt + skip: ${{ steps.list_to_csv.outputs.SKIP }} diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml index fa9f2edb21..8735e3ca43 100644 --- a/.github/workflows/codestyle.yml +++ b/.github/workflows/codestyle.yml @@ -5,6 +5,9 @@ on: - main - '[0-9]+.[0-9]+' pull_request: + branches: + - main + - '[0-9]+.[0-9]+' jobs: syntax-job: diff --git a/.github/workflows/mayhem-api.yml b/.github/workflows/mayhem-api-template.yml similarity index 71% rename from .github/workflows/mayhem-api.yml rename to .github/workflows/mayhem-api-template.yml index c25eee6812..c50f927d9e 100644 --- a/.github/workflows/mayhem-api.yml +++ b/.github/workflows/mayhem-api-template.yml @@ -1,16 +1,19 @@ -name: "Mayhem API analysis" +name: "Mayhem API analysis (Template)" on: - schedule: - - cron: '5 21 1-31/2 * *' + workflow_call: + inputs: + version: + required: true + type: string + duration: + required: true + type: string jobs: mayhem: name: Mayhem API analysis runs-on: ubuntu-latest - strategy: - matrix: - version: ["team", "guest", "admin", "jury"] permissions: actions: read contents: read @@ -23,13 +26,13 @@ jobs: - uses: actions/checkout@v2 - name: Install DOMjudge - run: .github/workflowscripts/baseinstall.sh ${{ matrix.version }} + run: .github/jobs/baseinstall.sh ${{ inputs.version }} - name: Dump the OpenAPI - run: .github/workflowscripts/getapi.sh + run: .github/jobs/getapi.sh - uses: actions/upload-artifact@v3 - if: ${{ matrix.version == 'guest' }} + if: ${{ inputs.version == 'guest' }} with: name: all-apispec path: | @@ -37,17 +40,17 @@ jobs: - name: Mayhem for API uses: ForAllSecure/mapi-action@v1 - if: ${{ matrix.version == 'guest' }} + if: ${{ inputs.version == 'guest' }} continue-on-error: true with: mapi-token: ${{ secrets.MAPI_TOKEN }} api-url: http://localhost/domjudge api-spec: http://localhost/domjudge/api/doc.json # swagger/openAPI doc hosted here - duration: 2m + duration: "auto" # Only spend time if we need to recheck issues from last time or find issues sarif-report: mapi.sarif run-args: | --config - .github/workflowscripts/mapi.config + .github/jobs/data/mapi.config --ignore-endpoint ".*strict=true.*" --ignore-endpoint @@ -55,18 +58,18 @@ jobs: - name: Mayhem for API (For application role) uses: ForAllSecure/mapi-action@v1 - if: ${{ matrix.version != 'guest' }} + if: ${{ inputs.version != 'guest' }} continue-on-error: true with: mapi-token: ${{ secrets.MAPI_TOKEN }} - target: domjudge-${{ matrix.version }} + target: domjudge-${{ inputs.version }} api-url: http://localhost/domjudge api-spec: http://localhost/domjudge/api/doc.json # swagger/openAPI doc hosted here - duration: 5m + duration: "${{ inputs.duration }}" sarif-report: mapi.sarif run-args: | --config - .github/workflowscripts/mapi.config + .github/jobs/data/mapi.config --basic-auth admin:password --ignore-endpoint @@ -81,7 +84,7 @@ jobs: - uses: actions/upload-artifact@v3 with: - name: ${{ matrix.version }}-logs + name: ${{ inputs.version }}-logs path: | /var/log/nginx /opt/domjudge/domserver/webapp/var/log/*.log diff --git a/.github/workflows/mayhem-daily.yml b/.github/workflows/mayhem-daily.yml new file mode 100644 index 0000000000..a7bf052ba7 --- /dev/null +++ b/.github/workflows/mayhem-daily.yml @@ -0,0 +1,12 @@ +name: "Mayhem API daily (admin role only)" + +on: + schedule: + - cron: '0 23 * * *' + +jobs: + mayhem-template: + uses: ./.github/workflows/mayhem-api-template.yml + with: + version: "admin" + duration: "auto" diff --git a/.github/workflows/mayhem-weekly.yml b/.github/workflows/mayhem-weekly.yml new file mode 100644 index 0000000000..cc3d13e2d5 --- /dev/null +++ b/.github/workflows/mayhem-weekly.yml @@ -0,0 +1,23 @@ +name: "Mayhem API weekly (all roles)" + +on: + schedule: + - cron: '0 23 * * 0' + +jobs: + mayhem-template: + strategy: + matrix: + include: + - version: "team" + duration: "5m" + - version: "guest" + duration: "auto" + - version: "jury" + duration: "5min" + - version: "admin" + duration: "10m" + uses: ./.github/workflows/mayhem-api-template.yml + with: + version: "${{ matrix.target }}" + duration: "${{ matrix.version }}" diff --git a/.github/workflows/phpcodesniffer.yml b/.github/workflows/phpcodesniffer.yml index 460927a4f7..296af0fafa 100644 --- a/.github/workflows/phpcodesniffer.yml +++ b/.github/workflows/phpcodesniffer.yml @@ -1,7 +1,15 @@ name: PHP CodeSniffer # Controls when the action will run. -on: ['pull_request','push','pull_request_target'] +on: + push: + branches: + - main + - '[0-9]+.[0-9]+' + pull_request: + branches: + - main + - '[0-9]+.[0-9]+' jobs: phpcs: runs-on: ubuntu-latest diff --git a/.github/workflows/shiftleft.yml b/.github/workflows/shiftleft.yml index 986856a307..58cfd0a908 100644 --- a/.github/workflows/shiftleft.yml +++ b/.github/workflows/shiftleft.yml @@ -2,12 +2,6 @@ name: SL Scan on: push: - branches: [ main ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ main ] - schedule: - - cron: '24 23 * * 6' jobs: Scan-Build: diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 30b8fd1948..b09e50a784 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -1,18 +1,54 @@ -name: Unit tests +name: Unit tests CI on: push: branches: - main - '[0-9]+.[0-9]+' pull_request: + branches: + - main + - '[0-9]+.[0-9]+' jobs: - check-static-codecov: + run-unit-tests: runs-on: ubuntu-latest + container: domjudge/gitlabci:2.1 + defaults: + run: + shell: bash + strategy: + matrix: + sqlserver: ['mariadb'] + phpversion: ['7.4','8.0','8.1','8.2'] + testtype: ["Unit","E2E"] + include: + - phpversion: "8.1" + sqlserver: "mysql" + testtype: "Unit" + - phpversion: "8.1" + sqlserver: "mysql" + testtype: "E2E" + services: + sqlserver: + image: "${{ matrix.sqlserver }}" + env: + MARIADB_ROOT_PASSWORD: domjudge steps: - uses: actions/checkout@v2 - - name: Download latest codecov upload script - run: wget https://codecov.io/bash -O newcodecov - - name: Detect changes to manually verify - run: diff newcodecov .github/jobs/uploadcodecov.sh + - name: Show current directory + run: pwd + - name: Run gitlab script in altered form + run: .github/jobs/unit-tests.sh "${{ matrix.phpversion }}" "${{ matrix.testtype }}" + - name: Publish Test Results + uses: EnricoMi/publish-unit-test-result-action@v2 + if: always() + with: + comment_mode: off + files: | + unit-tests.xml + - uses: actions/upload-artifact@v3 + with: + name: ci-run-logs-configs + path: | + "artifacts"