Skip to content

Commit c22ec5d

Browse files
committed
fix: fixing formatter issues
1 parent c278979 commit c22ec5d

File tree

2 files changed

+131
-28
lines changed

2 files changed

+131
-28
lines changed

actions/update_actions/scanner.py

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
import sys
4-
from io import StringIO
54
from pathlib import Path
65

76
from ruamel.yaml import YAML
@@ -84,36 +83,60 @@ def collect_workflow_files(root: Path, file_glob: str) -> list[Path]:
8483

8584
def apply_updates(text: str, upgrades: dict[tuple[str, str], str]) -> str:
8685
"""
87-
Apply updates to a YAML workflow file using ruamel.yaml.
88-
This preserves formatting and comments.
86+
Apply updates to a YAML workflow file by doing targeted text replacements.
87+
This preserves all original formatting and comments, only modifying the 'uses:' lines.
8988
"""
90-
yaml = YAML()
91-
yaml.preserve_quotes = True
92-
yaml.default_flow_style = False
93-
yaml.map_indent = 2
94-
yaml.sequence_indent = 4
95-
yaml.sequence_dash_offset = 2
89+
lines = text.split('\n')
9690

97-
try:
98-
docs = list(yaml.load_all(text))
99-
except Exception:
100-
# If parsing fails, return original text unchanged
101-
return text
91+
for i, line in enumerate(lines):
92+
# Look for lines that contain 'uses:' with a value
93+
# Handle both plain keys and list items with dashes
94+
stripped = line.lstrip()
10295

103-
# Check if any updates are needed
104-
any_updates = False
105-
for doc in docs:
106-
if doc is not None and update_uses_in_structure(doc, upgrades):
107-
any_updates = True
96+
# Check if line has 'uses:' (either "uses:" or "- uses:")
97+
if 'uses:' not in stripped:
98+
continue
10899

109-
if not any_updates:
110-
return text
100+
# Find the position of 'uses:' in the line
101+
uses_idx = stripped.find('uses:')
102+
if uses_idx == -1:
103+
continue
111104

112-
# Write back with preserved formatting
113-
output = StringIO()
114-
if len(docs) == 1:
115-
yaml.dump(docs[0], output)
116-
else:
117-
yaml.dump_all(docs, output)
105+
# Check if everything before 'uses:' is valid YAML (dash followed by spaces, or nothing)
106+
prefix = stripped[:uses_idx].strip()
107+
if prefix and prefix != '-':
108+
continue
118109

119-
return output.getvalue()
110+
# Extract the indentation from the original line
111+
indent = line[:len(line) - len(stripped)]
112+
113+
# Get the part after 'uses:'
114+
rest = stripped[uses_idx + 5:].strip() # Remove 'uses:' and leading whitespace
115+
116+
# Handle comments - extract value and any trailing comment
117+
comment = ""
118+
value_part = rest
119+
if '#' in rest:
120+
parts = rest.split('#', 1)
121+
value_part = parts[0].strip()
122+
comment = '#' + parts[1]
123+
124+
# Check if this value matches any upgrade
125+
for (repo, current_tag), new_tag in upgrades.items():
126+
old_value = f"{repo}@{current_tag}"
127+
new_value = f"{repo}@{new_tag}"
128+
if value_part == old_value:
129+
# Reconstruct the line, preserving list item syntax if present
130+
if stripped.startswith('- '):
131+
if comment:
132+
lines[i] = f"{indent}- uses: {new_value} {comment}"
133+
else:
134+
lines[i] = f"{indent}- uses: {new_value}"
135+
else:
136+
if comment:
137+
lines[i] = f"{indent}uses: {new_value} {comment}"
138+
else:
139+
lines[i] = f"{indent}uses: {new_value}"
140+
break
141+
142+
return '\n'.join(lines)

actions/update_actions/tests/test_scanner.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,86 @@ def test_collect_workflow_files(self):
5252
files = scanner.collect_workflow_files(root, ".github/**/*.yml")
5353
self.assertEqual(files, [target])
5454

55+
def test_apply_updates_preserves_non_uses_variables(self):
56+
"""
57+
Regression test: Ensure that non-'uses' variables and multi-line env vars
58+
are not modified when updating action versions.
59+
60+
This tests the issue where LOCAL_VERSION and LATEST_VERSION environment
61+
variables were being incorrectly split across multiple lines.
62+
"""
63+
text = """name: Automatic Version Synchronization
64+
65+
on:
66+
workflow_dispatch:
67+
schedule:
68+
- cron: "0 0 * * *"
69+
70+
env:
71+
PYTHON_VERSION: "3.14"
72+
73+
jobs:
74+
update-version:
75+
runs-on: ubuntu-latest
76+
env:
77+
LOCAL_VERSION: ${{ needs.get-current-local-version.outputs.local_version }}
78+
LATEST_VERSION: ${{ needs.get-newest-version.outputs.latest_version }}
79+
needs:
80+
- get-newest-version
81+
- get-current-local-version
82+
83+
steps:
84+
- name: Create temporary GitHub App Token
85+
id: app
86+
uses: actions/create-github-app-token@v1
87+
with:
88+
owner: ${{ github.repository_owner }}
89+
app-id: ${{ vars.BOT_APP_ID }}
90+
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
91+
92+
- name: Setup Python
93+
uses: actions/setup-python@v5
94+
with:
95+
cache: "pip"
96+
python-version: "${{ env.PYTHON_VERSION }}"
97+
98+
- name: Print and verify versions
99+
id: print-versions
100+
run: |
101+
echo "Local version: $LOCAL_VERSION"
102+
echo "Latest version: $LATEST_VERSION"
103+
"""
104+
105+
# Upgrade specific actions to new versions
106+
upgrades = {
107+
("actions/create-github-app-token", "v1"): "v2.2.1",
108+
("actions/setup-python", "v5"): "v6.2.0",
109+
}
110+
111+
updated = scanner.apply_updates(text, upgrades)
112+
113+
# Verify that the uses entries were updated
114+
self.assertIn("actions/create-github-app-token@v2.2.1", updated)
115+
self.assertIn("actions/setup-python@v6.2.0", updated)
116+
117+
# Verify that non-uses variables are preserved exactly as-is
118+
self.assertIn('PYTHON_VERSION: "3.14"', updated)
119+
self.assertIn(
120+
'LOCAL_VERSION: ${{ needs.get-current-local-version.outputs.local_version }}',
121+
updated
122+
)
123+
self.assertIn(
124+
'LATEST_VERSION: ${{ needs.get-newest-version.outputs.latest_version }}',
125+
updated
126+
)
127+
128+
# Verify that the run command is not split across lines
129+
self.assertIn('run: |\n echo "Local version: $LOCAL_VERSION"', updated)
130+
self.assertIn('echo "Latest version: $LATEST_VERSION"', updated)
131+
132+
# Verify that other comments and structure are preserved
133+
self.assertIn('cron: "0 0 * * *"', updated)
134+
55135

56136
if __name__ == "__main__":
57137
unittest.main()

0 commit comments

Comments
 (0)