diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml new file mode 100644 index 0000000..5dded9a --- /dev/null +++ b/.github/workflows/pr-title.yml @@ -0,0 +1,65 @@ +name: Pull Request Title + +on: + workflow_call: + +permissions: {} + +jobs: + pr-title: # zizmor: ignore[anonymous-definition] + runs-on: ubuntu-latest + permissions: {} + steps: + - name: Validate PR title matches target branch + env: + PR_TITLE: ${{ github.event.pull_request.title }} + BASE_BRANCH: ${{ github.event.pull_request.base.ref }} + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + run: | + # Validates PR title against target branch + # Returns error message if invalid, empty string if valid + validate_pr_title() { + local target_branch="$1" + local pr_title="$2" + local default_branch="$3" + + # Check if target branch is a version branch (e.g., 5.x, 4.x) + if [[ $target_branch =~ ^([0-9]+)\.x$ ]]; then + local version="${BASH_REMATCH[1]}" + if [[ ! $pr_title =~ ^\[$version\.x\][[:space:]] ]]; then + echo "PR targeting '$target_branch' must have title starting with '[$version.x] '" + return + fi + + # Check if target branch is master (next major version) + elif [[ $target_branch == "master" ]]; then + local current_version="${default_branch//\.x/}" + local next_version=$((current_version + 1)) + if [[ ! $pr_title =~ ^\[$next_version\.x\][[:space:]] ]]; then + echo "PR targeting 'master' must have title starting with '[$next_version.x] '" + return + fi + + # For other branches, just enforce that there's a version prefix + else + if [[ ! $pr_title =~ ^\[[0-9]+\.x\][[:space:]] ]]; then + echo "PR title must start with a version prefix like '[5.x] '" + return + fi + fi + + echo "" + } + + echo "PR Title: $PR_TITLE" + echo "Base Branch: $BASE_BRANCH" + echo "Default Branch: $DEFAULT_BRANCH" + + ERROR=$(validate_pr_title "$BASE_BRANCH" "$PR_TITLE" "$DEFAULT_BRANCH") + + if [[ -n $ERROR ]]; then + echo $ERROR + exit 1 + fi + + echo "PR title validation passed" diff --git a/.github/workflows/pull-requests.yml b/.github/workflows/pull-requests.yml new file mode 100644 index 0000000..cd0903f --- /dev/null +++ b/.github/workflows/pull-requests.yml @@ -0,0 +1,74 @@ +name: Pull Requests + +# Credit: https://github.com/github/docs/blob/main/.github/workflows/notify-when-maintainers-cannot-edit.yaml +# https://github.com/laravel/.github/blob/main/.github/workflows/pull-requests.yml + +on: + workflow_call: + +permissions: {} + +jobs: + uneditable: # zizmor: ignore[anonymous-definition] + runs-on: ubuntu-latest + permissions: + pull-requests: write # post comment and close PRs that don't allow maintainer edits + steps: + - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + script: | + const repo = context.repo.repo; + + const query = ` + query($number: Int!) { + repository(owner: "statamic", name: "${repo}") { + pullRequest(number: $number) { + headRepositoryOwner { + login + } + maintainerCanModify + state + } + } + } + `; + + const pullNumber = context.issue.number; + const variables = { number: pullNumber }; + + try { + console.log(`Check for maintainer edit access ...`); + const result = await github.graphql(query, variables); + console.log(JSON.stringify(result, null, 2)); + const pullRequest = result.repository.pullRequest; + + if (pullRequest.headRepositoryOwner.login === 'statamic') { + console.log('PR owned by statamic'); + return; + } + + if (pullRequest.state !== 'OPEN') { + console.log('PR has already been closed or merged'); + return; + } + + if (!pullRequest.maintainerCanModify) { + console.log('PR not owned by statamic and does not have maintainer edits enabled'); + + await github.rest.issues.createComment({ + issue_number: pullNumber, + owner: 'statamic', + repo, + body: "Thanks for submitting a PR!\n\nIn order to review and merge PRs most efficiently, we require that all PRs grant maintainer edit access before we review them. For information on how to do this, [see the relevant GitHub documentation](https://docs.github.com/en/github/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork). Additionally, GitHub doesn't allow maintainer permissions from organization accounts. Please resubmit this PR from a personal GitHub account with maintainer permissions enabled." + }); + + await github.rest.pulls.update({ + pull_number: pullNumber, + owner: 'statamic', + repo, + state: 'closed' + }); + } + } catch(e) { + console.log(e); + } diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..f302601 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,25 @@ +name: "Close stale issues" + +on: + workflow_call: + +permissions: {} + +jobs: + stale: # zizmor: ignore[anonymous-definition] + runs-on: ubuntu-latest + permissions: + issues: write # mark issues stale and close them + steps: + - uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + days-before-stale: 60 + days-before-close: 7 + ascending: true + only-labels: 'needs more info' + stale-issue-label: stale + stale-issue-message: > + This issue has not had recent activity and has been marked as stale — by me, a robot. + Simply reply to keep it open and send me away. If you do nothing, I will close it in + a week. I have no feelings, so whatever you do is fine by me. diff --git a/workflows/zizmor.yml b/.github/workflows/zizmor.yml similarity index 93% rename from workflows/zizmor.yml rename to .github/workflows/zizmor.yml index 0a7513b..1eedf2a 100644 --- a/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -2,6 +2,9 @@ name: GitHub Actions Security Analysis on: workflow_call: + push: + branches: ["**"] + pull_request: permissions: {}