Skip to content

Commit

Permalink
chore(ci): add script and workflow for auto-updating schema (#286)
Browse files Browse the repository at this point in the history
  • Loading branch information
rchl authored Dec 13, 2023
1 parent 0ea5ad0 commit 1b6218e
Show file tree
Hide file tree
Showing 6 changed files with 315 additions and 634 deletions.
60 changes: 60 additions & 0 deletions .github/workflows/schema.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Update schema in Dependabot PR

on:
pull_request:
branches:
- master

permissions:
pull-requests: write
repository-projects: write

jobs:
update_schema:
name: Run schema update
runs-on: ubuntu-latest

if: github.actor == 'dependabot[bot]'
steps:
- uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.11

- name: Update schema
id: update-schema
run: |
echo "::set-output name=UPDATE_OUTPUT::$(make update-schema)"
- name: Check for modified files
id: git-check
run: echo ::set-output name=modified::$(if [ -n "$(git status --porcelain)" ]; then echo "true"; else echo "false"; fi)

- name: Update changes in the PR
if: steps.git-check.outputs.modified == 'true'
run: |
git config --global user.name 'workflow'
git config --global user.email '[email protected]'
git add -A
git commit -m '[automated commit] update schema'
git push
- name: Find Comment
uses: peter-evans/find-comment@v2
id: find-comment
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: 'github-actions[bot]'
body-includes: Build output

- name: Create or update comment
uses: peter-evans/create-or-update-comment@v3
with:
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body: |
schema-update output:
${{ steps.update-schema.outputs.UPDATE_OUTPUT }}
edit-mode: replace
11 changes: 1 addition & 10 deletions LSP-pyright.sublime-settings
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,8 @@
// Specifies the level of logging for the Output panel
"python.analysis.logLevel": "Information",
// Defines the default rule set for type checking.
"python.analysis.typeCheckingMode": "basic",
"python.analysis.typeCheckingMode": "standard",
// Paths to look for typeshed modules.
// Hmm... doesn't seem to work on my side. May track https://github.com/microsoft/pylance-release/issues/29
"python.analysis.typeshedPaths": [],
// Use library implementations to extract type information when type stub is not present.
"python.analysis.useLibraryCodeForTypes": true,
Expand All @@ -58,13 +57,5 @@
// Path to folder with a list of Virtual Environments.
"python.venvPath": "",
},
// ST4
"selector": "source.python",
// ST3
"languages": [
{
"scopes": ["source.python - source.python.lsp"],
"syntaxes": ["Packages/Python/Python.sublime-syntax"],
},
],
}
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ fix:
autoflake --in-place .
black --preview .
isort .

.PHONY: update-schema
update-schema:
python3 ./scripts/update_schema.py
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ skip_glob = [
"branch-*/**",
"libs/**",
"resources/**",
"scripts/**",
"stubs/**",
"typings/**",
"vendor/**",
Expand All @@ -20,7 +21,7 @@ skip_glob = [
quiet = true
recursive = true
remove-all-unused-imports = true
exclude = '\.git,\.?venv(-.*)?,\.mypy_cache,br-.*,branch-.*,libs,stubs,tests/files,typings'
exclude = '\.git,\.?venv(-.*)?,\.mypy_cache,br-.*,branch-.*,libs,scripts,stubs,tests/files,typings'

[tool.black]
preview = true # use latest feature
Expand All @@ -33,6 +34,7 @@ exclude = '''
language-server |
plugin/libs |
resources |
scripts |
stubs |
typings |
_resources
Expand Down
103 changes: 103 additions & 0 deletions scripts/update_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
from json import dump, dumps, load
from typing import Any, Dict, List, Optional, Tuple
from urllib.request import urlopen
import os

DIRNAME = os.path.dirname(os.path.abspath(__file__))
PYRIGHTCONFIG_SCHEMA_ID = 'sublime://pyrightconfig'
PYRIGHT_CONFIGURATION_SCHEMA_URL = 'https://raw.githubusercontent.com/microsoft/pyright/main/packages/vscode-pyright/schemas/pyrightconfig.schema.json' # noqa: E501
SUBLIME_PACKAGE_JSON_PATH = os.path.join(DIRNAME, '..', 'sublime-package.json')
# Keys that are in the pyrightconfig.json schema but should not raise a comment when not present in the LSP schema.
IGNORED_PYRIGHTCONFIG_KEYS = [
'defineConstant',
'exclude',
'executionEnvironments',
'ignore',
'include',
'pythonPlatform',
'pythonVersion',
'strict',
'typeshedPath',
'venv',
'verboseOutput',
]

JSON = Dict[str, Any]


def main() -> None:
pyrightconfig_schema_json, sublime_package_schema_json = read_sublime_package_json()
before = dumps(sublime_package_schema_json)
new_schema_keys = update_schema(sublime_package_schema_json, pyrightconfig_schema_json)
after = dumps(sublime_package_schema_json)
if before != after:
with open(SUBLIME_PACKAGE_JSON_PATH, 'w', encoding='utf-8') as f:
dump(sublime_package_schema_json, f, indent=2)
print('sublime-package.json schema updated.')
else:
print('No updates done to sublime-package.json.')
if new_schema_keys:
print('\nThe following new keys were found in the latest pyrightconfig.json schema: {}\n\n'.format(
'\n - '.join(new_schema_keys)))
print('Ensure that those are added to the sublime-package.json manually, if relevant.')


def read_sublime_package_json() -> Tuple[JSON, JSON]:
with urlopen(PYRIGHT_CONFIGURATION_SCHEMA_URL) as response:
pyrightconfig_schema_json = load(response)
with open(SUBLIME_PACKAGE_JSON_PATH, 'r', encoding='utf-8') as f:
sublime_package_schema_json = load(f)
return (pyrightconfig_schema_json, sublime_package_schema_json)


def update_schema(sublime_package_json: JSON, pyrightconfig_schema_json: JSON) -> List[str]:
pyrightconfig_contribution: Optional[JSON] = None
lsp_pyright_contribution: Optional[JSON] = None
for contribution in sublime_package_json['contributions']['settings']:
if '/pyrightconfig.json' in contribution['file_patterns']:
pyrightconfig_contribution = contribution
elif '/LSP-pyright.sublime-settings' in contribution['file_patterns']:
lsp_pyright_contribution = contribution
if not pyrightconfig_contribution or not lsp_pyright_contribution:
raise Exception('Expected contributions not found in sublime-package.json!')
# Update to latest pyrightconfig schema.
pyrightconfig_contribution['schema'] = pyrightconfig_schema_json
# Add ID.
pyrightconfig_contribution['schema']['$id'] = PYRIGHTCONFIG_SCHEMA_ID
# Update LSP settings to reference options from the pyrightconfig schema.
settings_properties: JSON = lsp_pyright_contribution['schema']['definitions']['PluginConfig']['properties']['settings']['properties'] # noqa: E501
pyrightconfig_properties: JSON = pyrightconfig_contribution['schema']['properties']
for setting_key, setting_value in settings_properties.items():
# get last dotted component.
last_component_key = setting_key.split('.').pop()
if last_component_key in pyrightconfig_properties:
update_property_ref(last_component_key, setting_value, pyrightconfig_properties)
if setting_key == 'python.analysis.diagnosticSeverityOverrides':
overrides_properties: JSON = setting_value['properties']
for override_key, override_value in overrides_properties.items():
if override_key in pyrightconfig_properties:
update_property_ref(override_key, override_value, pyrightconfig_properties)
else:
del overrides_properties[override_key]
# Check if there are any properties that might need to be added to the LSP properties.
# If the property is neither in `diagnosticSeverityOverrides`, the root LSP settings nor in ignored keys
# then it might have to be added manually.
all_settings_keys = list(map(lambda k: k.split('.').pop(), settings_properties.keys()))
all_overrides_keys = settings_properties['python.analysis.diagnosticSeverityOverrides']['properties'].keys()
new_schema_keys = []
for pyrightconfig_key in pyrightconfig_properties.keys():
if pyrightconfig_key not in all_settings_keys \
and pyrightconfig_key not in all_overrides_keys \
and pyrightconfig_key not in IGNORED_PYRIGHTCONFIG_KEYS:
new_schema_keys.append(pyrightconfig_key)
return new_schema_keys


def update_property_ref(property_key: str, property_schema: JSON, pyrightconfig_properties: JSON) -> None:
property_schema.clear()
pyrightconfig_property_id: str = pyrightconfig_properties[property_key]['$id']
property_schema['$ref'] = PYRIGHTCONFIG_SCHEMA_ID + pyrightconfig_property_id


if __name__ == '__main__':
main()
Loading

0 comments on commit 1b6218e

Please sign in to comment.