@@ -19,68 +19,155 @@ jobs:
1919 token : ${{ secrets.GITHUB_TOKEN }}
2020 ref : stable
2121
22- - name : Get latest upstream tag
23- id : upstream
22+ - name : Check upstream tags for all parts
23+ id : check
2424 run : |
25- # Fetch tags from upstream repository
26- LATEST_TAG=$(git ls-remote --tags --sort=-v:refname \
27- https://github.com/lemonade-sdk/lemonade.git \
28- | grep -oP 'refs/tags/\K[^{}]+$' \
29- | head -n 1)
25+ python3 << 'PYEOF'
26+ import yaml, re, subprocess, json, os
3027
31- echo "Latest upstream tag: $LATEST_TAG"
32- echo "tag=$LATEST_TAG" >> $GITHUB_OUTPUT
28+ with open('snap/snapcraft.yaml', 'r') as f:
29+ data = yaml.safe_load(f)
3330
34- - name : Get current source-tag from snapcraft.yaml
35- id : current
36- run : |
37- # Extract current source-tag if it exists
38- CURRENT_TAG=$(grep -oP '^\s+source-tag:\s*\K.*' snap/snapcraft.yaml || echo "")
39- echo "Current source-tag: $CURRENT_TAG"
40- echo "tag=$CURRENT_TAG" >> $GITHUB_OUTPUT
31+ parts = data.get('parts', {})
32+ updates = []
4133
42- - name : Check if update is needed
43- id : check
34+ for part_name, part_data in parts.items():
35+ if not part_data:
36+ continue
37+ source_tag = part_data.get('source-tag')
38+ source_url = part_data.get('source', '')
39+ if not source_tag or not source_url:
40+ continue
41+ m = re.match(r'https://github\.com/([^/]+/[^/]+?)(?:\.git)?$', source_url)
42+ if not m:
43+ print(f"Skipping {part_name}: not a plain GitHub URL")
44+ continue
45+ repo = m.group(1)
46+ result = subprocess.run(
47+ ['git', 'ls-remote', '--tags', '--sort=-v:refname',
48+ f'https://github.com/{repo}.git'],
49+ capture_output=True, text=True
50+ )
51+ tags = [
52+ line.split('refs/tags/')[-1].strip()
53+ for line in result.stdout.strip().split('\n')
54+ if line and not line.endswith('^{}')
55+ ]
56+ if not tags:
57+ print(f"No tags found for {part_name} ({repo})")
58+ continue
59+ latest = tags[0]
60+ current = str(source_tag)
61+ print(f"{part_name}: current={current}, latest={latest}")
62+ if latest != current:
63+ updates.append({'part': part_name, 'repo': repo,
64+ 'current': current, 'latest': latest})
65+
66+ with open('/tmp/updates.json', 'w') as f:
67+ json.dump(updates, f)
68+
69+ if updates:
70+ print(f"Updates needed: {len(updates)}")
71+ with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
72+ f.write('update_needed=true\n')
73+ else:
74+ print("All parts up to date")
75+ with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
76+ f.write('update_needed=false\n')
77+ PYEOF
78+
79+ - name : Apply updates to snapcraft.yaml
80+ if : steps.check.outputs.update_needed == 'true'
4481 run : |
45- if [ "${{ steps.upstream.outputs.tag }}" != "${{ steps.current.outputs.tag }}" ]; then
46- echo "Update needed: ${{ steps.current.outputs.tag }} -> ${{ steps.upstream.outputs.tag }}"
47- echo "update_needed=true" >> $GITHUB_OUTPUT
48- else
49- echo "Already up to date"
50- echo "update_needed=false" >> $GITHUB_OUTPUT
51- fi
52-
53- - name : Update snapcraft.yaml
82+ python3 << 'PYEOF'
83+ import json, re
84+
85+ with open('/tmp/updates.json') as f:
86+ updates = json.load(f)
87+
88+ update_map = {u['part']: u['latest'] for u in updates}
89+
90+ with open('snap/snapcraft.yaml', 'r') as f:
91+ lines = f.readlines()
92+
93+ new_lines = []
94+ current_part = None
95+ in_parts = False
96+
97+ for line in lines:
98+ stripped = line.lstrip()
99+ indent = len(line) - len(stripped)
100+
101+ if line.startswith('parts:'):
102+ in_parts = True
103+ elif in_parts and indent == 2 and not stripped.startswith('#'):
104+ m = re.match(r'([\w][\w-]*):\s*\n', stripped)
105+ if m:
106+ current_part = m.group(1)
107+
108+ if (in_parts and current_part in update_map
109+ and re.match(r'\s+source-tag:', line)
110+ and not stripped.startswith('#')):
111+ new_tag = update_map[current_part]
112+ if "'" in line:
113+ line = re.sub(r"(source-tag:\s*')[^']*(')", rf"\g<1>{new_tag}\g<2>", line)
114+ elif '"' in line:
115+ line = re.sub(r'(source-tag:\s*")[^"]*(")', rf"\g<1>{new_tag}\g<2>", line)
116+ else:
117+ line = re.sub(r'(source-tag:\s*)\S+', rf'\g<1>{new_tag}', line)
118+
119+ new_lines.append(line)
120+
121+ with open('snap/snapcraft.yaml', 'w') as f:
122+ f.writelines(new_lines)
123+
124+ print("Updated snap/snapcraft.yaml:")
125+ for u in updates:
126+ print(f" {u['part']}: {u['current']} -> {u['latest']}")
127+ PYEOF
128+
129+ - name : Build PR metadata
54130 if : steps.check.outputs.update_needed == 'true'
131+ id : pr_meta
55132 run : |
56- NEW_TAG="${{ steps.upstream.outputs.tag }}"
133+ python3 << 'PYEOF'
134+ import json, os
57135
58- # Check if source-tag already exists in the lemonade part
59- if grep -q '^\s\+source-tag:' snap/snapcraft.yaml; then
60- # Update existing source-tag
61- sed -i "s/^\(\s\+source-tag:\s*\).*/\1$NEW_TAG/" snap/snapcraft.yaml
62- else
63- # Add source-tag after source-subdir line in lemonade part
64- sed -i "/^\s\+source-subdir: src\/app/a\\ source-tag: $NEW_TAG" snap/snapcraft.yaml
65- fi
136+ with open('/tmp/updates.json') as f:
137+ updates = json.load(f)
66138
67- echo "Updated snapcraft.yaml to use tag: $NEW_TAG"
68- cat snap/snapcraft.yaml
139+ if len(updates) == 1:
140+ u = updates[0]
141+ title = f"Update {u['part']} to {u['latest']}"
142+ else:
143+ parts_str = ', '.join(u['part'] for u in updates)
144+ title = f"Update upstream releases: {parts_str}"
145+
146+ body_lines = [
147+ "Automated update to track upstream releases.",
148+ "",
149+ "**Changes:**",
150+ ]
151+ for u in updates:
152+ body_lines.append(
153+ f"- **{u['part']}**: `{u['current']}` \u2192 `{u['latest']}` "
154+ f"([release](https://github.com/{u['repo']}/releases/tag/{u['latest']}))"
155+ )
156+
157+ body = '\n'.join(body_lines)
158+
159+ with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
160+ f.write(f"title={title}\n")
161+ f.write(f"body<<PREOF\n{body}\nPREOF\n")
162+ PYEOF
69163
70164 - name : Create Pull Request
71165 if : steps.check.outputs.update_needed == 'true'
72166 uses : peter-evans/create-pull-request@v6
73167 with :
74168 token : ${{ secrets.GITHUB_TOKEN }}
75- commit-message : " Update to upstream ${{ steps.upstream.outputs.tag }}"
76- title : " Update to upstream ${{ steps.upstream.outputs.tag }}"
77- body : |
78- Automated update to track upstream release.
79-
80- **Changes:**
81- - Updated source-tag from `${{ steps.current.outputs.tag }}` to `${{ steps.upstream.outputs.tag }}`
82-
83- **Upstream release:**
84- https://github.com/lemonade-sdk/lemonade/releases/tag/${{ steps.upstream.outputs.tag }}
85- branch : update-upstream-${{ steps.upstream.outputs.tag }}
169+ commit-message : " ${{ steps.pr_meta.outputs.title }}"
170+ title : " ${{ steps.pr_meta.outputs.title }}"
171+ body : " ${{ steps.pr_meta.outputs.body }}"
172+ branch : update-upstream-tags
86173 delete-branch : true
0 commit comments