Skip to content

Automation ​

What happens by itself after a merge to main, and how to trigger each step by hand when you need to.

For writing content, see Editorial.

The chain ​

Weekdays 06:00 (Europe/Berlin)
  └─ sync:changelog reads the CHANGELOG.md of six repositories
       ├─ nothing new  ->  stop, no commit
       └─ something new -> commit to main
                              │
Push to main ─────────────────┘
  ├─ deploy:production   deploy the docs to Vercel
  └─ notify:slack        post to #guppy if there is anything to announce

The deploy runs before the announcement. GitLab skips a stage when an earlier one failed, so a broken deploy suppresses the message instead of posting one full of dead links.

No loop is possible: sync:changelog runs only on a schedule, and notify:slack never pushes.

What triggers a message ​

ChangeAnnounced
New file in docs/news/yes
Release opening a new minor or major lineyes
Release with Breaking changesyes, whatever the version segment
Withdrawn releaseyes
Release candidate such as 2.8.0-rc1yes, tagged #ReleaseCandidate
Plain patch releaseno, counted in a trailing line
Edit to an existing postno, only added files count

Everything from one push becomes a single message, never one per release.

The point that matters most for you as a developer: a genuine breaking change belongs under a Breaking changes heading, even in a patch. That heading is what decides between announcing and silently counting.

The three jobs ​

All of it lives in .gitlab-ci.yml.

JobRuns whenDoes what
sync:changelogschedule onlyRead changelogs, commit and push if anything changed
deploy:productionpush to mainvercel deploy --prod
notify:slackpush to mainDigest into #guppy

Why not Vercel's git integration ​

Vercel attributes a push to the Vercel account behind the commit author. That account is a viewer on the team, so those deployments were refused. Deploying from the pipeline sidesteps the attribution and uses a token from an account that may deploy. The git integration has since been disconnected, so GitLab is the single source.

Doing it by hand ​

Collect the changelogs ​

bash
npm run changelog:sync

Writes docs/.vitepress/data/changelog.json. Needs GUPPY_GITLAB_TOKEN in .env.local.

When nothing changed the file stays byte identical, including the generatedAt field. An empty git diff therefore reliably means "nothing new", and that is exactly what the scheduled job branches on.

Preview a message ​

bash
node scripts/notify-slack.mjs --dry-run
node scripts/notify-slack.mjs --dry-run --since <commit>

Prints the finished Slack payload as JSON and sends nothing. Without a token configured the script never sends anything anyway, so a local run cannot post by accident.

The JSON pastes straight into Slack's Block Kit Builder if you want to see it rendered.

Deploy ​

bash
npx vercel deploy --yes          # preview
npx vercel deploy --prod --yes   # production

You normally do not need this, the pipeline handles it. Useful for showing something before merging.

Run the schedule now ​

Build, Pipeline schedules, Play on Nightly changelog sync. Runs immediately and is otherwise identical to the nightly run.

Test the pipeline on a branch ​

Start a pipeline with the variable SLACK_NOTIFY_TEST set to 1. Then notify:slack also runs outside main, as a manual job.

Careful: the Slack variables are protected, so they only reach protected branches. On an ordinary feature branch the job runs, finds no token, prints the message instead of sending it, and goes green. That looks like success but sent nothing.

Variables ​

All under Settings, CI/CD, Variables of the guppy-docs project, each masked and protected.

VariablePurpose
GUPPY_GITLAB_TOKENRead the changelogs of the other projects
GUPPY_PUSH_TOKENPush the commit to main, needs the Maintainer role
VERCEL_TOKENDeployment, a user token scoped to the team
SLACK_BOT_TOKENSend the message, scope chat:write
SLACK_CHANNELTarget channel, an id is stabler than a name

Values belong nowhere in the repository. .env.local is for local runs and is listed in .gitignore.

Troubleshooting ​

SymptomCause
Job green but nothing in SlackNo token reached the job, usually protected on an unprotected branch. It says so in the log
invalid_authSlack token wrong or revoked
not_in_channelApp not in the channel. /invite @Guppy Docs, or add scope chat:write.public
Could not retrieve Project SettingsVercel token has the wrong scope. It must be a user token scoped to the team
Schedule does not pushGUPPY_PUSH_TOKEN lacks the Maintainer role. main is protected
Nothing announced although a release landedPatch without Breaking changes. Working as intended

The script reports every Slack error in plain text along with what to do about it, so the job log is the first place to look rather than guesswork.