Skip to content

Commit 6630c68

Browse files
committed
adding workflow
1 parent 9bdeda2 commit 6630c68

4 files changed

Lines changed: 373 additions & 0 deletions

File tree

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
name: Sanitize Postman Files
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
sanitize:
11+
runs-on: ubuntu-latest
12+
permissions:
13+
contents: write
14+
pull-requests: write
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
with:
19+
fetch-depth: 0
20+
21+
- name: Set up Python
22+
uses: actions/setup-python@v5
23+
with:
24+
python-version: '3.11'
25+
26+
- name: Install dependencies
27+
run: |
28+
python -m pip install --upgrade pip
29+
pip install black
30+
31+
- name: Run sanitization script
32+
id: sanitize
33+
run: |
34+
python scripts/sanitize_postman.py .
35+
echo "modified_files<<EOF" >> $GITHUB_OUTPUT
36+
git status --porcelain | grep -E '\.postman_(collection|environment)\.json$' | awk '{print $2}' >> $GITHUB_OUTPUT
37+
echo "EOF" >> $GITHUB_OUTPUT
38+
39+
- name: Configure Git
40+
run: |
41+
git config --local user.email "github-actions[bot]@users.noreply.github.com"
42+
git config --local user.name "github-actions[bot]"
43+
44+
- name: Commit and push if changes exist
45+
if: steps.sanitize.outputs.modified_files != ''
46+
run: |
47+
git add .
48+
git commit -m "chore: sanitize Postman files [skip ci]"
49+
git push
50+
51+
- name: Create Pull Request Comment
52+
if: github.event_name == 'pull_request' && steps.sanitize.outputs.modified_files != ''
53+
uses: actions/github-script@v7
54+
with:
55+
script: |
56+
const modifiedFiles = process.env.MODIFIED_FILES.split('\n').filter(Boolean);
57+
const comment = `## Postman Files Sanitized 🔧\n\nThe following Postman files were automatically sanitized to remove metadata:\n\n${modifiedFiles.map(file => `- \`${file}\``).join('\n')}\n\nThis sanitization removes internal IDs and other metadata to keep the repository clean.`;
58+
59+
github.rest.issues.createComment({
60+
issue_number: context.issue.number,
61+
owner: context.repo.owner,
62+
repo: context.repo.repo,
63+
body: comment
64+
});
65+
env:
66+
MODIFIED_FILES: ${{ steps.sanitize.outputs.modified_files }}

.gitignore

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,198 @@
77
# Exclude some file types
88
*.sublime-project
99
*.sublime-workspace
10+
11+
# Byte-compiled / optimized / DLL files
12+
__pycache__/
13+
*.py[cod]
14+
*$py.class
15+
16+
# C extensions
17+
*.so
18+
19+
# Distribution / packaging
20+
.Python
21+
build/
22+
develop-eggs/
23+
dist/
24+
downloads/
25+
eggs/
26+
.eggs/
27+
lib/
28+
lib64/
29+
parts/
30+
sdist/
31+
var/
32+
wheels/
33+
share/python-wheels/
34+
*.egg-info/
35+
.installed.cfg
36+
*.egg
37+
MANIFEST
38+
39+
# PyInstaller
40+
# Usually these files are written by a python script from a template
41+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
42+
*.manifest
43+
*.spec
44+
45+
# Installer logs
46+
pip-log.txt
47+
pip-delete-this-directory.txt
48+
49+
# Unit test / coverage reports
50+
htmlcov/
51+
.tox/
52+
.nox/
53+
.coverage
54+
.coverage.*
55+
.cache
56+
nosetests.xml
57+
coverage.xml
58+
*.cover
59+
*.py,cover
60+
.hypothesis/
61+
.pytest_cache/
62+
cover/
63+
64+
# Translations
65+
*.mo
66+
*.pot
67+
68+
# Django stuff:
69+
*.log
70+
local_settings.py
71+
db.sqlite3
72+
db.sqlite3-journal
73+
74+
# Flask stuff:
75+
instance/
76+
.webassets-cache
77+
78+
# Scrapy stuff:
79+
.scrapy
80+
81+
# Sphinx documentation
82+
docs/_build/
83+
84+
# PyBuilder
85+
.pybuilder/
86+
target/
87+
88+
# Jupyter Notebook
89+
.ipynb_checkpoints
90+
91+
# IPython
92+
profile_default/
93+
ipython_config.py
94+
95+
# pyenv
96+
# For a library or package, you might want to ignore these files since the code is
97+
# intended to run in multiple environments; otherwise, check them in:
98+
# .python-version
99+
100+
# pipenv
101+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
102+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
103+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
104+
# install all needed dependencies.
105+
#Pipfile.lock
106+
107+
# UV
108+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
109+
# This is especially recommended for binary packages to ensure reproducibility, and is more
110+
# commonly ignored for libraries.
111+
#uv.lock
112+
113+
# poetry
114+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
115+
# This is especially recommended for binary packages to ensure reproducibility, and is more
116+
# commonly ignored for libraries.
117+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
118+
#poetry.lock
119+
120+
# pdm
121+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
122+
#pdm.lock
123+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
124+
# in version control.
125+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
126+
.pdm.toml
127+
.pdm-python
128+
.pdm-build/
129+
130+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
131+
__pypackages__/
132+
133+
# Celery stuff
134+
celerybeat-schedule
135+
celerybeat.pid
136+
137+
# SageMath parsed files
138+
*.sage.py
139+
140+
# Environments
141+
.env
142+
.venv
143+
env/
144+
venv/
145+
ENV/
146+
env.bak/
147+
venv.bak/
148+
149+
# Spyder project settings
150+
.spyderproject
151+
.spyproject
152+
153+
# Rope project settings
154+
.ropeproject
155+
156+
# mkdocs documentation
157+
/site
158+
159+
# mypy
160+
.mypy_cache/
161+
.dmypy.json
162+
dmypy.json
163+
164+
# Pyre type checker
165+
.pyre/
166+
167+
# pytype static type analyzer
168+
.pytype/
169+
170+
# Cython debug symbols
171+
cython_debug/
172+
173+
# PyCharm
174+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
175+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
176+
# and can be added to the global gitignore or merged into this file. For a more nuclear
177+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
178+
#.idea/
179+
180+
# Abstra
181+
# Abstra is an AI-powered process automation framework.
182+
# Ignore directories containing user credentials, local state, and settings.
183+
# Learn more at https://abstra.io/docs
184+
.abstra/
185+
186+
# Visual Studio Code
187+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
188+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
189+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
190+
# you could uncomment the following to ignore the enitre vscode folder
191+
# .vscode/
192+
193+
# Ruff stuff:
194+
.ruff_cache/
195+
196+
# PyPI configuration file
197+
.pypirc
198+
199+
# Cursor
200+
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
201+
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
202+
# refer to https://docs.cursor.com/context/ignore-files
203+
.cursorignore
204+
.cursorindexingignore

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
black==24.2.0

scripts/sanitize_postman.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#!/usr/bin/env python3
2+
3+
import json
4+
import os
5+
import sys
6+
from pathlib import Path
7+
from typing import Dict, List, Set
8+
9+
# Properties to remove from Postman files
10+
METADATA_PROPERTIES = {
11+
'_postman_id',
12+
'_exporter_id',
13+
'id',
14+
'uid',
15+
'owner',
16+
'createdAt',
17+
'updatedAt',
18+
'lastUpdatedBy',
19+
'lastRevision',
20+
}
21+
22+
# Required schema versions for Postman files
23+
COLLECTION_SCHEMA = "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
24+
ENVIRONMENT_SCHEMA = "https://schema.getpostman.com/json/environment/v1.0.0/environment.json"
25+
26+
def remove_metadata(data: Dict, properties: Set[str]) -> Dict:
27+
"""Recursively remove specified properties from a dictionary."""
28+
if not isinstance(data, dict):
29+
return data
30+
31+
result = {}
32+
for key, value in data.items():
33+
if key in properties:
34+
continue
35+
36+
if isinstance(value, dict):
37+
result[key] = remove_metadata(value, properties)
38+
elif isinstance(value, list):
39+
result[key] = [remove_metadata(item, properties) if isinstance(item, dict) else item for item in value]
40+
else:
41+
result[key] = value
42+
43+
return result
44+
45+
def sanitize_file(file_path: Path) -> bool:
46+
"""Sanitize a single Postman file and return True if changes were made."""
47+
try:
48+
with open(file_path, 'r', encoding='utf-8') as f:
49+
data = json.load(f)
50+
51+
# Preserve the original schema
52+
original_schema = data.get('info', {}).get('schema') if 'info' in data else data.get('schema')
53+
54+
# Remove metadata
55+
sanitized_data = remove_metadata(data, METADATA_PROPERTIES)
56+
57+
# Restore schema if it was present
58+
if original_schema:
59+
if 'info' in sanitized_data:
60+
sanitized_data['info']['schema'] = original_schema
61+
else:
62+
sanitized_data['schema'] = original_schema
63+
64+
# Format the JSON with consistent indentation
65+
new_data = json.dumps(sanitized_data, indent=2)
66+
67+
# Compare the sanitized data with original
68+
original_data = json.dumps(data, indent=2)
69+
if original_data != new_data:
70+
with open(file_path, 'w', encoding='utf-8') as f:
71+
f.write(new_data)
72+
return True
73+
return False
74+
except Exception as e:
75+
print(f"Error processing {file_path}: {str(e)}", file=sys.stderr)
76+
return False
77+
78+
def find_postman_files(directory: Path) -> List[Path]:
79+
"""Find all Postman collection and environment files in the directory."""
80+
patterns = ['*.postman_collection.json', '*.postman_environment.json']
81+
files = []
82+
for pattern in patterns:
83+
files.extend(directory.rglob(pattern))
84+
return files
85+
86+
def main():
87+
if len(sys.argv) != 2:
88+
print("Usage: python sanitize_postman.py <directory>")
89+
sys.exit(1)
90+
91+
directory = Path(sys.argv[1])
92+
if not directory.exists():
93+
print(f"Directory {directory} does not exist", file=sys.stderr)
94+
sys.exit(1)
95+
96+
modified_files = []
97+
for file_path in find_postman_files(directory):
98+
if sanitize_file(file_path):
99+
modified_files.append(str(file_path))
100+
101+
if modified_files:
102+
print("Modified files:")
103+
for file in modified_files:
104+
print(f"- {file}")
105+
sys.exit(0)
106+
else:
107+
print("No files were modified")
108+
sys.exit(0)
109+
110+
if __name__ == '__main__':
111+
main()

0 commit comments

Comments
 (0)