feat: Add Modern clock for desktop. #1067
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: Automatic Code Quality Review | |
| on: | |
| pull_request_target: | |
| types: | |
| - opened | |
| - synchronize | |
| - reopened | |
| paths: | |
| - "**.qml" | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| jobs: | |
| code-quality: | |
| if: github.event.pull_request.draft == false | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| - name: Automatic Code Quality | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| BASE_REF: ${{ github.base_ref }} | |
| HEAD_REF: ${{ github.head_ref }} | |
| run: | | |
| git fetch origin "$BASE_REF" | |
| diff_changes=$(git diff -U10000 origin/$BASE_REF...HEAD | | |
| awk '/^diff --git.*\.qml /{found=1} /^diff --git/{if(!/\.qml /) found=0} found{print}' | | |
| grep -vE "^(index|\+\+\+|-)") || echo "No qml file changed" | |
| if [ -z "$diff_changes" ]; then | |
| echo "No diff changes found!" | |
| echo "The base ref checking: $BASE_REF" | |
| echo "The head ref checking: $HEAD_REF" | |
| exit 0 | |
| fi | |
| comment_body=$(printf -- '### Automatic Code Quality Review') | |
| issues=0 | |
| line_index=0 | |
| l_priority="[(L)]($PR_NUMBER 'Low priority, it is okay for this to remain unfixed before merging')" | |
| h_priority="[(H)]($PR_NUMBER 'High priority, this needs to be fixed for the PR to be merged')" | |
| function print_line() { | |
| check_file_title | |
| local priority=$1 | |
| local index=$2 | |
| local comment=$3 | |
| local code_line=$4 | |
| comment_body+=$(printf -- '\n- %s Line %d: %s\n```qml\n%s\n```' "$priority" "$index" "$comment" "$code_line") | |
| } | |
| function print_missing_property() { | |
| check_file_title | |
| local priority=$1 | |
| local property=$2 | |
| local code_line=$3 | |
| comment_body+=$(printf -- '\n- %s Missing required property `%s`. For example:\n```qml\n%s\n```' "$priority" "$property" "$code_line") | |
| } | |
| title_added=false | |
| file_title="" | |
| function check_file_title() { | |
| if [ "$title_added" = false ]; then | |
| title_added=true | |
| comment_body+="$(printf -- '\n---\n### File: %s' "$file_title")" | |
| fi | |
| } | |
| # Required Properties in Components | |
| inBarWidget=false | |
| inDesktopWidget=false | |
| inDesktopWidgetSettings=false | |
| inControlCenterWidget=false | |
| inLauncherProvider=false | |
| inMain=false | |
| inPanel=false | |
| inSettings=false | |
| hasPluginApi=false | |
| hasScreen=false | |
| hasWidgetId=false | |
| hasSection=false | |
| hasSectionWidgetIndex=false | |
| hasSectionWidgetsCount=false | |
| hasWidgetSettings=false | |
| hasLauncher=false | |
| hasName=false | |
| hasGeometryPlaceholder=false | |
| hasAllowAttach=false | |
| function reset_required_properties() { | |
| inBarWidget=false | |
| inDesktopWidget=false | |
| inDesktopWidgetSettings=false | |
| inControlCenterWidget=false | |
| inLauncherProvider=false | |
| inMain=false | |
| inPanel=false | |
| inSettings=false | |
| hasPluginApi=false | |
| hasScreen=false | |
| hasWidgetId=false | |
| hasSection=false | |
| hasSectionWidgetIndex=false | |
| hasSectionWidgetsCount=false | |
| hasWidgetSettings=false | |
| hasLauncher=false | |
| hasName=false | |
| hasGeometryPlaceholder=false | |
| hasAllowAttach=false | |
| } | |
| function print_required_properties() { | |
| if [ "$inBarWidget" = true ]; then | |
| if [ "$hasPluginApi" = false ]; then | |
| print_missing_property "$h_priority" 'pluginApi' 'property var pluginApi: null' | |
| issues=$((issues + 1)) | |
| fi | |
| if [ "$hasScreen" = false ]; then | |
| print_missing_property "$h_priority" 'screen' 'property ShellScreen screen' | |
| issues=$((issues + 1)) | |
| fi | |
| if [ "$hasWidgetId" = false ]; then | |
| print_missing_property "$h_priority" 'widgetId' 'property string widgetId: ""' | |
| issues=$((issues + 1)) | |
| fi | |
| if [ "$hasSection" = false ]; then | |
| print_missing_property "$h_priority" 'section' 'property string section: ""' | |
| issues=$((issues + 1)) | |
| fi | |
| if [ "$hasSectionWidgetIndex" = false ]; then | |
| print_missing_property "$h_priority" 'sectionWidgetIndex' 'property int sectionWidgetIndex: -1' | |
| issues=$((issues + 1)) | |
| fi | |
| if [ "$hasSectionWidgetsCount" = false ]; then | |
| print_missing_property "$h_priority" 'sectionWidgetsCount' 'property int sectionWidgetsCount: 0' | |
| issues=$((issues + 1)) | |
| fi | |
| fi | |
| if [ "$inDesktopWidget" = true ]; then | |
| if [ "$hasPluginApi" = false ]; then | |
| print_missing_property "$h_priority" 'pluginApi' 'property var pluginApi: null' | |
| issues=$((issues + 1)) | |
| fi | |
| fi | |
| if [ "$inDesktopWidgetSettings" = true ]; then | |
| if [ "$hasPluginApi" = false ]; then | |
| print_missing_property "$h_priority" 'pluginApi' 'property var pluginApi: null' | |
| issues=$((issues + 1)) | |
| fi | |
| if [ "$hasWidgetSettings" = false ]; then | |
| print_missing_property "$h_priority" 'widgetSettings' 'property var widgetSettings: null' | |
| issues=$((issues + 1)) | |
| fi | |
| fi | |
| if [ "$inControlCenterWidget" = true ]; then | |
| if [ "$hasPluginApi" = false ]; then | |
| print_missing_property "$h_priority" 'pluginApi' 'property var pluginApi: null' | |
| issues=$((issues + 1)) | |
| fi | |
| if [ "$hasScreen" = false ]; then | |
| print_missing_property "$h_priority" 'screen' 'property ShellScreen screen' | |
| issues=$((issues + 1)) | |
| fi | |
| fi | |
| if [ "$inLauncherProvider" = true ]; then | |
| if [ "$hasPluginApi" = false ]; then | |
| print_missing_property "$h_priority" 'pluginApi' 'property var pluginApi: null' | |
| issues=$((issues + 1)) | |
| fi | |
| if [ "$hasLauncher" = false ]; then | |
| print_missing_property "$h_priority" 'launcher' 'property var launcher: ""' | |
| issues=$((issues + 1)) | |
| fi | |
| if [ "$hasName" = false ]; then | |
| print_missing_property "$h_priority" 'name' 'property string name: "Example"' | |
| issues=$((issues + 1)) | |
| fi | |
| fi | |
| if [ "$inMain" = true ]; then | |
| if [ "$hasPluginApi" = false ]; then | |
| print_missing_property "$h_priority" 'pluginApi' 'property var pluginApi: null' | |
| issues=$((issues + 1)) | |
| fi | |
| fi | |
| if [ "$inPanel" = true ]; then | |
| if [ "$hasPluginApi" = false ]; then | |
| print_missing_property "$h_priority" 'pluginApi' 'property var pluginApi: null' | |
| issues=$((issues + 1)) | |
| fi | |
| if [ "$hasGeometryPlaceholder" = false ]; then | |
| print_missing_property "$h_priority" 'geometryPlaceholder' 'readonly property var geometryPlaceholder: panelContainer' | |
| issues=$((issues + 1)) | |
| fi | |
| if [ "$hasAllowAttach" = false ]; then | |
| print_missing_property "$h_priority" 'allowAttach' 'readonly property bool allowAttach: true' | |
| issues=$((issues + 1)) | |
| fi | |
| fi | |
| if [ "$inSettings" = true ]; then | |
| if [ "$hasPluginApi" = false ]; then | |
| print_missing_property "$h_priority" 'pluginApi' 'property var pluginApi: null' | |
| issues=$((issues + 1)) | |
| fi | |
| fi | |
| } | |
| while IFS= read -r line; do | |
| if echo "$line" | grep -E "^diff --git" >/dev/null; then | |
| print_required_properties | |
| reset_required_properties | |
| title_added=false | |
| file_title=$(echo "$line" | sed 's/diff --git a\/\(.*\.qml\) .*/\1/g') | |
| echo "Checking file: $file_title" | |
| if [[ "$file_title" == */BarWidget.qml ]]; then | |
| inBarWidget=true | |
| elif [[ "$file_title" == */DesktopWidget.qml ]]; then | |
| inDesktopWidget=true | |
| elif [[ "$file_title" == */DesktopWidgetSettings.qml ]]; then | |
| inDesktopWidgetSettings=true | |
| elif [[ "$file_title" == */ControlCenterWidget.qml ]]; then | |
| inControlCenterWidget=true | |
| elif [[ "$file_title" == */LauncherProvider.qml ]]; then | |
| inLauncherProvider=true | |
| elif [[ "$file_title" == */Main.qml ]]; then | |
| inMain=true | |
| elif [[ "$file_title" == */Panel.qml ]]; then | |
| inPanel=true | |
| elif [[ "$file_title" == */Settings.qml ]]; then | |
| inSettings=true | |
| fi | |
| elif echo "$line" | grep -E "^@@" >/dev/null; then | |
| line_index=$(echo "$line" | grep -oE "\+[0-9]+" | grep -oE "[0-9]+") | |
| echo "Current line index reset: $line_index" | |
| else | |
| if echo "$line" | grep -E "^\+" >/dev/null; then | |
| # Only new lines should be auto checked for this type of code quality | |
| if echo "$line" | grep -E "(border(\.width)?|spacing|pointSize|radius|margin(s)?): [1-9]+[0-9]*" >/dev/null; then | |
| print_line "$h_priority" "$line_index" 'Do not use hardcoded values, always prefer to use the `Style` singleton instead' "$line" | |
| issues=$((issues + 1)) | |
| fi | |
| if echo "$line" | grep -E "console\.log" >/dev/null; then | |
| print_line "$h_priority" "$line_index" 'Do not use `console.log`, always prefer to use the `Logger` singleton instead' "$line" | |
| issues=$((issues + 1)) | |
| fi | |
| if echo "$line" | grep -E "^(Text|Button|Checkbox|Switch) *\{" >/dev/null; then | |
| print_line "$h_priority" "$line_index" 'Always prefer to use noctalia-widgets instead of qml widgets to keep it consistent with the shell. For example instead of `Text`, use `NText`' "$line" | |
| issues=$((issues + 1)) | |
| fi | |
| if echo "$line" | grep -E "applyUiScale: *false" >/dev/null; then | |
| if [[ "$file_title" != *BarWidget.qml ]]; then | |
| print_line "$l_priority" "$line_index" 'The `applyUiScale: false` would make it so that the component does not support ui scaling. Always check if this is the correct behaviour you want when changing the ui scale!' "$line" | |
| issues=$((issues + 1)) | |
| fi | |
| fi | |
| if echo "$line" | grep -E "pluginApi\??\.tr\((.)*\) *(\?\?|\|\|)" >/dev/null; then | |
| print_line "$l_priority" "$line_index" 'When it comes to translations there is no need for fallback values. From: `pluginApi?.tr("example") || "value"`. To: `pluginApi?.tr("example")`' "$line" | |
| issues=$((issues + 1)) | |
| fi | |
| if echo "$line" | grep -E "(text|label|description): *(\"|').+(\"|')" >/dev/null; then | |
| print_line "$h_priority" "$line_index" 'Use translations instead of hardcoded text. Instead of: `"Example Label"`. To: `pluginApi?.tr("panel.example-label")`' "$line" | |
| issues=$((issues + 1)) | |
| fi | |
| fi | |
| # Check for required properties | |
| if [ "$inBarWidget" = true ]; then | |
| if echo "$line" | grep -E 'property +var +pluginApi: +null' >/dev/null; then | |
| hasPluginApi=true | |
| fi | |
| if echo "$line" | grep -E 'property +ShellScreen +screen' >/dev/null; then | |
| hasScreen=true | |
| fi | |
| if echo "$line" | grep -E 'property +string +widgetId: +""' >/dev/null; then | |
| hasWidgetId=true | |
| fi | |
| if echo "$line" | grep -E 'property +string +section: +""' >/dev/null; then | |
| hasSection=true | |
| fi | |
| if echo "$line" | grep -E 'property +int +sectionWidgetIndex: +-1' >/dev/null; then | |
| hasSectionWidgetIndex=true | |
| fi | |
| if echo "$line" | grep -E 'property +int +sectionWidgetsCount: +0' >/dev/null; then | |
| hasSectionWidgetsCount=true | |
| fi | |
| fi | |
| if [ "$inDesktopWidget" = true ]; then | |
| if echo "$line" | grep -E 'property +var +pluginApi: +null' >/dev/null; then | |
| hasPluginApi=true | |
| fi | |
| fi | |
| if [ "$inDesktopWidgetSettings" = true ]; then | |
| if echo "$line" | grep -E 'property +var +pluginApi: +null' >/dev/null; then | |
| hasPluginApi=true | |
| fi | |
| if echo "$line" | grep -E 'property +var +widgetSettings: +null' >/dev/null; then | |
| hasWidgetSettings=true | |
| fi | |
| fi | |
| if [ "$inControlCenterWidget" = true ]; then | |
| if echo "$line" | grep -E 'property +var +pluginApi: +null' >/dev/null; then | |
| hasPluginApi=true | |
| fi | |
| if echo "$line" | grep -E 'property +ShellScreen +screen' >/dev/null; then | |
| hasScreen=true | |
| fi | |
| fi | |
| if [ "$inLauncherProvider" = true ]; then | |
| if echo "$line" | grep -E 'property +var +pluginApi: +null' >/dev/null; then | |
| hasPluginApi=true | |
| fi | |
| if echo "$line" | grep -E 'property +var +launcher: +null' >/dev/null; then | |
| hasLauncher=true | |
| fi | |
| if echo "$line" | grep -E 'property +string +name: +".*"' >/dev/null; then | |
| hasName=true | |
| fi | |
| fi | |
| if [ "$inMain" = true ]; then | |
| if echo "$line" | grep -E 'property +var +pluginApi: +null' >/dev/null; then | |
| hasPluginApi=true | |
| fi | |
| fi | |
| if [ "$inPanel" = true ]; then | |
| if echo "$line" | grep -E 'property +var +pluginApi: +null' >/dev/null; then | |
| hasPluginApi=true | |
| fi | |
| if echo "$line" | grep -E 'readonly +property +var +geometryPlaceholder:' >/dev/null; then | |
| hasGeometryPlaceholder=true | |
| fi | |
| if echo "$line" | grep -E 'readonly +property +bool +allowAttach:' >/dev/null; then | |
| hasAllowAttach=true | |
| fi | |
| fi | |
| if [ "$inSettings" = true ]; then | |
| if echo "$line" | grep -E 'property +var +pluginApi: +null' >/dev/null; then | |
| hasPluginApi=true | |
| fi | |
| fi | |
| line_index=$((line_index + 1)) | |
| fi | |
| done <<<"$diff_changes" | |
| # Print any required properties not printed on a new file found. | |
| print_required_properties | |
| if [[ "$issues" -ne 0 ]]; then | |
| gh pr comment "$PR_NUMBER" --body "$comment_body" | |
| fi |