Update index: Prototype Insect-Proof Ventilating Window Installed in … #32
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Cross-post to LinkedIn | ||
| on: | ||
| push: | ||
| branches: [main] | ||
| paths: | ||
| - 'blog/posts/*.json' | ||
| jobs: | ||
| linkedin-post: | ||
| runs-on: ubuntu-latest | ||
| if: ${{ vars.LINKEDIN_ENABLED == 'true' }} | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 2 | ||
| token: ${{ secrets.SYNC_PAT }} | ||
| - name: Find new/changed post files | ||
| id: posts | ||
| run: | | ||
| CHANGED=$(git diff --name-only --diff-filter=AM HEAD~1 HEAD -- 'blog/posts/*.json' | head -1) | ||
| echo "file=$CHANGED" >> $GITHUB_OUTPUT | ||
| if [ -z "$CHANGED" ]; then | ||
| echo "skip=true" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "skip=false" >> $GITHUB_OUTPUT | ||
| fi | ||
| - name: Post to LinkedIn | ||
| if: steps.posts.outputs.skip == 'false' | ||
| env: | ||
| LINKEDIN_ACCESS_TOKEN: ${{ secrets.LINKEDIN_ACCESS_TOKEN }} | ||
| LINKEDIN_ORG_ID: ${{ vars.LINKEDIN_ORG_ID }} | ||
| POST_FILE: ${{ steps.posts.outputs.file }} | ||
| run: | | ||
| set -e | ||
| TITLE=$(jq -r '.title' "$POST_FILE") | ||
| EXCERPT=$(jq -r '.excerpt' "$POST_FILE") | ||
| SLUG=$(jq -r '.slug' "$POST_FILE") | ||
| LINKEDIN_REQUESTED=$(jq -r '.linkedinRequested // false' "$POST_FILE") | ||
| EXISTING_URL=$(jq -r '.linkedinUrl // empty' "$POST_FILE") | ||
| COVER_IMAGE=$(jq -r '.coverImage // ""' "$POST_FILE") | ||
| if [ "$LINKEDIN_REQUESTED" != "true" ]; then | ||
| echo "LinkedIn posting not requested for this post. Skipping." | ||
| exit 0 | ||
| fi | ||
| if [ -n "$EXISTING_URL" ]; then | ||
| echo "Post already cross-posted to LinkedIn: $EXISTING_URL. Skipping." | ||
| exit 0 | ||
| fi | ||
| if [ -z "$LINKEDIN_ACCESS_TOKEN" ]; then | ||
| echo "LinkedIn access token not configured. Skipping." | ||
| exit 0 | ||
| fi | ||
| if [ -z "$LINKEDIN_ORG_ID" ]; then | ||
| echo "LINKEDIN_ORG_ID repo variable not set. Skipping." | ||
| exit 1 | ||
| fi | ||
| AUTHOR_URN="urn:li:organization:$LINKEDIN_ORG_ID" | ||
| SITE_URL="https://actionresearchprojects.github.io" | ||
| POST_URL="${SITE_URL}/blog/#${SLUG}" | ||
| POST_TEXT="${TITLE} | ||
| ${EXCERPT} | ||
| Read more: ${POST_URL}" | ||
| if [ -n "$COVER_IMAGE" ] && [ "$COVER_IMAGE" != "null" ]; then | ||
| BODY=$(jq -n \ | ||
| --arg author "$AUTHOR_URN" \ | ||
| --arg text "$POST_TEXT" \ | ||
| --arg url "$POST_URL" \ | ||
| --arg title "$TITLE" \ | ||
| --arg desc "$EXCERPT" \ | ||
| '{ | ||
| "author": $author, | ||
| "commentary": $text, | ||
| "visibility": "PUBLIC", | ||
| "distribution": { | ||
| "feedDistribution": "MAIN_FEED", | ||
| "targetEntities": [], | ||
| "thirdPartyDistributionChannels": [] | ||
| }, | ||
| "content": { | ||
| "article": { | ||
| "source": $url, | ||
| "title": $title, | ||
| "description": $desc | ||
| } | ||
| }, | ||
| "lifecycleState": "PUBLISHED", | ||
| "isReshareDisabledByAuthor": false | ||
| }') | ||
| else | ||
| BODY=$(jq -n \ | ||
| --arg author "$AUTHOR_URN" \ | ||
| --arg text "$POST_TEXT" \ | ||
| '{ | ||
| "author": $author, | ||
| "commentary": $text, | ||
| "visibility": "PUBLIC", | ||
| "distribution": { | ||
| "feedDistribution": "MAIN_FEED", | ||
| "targetEntities": [], | ||
| "thirdPartyDistributionChannels": [] | ||
| }, | ||
| "lifecycleState": "PUBLISHED", | ||
| "isReshareDisabledByAuthor": false | ||
| }') | ||
| fi | ||
| echo "Posting to LinkedIn..." | ||
| HTTP_CODE=$(curl -s \ | ||
| -o /tmp/li_response.txt \ | ||
| -D /tmp/li_headers.txt \ | ||
| -w "%{http_code}" \ | ||
| -X POST "https://api.linkedin.com/rest/posts" \ | ||
| -H "Authorization: Bearer $LINKEDIN_ACCESS_TOKEN" \ | ||
| -H "Content-Type: application/json" \ | ||
| -H "LinkedIn-Version: 202401" \ | ||
| -H "X-Restli-Protocol-Version: 2.0.0" \ | ||
| -d "$BODY") | ||
| RESPONSE_BODY=$(cat /tmp/li_response.txt) | ||
| if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then | ||
| echo "Successfully posted to LinkedIn!" | ||
| POST_URN=$(grep -i "^x-restli-id:" /tmp/li_headers.txt | awk '{print $2}' | tr -d '\r\n') | ||
| if [ -n "$POST_URN" ]; then | ||
| LINKEDIN_URL="https://www.linkedin.com/feed/update/${POST_URN}" | ||
| echo "LinkedIn post URL: $LINKEDIN_URL" | ||
| jq --arg url "$LINKEDIN_URL" '. + {linkedinUrl: $url}' "$POST_FILE" > tmp.json && mv tmp.json "$POST_FILE" | ||
| SLUG_VAL=$(jq -r '.slug' "$POST_FILE") | ||
| jq --arg slug "$SLUG_VAL" --arg url "$LINKEDIN_URL" \ | ||
| 'map(if .slug == $slug then . + {linkedinUrl: $url} else . end)' \ | ||
| blog/posts.json > tmp.json && mv tmp.json blog/posts.json | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git add "$POST_FILE" blog/posts.json | ||
| git commit -m "Add LinkedIn URL to post: ${TITLE}" || true | ||
| git push || true | ||
| fi | ||
| else | ||
| echo "Failed to post to LinkedIn (HTTP $HTTP_CODE)" | ||
| echo "Response: $RESPONSE_BODY" | ||
| exit 1 | ||
| fi | ||