Skip to content

Publish releases

Publish releases #22

Workflow file for this run

name: Publish releases
# Consolidates canary and stable releases into single workflow
# Trusted workflow for publishing to npm
on:
push:
branches: [master]
workflow_dispatch:
inputs:
version_specifier:
description: 'Semver bump (patch|minor|major|pre*) or exact version (v1.2.3)'
required: true
type: string
env:
NODE_VERSION: '20'
jobs:
release-stable: # stable releases can only be manually triggered
if: ${{ github.event_name == 'workflow_dispatch' }}
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: Generate GitHub App token (with org members:read)
id: app-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
- name: Check if actor is member of admin or client-libs team
id: team-check
uses: actions/github-script@v7
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
const org = 'supabase'
const { actor } = context
async function isOrgAdmin() {
try {
const res = await github.rest.orgs.getMembershipForUser({ org, username: actor })
return res?.status === 200 && res.data?.role === 'admin' && res.data?.state === 'active'
} catch (e) {
console.log('Org membership check failed', e)
return false
}
}
async function resolveTeamSlug(preferredSlugs) {
try {
const teams = await github.paginate(github.rest.teams.list, { org })
const lower = (s) => (s || '').toLowerCase()
const candidates = preferredSlugs.map(lower)
const team = teams.find((t) => {
const slug = lower(t.slug)
const name = lower(t.name)
return candidates.includes(slug) || candidates.includes(name)
})
return team?.slug
} catch (e) {
console.log('Failed to list teams', e)
return undefined
}
}
async function isTeamMemberByResolvedSlug(preferredSlugs) {
const resolved = await resolveTeamSlug(preferredSlugs)
if (!resolved) return false
try {
const res = await github.rest.teams.getMembershipForUserInOrg({
org,
team_slug: resolved,
username: actor,
})
return res?.status === 200
} catch (err) {
console.log(`Membership check failed for slug ${resolved}`, err)
return false
}
}
const isAdminOrg = await isOrgAdmin()
const isAdminTeam = await isTeamMemberByResolvedSlug(['admin','admins','owners'])
const isClientLibs = await isTeamMemberByResolvedSlug(['client-libs','clientlibs','client-libraries'])
const isMember = Boolean(isAdminOrg || isAdminTeam || isClientLibs)
core.setOutput('is_team_member', isMember ? 'true' : 'false')
- name: Fail if not authorized
if: steps.team-check.outputs.is_team_member != 'true'
run: |
echo "You must be a member of @supabase/admin or @supabase/client-libs."
exit 1
# - uses: actions/checkout@v5
# with:
# fetch-depth: 0