Posting to social media from GitHub Actions
The final step in my efforts to automatically announce new blog posts to social media from GitHub Actions was the actual act of posting the prepared message to selected social media platforms. After a bit of search and testing, I managed to find existing actions for all my platforms of interest.
For Mastodon, I chose the cbrgm/mastodon-github-action:
- name: Post message to Mastodon
if: ${{ env.NEW_POST == 'true' }}
continue-on-error: true
uses: cbrgm/mastodon-github-action@v2
with:
url: ${{ secrets.MASTODON_URL }}
access-token: ${{ secrets.MASTODON_ACCESS_TOKEN }}
message: ${{ steps.social-media-message.outputs.message }}
In addition to the obvious message
input, which I set to my precomposed message, I had to set the following secrets for authentication:
MASTODON_URL
: the domain of my Mastodon instance, e.g.,https://mas.to
.MASTODON_ACCESS_TOKEN
: the access token, created via the New application button on the Preferences > Development page in the Mastodon web interface. I only had to grant thewrite:statuses
scope. I had to use the generated value for Your access token:
You might have also noticed that I set the continue-on-error
property of the step to true
. I did this for all actions, which attempt to post an update to social media. Even if one of them fails, I want the remaining ones to post to the other platforms.
For Bluesky, I chose myConsciousness/bluesky-post:
- name: Post message to Bluesky
if: ${{ env.NEW_POST == 'true' }}
continue-on-error: true
uses: myConsciousness/bluesky-post@v5
with:
identifier: ${{ secrets.BLUESKY_IDENTIFIER }}
password: ${{ secrets.BLUESKY_PASSWORD }}
text: ${{ steps.social-media-message.outputs.message }}
link-preview-url: ${{ env.POST_URL }}
Here, the precomposed message is set to text
. But for the link in the message to work, I also had to set it as link-preview-url
. This also ensured that a preview card was generated. Bluesky API authentication currently requires your username and password, so that's what I had to store in the secrets:
BLUESKY_IDENTIFIER
: my Bluesky handle.BLUESKY_PASSWORD
: the password I log into Bluesky with.
For X, I chose rg-wood/send-tweet-action:
- name: Post message to X
if: ${{ env.NEW_POST == 'true' }}
continue-on-error: true
uses: rg-wood/send-tweet-action@v1
with:
consumer-key: ${{ secrets.X_CONSUMER_API_KEY }}
consumer-secret: ${{ secrets.X_CONSUMER_API_SECRET }}
access-token: ${{ secrets.X_ACCESS_TOKEN }}
access-token-secret: ${{ secrets.X_ACCESS_TOKEN_SECRET }}
status: ${{ steps.social-media-message.outputs.message }}
The status
input is set to my precomposed message. All the others are set to secrets with my authentication data. To get it, I first had to sign up for the Free API package:
This automatically created for me the only project and app I am entitled to. I renamed both to make it more obvious to me what I am using them for.
The more important part of the configuration was changing the permissions. By default, the app was configured with read permissions only. I could change that in User authentication settings on the app Settings tab:
- I changed App permissions from Read to Read and write.
- I set the Type of app to Web app, Automated App or Bot. (I think my use case is best categorized as a bot.) Before I was allowed to Save the changes, I also had to fill out the Callback URI / Redirect URL and Website URL fields, although they aren't really applicable in my case.
Only then was I ready to get the authentication data I needed from the Keys and tokens tab:
X_CONSUMER_API_KEY
andX_CONSUMER_API_SECRET
: They can only be accessed once, after you click the Regenerate button for API Key and Secret in the Consumer Keys section. (Of course, this action invalidates any previously generated API key and secret.)X_ACCESS_TOKEN
andX_ACCESS_TOKEN_SECRET
: They can also only be accessed once, after you click the Regenerate button for Access Token and Secret in the Authentication Tokens section. This is where you should make sure that they were generated with Read and Write permissions or the GitHub action will fail with a 403 error. (Of course, this action invalidates any previously generated access token and secret.)
With this, I have covered all the social media platforms, I wanted to post to. The chosen actions did everything I required them to, so I didn't have to write any code to interact with the APIs directly. For certain, this has saved me a lot of time and effort.