1+ name : Freshness (manual export + runtime ms.date check)
2+
3+ on :
4+ workflow_dispatch :
5+ push :
6+ paths :
7+ - ' data/engagement-latest.xlsx'
8+
9+ permissions :
10+ contents : write
11+ pull-requests : write
12+
13+ env :
14+ TARGET_BRANCH : main
15+ WORKING_BRANCH_PREFIX : chore/freshness
16+ DOCSET_ROOT : powerbi-docs
17+ REPORT_XLSX : data/engagement-latest.xlsx
18+ STALE_FILE_LIST : tools/stale-files.txt
19+ BATCH_LIMIT : " 50"
20+ FRESH_WINDOW_DAYS : " 365"
21+ PR_LABELS : " freshness,automation,doc-hygiene"
22+
23+ jobs :
24+ freshness :
25+ runs-on : ubuntu-latest
26+
27+ steps :
28+ - name : Checkout
29+ uses : actions/checkout@v4
30+ with :
31+ fetch-depth : 0
32+
33+ - name : Setup Python
34+ uses : actions/setup-python@v5
35+ with :
36+ python-version : " 3.11"
37+
38+ - name : Install Python deps
39+ run : |
40+ python -m pip install --upgrade pip
41+ pip install pandas openpyxl python-dateutil pyyaml
42+
43+ - name : Generate stale batch from XLSX + runtime ms.date check
44+ run : |
45+ python tools/generate-stale-list.py \
46+ --input "${{ env.REPORT_XLSX }}" \
47+ --output "${{ env.STALE_FILE_LIST }}" \
48+ --docroot "${{ env.DOCSET_ROOT }}" \
49+ --limit "${{ env.BATCH_LIMIT }}" \
50+ --fresh-window-days "${{ env.FRESH_WINDOW_DAYS }}"
51+
52+ - name : Show batch
53+ run : |
54+ echo "Files to process:"
55+ cat "${{ env.STALE_FILE_LIST }}" || true
56+ echo ""
57+ echo "Summary:"
58+ head -n 10 "${{ env.STALE_FILE_LIST }}.summary.csv" || true
59+ echo ""
60+ echo "Skipped:"
61+ head -n 10 "${{ env.STALE_FILE_LIST }}.skipped.csv" || true
62+
63+ - name : Run DocuMentor passes (placeholder)
64+ shell : bash
65+ run : |
66+ if [ ! -s "${{ env.STALE_FILE_LIST }}" ]; then
67+ echo "No files selected; skipping DocuMentor."
68+ exit 0
69+ fi
70+ while IFS= read -r f; do
71+ [ -z "$f" ] && continue
72+ echo "→ DocuMentor on $f"
73+ # Replace with your real CLI commands:
74+ # ./documentor fix --file "$f" --rules "learn-markdown,frontmatter"
75+ # ./documentor optimize --file "$f" --prompts "seo,geo"
76+ done < "${{ env.STALE_FILE_LIST }}"
77+
78+ # ───────── PR via your fork (robust, no blocked actions) ─────────
79+
80+ - name : Meta (branch label)
81+ id : meta
82+ shell : bash
83+ run : echo "label=$(date -u +'%Y%m%d')" >> "$GITHUB_OUTPUT"
84+
85+ - name : Detect changes
86+ id : detect
87+ shell : bash
88+ run : |
89+ if git status --porcelain | grep -q .; then
90+ echo "changed=true" >> $GITHUB_OUTPUT
91+ else
92+ echo "changed=false" >> $GITHUB_OUTPUT
93+ fi
94+
95+ - name : Commit locally
96+ if : ${{ steps.detect.outputs.changed == 'true' }}
97+ id : commit
98+ shell : bash
99+ run : |
100+ set -e
101+ git config user.name "docs-automation"
102+ git config user.email "[email protected] " 103+ BRANCH="${WORKING_BRANCH_PREFIX}/${{ steps.meta.outputs.label }}"
104+ echo "branch=$BRANCH" >> $GITHUB_OUTPUT
105+ git checkout -b "$BRANCH" "origin/${TARGET_BRANCH}"
106+ git add -A
107+ git commit -m "Freshness automation (runtime ms.date check + DocuMentor placeholders)"
108+
109+ - name : Push branch to fork (JulCsc/powerbi-docs-pr)
110+ if : ${{ steps.detect.outputs.changed == 'true' }}
111+ env :
112+ FORK_PR_TOKEN : ${{ secrets.FORK_PR_TOKEN }}
113+ shell : bash
114+ run : |
115+ set -euo pipefail
116+
117+ # --- Config ---
118+ FORK_OWNER="JulCsc"
119+ FORK_REPO="powerbi-docs-pr"
120+ BRANCH="${{ steps.commit.outputs.branch }}"
121+ FORK_URL="https://x-access-token:${FORK_PR_TOKEN}@github.com/${FORK_OWNER}/${FORK_REPO}.git"
122+
123+ # 1) Prevent the checkout token from overriding our PAT auth
124+ git config --global http.https://github.com/.extraheader ""
125+
126+ # 2) Add or update the 'fork' remote idempotently
127+ if git remote | grep -q "^fork$"; then
128+ git remote set-url fork "${FORK_URL}"
129+ else
130+ git remote add fork "${FORK_URL}"
131+ fi
132+
133+ # 3) Verify permissions (read) before push
134+ if ! git ls-remote --heads fork >/dev/null 2>&1; then
135+ echo "ERROR: Cannot access fork via provided token. Check FORK_PR_TOKEN scopes and repo access." >&2
136+ exit 128
137+ fi
138+
139+ # 4) Create the branch on fork (force-with-lease handles existing branch safely)
140+ git push --force-with-lease fork "${BRANCH}:${BRANCH}"
141+
142+ - name : Install jq (for JSON body)
143+ if : ${{ steps.detect.outputs.changed == 'true' }}
144+ run : sudo apt-get update && sudo apt-get install -y jq
145+
146+ - name : Open PR from fork → upstream (GitHub REST)
147+ if : ${{ steps.detect.outputs.changed == 'true' }}
148+ env :
149+ GH_TOKEN : ${{ github.token }}
150+ shell : bash
151+ run : |
152+ set -euo pipefail
153+ UPSTREAM_OWNER="${{ github.repository_owner }}"
154+ UPSTREAM_REPO="${{ github.event.repository.name }}"
155+ HEAD="JulCsc:${{ steps.commit.outputs.branch }}"
156+ BASE="${{ env.TARGET_BRANCH }}"
157+ TITLE="Freshness: automated pass (forked PR) – ${{ steps.meta.outputs.label }}"
158+
159+ read -r -d '' BODY <<'EOF'
160+ This PR was generated by the freshness workflow.
161+
162+ **What happened**
163+ - Built a batch from the engagement export/report
164+ - Re-checked each file’s current **ms.date**; skipped those already fresh
165+ - Ran DocuMentor passes (if configured)
166+
167+ **Run artifacts**
168+ - Processed : ` tools/stale-files.txt`
169+ - Summary : ` tools/stale-files.summary.csv`
170+ - Skipped : ` tools/stale-files.skipped.csv`
171+ EOF
172+
173+ # Create PR
174+ RESP=$(curl -sS -X POST \
175+ -H "Authorization : Bearer ${GH_TOKEN}" \
176+ -H "Accept : application/vnd.github+json" \
177+ " https://api.github.com/repos/${UPSTREAM_OWNER}/${UPSTREAM_REPO}/pulls" \
178+ -d "$(jq -n --arg t "$TITLE" --arg h "$HEAD" --arg b "$BASE" --arg body "$BODY" '{title:$t, head:$h, base:$b, body:$body}')")
179+
180+ echo "$RESP" | jq -r '.html_url // "PR creation response logged above."' || true
181+
182+ - name : No-op note
183+ if : ${{ steps.detect.outputs.changed != 'true' }}
184+ run : echo "No changes detected; skipping PR creation."
0 commit comments