|
4 | 4 | push: |
5 | 5 | branches: [main] |
6 | 6 |
|
| 7 | +env: |
| 8 | + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true |
| 9 | + |
7 | 10 | jobs: |
8 | 11 | build-paper: |
9 | 12 | runs-on: ubuntu-latest |
10 | 13 | name: Build Preprint PDF and Package |
11 | 14 |
|
12 | 15 | steps: |
13 | 16 | - name: Checkout repository |
14 | | - uses: actions/checkout@v4 |
| 17 | + uses: actions/checkout@v6 |
15 | 18 |
|
16 | 19 | - name: Cache apt packages |
17 | 20 | uses: awalsh128/cache-apt-pkgs-action@latest |
18 | 21 | with: |
19 | | - packages: pandoc texlive texlive-latex-extra texlive-fonts-recommended texlive-xetex zip python3-yaml |
| 22 | + packages: > |
| 23 | + pandoc texlive texlive-latex-extra texlive-fonts-recommended |
| 24 | + texlive-xetex texlive-fonts-extra zip python3-yaml |
20 | 25 | version: 1.0 |
21 | 26 |
|
22 | | - - name: Extract author names from JOSS frontmatter |
| 27 | + - name: Extract JOSS frontmatter and build LaTeX assets |
23 | 28 | run: | |
24 | | - python3 - << 'EOF' |
25 | | - import yaml |
| 29 | + python3 - << 'PYEOF' |
| 30 | + import yaml, re |
26 | 31 |
|
27 | 32 | with open('paper/paper.md', 'r') as f: |
28 | 33 | content = f.read() |
29 | 34 |
|
30 | | - # YAML frontmatter is between the first two '---' delimiters |
31 | 35 | parts = content.split('---\n') |
32 | | - frontmatter = yaml.safe_load(parts[1]) |
33 | | -
|
34 | | - authors = frontmatter.get('authors', []) |
35 | | - author_names = [a['name'] for a in authors] |
| 36 | + fm = yaml.safe_load(parts[1]) |
36 | 37 |
|
37 | | - metadata = {'author': author_names} |
| 38 | + authors = fm.get('authors', []) |
| 39 | + affiliations = {a['index']: a['name'] for a in fm.get('affiliations', [])} |
38 | 40 |
|
| 41 | + # ── Pandoc metadata (title + date only; authors handled in title block) ── |
| 42 | + meta = { |
| 43 | + 'title': fm.get('title', ''), |
| 44 | + 'date': str(fm.get('date', '')), |
| 45 | + } |
39 | 46 | with open('/tmp/pandoc_meta.yaml', 'w') as f: |
40 | | - yaml.dump(metadata, f, allow_unicode=True) |
41 | | -
|
42 | | - print("Authors found:", author_names) |
43 | | - EOF |
44 | | -
|
45 | | - - name: Create LaTeX header (preprint watermark + URL fix) |
| 47 | + yaml.dump(meta, f, allow_unicode=True) |
| 48 | +
|
| 49 | + # ── Build LaTeX title block ── |
| 50 | + lines = [] |
| 51 | + lines.append(r'\begin{center}') |
| 52 | + lines.append(r'{\LARGE\bfseries ' + fm.get('title','').replace('&', r'\&') + r'}\\[0.8em]') |
| 53 | +
|
| 54 | + # Authors with superscript affiliation numbers |
| 55 | + author_parts = [] |
| 56 | + for a in authors: |
| 57 | + affs = a.get('affiliation', '') |
| 58 | + nums = [s.strip() for s in str(affs).split(',')] |
| 59 | + sup = ','.join(nums) |
| 60 | + name = a['name'].replace('&', r'\&') |
| 61 | + if a.get('corresponding'): |
| 62 | + author_parts.append(rf'{name}$^{{{sup},*}}$') |
| 63 | + else: |
| 64 | + author_parts.append(rf'{name}$^{{{sup}}}$') |
| 65 | +
|
| 66 | + lines.append(r'\large ' + r',\quad '.join(author_parts) + r'\\[0.5em]') |
| 67 | +
|
| 68 | + # Affiliation list |
| 69 | + for idx, name in sorted(affiliations.items()): |
| 70 | + lines.append(rf'$^{{{idx}}}$\small {name.replace("&", r"&")}\\[0.2em]') |
| 71 | +
|
| 72 | + # Corresponding author email |
| 73 | + for a in authors: |
| 74 | + if a.get('corresponding') and a.get('email'): |
| 75 | + lines.append(r'\small $^{*}$Corresponding author: \href{mailto:' |
| 76 | + + a['email'] + r'}{' + a['email'] + r'}\\[0.3em]') |
| 77 | +
|
| 78 | + lines.append(r'\small ' + str(fm.get('date','')) + r'\\') |
| 79 | + lines.append(r'\end{center}') |
| 80 | + lines.append(r'\vspace{1em}') |
| 81 | + lines.append(r'\noindent\rule{\textwidth}{0.4pt}') |
| 82 | + lines.append(r'\vspace{0.5em}') |
| 83 | +
|
| 84 | + with open('/tmp/title_block.tex', 'w') as f: |
| 85 | + f.write('\n'.join(lines)) |
| 86 | +
|
| 87 | + print("Done. Authors:", [a['name'] for a in authors]) |
| 88 | + PYEOF |
| 89 | +
|
| 90 | + - name: Create LaTeX header |
46 | 91 | run: | |
47 | | - cat > /tmp/preprint-header.tex << 'EOF' |
| 92 | + cat > /tmp/header.tex << 'EOF' |
| 93 | + % ── URL / hyperlink handling ────────────────────────────────────────── |
| 94 | + \PassOptionsToPackage{hyphens}{url} |
48 | 95 | \usepackage{xurl} |
| 96 | + \usepackage[ |
| 97 | + colorlinks=true, |
| 98 | + linkcolor=blue, |
| 99 | + citecolor=blue, |
| 100 | + urlcolor=blue, |
| 101 | + breaklinks=true |
| 102 | + ]{hyperref} |
| 103 | +
|
| 104 | + % ── Page geometry ───────────────────────────────────────────────────── |
| 105 | + \usepackage[a4paper, margin=2.5cm]{geometry} |
| 106 | +
|
| 107 | + % ── Fonts ───────────────────────────────────────────────────────────── |
| 108 | + \usepackage{fontspec} |
| 109 | + \setmainfont{TeX Gyre Termes} |
| 110 | + \usepackage{microtype} |
| 111 | +
|
| 112 | + % ── Preprint watermark header ───────────────────────────────────────── |
49 | 113 | \usepackage{fancyhdr} |
50 | 114 | \usepackage{xcolor} |
51 | 115 | \pagestyle{fancy} |
52 | 116 | \fancyhf{} |
53 | | - \fancyhead[C]{\textcolor{red}{\textbf{PREPRINT --- NOT PEER REVIEWED}}} |
| 117 | + \fancyhead[C]{% |
| 118 | + \textcolor{red}{\textbf{PREPRINT\,---\,NOT PEER REVIEWED}}% |
| 119 | + } |
54 | 120 | \fancyfoot[C]{\thepage} |
55 | 121 | \renewcommand{\headrulewidth}{0.4pt} |
| 122 | +
|
| 123 | + % ── Suppress Pandoc's auto title block (we use our own) ─────────────── |
| 124 | + \renewcommand{\maketitle}{} |
56 | 125 | EOF |
57 | 126 |
|
58 | | - - name: Generate PDF and Preprint Package |
| 127 | + - name: Generate Preprint PDF and LaTeX source |
59 | 128 | run: | |
60 | 129 | cd paper |
61 | 130 |
|
62 | | - # 1. Generate preprint PDF |
| 131 | + # ── Preprint PDF ────────────────────────────────────────────────────── |
63 | 132 | pandoc paper.md -o paper.pdf \ |
64 | 133 | --standalone \ |
65 | 134 | --citeproc \ |
66 | 135 | --pdf-engine=xelatex \ |
67 | 136 | --metadata-file=/tmp/pandoc_meta.yaml \ |
68 | | - --include-in-header=/tmp/preprint-header.tex |
| 137 | + --include-in-header=/tmp/header.tex \ |
| 138 | + --include-before-body=/tmp/title_block.tex |
69 | 139 |
|
70 | | - # 2. Generate LaTeX source for preprint submission |
| 140 | + # ── LaTeX source (self-contained, bibliography embedded) ────────────── |
71 | 141 | pandoc paper.md -o paper.tex \ |
72 | 142 | --standalone \ |
73 | 143 | --citeproc \ |
74 | 144 | --pdf-engine=xelatex \ |
75 | 145 | --metadata-file=/tmp/pandoc_meta.yaml \ |
76 | | - --include-in-header=/tmp/preprint-header.tex |
| 146 | + --include-in-header=/tmp/header.tex \ |
| 147 | + --include-before-body=/tmp/title_block.tex |
77 | 148 |
|
78 | | - # 3. Create preprint submission ZIP |
79 | | - # Add figures here if needed, e.g.: figures/fig1.png |
| 149 | + # ── Preprint submission ZIP ─────────────────────────────────────────── |
| 150 | + # Append figure paths here if needed, e.g.: figures/fig1.pdf |
80 | 151 | zip preprint_submission.zip paper.tex |
81 | 152 |
|
82 | | - - name: Upload Preprint PDF Artifact |
83 | | - uses: actions/upload-artifact@v4 |
| 153 | + - name: Upload Preprint PDF |
| 154 | + uses: actions/upload-artifact@v6 |
84 | 155 | with: |
85 | 156 | name: preprint-pdf |
86 | 157 | path: paper/paper.pdf |
87 | 158 |
|
88 | | - - name: Upload Preprint Package Artifact |
89 | | - uses: actions/upload-artifact@v4 |
| 159 | + - name: Upload Preprint Package |
| 160 | + uses: actions/upload-artifact@v6 |
90 | 161 | with: |
91 | 162 | name: preprint-package |
92 | 163 | path: paper/preprint_submission.zip |
0 commit comments