mirror of
https://github.com/pytorch/pytorch.git
synced 2025-10-21 21:49:24 +08:00
Run ShellCheck on scripts in GitHub Actions workflows (#55486)
Summary: Resolves https://github.com/pytorch/pytorch/issues/55314. - [x] Extract shell scripts from `.github/workflows/*.yml` into `.shellcheck_generated` dir - [x] Run ShellCheck on `.shellcheck_generated` - [x] Fail if any of the extracted scripts contain [GitHub Actions expressions][]: `${{ <expression> }}` - [x] Fix the newly-surfaced warnings Pull Request resolved: https://github.com/pytorch/pytorch/pull/55486 Test Plan: Locally run the "ShellCheck" step from "Lint / quick-checks". [github actions expressions]: https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#about-contexts-and-expressions Reviewed By: malfet Differential Revision: D27627590 Pulled By: samestep fbshipit-source-id: 8a22c6743e11b3059506043735f100efdd7c5a26
This commit is contained in:
committed by
Facebook GitHub Bot
parent
960b40156c
commit
adc65974b2
76
tools/extract_scripts.py
Executable file
76
tools/extract_scripts.py
Executable file
@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# these two pages have some relevant information:
|
||||
# https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
|
||||
# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict
|
||||
|
||||
import yaml
|
||||
|
||||
Job = Dict[str, Any]
|
||||
|
||||
windows_labels = {'windows-latest', 'windows-2019'}
|
||||
|
||||
|
||||
def get_default_shell(job: Job) -> str:
|
||||
return 'pwsh' if job['runs-on'] in windows_labels else 'bash'
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--out', required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
out = Path(args.out)
|
||||
if out.exists():
|
||||
sys.exit(f'{out} already exists; aborting to avoid overwriting')
|
||||
|
||||
gha_expressions_found = False
|
||||
|
||||
for p in Path('.github/workflows').iterdir():
|
||||
with open(p) as f:
|
||||
workflow = yaml.safe_load(f)
|
||||
|
||||
for job_name, job in workflow['jobs'].items():
|
||||
job_dir = out / p / job_name
|
||||
default_shell = get_default_shell(job)
|
||||
steps = job['steps']
|
||||
index_chars = len(str(len(steps) - 1))
|
||||
for i, step in enumerate(steps, start=1):
|
||||
script = step.get('run')
|
||||
if script:
|
||||
step_name = step['name']
|
||||
if '${{' in script:
|
||||
gha_expressions_found = True
|
||||
print(
|
||||
f'{p} job `{job_name}` step {i}: {step_name}',
|
||||
file=sys.stderr
|
||||
)
|
||||
|
||||
if step.get('shell', default_shell) == 'bash':
|
||||
job_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
sanitized = re.sub(
|
||||
'[^a-zA-Z_]+', '_',
|
||||
f'_{step_name}',
|
||||
).rstrip('_')
|
||||
filename = f'{i:0{index_chars}}{sanitized}.sh'
|
||||
(job_dir / filename).write_text(
|
||||
f'#!/usr/bin/env bash\nset -eo pipefail\n{script}'
|
||||
)
|
||||
|
||||
if gha_expressions_found:
|
||||
sys.exit(
|
||||
'Each of the above scripts contains a GitHub Actions '
|
||||
'${{ <expression> }} which must be replaced with an `env` variable'
|
||||
' for security reasons.'
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Reference in New Issue
Block a user