Daily LinkedIn Post #29
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: Daily LinkedIn Post | |
| on: | |
| schedule: | |
| # GitHub `schedule` uses UTC only (no Europe/Madrid in cron). | |
| # 06:00 UTC = 07:00 in Europe/Madrid when offset is CET (UTC+1, roughly late Oct–late Mar). | |
| # For 07:00 during CEST (UTC+2, roughly late Mar–late Oct), use: cron: '0 5 * * *' | |
| # Post goes live when this job finishes — the LinkedIn UGC API does not support “publish at midnight” | |
| # from an earlier run; for ~midnight local posts, run the job near midnight instead (e.g. 23:00 UTC ≈ 00:00 CET). | |
| - cron: '0 6 * * *' | |
| workflow_dispatch: | |
| inputs: | |
| day_number: | |
| description: 'Specific day number to post (1-500, leave empty for auto)' | |
| required: false | |
| default: '' | |
| dry_run: | |
| description: 'Dry run - generate but do not publish' | |
| required: false | |
| default: 'false' | |
| type: choice | |
| options: | |
| - 'false' | |
| - 'true' | |
| jobs: | |
| post: | |
| name: Generate and Publish Post | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Set up Python 3.11 | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: pip install -r requirements.txt | |
| # LINKEDIN_MEMBER_SUB = OpenID id_token "sub" (same as local .env). Required if userinfo/me fail in CI. | |
| - name: Create .env file from GitHub Secrets | |
| run: | | |
| cat > .env << EOF | |
| GEMINI_API_KEY=${{ secrets.GEMINI_API_KEY }} | |
| LINKEDIN_EMAIL=${{ secrets.LINKEDIN_EMAIL }} | |
| LINKEDIN_PASSWORD=${{ secrets.LINKEDIN_PASSWORD }} | |
| LINKEDIN_ACCESS_TOKEN=${{ secrets.LINKEDIN_ACCESS_TOKEN }} | |
| LINKEDIN_MEMBER_SUB=${{ secrets.LINKEDIN_MEMBER_SUB }} | |
| CHROMA_PERSIST_DIR=./data/chroma | |
| POST_CALENDAR_PATH=./data/post_calendar.csv | |
| SCHEDULE_HOUR=12 | |
| SCHEDULE_MINUTE=15 | |
| TIMEZONE=Europe/Madrid | |
| CALENDAR_SEQUENCE_START=${{ vars.CALENDAR_SEQUENCE_START }} | |
| DRY_RUN=${{ github.event.inputs.dry_run || secrets.DRY_RUN || 'false' }} | |
| EOF | |
| - name: Run post pipeline | |
| run: | | |
| if [ -n "${{ github.event.inputs.day_number }}" ]; then | |
| python main.py --run-now --day ${{ github.event.inputs.day_number }} | |
| else | |
| python main.py --run-now | |
| fi | |
| env: | |
| GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} | |
| LINKEDIN_EMAIL: ${{ secrets.LINKEDIN_EMAIL }} | |
| LINKEDIN_PASSWORD: ${{ secrets.LINKEDIN_PASSWORD }} | |
| LINKEDIN_ACCESS_TOKEN: ${{ secrets.LINKEDIN_ACCESS_TOKEN }} | |
| LINKEDIN_MEMBER_SUB: ${{ secrets.LINKEDIN_MEMBER_SUB }} | |
| # Must match .env above: scheduled runs use secrets.DRY_RUN (omit or set false for real posts). | |
| DRY_RUN: ${{ github.event.inputs.dry_run || secrets.DRY_RUN || 'false' }} | |
| - name: Clean up .env | |
| if: always() | |
| run: rm -f .env |