-
Notifications
You must be signed in to change notification settings - Fork 1
ci: add conventional commit checks and release branching actions #203
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
88bf6e6
f7ef0a9
42f1a8f
5efeed3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| #!/usr/bin/env bash | ||
| # Verifies github.actor is listed in CODEOWNERS (individual users only). | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How hard is it to add check for github group as well? For example to have whole @devrev/airdrop here or @devrev/aidrop-admin? |
||
| # Usage: check-authorized-release-actor.sh | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| ACTOR="${GITHUB_ACTOR:?GITHUB_ACTOR required}" | ||
| CODEOWNERS_FILE="${1:-.github/CODEOWNERS}" | ||
|
|
||
| AUTHORIZED_USERS=$(grep -o '@[a-zA-Z0-9_-]*[^/]' "$CODEOWNERS_FILE" | grep -v '@devrev/' | sed 's/@//' | tr '\n' ' ') | ||
|
|
||
| if ! echo "$AUTHORIZED_USERS" | grep -q "\b${ACTOR}\b"; then | ||
| echo "::error::User $ACTOR is not authorized to run release workflows" >&2 | ||
| echo "Only users listed in $CODEOWNERS_FILE can trigger releases" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "Authorized release actor: $ACTOR" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe rename file to check-conflicting-versions.sh or sth like that? |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| #!/usr/bin/env bash | ||
| # Fails if npm already has a version in the same minor line >= target version. | ||
| # Usage: check-npm-minor-line.sh <package_name> <target_version> | ||
| # Example: check-npm-minor-line.sh @devrev/ts-adaas 1.19.0 | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| PACKAGE="${1:?package name required}" | ||
| TARGET="${2:?target version required}" | ||
|
|
||
| MAJOR=$(echo "$TARGET" | cut -d. -f1) | ||
| MINOR=$(echo "$TARGET" | cut -d. -f2) | ||
| PREFIX="${MAJOR}.${MINOR}." | ||
|
|
||
| VERSIONS_JSON=$(npm view "$PACKAGE" versions --json 2>/dev/null || echo "[]") | ||
|
|
||
| CONFLICT=$(echo "$VERSIONS_JSON" | jq -r --arg prefix "$PREFIX" --arg target "$TARGET" ' | ||
| [.[] | select(startswith($prefix))] | | ||
| map(select(. >= $target)) | | ||
| if length > 0 then .[-1] else empty end | ||
| ') | ||
|
|
||
| if [ -n "$CONFLICT" ]; then | ||
| echo "::error::Cannot publish $TARGET: npm already has version $CONFLICT in the ${MAJOR}.${MINOR} line" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "No conflicting versions found in ${MAJOR}.${MINOR} line for target $TARGET" |
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please improve the filename. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| #!/usr/bin/env bash | ||
| # Validates PR title and all commits in a pull request for conventional or release-command format. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is expected/valid PR title and commits here? What do we actually validate? |
||
| # Requires: PR_TITLE, BASE_SHA, HEAD_SHA environment variables. | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| PR_TITLE="${PR_TITLE:?PR_TITLE required}" | ||
| BASE_SHA="${BASE_SHA:?BASE_SHA required}" | ||
| HEAD_SHA="${HEAD_SHA:?HEAD_SHA required}" | ||
|
|
||
| lint_message() { | ||
| local msg="$1" | ||
| local first | ||
| first=$(echo "$msg" | head -n1) | ||
|
|
||
| case "$first" in | ||
| beta/*|release/*|patch/*) | ||
| bash .github/scripts/validate-release-command.sh "$first" | ||
| ;; | ||
| *) | ||
| echo "$msg" | npx commitlint | ||
| ;; | ||
| esac | ||
| } | ||
|
|
||
| echo "Validating PR title: $PR_TITLE" | ||
| lint_message "$PR_TITLE" | ||
|
|
||
| if [ "$BASE_SHA" = "$HEAD_SHA" ]; then | ||
| echo "No commits to validate" | ||
| exit 0 | ||
| fi | ||
|
|
||
| echo "Validating commits between $BASE_SHA and $HEAD_SHA" | ||
| while read -r sha; do | ||
| [ -z "$sha" ] && continue | ||
| msg=$(git log -1 --pretty=%B "$sha") | ||
| echo "Checking commit $sha" | ||
| lint_message "$msg" | ||
| done < <(git rev-list "${BASE_SHA}..${HEAD_SHA}") | ||
|
|
||
| echo "All commit messages valid" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| #!/usr/bin/env bash | ||
| # Parses the first line of a commit message for release commands. | ||
| # Usage: parse-release-commit.sh "<commit message>" "<ref_name>" | ||
| # Writes command, version, and release_line to GITHUB_OUTPUT when set. | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| COMMIT_MSG="${1:?commit message required}" | ||
| REF_NAME="${2:?ref name required}" | ||
|
|
||
| FIRST_LINE=$(echo "$COMMIT_MSG" | head -n1) | ||
|
|
||
| write_output() { | ||
| if [ -n "${GITHUB_OUTPUT:-}" ]; then | ||
| echo "command=$1" >> "$GITHUB_OUTPUT" | ||
| echo "version=${2:-}" >> "$GITHUB_OUTPUT" | ||
| echo "release_line=${3:-}" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "command=$1" | ||
| echo "version=${2:-}" | ||
| echo "release_line=${3:-}" | ||
| fi | ||
| } | ||
|
|
||
| if [[ "$FIRST_LINE" =~ ^beta/([0-9]+\.[0-9]+\.[0-9]+-beta\.[0-9]+)$ ]]; then | ||
| if [[ "$REF_NAME" != "main" ]]; then | ||
| echo "::error::beta release commands must be merged to main (current branch: $REF_NAME)" >&2 | ||
| exit 1 | ||
| fi | ||
| write_output "beta" "${BASH_REMATCH[1]}" "" | ||
| exit 0 | ||
| fi | ||
|
|
||
| if [[ "$FIRST_LINE" =~ ^release/([0-9]+\.[0-9]+)$ ]]; then | ||
| if [[ "$REF_NAME" != "main" ]]; then | ||
| echo "::error::release commands must be merged to main (current branch: $REF_NAME)" >&2 | ||
| exit 1 | ||
| fi | ||
| MINOR="${BASH_REMATCH[1]}" | ||
| write_output "release" "${MINOR}.0" "$MINOR" | ||
| exit 0 | ||
| fi | ||
|
|
||
| if [[ "$FIRST_LINE" =~ ^patch/([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then | ||
| VERSION="${BASH_REMATCH[1]}" | ||
| MINOR=$(echo "$VERSION" | cut -d. -f1-2) | ||
| EXPECTED_BRANCH="release/$MINOR" | ||
| if [[ "$REF_NAME" != "$EXPECTED_BRANCH" ]]; then | ||
| echo "::error::patch/$VERSION must be merged to $EXPECTED_BRANCH (current branch: $REF_NAME)" >&2 | ||
| exit 1 | ||
| fi | ||
| write_output "patch" "$VERSION" "$MINOR" | ||
| exit 0 | ||
| fi | ||
|
|
||
| write_output "none" "" "" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| #!/usr/bin/env bash | ||
| # Prints a PR comment body for a release-command PR title. | ||
| # Usage: pr-release-comment.sh "<pr title>" "<base branch>" | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| TITLE="${1:?PR title required}" | ||
| BASE="${2:?base branch required}" | ||
| FIRST_LINE=$(echo "$TITLE" | head -n1) | ||
|
|
||
| if [[ "$FIRST_LINE" =~ ^beta/([0-9]+\.[0-9]+\.[0-9]+-beta\.[0-9]+)$ ]]; then | ||
| VERSION="${BASH_REMATCH[1]}" | ||
| if [[ "$BASE" != "main" ]]; then | ||
| echo "::error::Beta releases must target \`main\` (current base: \`$BASE\`)" | ||
| exit 1 | ||
| fi | ||
| cat <<EOF | ||
| ## Release command: beta | ||
|
|
||
| Merging this PR to \`main\` with the title \`$FIRST_LINE\` will trigger the **beta release** workflow: | ||
|
|
||
| - Set package version to \`$VERSION\` | ||
| - Run tests and publish \`@devrev/ts-adaas@$VERSION\` to npm with the \`beta\` tag | ||
| - Push version commit and git tag to \`main\` | ||
|
|
||
| **Requirements:** squash merge with PR title as the commit message; only CODEOWNERS can merge. | ||
| EOF | ||
| exit 0 | ||
| fi | ||
|
|
||
| if [[ "$FIRST_LINE" =~ ^release/([0-9]+\.[0-9]+)$ ]]; then | ||
| MINOR="${BASH_REMATCH[1]}" | ||
| VERSION="${MINOR}.0" | ||
| if [[ "$BASE" != "main" ]]; then | ||
| echo "::error::Release line cuts must target \`main\` (current base: \`$BASE\`)" | ||
| exit 1 | ||
| fi | ||
| cat <<EOF | ||
| ## Release command: release line | ||
|
|
||
| Merging this PR to \`main\` with the title \`$FIRST_LINE\` will trigger the **release line** workflow: | ||
|
|
||
| - Create branch \`release/$MINOR\` from \`main\` | ||
| - Set package version to \`$VERSION\` and publish to npm with the \`latest\` tag | ||
| - Push \`release/$MINOR\` and git tag \`$VERSION\` | ||
|
|
||
| Fails if \`release/$MINOR\` already exists or npm already has a \`$MINOR.x\` version >= \`$VERSION\`. | ||
|
|
||
| **Requirements:** squash merge with PR title as the commit message; only CODEOWNERS can merge. | ||
| EOF | ||
| exit 0 | ||
| fi | ||
|
|
||
| if [[ "$FIRST_LINE" =~ ^patch/([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then | ||
| VERSION="${BASH_REMATCH[1]}" | ||
| MINOR=$(echo "$VERSION" | cut -d. -f1-2) | ||
| EXPECTED="release/$MINOR" | ||
| if [[ "$BASE" != "$EXPECTED" ]]; then | ||
| echo "::error::Patch releases must target \`$EXPECTED\` (current base: \`$BASE\`)" | ||
| exit 1 | ||
| fi | ||
| cat <<EOF | ||
| ## Release command: patch | ||
|
|
||
| Merging this PR to \`$EXPECTED\` with the title \`$FIRST_LINE\` will trigger the **patch release** workflow: | ||
|
|
||
| - Set package version to \`$VERSION\` and publish to npm with the \`latest\` tag | ||
| - Open an automated backport PR to \`main\` titled \`backport: patch/$VERSION\` | ||
|
|
||
| **Requirements:** squash merge with PR title as the commit message; only CODEOWNERS can merge. | ||
| EOF | ||
| exit 0 | ||
| fi | ||
|
|
||
| echo "Invalid release command in PR title: $FIRST_LINE" >&2 | ||
| exit 1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| #!/usr/bin/env bash | ||
| # Validates release command format (branch-agnostic). Exits 0 on valid format, 1 otherwise. | ||
| # Usage: validate-release-command.sh "<first line of commit message>" | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| MSG="${1:?commit message required}" | ||
| FIRST_LINE=$(echo "$MSG" | head -n1) | ||
|
|
||
| if [[ "$FIRST_LINE" =~ ^beta/[0-9]+\.[0-9]+\.[0-9]+-beta\.[0-9]+$ ]]; then | ||
| exit 0 | ||
| fi | ||
|
|
||
| if [[ "$FIRST_LINE" =~ ^release/[0-9]+\.[0-9]+$ ]]; then | ||
| exit 0 | ||
| fi | ||
|
|
||
| if [[ "$FIRST_LINE" =~ ^patch/[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | ||
| exit 0 | ||
| fi | ||
|
|
||
| echo "Invalid release command format: $FIRST_LINE" >&2 | ||
| echo "Expected one of:" >&2 | ||
| echo " beta/X.Y.Z-beta.N (e.g. beta/1.19.4-beta.0)" >&2 | ||
| echo " release/X.Y (e.g. release/1.19)" >&2 | ||
| echo " patch/X.Y.Z (e.g. patch/1.19.5)" >&2 | ||
| exit 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of maintainer taking care of opening a PR for this, maybe automation can do this for us on workflow trigger?