Skip to content

Commit 723d3d3

Browse files
authored
Merge pull request #28 from YunoHost-Apps/testing
Testing
2 parents 18972d0 + c904eb9 commit 723d3d3

File tree

3 files changed

+249
-4
lines changed

3 files changed

+249
-4
lines changed

.github/workflows/check-config.yml

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
name: Check Upstream Config Changes
2+
3+
on:
4+
pull_request:
5+
workflow_dispatch:
6+
7+
permissions:
8+
contents: read
9+
pull-requests: write
10+
11+
jobs:
12+
compare-configs:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout Code
16+
uses: actions/checkout@v4
17+
18+
- name: Set up Python
19+
uses: actions/setup-python@v4
20+
with:
21+
python-version: '3.x'
22+
23+
- name: Install Packaging Lib
24+
run: pip install packaging
25+
26+
- name: Determine Latest OJS Version
27+
id: get_version
28+
run: |
29+
LATEST_TAG=$(curl -sL "https://api.github.com/repos/pkp/ojs/tags?per_page=100" \
30+
| python3 -c "
31+
import sys, json, re
32+
from packaging.version import parse
33+
try:
34+
tags = json.load(sys.stdin)
35+
valid_tags = []
36+
tag_map = {}
37+
for t in tags:
38+
name = t['name']
39+
m = re.search(r'(?:ojs-)?(3[._]\d+[._]\d+[-_]\d+)', name)
40+
if m:
41+
version_str = m.group(1).replace('_', '.').replace('-', '.')
42+
valid_tags.append(version_str)
43+
tag_map[version_str] = name
44+
if not valid_tags:
45+
print('stable-3_4_0')
46+
sys.exit(0)
47+
valid_tags.sort(key=parse, reverse=True)
48+
print(tag_map[valid_tags[0]])
49+
except Exception:
50+
print('stable-3_4_0')
51+
")
52+
echo "Detected latest tag: $LATEST_TAG"
53+
echo "tag=$LATEST_TAG" >> $GITHUB_OUTPUT
54+
55+
- name: Fetch Upstream Config
56+
env:
57+
TAG: ${{ steps.get_version.outputs.tag }}
58+
run: |
59+
echo "Downloading config template for tag: $TAG"
60+
curl -sSL "https://raw.githubusercontent.com/pkp/ojs/$TAG/config.TEMPLATE.inc.php" -o upstream.config.php
61+
62+
- name: Run Comparison Script
63+
id: check_diff
64+
shell: python
65+
env:
66+
TAG: ${{ steps.get_version.outputs.tag }}
67+
run: |
68+
import configparser
69+
import sys
70+
import os
71+
import re
72+
73+
# --- CONFIGURATION ---
74+
LOCAL_FILE = 'conf/config.inc.php'
75+
UPSTREAM_FILE = 'upstream.config.php'
76+
IGNORED_SECTIONS = []
77+
# ---------------------
78+
79+
def load_ini(filepath):
80+
config = configparser.ConfigParser(strict=False, allow_no_value=True)
81+
config.optionxform = str
82+
try:
83+
config.read(filepath)
84+
except Exception as e:
85+
print(f"Error reading {filepath}: {e}")
86+
sys.exit(1)
87+
return config
88+
89+
if not os.path.exists(LOCAL_FILE):
90+
print(f"::error::Local file {LOCAL_FILE} not found!")
91+
sys.exit(1)
92+
93+
local_cfg = load_ini(LOCAL_FILE)
94+
upstream_cfg = load_ini(UPSTREAM_FILE)
95+
96+
# Read raw upstream content for context extraction
97+
with open(UPSTREAM_FILE, 'r') as f:
98+
upstream_lines = f.readlines()
99+
upstream_raw = "".join(upstream_lines)
100+
101+
# --- HELPER: Extract comments and raw line for a key ---
102+
def get_key_context(target_section, target_key):
103+
current_section = None
104+
for i, line in enumerate(upstream_lines):
105+
stripped = line.strip()
106+
# Detect section header
107+
if stripped.startswith('[') and stripped.endswith(']'):
108+
current_section = stripped[1:-1]
109+
continue
110+
111+
# If we are in the right section, look for the key
112+
if current_section == target_section:
113+
# Regex: Start of line, optional whitespace, key, whitespace, equals
114+
if re.match(r'^\s*' + re.escape(target_key) + r'\s*=', line):
115+
# Found the key line! Now look backwards for comments.
116+
comments = []
117+
j = i - 1
118+
while j >= 0:
119+
prev = upstream_lines[j]
120+
if prev.strip().startswith(';'):
121+
comments.insert(0, prev.rstrip())
122+
elif not prev.strip():
123+
# Stop at blank line (end of comment block)
124+
break
125+
else:
126+
# Stop if we hit another key or section
127+
break
128+
j -= 1
129+
130+
# Return (list of comment lines, the raw key line)
131+
return comments, line.rstrip()
132+
return [], f"{target_key} ="
133+
134+
missing_sections = []
135+
# Dictionary to hold missing keys grouped by section: { 'section': [text_block, text_block] }
136+
missing_keys_grouped = {}
137+
deprecated_keys = []
138+
139+
# 1. Check for NEW items
140+
for section in upstream_cfg.sections():
141+
if section in IGNORED_SECTIONS: continue
142+
143+
if not local_cfg.has_section(section):
144+
missing_sections.append(section)
145+
# If whole section is missing, we could list all keys,
146+
# but usually just flagging the section is enough.
147+
continue
148+
149+
for key in upstream_cfg.options(section):
150+
if not local_cfg.has_option(section, key):
151+
# Extract the raw context
152+
comments, raw_line = get_key_context(section, key)
153+
154+
# Format the block
155+
block = ""
156+
for c in comments:
157+
block += f"{c}\n"
158+
block += f"{raw_line}"
159+
160+
if section not in missing_keys_grouped:
161+
missing_keys_grouped[section] = []
162+
missing_keys_grouped[section].append(block)
163+
164+
# 2. Check for DEPRECATED items
165+
# Helper for raw check
166+
def key_exists_in_raw(key_name):
167+
pattern = r"^\s*;?\s*" + re.escape(key_name) + r"\s*="
168+
return re.search(pattern, upstream_raw, re.MULTILINE) is not None
169+
170+
for section in local_cfg.sections():
171+
if section in IGNORED_SECTIONS: continue
172+
173+
if not upstream_cfg.has_section(section):
174+
# Check if section header exists in raw even if commented out
175+
if f"[{section}]" not in upstream_raw:
176+
for key in local_cfg.options(section):
177+
deprecated_keys.append(f"[{section}] {key} (Section removed)")
178+
continue
179+
180+
for key in local_cfg.options(section):
181+
if not upstream_cfg.has_option(section, key):
182+
if not key_exists_in_raw(key):
183+
deprecated_keys.append(f"[{section}] {key}")
184+
185+
# 3. Generate Report
186+
if missing_sections or missing_keys_grouped or deprecated_keys:
187+
tag_name = os.environ.get('TAG', 'unknown')
188+
report = f"### ⚠️ Upstream Config Changes Detected ({tag_name})\n\n"
189+
190+
if missing_sections:
191+
report += "**Missing Sections (New in Upstream):**\n"
192+
for s in missing_sections:
193+
report += f"- `[{s}]`\n"
194+
report += "\n"
195+
196+
if missing_keys_grouped:
197+
report += "**Missing Keys (New in Upstream):**\n"
198+
report += "Below are the missing keys with their original comments and default values.\n\n"
199+
200+
for section, blocks in missing_keys_grouped.items():
201+
report += f"**Section `[{section}]`**\n"
202+
report += "```ini\n"
203+
for block in blocks:
204+
report += f"{block}\n\n"
205+
report += "```\n"
206+
207+
if deprecated_keys:
208+
report += "**Deprecated Keys (Removed from Upstream):**\n"
209+
report += "> *These keys exist in your local file but seem to be completely removed from the upstream template.*\n"
210+
for k in deprecated_keys:
211+
report += f"- `{k}`\n"
212+
213+
delimiter = "EOF"
214+
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
215+
f.write(f"comment<<{delimiter}\n{report}\n{delimiter}\n")
216+
f.write("has_changes=true\n")
217+
else:
218+
print("Configs match perfectly.")
219+
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
220+
f.write("has_changes=false\n")
221+
222+
- name: Post Comment on PR
223+
if: steps.check_diff.outputs.has_changes == 'true'
224+
uses: actions/github-script@v6
225+
env:
226+
COMMENT_BODY: ${{ steps.check_diff.outputs.comment }}
227+
with:
228+
script: |
229+
const output = process.env.COMMENT_BODY;
230+
const { data: comments } = await github.rest.issues.listComments({
231+
owner: context.repo.owner,
232+
repo: context.repo.repo,
233+
issue_number: context.issue.number,
234+
});
235+
const botComment = comments.find(c => c.body.includes('Upstream Config Changes Detected'));
236+
237+
if (botComment) {
238+
await github.rest.issues.updateComment({
239+
owner: context.repo.owner, repo: context.repo.repo, comment_id: botComment.id, body: output
240+
});
241+
} else {
242+
await github.rest.issues.createComment({
243+
issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: output
244+
});
245+
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ It shall NOT be edited by hand.
1111
Software to manage scholarly journals
1212

1313
[![🌐 Official app website](https://img.shields.io/badge/Official_app_website-darkgreen?style=for-the-badge)](https://pkp.sfu.ca/software/ojs)
14-
[![Version: 3.5.0-1~ynh4](https://img.shields.io/badge/Version-3.5.0--1~ynh4-rgb(18,138,11)?style=for-the-badge)](https://ci-apps.yunohost.org/ci/apps/ojs/)
14+
[![Version: 3.5.0-3~ynh1](https://img.shields.io/badge/Version-3.5.0--3~ynh1-rgb(18,138,11)?style=for-the-badge)](https://ci-apps.yunohost.org/ci/apps/ojs/)
1515

1616
<div align="center">
1717
<a href="https://apps.yunohost.org/app/ojs"><img height="100px" src="https://github.com/YunoHost/yunohost-artwork/raw/refs/heads/main/badges/neopossum-badges/badge_more_info_on_the_appstore.svg"/></a>

manifest.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ name = "OJS"
77
description.en = "Software to manage scholarly journals"
88
description.fr = "Logiciel pour gérer des revues scientifiques"
99

10-
version = "3.5.0-1~ynh4"
10+
version = "3.5.0-3~ynh1"
1111

1212
maintainers = ["DeMiro5001"]
1313

@@ -206,8 +206,8 @@ ram.runtime = "50M"
206206
[resources.sources]
207207

208208
[resources.sources.main]
209-
url = "https://pkp.sfu.ca/ojs/download/ojs-3.5.0-1.tar.gz"
210-
sha256 = "78e423421310951cfb290c3856f85aa014ff0fe3d3c02d200d6a65984951b124"
209+
url = "https://pkp.sfu.ca/ojs/download/ojs-3.5.0-3.tar.gz"
210+
sha256 = "af501e4f8d99af84d47c26eca3347400d94b3ace08806b5e30a7b6d0ce91e3e5"
211211

212212
[resources.system_user]
213213
allow_email = true

0 commit comments

Comments
 (0)