diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f06c1bdd8..972a2cc426 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,64 +8,61 @@ env: BASENAME: "vorestation" jobs: - file_tests: + run_linters: + if: ( !contains(github.event.head_commit.message, '[ci skip]') ) name: Run Linters - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 + concurrency: + group: run_linters-${{ github.head_ref || github.run_id }} + cancel-in-progress: true steps: - uses: actions/checkout@v4 - name: Ensure +x on CI directory run: | chmod -R +x ./tools/ci - - name: Install Tools - run: | - bash tools/ci/install_build_deps.sh - - name: Restore Yarn cache - if: "${{ contains(github.event.pull_request.labels.*.name, 'Type: TGUI Bundle') }}" - uses: actions/cache@v3 - with: - path: tgui/.yarn/cache - key: ${{ runner.os }}-yarn-${{ secrets.CACHE_PURGE_KEY }}-${{ hashFiles('tgui/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-build-${{ secrets.CACHE_PURGE_KEY }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - - name: Run Tests - run: | - tools/ci/validate_files.sh - - name: Run TGUI Checks - run: tools/build/build --ci lint tgui-test - - dreamchecker: - name: DreamChecker - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v4 - - - name: Cache SpacemanDMM + - name: Restore SpacemanDMM cache uses: actions/cache@v3 with: path: ~/SpacemanDMM - key: ${{ runner.os }}-dreamchecker-${{ hashFiles('dependencies.sh')}} - restore-keys: ${{ runner.os }}-dreamchecker - - - name: Install Dependencies - run: | - tools/ci/install_spaceman_dmm.sh dreamchecker - - - name: Run Linter - id: linter - run: | - ~/dreamchecker > ${GITHUB_WORKSPACE}/output-annotations.txt 2>&1 - - - name: Annotate Linter - uses: yogstation13/DreamAnnotate@v2 - if: always() + key: ${{ runner.os }}-spacemandmm + - name: Restore Yarn cache + uses: actions/cache@v3 with: - outputFile: output-annotations.txt + path: tgui/.yarn/cache + key: ${{ runner.os }}-yarn-${{ hashFiles('tgui/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + - name: Restore Node cache + uses: actions/cache@v3 + with: + path: ~/.nvm + key: ${{ runner.os }}-node-${{ hashFiles('_dependencies.sh') }} + restore-keys: | + ${{ runner.os }}-node- + - name: Restore Bootstrap cache + uses: actions/cache@v3 + with: + path: tools/bootstrap/.cache + key: ${{ runner.os }}-bootstrap-${{ hashFiles('tools/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-bootstrap- + - name: Install Tools + run: | + bash tools/ci/install_build_deps.sh + bash tools/ci/install_spaceman_dmm.sh dreamchecker + - name: Run Tests + run: | + tools/ci/validate_files.sh + - name: Run DreamChecker + shell: bash + run: ~/dreamchecker 2>&1 | bash tools/ci/annotate_dm.sh + - name: Run TGUI Checks + run: tools/build/build --ci lint tgui-test unit_tests: + if: ( !contains(github.event.head_commit.message, '[ci skip]') ) name: Integration Tests - # needs: ['file_tests', 'dreamchecker'] + # needs: ['run_linters', 'dreamchecker'] runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v4 @@ -109,8 +106,9 @@ jobs: RUN: "0" tests_successful: + if: ( !contains(github.event.head_commit.message, '[ci skip]') ) name: Integration Tests - needs: ['file_tests', 'dreamchecker', 'unit_tests'] + needs: ['run_linters', 'unit_tests'] runs-on: ubuntu-20.04 steps: - name: Report Success diff --git a/tools/ci/annotate_dm.sh b/tools/ci/annotate_dm.sh new file mode 100644 index 0000000000..e43f930ba1 --- /dev/null +++ b/tools/ci/annotate_dm.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +set -euo pipefail +tools/bootstrap/python -m dm_annotator "$@" diff --git a/tools/dm_annotator/__main__.py b/tools/dm_annotator/__main__.py new file mode 100644 index 0000000000..4948fd0865 --- /dev/null +++ b/tools/dm_annotator/__main__.py @@ -0,0 +1,51 @@ +import sys +import re +import os.path as path + +# Usage: tools/bootstrap/python -m dm_annotator [filename] +# If filename is not provided, stdin is checked instead + +def red(text): + return "\033[31m" + str(text) + "\033[0m" + +def green(text): + return "\033[32m" + str(text) + "\033[0m" + +def yellow(text): + return "\033[33m" + str(text) + "\033[0m" + +def annotate(raw_output): + # Remove ANSI escape codes + raw_output = re.sub(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]', '', raw_output) + + print("::group::DreamChecker Output") + print(raw_output) + print("::endgroup::") + + annotation_regex = r'(?P.*?), line (?P\d+), column (?P\d+):\s{1,2}(?Perror|warning): (?P.*)' + has_issues = False + + print("DM Code Annotations:") + for annotation in re.finditer(annotation_regex, raw_output): + print(f"::{annotation['type']} file={annotation['filename']},line={annotation['line']},col={annotation['column']}::{annotation['message']}") + has_issues = True + + if not has_issues: + print(green("No DM issues found")) + +def main(): + if len(sys.argv) > 1: + if not path.exists(sys.argv[1]): + print(red(f"Error: Annotations file '{sys.argv[1]}' does not exist")) + sys.exit(1) + with open(sys.argv[1], 'r') as f: + annotate(f.read()) + elif not sys.stdin.isatty(): + annotate(sys.stdin.read()) + else: + print(red("Error: No input provided")) + print("Usage: tools/bootstrap/python -m dm_annotator [filename]") + sys.exit(1) + +if __name__ == '__main__': + main()