Test #12352
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Test | |
| on: | |
| push: | |
| branches: | |
| # Do not build PRs twice | |
| - 'master' | |
| paths: | |
| - 'data/**' | |
| pull_request: | |
| paths: | |
| - 'data/**' | |
| # Merges by a workflow (auto-merge in publish-pr-screenshot.yml) do not | |
| # trigger push runs, so it starts this with the merge commit | |
| workflow_dispatch: | |
| inputs: | |
| commit: | |
| description: 'Commit on master whose changed files in data/ to test' | |
| required: false | |
| files: | |
| description: 'Or: names of entries in data/ to re-test, separated by blanks (e.g. to regenerate database/)' | |
| required: false | |
| # A new push to a PR makes the previous test run obsolete | |
| concurrency: | |
| group: test-${{ github.event.pull_request.number || github.run_id }} | |
| cancel-in-progress: true | |
| env: | |
| DISPLAY: :99 | |
| IS_PULLREQUEST: ${{ github.event_name == 'pull_request' }} | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| WORKER_TIMEOUT: 600 # seconds per app; must stay below the job's timeout-minutes | |
| jobs: | |
| test: | |
| # Pushes (and manual runs) write database/ and commit it: only here. In a | |
| # fork, a push to its master would commit "Add automatically parsed data" | |
| # to the fork, and a PR from that branch would carry the commit (#3948). | |
| # PRs are tested wherever they are opened. | |
| if: github.event_name == 'pull_request' || github.repository == 'AppImage/appimage.github.io' | |
| runs-on: ubuntu-22.04 | |
| timeout-minutes: 20 | |
| permissions: | |
| actions: write | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| # https://github.com/actions/checkout#Fetch-all-history-for-all-tags-and-branches | |
| # According to the docs for checkout@v2, Only a single commit is fetched by default, but | |
| # providing a fetch-depth of 0 should fetch all history. | |
| with: | |
| fetch-depth: 0 | |
| - name: Check that the pull request changes exactly one file in data/ | |
| # Not for branches in this repository, so that maintainers can test | |
| # changes to the test together with a change in data/ | |
| if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository | |
| run: | | |
| CHANGED=$(git diff --name-only "origin/${{ github.base_ref }}...HEAD") | |
| if [ "$(echo "$CHANGED" | grep -c .)" -ne 1 ] || ! echo "$CHANGED" | grep -qxE 'data/[^/]+' ; then | |
| { | |
| echo "ERROR: A pull request must change exactly one file in data/ and nothing else, but this one changes:" | |
| echo "$CHANGED" | sed 's/^/ /' | |
| } | tee log.txt | |
| exit 1 | |
| fi | |
| - name: Configure APT Packages | |
| uses: awalsh128/cache-apt-pkgs-action@v1.4.3 | |
| # This action handles caching APT packages, and leaves the option for package configuration scripts to be run if needed, | |
| # saving a boat-load of time, if needed bump the action version. | |
| with: | |
| packages: sudo imagemagick libasound2-dev pulseaudio-utils alsa-utils alsa-oss libjack0 desktop-file-utils xmlstarlet xsel xterm xvfb icewm x11-utils x11-apps netpbm xdotool libgl1-mesa-dri libgl1-mesa-dev mesa-utils libosmesa6 libsdl1.2-dev libsdl2-2.0-0 fonts-wqy-microhei libfile-mimeinfo-perl tesseract-ocr tesseract-ocr-eng tesseract-ocr-chi-sim tesseract-ocr-ara tesseract-ocr-rus tesseract-ocr-ell libfuse2 stalonetray | |
| version: 1.5 | |
| # Bump me ^ if you have added any new packages | |
| - name: Cache test dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: deps | |
| key: test-deps-${{ hashFiles('code/fetch-deps.sh') }} | |
| - name: Fetch test dependencies | |
| run: | | |
| bash code/fetch-deps.sh # No-op when restored from the cache | |
| cp -a deps/. . # worker.sh expects them in the working directory | |
| - name: Install dependencies | |
| shell: bash | |
| run: | | |
| # set -e | |
| sudo bash code/prep-dummy-soundcard.sh | |
| # TODO Cache gem and npm packages | |
| sudo gem install dupervisor -v 1.0.5 # To convert ini to yaml files | |
| sudo npm install -g asar # to get pacakges.json from resources/app.asar for electron-builder applications | |
| # npm install -g @alexlafroscia/yaml-merge # to merge yaml files | |
| - name: Main test | |
| id: main | |
| env: | |
| DISPATCH_COMMIT: ${{ inputs.commit }} | |
| DISPATCH_FILES: ${{ inputs.files }} | |
| run: | | |
| touch .test-start # Screenshots newer than this are from this run | |
| mkdir $HOME/.icewm/ | |
| cat > $HOME/.icewm/preferences <<EOF | |
| ShowTaskBar = 0 | |
| TaskBarAutoHide = 1 | |
| TaskBarShowWorkspaces = 0 | |
| TaskBarShowAllWindows = 0 | |
| TaskBarShowClock = 0 | |
| TaskBarShowMailboxStatus = 0 | |
| TaskBarShowCPUStatus = 0 | |
| TaskBarShowWindowListMenu = 0 | |
| EOF | |
| Xvfb :99 -screen 0 800x600x24 >/dev/null 2>&1 & # Need to set bit depth, otherwise get some black screenshots | |
| # Files in data/ added or changed by this PR (or by this push) | |
| if [ "$IS_PULLREQUEST" = true ] ; then | |
| FILES=$(git diff --name-only --diff-filter=AMR "origin/${{ github.base_ref }}...HEAD" -- data/) | |
| elif [ -n "$DISPATCH_FILES" ] ; then | |
| FILES="" | |
| for NAME in $DISPATCH_FILES ; do | |
| [[ "$NAME" =~ ^[A-Za-z0-9._+-]+$ ]] && [ -f "data/$NAME" ] || { echo "Not an entry in data/: $NAME" ; exit 1 ; } | |
| FILES="$FILES data/$NAME" | |
| done | |
| elif [ -n "$DISPATCH_COMMIT" ] ; then | |
| [[ "$DISPATCH_COMMIT" =~ ^[0-9a-f]{7,40}$ ]] || { echo "Not a commit: $DISPATCH_COMMIT" ; exit 1 ; } | |
| FILES=$(git diff --name-only --diff-filter=AMR "$DISPATCH_COMMIT~1" "$DISPATCH_COMMIT" -- data/) | |
| elif [ -n "${{ github.event.before }}" ] && git cat-file -e "${{ github.event.before }}" 2>/dev/null ; then | |
| FILES=$(git diff --name-only --diff-filter=AMR "${{ github.event.before }}" HEAD -- data/) | |
| else | |
| FILES=$(git diff --name-only --diff-filter=AMR HEAD~1 HEAD -- data/) | |
| fi | |
| echo "Changed files:" | |
| echo "$FILES" | |
| if [ -z "$FILES" ] ; then | |
| # E.g. a PR that only removes an application | |
| echo "No added or changed files in data/, nothing to test" | |
| touch .nothing-tested | |
| exit 0 | |
| fi | |
| for FILE in $FILES; do | |
| echo "$FILE" | |
| # The timeout keeps a hanging application from running into the job | |
| # timeout, which would cancel the job without a report on the PR | |
| # Name rules are errors only for files a PR adds (existing entries may have older names) | |
| STRICT=false | |
| if [ "$IS_PULLREQUEST" = true ] && [ -n "$(git diff --name-only --diff-filter=A "origin/${{ github.base_ref }}...HEAD" -- "$FILE")" ] ; then | |
| STRICT=true | |
| fi | |
| export STRICT | |
| timeout --kill-after=30 "$WORKER_TIMEOUT" bash -e code/worker.sh "$(readlink -f "$FILE")" 2>&1 | tee -a log.txt | |
| EXIT_CODE=${PIPESTATUS[0]} # bashism; get the return code of the leftmost element of the pipe | |
| if [ $EXIT_CODE -eq 124 ] || [ $EXIT_CODE -eq 137 ] ; then | |
| echo "ERROR: Timed out after $WORKER_TIMEOUT seconds while testing $FILE" | tee -a log.txt | |
| fi | |
| if [ $EXIT_CODE -ne 0 ]; then | |
| echo "worker.sh exited with a non-zero code: $EXIT_CODE" | |
| # Re-testing chosen entries: go on with the others | |
| if [ -n "$DISPATCH_FILES" ] ; then | |
| FAILED="${FAILED:-} $FILE" | |
| # Drop what the failed file left in database/ and apps/, so that nothing commits it | |
| git checkout -q -- database apps 2>/dev/null || true | |
| git clean -fdq -- database apps | |
| continue | |
| fi | |
| exit $EXIT_CODE | |
| fi | |
| done | |
| killall Xvfb | |
| if [ -n "${FAILED:-}" ] ; then | |
| echo "Failed:$FAILED" | |
| exit 1 | |
| fi | |
| - name: Collect result for the PR comment | |
| if: always() && github.event_name == 'pull_request' | |
| run: | | |
| # Read by publish-pr-screenshot.yml, which has the permissions to comment on PRs from forks | |
| [ -e .nothing-tested ] && exit 0 # No artifact, no comment | |
| mkdir -p pr-result | |
| echo "${{ github.event.pull_request.number }}" > pr-result/pr-number | |
| # If the screenshot's text is predominantly Chinese (check-screenshot.sh | |
| # OCRs it), record it so publish-pr-screenshot.yml can invite the author | |
| # to offer an English default instead of posting the usual report. | |
| grep -q 'not in English but in Chinese script' log.txt && echo chinese > pr-result/language.txt || true | |
| if [ "${{ steps.main.outcome }}" = success ] ; then | |
| find database -type f -path '*/screenshot.png' -newer .test-start -print | while IFS= read -r screenshot ; do | |
| appname=$(basename "$(dirname "$screenshot")" | tr -cd 'A-Za-z0-9._-') | |
| cp "$screenshot" "pr-result/${appname}.png" | |
| done | |
| # For the screenshot-ok label: a screenshot, and code/check-screenshot.sh had no remarks | |
| if ls pr-result/*.png >/dev/null 2>&1 && ! grep -qE '^(WARNING|ERROR): The (window|screenshot)' log.txt ; then | |
| touch pr-result/screenshot-ok | |
| fi | |
| else | |
| cp failure-screens/*.png pr-result/ 2>/dev/null || true | |
| bash code/diagnose.sh --excerpt log.txt > pr-result/error.txt | |
| bash code/diagnose.sh --labels log.txt > pr-result/labels.txt | |
| [ -s pr-result/labels.txt ] || echo error-other > pr-result/labels.txt | |
| fi | |
| # Also on success, e.g., a helper failing because of a too new glibc | |
| bash code/diagnose.sh log.txt > pr-result/hints.md | |
| # Remarks about the name of the file in data/ and of the AppImage | |
| grep -hE "^(ERROR|WARNING): ((File name|AppImage name) '|The names of the .* differ: )" log.txt | sort -u > pr-result/names.txt || true | |
| # Notes about the name of the file in data/ (not warnings) | |
| grep -h "^NOTE: File name '" log.txt | sort -u > pr-result/notes.txt || true | |
| # Whether the AppImage needs a compatible C library on the host | |
| grep -h '^X-AppImage-\(Libc\|Runtime\|Self-Contained\|Glibc-Required\)=' log.txt | sort -u > pr-result/libc.txt || true | |
| ls -la pr-result/ | |
| - name: Upload result | |
| if: always() && github.event_name == 'pull_request' && hashFiles('pr-result/**') != '' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: pr-result | |
| path: pr-result/ | |
| retention-days: 7 |