Skip to content

Commit

Permalink
ci: add release please action (#10)
Browse files Browse the repository at this point in the history
Adds a release process based on Release Please similar to other
libraries owned by the Auth team.
  • Loading branch information
hf authored May 27, 2024
1 parent de19d4f commit b115940
Show file tree
Hide file tree
Showing 5 changed files with 289 additions and 2 deletions.
101 changes: 101 additions & 0 deletions .github/workflows/conventional-commits-lint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
"use strict";

const fs = require("fs");

const TITLE_PATTERN =
/^(?<prefix>[^:!(]+)(?<package>\([^)]+\))?(?<breaking>[!])?:.+$/;
const RELEASE_AS_DIRECTIVE = /^\s*Release-As:/im;
const BREAKING_CHANGE_DIRECTIVE = /^\s*BREAKING[ \t]+CHANGE:/im;

const ALLOWED_CONVENTIONAL_COMMIT_PREFIXES = [
"feat",
"fix",
"ci",
"docs",
"chore",
];

const object = process.argv[2];
const payload = JSON.parse(fs.readFileSync(process.stdin.fd, "utf-8"));

let validate = [];

if (object === "pr") {
validate.push({
title: payload.pull_request.title,
content: payload.pull_request.body,
});
} else if (object === "push") {
validate.push(
...payload.commits.map((commit) => ({
title: commit.message.split("\n")[0],
content: commit.message,
})),
);
} else {
console.error(
`Unknown object for first argument "${object}", use 'pr' or 'push'.`,
);
process.exit(0);
}

let failed = false;

validate.forEach((payload) => {
if (payload.title) {
const { groups } = payload.title.match(TITLE_PATTERN);

if (groups) {
if (groups.breaking) {
console.error(
`PRs are not allowed to declare breaking changes at this stage of the project. Please remove the ! in your PR title or commit message and adjust the functionality to be backward compatible.`,
);
failed = true;
}

if (
!ALLOWED_CONVENTIONAL_COMMIT_PREFIXES.find(
(prefix) => prefix === groups.prefix,
)
) {
console.error(
`PR (or a commit in it) is using a disallowed conventional commit prefix ("${groups.prefix}"). Only ${ALLOWED_CONVENTIONAL_COMMIT_PREFIXES.join(", ")} are allowed. Make sure the prefix is lowercase!`,
);
failed = true;
}

if (groups.package && groups.prefix !== "chore") {
console.warn(
"Avoid using package specifications in PR titles or commits except for the `chore` prefix.",
);
}
} else {
console.error(
"PR or commit title must match conventional commit structure.",
);
failed = true;
}
}

if (payload.content) {
if (payload.content.match(RELEASE_AS_DIRECTIVE)) {
console.error(
"PR descriptions or commit messages must not contain Release-As conventional commit directives.",
);
failed = true;
}

if (payload.content.match(BREAKING_CHANGE_DIRECTIVE)) {
console.error(
"PR descriptions or commit messages must not contain a BREAKING CHANGE conventional commit directive. Please adjust the functionality to be backward compatible.",
);
failed = true;
}
}
});

if (failed) {
process.exit(1);
}

process.exit(0);
43 changes: 43 additions & 0 deletions .github/workflows/conventional-commits.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Check pull requests

on:
push:
branches-ignore: # Run the checks on all branches but the protected ones
- master
- release/*

pull_request_target:
branches:
- master
- release/*
types:
- opened
- edited
- reopened
- ready_for_review

jobs:
check-conventional-commits:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
sparse-checkout: |
.github
- if: ${{ github.event_name == 'pull_request_target' }}
run: |
set -ex
node .github/workflows/conventional-commits-lint.js pr <<EOF
${{ toJSON(github.event) }}
EOF
- if: ${{ github.event_name == 'push' }}
run: |
set -ex
node .github/workflows/conventional-commits-lint.js push <<EOF
${{ toJSON(github.event) }}
EOF
143 changes: 143 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
name: Release

on:
push:
branches:
- main
- release/*

jobs:
release_please:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: googleapis/release-please-action@v4
id: release
with:
release-type: go
target-branch: ${{ github.ref_name }}

- uses: actions/checkout@v4
if: ${{ steps.release.outputs.release_created == 'true' || steps.release.outputs.prs_created == 'true' }}
with:
fetch-depth: 0

- if: ${{ steps.release.outputs }}
id: versions
run: |
set -ex
RELEASE_CANDIDATE=true
NOT_RELEASE_CANDIDATE='${{ steps.release.outputs.release_created }}'
if [ "$NOT_RELEASE_CANDIDATE" == "true" ]
then
RELEASE_CANDIDATE=false
fi
MAIN_RELEASE_VERSION=x
RELEASE_VERSION=y
if [ "$RELEASE_CANDIDATE" == "true" ]
then
# Release please doesn't tell you the candidate version when it
# creates the PR, so we have to take it from the title.
MAIN_RELEASE_VERSION=$(node -e "console.log('${{ steps.release.outputs.pr && fromJSON(steps.release.outputs.pr).title }}'.split(' ').reverse().find(x => x.match(/[0-9]+[.][0-9]+[.][0-9]+/)))")
# Use git describe tags to identify the number of commits the branch
# is ahead of the most recent non-release-candidate tag, which is
# part of the rc.<commits> value.
RELEASE_VERSION=$MAIN_RELEASE_VERSION-rc.$(node -e "console.log('$(git describe --tags --exclude *rc*)'.split('-')[1])")
# release-please only ignores releases that have a form like [A-Z0-9]<version>, so prefixing with rc<version>
RELEASE_NAME="rc$RELEASE_VERSION"
else
MAIN_RELEASE_VERSION=${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}.${{ steps.release.outputs.patch }}
RELEASE_VERSION="$MAIN_RELEASE_VERSION"
RELEASE_NAME="v$RELEASE_VERSION"
fi
echo "MAIN_RELEASE_VERSION=${MAIN_RELEASE_VERSION}" >> "${GITHUB_ENV}"
echo "RELEASE_VERSION=${RELEASE_VERSION}" >> "${GITHUB_ENV}"
echo "RELEASE_CANDIDATE=${RELEASE_CANDIDATE}" >> "${GITHUB_ENV}"
echo "RELEASE_NAME=${RELEASE_NAME}" >> "${GITHUB_ENV}"
echo "MAIN_RELEASE_VERSION=${MAIN_RELEASE_VERSION}" >> "${GITHUB_OUTPUT}"
echo "RELEASE_VERSION=${RELEASE_VERSION}" >> "${GITHUB_OUTPUT}"
echo "RELEASE_CANDIDATE=${RELEASE_CANDIDATE}" >> "${GITHUB_OUTPUT}"
echo "RELEASE_NAME=${RELEASE_NAME}" >> "${GITHUB_OUTPUT}"
- uses: actions/setup-node@v4
if: ${{ steps.release.outputs.release_created == 'true' || steps.release.outputs.prs_created == 'true' }}
with:
node-version: 20

- name: Build release artifacts
if: ${{ steps.release.outputs.release_created == 'true' || steps.release.outputs.prs_created == 'true' }}
run: |
set -ex
echo "export const VERSION = '$RELEASE_VERSION';" > src/version.ts
npm ci
npm run build
for f in package.json package-lock.json
do
sed -i 's|"version": "0.0.0",|"version": "'"$RELEASE_VERSION"'",|g' "$f"
done
echo '//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}' > ~/.npmrc
DIST_TAG=patched
if [ "$RELEASE_CANDIDATE" == "true" ]
then
DIST_TAG=rc
elif [ "$GITHUB_REF" == "refs/heads/main" ] && [ "$GITHUB_REF" == "refs/heads/master" ]
then
# This is the main branch and it's not a prerelease, so the dist-tag should be `latest`.
DIST_TAG=latest
fi
echo "Publishing @supabase/ssr now..."
npm publish --tag "$DIST_TAG"
- name: Create GitHub release and branches
if: ${{ steps.release.outputs.release_created == 'true' || steps.release.outputs.prs_created == 'true' }}
run: |
set -ex
if [ "$RELEASE_CANDIDATE" == "true" ]
then
PR_NUMBER='${{ steps.release.outputs.pr && fromJSON(steps.release.outputs.pr).number }}'
GH_TOKEN='${{ github.token }}' gh release \
create $RELEASE_NAME \
--title "v$RELEASE_VERSION" \
--prerelease \
-n "This is a release candidate. See release-please PR #$PR_NUMBER for context."
GH_TOKEN='${{ github.token }}' gh pr comment "$PR_NUMBER" \
-b "Release candidate [v$RELEASE_VERSION](https://github.com/supabase/ssr/releases/tag/$RELEASE_NAME) published."
else
if [ "$GITHUB_REF" == "refs/heads/main" ] || [ "$GITHUB_REF" == "refs/heads/master" ]
then
IS_PATCH_ZERO=$(node -e "console.log('$RELEASE_VERSION'.endsWith('.0'))")
if [ "$IS_PATCH_ZERO" == "true" ]
then
# Only create release branch if patch version is 0, as this
# means that the release can be patched in the future.
GH_TOKEN='${{ github.token }}' gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/supabase/ssr/git/refs \
-f "ref=refs/heads/release/${RELEASE_VERSION}" \
-f "sha=$GITHUB_SHA"
fi
fi
fi
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@supabase/ssr",
"version": "0.3.0",
"version": "0.0.0",
"description": "Use the Supabase JavaScript library in popular server-side rendering (SSR) frameworks.",
"main": "dist/main/index.js",
"module": "dist/module/index.js",
Expand Down
2 changes: 1 addition & 1 deletion src/version.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const VERSION = "0.3.0";
export const VERSION = "0.0.0";

0 comments on commit b115940

Please sign in to comment.