From 60275fbec84436ea1c2b40faf14cae06c745301d Mon Sep 17 00:00:00 2001 From: krzywon Date: Wed, 13 May 2026 12:03:08 -0400 Subject: [PATCH 1/4] Move contributors to two lists and add a list of all affiliations as includes in people.md --- _includes/affiliations.html | 1 + _includes/creators.html | 1 + _includes/producers.html | 1 + people.md | 9 +++++++-- 4 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 _includes/affiliations.html create mode 100644 _includes/creators.html create mode 100644 _includes/producers.html diff --git a/_includes/affiliations.html b/_includes/affiliations.html new file mode 100644 index 0000000..40a400a --- /dev/null +++ b/_includes/affiliations.html @@ -0,0 +1 @@ +1 _University of Luxembourg_, 2 _Institut Laue-Langevin_, 3 _University of Tennessee, Knoxville_, 4 _ISIS Neutron and Muon Source_, 5 _Oak Ridge National Laboratory_, 6 _Technical University, Delft_, 7 _National Institute of Standards and Technology_, 8 _University of Delaware_, 9 _Paul Scherrer Institute_, 10 _Charles University_, 11 _The Debian Project_, 12 _University of Cologne_, 13 _ETH Zurich_, 14 _European Spallation Source_, 15 _California Institute of Technology_, 16 _Diamond Light Source_, 17 _University of Maryland_, 18 _University of Copenhagen_, 19 _Brookhaven National Laboratory_, 20 _Aarhus University_, 21 _Australian National Science and Technology Organisation_, 22 _Lund University_, 23 _SciLifeLab at Lund University_, 24 _University of New South Wales_, 25 _University of Princeton_, 26 _Columbia University_ \ No newline at end of file diff --git a/_includes/creators.html b/_includes/creators.html new file mode 100644 index 0000000..b435f70 --- /dev/null +++ b/_includes/creators.html @@ -0,0 +1 @@ +M. Adams1, N. Agouzal2, G. Alina3, Z. Attala4, M. Backman5, J. Bakker6, P. Beaucage7, J. Berger8, R. Bourne4, W. Bouwman6, I. Bressler9, P. Butler7, I. Cadwallader-Jones2, K. Campbell4, J. Cho3, R. Conan10, T. Cooper-Benun4, R. Cortes Hernandez3, J. Crake-Merani4, A. Detiste11, M. Doucet5, J. Doutch4, D. Dresen12, G. Drosos13, C. Durniak14, C. Farrow15, R. Ferraz Leal5, R. Ford15, L. Forster16, J. Gaudet17, M. Gerina10, P. Gilbert7, M. Gonzalez2, O. Hammond14, T. Hansen18, R. Heenan4, S. Henson5, E. Hewins4, A. Hicks5, D. Honecker4, A. Jackson14, G. Jensen7, P. Juhas19, J. Karliczek2, P. Kienzle7, S. King4, S. Kline7, J. Krzywon7, J. Lin15, Y. Liu7, R. Lopes4, D. Lozano2, K. Lytje20, D. Mannicke21, B. Maranville7, A. Markvardsen4, N. Martinez2, M. McKerns15, B. Miller7, K. Mothander22, R. Murphy7, A. Nelson21, T. Nielsen14, L. O'Driscoll4, M. Oakley4, H. Park7, P. Parker4, M. Patrou5, P. Peterson5, W. Potrzebowski23, S. Prescott24, M. Rakitin19, T. Richter16, J. Rooks8, P. Rozyczko14, X. Shan7, P. Sharp4, S. Shrestha4, T. Snow16, A. Stellhorn14, S. Teixeira7, J. Tumarkin3, A. Washington4, K. Weigandt7, R. Whitley4, L. Wilkins4, C. Wolf7, A. Zhang25, A. Zheng7 diff --git a/_includes/producers.html b/_includes/producers.html new file mode 100644 index 0000000..c7d3d99 --- /dev/null +++ b/_includes/producers.html @@ -0,0 +1 @@ +A. Anuchitanukul4, P. Corona26, G. Fragneto14, B. Fultz15, M. Knudsen18, S. Krueger7, A. Larsen18, S. Lee27, T. Narayanan28, D. Parsons29, B. Pauw30, T. Perring4, L. Porcar2, L. Pozzo31, S. Prevost2, A. Rennie32, G. Roberts33, T. Rod14, Y. Shang5, J. Taylor14, L. Udby34, D. Zakoutna10 diff --git a/people.md b/people.md index 4d3b091..222a97d 100644 --- a/people.md +++ b/people.md @@ -8,15 +8,20 @@ Many people have contributed to this SAS analysis software over the years, and w ### Developers and contributors: In addition to the core development, contributions include documentation writing and editing, tutorial writing and editing, performing code reviews, setting up and maintaining a variety of related services such as the marketplace, and admin tasks required to keep the infrastructure of the collaboration running. -M. Adams, N. Agouzal, G. Alina, Z. Attala, M. Backman, J. Bakker, P. Beaucage, J. Berger, R. Bourne, W. Bouwman, I. Breßler, P. Butler, I. Caddy-Jones, K. Campbell, R. Charles, J-H. Cho, T. Cooper-Bennun, R. Cortes Hernandez, J. Crake-Merani, A. Detiste, M. Doucet, J. Doutch, D. Dresen, G. Drosos, C. Durniak, C. Farrow, R. Ferraz Leal, R. Ford, L. Forster, J. Gaudet, M. Gerina, P. Gilbert, M. Gonzalez, O. Hammond, T. Hansen, R. Heenan, S. Henson, E. Hewins, A. Hicks, D. Honecker, A. Jackson, G. Jensen, P. Juhas, J. Karliczek, P. Kienzle, S. King, S. Kline, J. Krzywon, A. Larsen, S. Lee, J. Lin, Y. Liu, R. Lopes, D. Lozano, K. Lytje, D. Mannicke, B. Maranville, N. Martinez, M. McKerns, B. Miller, K. Mothander, R. Murphy, A. Nelson, T. Nielsen, M. Oakley, L. O'Driscoll, H. Park, P. Parker, M. Patrou, P. Peterson, W. Potrzebowski, S. Prescott, M. Rakitin, T. Richter, J. Rooks, P. Rozyczko, X. Shan, S. Shrestha, P. Sharp, T. Snow, A. Stellhorn, S, Teixeira, J. Tumarkin, A. Washington, K. Weigandt, R. Whitley, L. Wilkins, C. Wolf, A. Zhang, A. Zheng. +{% include creators.html %} ### Community contributors and external collaborators: The SasView collaboration goes well beyond the contributions listed above. In particular we wish to thank the following people from the scattering community and beyond for their time in providing feedback and ideas and being advocates for the collaboration. -A. Anuchitanukul, P. Corona, G. Fragneto, M. Knudsen, S. Krueger, A. Markvardsen, T. Narayanan, D. Parsons, B. Pauw, R. Pellicelli, T. Perring, L. Porcar, L. Pozzo, S. Prevost, A. Rennie, G. Roberts, T. Holm Rod, Y. Shang, J. Taylor, L. Udby, D. Zakoutna and J. Zhou. +{% include producers.html %} Last, but by no means least, we thank all those colleagues and SasView users that help further the collaboration by assisting us with beta testing, by reporting bugs and other idiosyncrasies of the program, and by suggesting improvements and new features. +### Affiliations +Contributions have come from the following facilities and institutions, in the order contributors appear in the above lists. + +{% include affiliations.html %} + ### Funding In addition to the staff time and support for code camps provided by the collaboration partners, the following people have been instrumental in obtaining funding for development of SasView. - B. Fultz (DANSE - NSF Award #0412074) From c3556bcd51c27753a276e1c33328adc43058cfd5 Mon Sep 17 00:00:00 2001 From: krzywon Date: Wed, 13 May 2026 12:03:41 -0400 Subject: [PATCH 2/4] Add a cron based workflow to update the contributors lists, as needed. --- .github/workflows/update_people.yml | 168 ++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 .github/workflows/update_people.yml diff --git a/.github/workflows/update_people.yml b/.github/workflows/update_people.yml new file mode 100644 index 0000000..8428f7f --- /dev/null +++ b/.github/workflows/update_people.yml @@ -0,0 +1,168 @@ +name: Update People List + +on: + schedule: + # Runs automatically daily at midnight UTC + - cron: '0 0 * * *' + workflow_dispatch: + # Allows you to trigger the workflow manually from the Actions tab + +permissions: + contents: write # Necessary to allow the bot to commit and push changes + +jobs: + update-people-md: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.14' + + - name: Process TSV and Update Markdown + run: | + python3 - <<'EOF' + import urllib.request + import csv + import os + import re + from collections import OrderedDict + + # Define the source TSV URL from the main SasView repo + url = "https://raw.githubusercontent.com/SasView/sasview/main/build_tools/contributors.tsv" + + try: + req = urllib.request.Request(url) + with urllib.request.urlopen(req) as response: + lines = [line.decode('utf-8') for line in response.readlines()] + except Exception as e: + print(f"Error fetching TSV: {e}") + exit(1) + + # Parse the TSV + reader = csv.DictReader(lines, delimiter='\t') + + # Dynamically map headers to be case-insensitive to ensure resilience + headers = {name.lower().strip(): name for name in reader.fieldnames if name} + + name_col = headers.get('name', 'Name') + creator_col = headers.get('creator', 'Creator') + producer_col = headers.get('producer', 'Producer') + # Fallback through possible affiliation header names + affil_col = headers.get('affiliation', headers.get('institution', 'Affiliation')) + + creators = [] + producers = [] + + # Categorize users by their roles + for row in reader: + raw_name = row.get(name_col, '').strip() + creator = row.get(creator_col, '').strip().lower() + producer = row.get(producer_col, '').strip().lower() + affiliation = row.get(affil_col, '').strip() + + if not raw_name: + continue + + # Convert "Last Name, First Name" to "F. Last Name" + if ',' in raw_name: + last_name, first_name = raw_name.split(',', 1) + last_name = last_name.strip() + first_name = first_name.strip() + + if first_name: + formatted_name = f"{first_name[0].upper()}. {last_name}" + else: + formatted_name = last_name + else: + formatted_name = raw_name + + # Store raw_name as a sort_key so it still alphabetizes by Last Name + entry = {'name': formatted_name, 'sort_key': raw_name, 'affiliation': affiliation} + + if 'x' in creator: + creators.append(entry) + elif 'x' in producer: + producers.append(entry) + + # Sort alphabetically by the original Last Name format + creators.sort(key=lambda x: x['sort_key'].lower()) + producers.sort(key=lambda x: x['sort_key'].lower()) + + affil_dict = OrderedDict() + + # Helper function to generate publication-style citation numbers + def format_section(people): + formatted_names = [] + for p in people: + # Assuming multiple affiliations might be separated by semicolons + affiliations = [a.strip() for a in p['affiliation'].split(';') if a.strip()] + superscripts = [] + for a in affiliations: + if a not in affil_dict: + affil_dict[a] = len(affil_dict) + 1 + superscripts.append(str(affil_dict[a])) + + if superscripts: + formatted_names.append(f"{p['name']}{','.join(superscripts)}") + else: + formatted_names.append(p['name']) + return ", ".join(formatted_names) + + + creators_str = format_section(creators) + producers_str = format_section(producers) + + # Format affiliations block (e.g. 1 Institution A) + affil_str = ", ".join([f"{idx} _{affil}_" for affil, idx in affil_dict.items()]) + + # Combine into the final markdown + markdown_content = f"""## Developers and Contributors + {creators_str} + + ## Community Contributors + {producers_str} + + ### Affiliations + {affil_str} + """ + + file_path = "people.md" + + # Restored markers to prevent catastrophic regex replacement failure + marker_start = "" + marker_end = "" + print(markdown_content) + + # Inject the new markdown into people.md + if os.path.exists(file_path): + with open(file_path, "r", encoding="utf-8") as f: + content = f.read() + + pattern = f"{marker_start}.*?{marker_end}" + new_section = f"{marker_start}\n{markdown_content}\n{marker_end}" + + if re.search(pattern, content, flags=re.DOTALL): + updated_content = re.sub(pattern, new_section, content, flags=re.DOTALL) + else: + updated_content = content.rstrip() + f"\n\n{new_section}\n" + + with open(file_path, "w", encoding="utf-8") as f: + f.write(updated_content) + print(f"Updated {file_path}") + else: + with open(file_path, "w", encoding="utf-8") as f: + f.write(f"# People\n\n{marker_start}\n{markdown_content}\n{marker_end}\n") + print(f"Created {file_path}") + + EOF + + - name: Commit and Push Changes + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "docs: automatic update of people.md from contributors.tsv" + file_pattern: "people.md" \ No newline at end of file From 257dbb4920c2e45c00975325ac0c39e9ce28dc9c Mon Sep 17 00:00:00 2001 From: krzywon Date: Wed, 13 May 2026 13:51:23 -0400 Subject: [PATCH 3/4] Include RelatedPerson in producers list --- .github/workflows/update_people.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/update_people.yml b/.github/workflows/update_people.yml index 8428f7f..d411705 100644 --- a/.github/workflows/update_people.yml +++ b/.github/workflows/update_people.yml @@ -52,6 +52,8 @@ jobs: name_col = headers.get('name', 'Name') creator_col = headers.get('creator', 'Creator') producer_col = headers.get('producer', 'Producer') + related_person_col = headers.get('relatedperson', 'RelatedPerson') + # Fallback through possible affiliation header names affil_col = headers.get('affiliation', headers.get('institution', 'Affiliation')) @@ -63,6 +65,7 @@ jobs: raw_name = row.get(name_col, '').strip() creator = row.get(creator_col, '').strip().lower() producer = row.get(producer_col, '').strip().lower() + related_person = row.get(related_person_col, '').strip().lower() affiliation = row.get(affil_col, '').strip() if not raw_name: @@ -86,7 +89,7 @@ jobs: if 'x' in creator: creators.append(entry) - elif 'x' in producer: + elif 'x' in producer or 'x' in related_person: producers.append(entry) # Sort alphabetically by the original Last Name format From 0c4e23a6e13288f1ef7d45061a008254d95438f3 Mon Sep 17 00:00:00 2001 From: krzywon Date: Wed, 13 May 2026 13:52:08 -0400 Subject: [PATCH 4/4] Update included html files rather than people.md --- .github/workflows/update_people.yml | 58 +++++++++-------------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/.github/workflows/update_people.yml b/.github/workflows/update_people.yml index d411705..018d75f 100644 --- a/.github/workflows/update_people.yml +++ b/.github/workflows/update_people.yml @@ -29,7 +29,6 @@ jobs: import urllib.request import csv import os - import re from collections import OrderedDict # Define the source TSV URL from the main SasView repo @@ -123,49 +122,26 @@ jobs: # Format affiliations block (e.g. 1 Institution A) affil_str = ", ".join([f"{idx} _{affil}_" for affil, idx in affil_dict.items()]) - # Combine into the final markdown - markdown_content = f"""## Developers and Contributors - {creators_str} + # Ensure the _includes directory exists + os.makedirs('_includes', exist_ok=True) - ## Community Contributors - {producers_str} - - ### Affiliations - {affil_str} - """ - - file_path = "people.md" - - # Restored markers to prevent catastrophic regex replacement failure - marker_start = "" - marker_end = "" - print(markdown_content) - - # Inject the new markdown into people.md - if os.path.exists(file_path): - with open(file_path, "r", encoding="utf-8") as f: - content = f.read() - - pattern = f"{marker_start}.*?{marker_end}" - new_section = f"{marker_start}\n{markdown_content}\n{marker_end}" - - if re.search(pattern, content, flags=re.DOTALL): - updated_content = re.sub(pattern, new_section, content, flags=re.DOTALL) - else: - updated_content = content.rstrip() + f"\n\n{new_section}\n" - - with open(file_path, "w", encoding="utf-8") as f: - f.write(updated_content) - print(f"Updated {file_path}") - else: - with open(file_path, "w", encoding="utf-8") as f: - f.write(f"# People\n\n{marker_start}\n{markdown_content}\n{marker_end}\n") - print(f"Created {file_path}") - + # Write out the three files + with open('_includes/creators.html', 'w', encoding='utf-8') as f: + f.write(creators_str + "\n") + print("Updated _includes/creators.html") + + with open('_includes/producers.html', 'w', encoding='utf-8') as f: + f.write(producers_str + "\n") + print("Updated _includes/producers.html") + + with open('_includes/affiliations.html', 'w', encoding='utf-8') as f: + f.write(affil_str + "\n") + print("Updated _includes/affiliations.html") + EOF - name: Commit and Push Changes uses: stefanzweifel/git-auto-commit-action@v5 with: - commit_message: "docs: automatic update of people.md from contributors.tsv" - file_pattern: "people.md" \ No newline at end of file + commit_message: "docs: automatic update of people from the SasView contributors.tsv" + file_pattern: "_includes/*" \ No newline at end of file