Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,18 +378,19 @@ exist in repository settings, like the `run-*` labels above.
These workflows have their own triggers because they fire on events the
umbrella doesn't watch, or operate independently of the rest of CI:

| File | Why standalone |
| ---------------------- | ---------------------------------------------------------------------------------------------------- |
| `pr_title_check.yml` | Fires on `pull_request.types: [edited]` so it re-runs when a PR title is edited without a code push. |
| `codeql.yml` | Security scanner; weekly schedule + on every push/PR. |
| `miri.yml` | Nightly Miri safety checks. |
| `publish_snapshot.yml` | Nightly SNAPSHOT jars to repository.apache.org; skips when main has not changed. `dry_run` dispatch. |
| `stale.yml` | Daily stale-PR closer. |
| `take.yml` | Issue-comment trigger for `take` / `untake`. |
| `label_new_issues.yml` | Issue trigger to apply `requires-triage`. |
| `label_prs.yml` | Runs on `pull_request_target` so it can label pull requests opened from forks. |
| `ci_fork.yml` | Runs `ci.yml` on a push to a fork's branch; skipped upstream. See [Fork runs](#fork-runs). |
| `fork_ci_status.yml` | Mirrors a fork's run onto its pull request as `CI (fork)`. See [Fork runs](#fork-runs). |
| File | Why standalone |
| ----------------------- | ------------------------------------------------------------------------------------------------------- |
| `pr_title_check.yml` | Fires on `pull_request.types: [edited]` so it re-runs when a PR title is edited without a code push. |
| `codeql.yml` | Security scanner; weekly schedule + on every push/PR. |
| `miri.yml` | Nightly Miri safety checks. |
| `publish_snapshot.yml` | Nightly SNAPSHOT jars to repository.apache.org; skips when main has not changed. `dry_run` dispatch. |
| `stale.yml` | Daily stale-PR closer. |
| `take.yml` | Issue-comment trigger for `take` / `untake`. |
| `label_new_issues.yml` | Issue trigger to apply `requires-triage`. |
| `label_prs_trigger.yml` | Fires on `pull_request` with a read-only token and does nothing; its completion starts `label_prs.yml`. |
| `label_prs.yml` | Runs on `workflow_run` from the default branch so it can label pull requests opened from forks. |
| `ci_fork.yml` | Runs `ci.yml` on a push to a fork's branch; skipped upstream. See [Fork runs](#fork-runs). |
| `fork_ci_status.yml` | Mirrors a fork's run onto its pull request as `CI (fork)`. See [Fork runs](#fork-runs). |

## Reusable workflows (called by `ci.yml`)

Expand Down
96 changes: 62 additions & 34 deletions .github/workflows/label_prs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,73 +15,101 @@
# specific language governing permissions and limitations
# under the License.


name: Label pull requests

# Runs on pull_request_target so it can label pull requests from forks. Nothing from the pull
# request is checked out or executed: the labeler reads the changed file list through the API
# and the title step reads the event payload.
# Labels a pull request after label_prs_trigger.yml runs for it. GitHub blocks
# pull_request_target on public repositories, and a pull_request run from a fork only gets a
# read-only token, so the labels are written here: workflow_run runs this file from the default
# branch with a token that can write them. Nothing from the pull request is checked out or
# executed, and nothing its run produced is read. The pull request is looked up from the run's
# head repository, branch and commit, and its title, labels and changed files come from the API.
on:
pull_request_target:
types: [opened, synchronize, reopened]
workflow_run:
workflows: [Label pull requests trigger]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing checks that this entry stays equal to the name: of label_prs_trigger.yml. If either is renamed, labeling stops without a failing check. dev/ci/check-ci-config.py already guards the same pairing for the fork bridge (BRIDGE_WORKFLOW against the name of ci.yml, plus the repository guard). Could it cover this pair too?

types: [completed]

permissions:
contents: read
pull-requests: write
permissions: {}

# One group per pull request with cancellation, so at most one run writes labels at a time:
# the labeler action reads the label set and writes it back whole, and two runs writing at
# once can drop a label the other just added. A cancelled or replaced run loses nothing
# because every step below is safe to repeat on the next event.
# One group per pull request branch with cancellation, so at most one run writes labels at a
# time: the labeler action reads the label set and writes it back whole, and two runs writing at
# once can drop a label the other just added. A cancelled or replaced run loses nothing because
# every step below is safe to repeat on the next event. workflow_run carries the head repository
# and branch rather than the pull request number.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true

jobs:
label:
if: >-
github.repository == 'apache/datafusion-comet'
&& github.event.workflow_run.event == 'pull_request'
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-slim
timeout-minutes: 10
steps:
# Checks out the base branch, never the pull request's code: under pull_request_target the
# default ref is the base commit, and only dev/ci/pr-type-label.mjs is read from it.
# Checks out the default branch, never the pull request's code: under workflow_run the
# default ref is the default branch, and only dev/ci/pr-type-label.mjs is read from it.
- uses: actions/checkout@v7
with:
persist-credentials: false

# The type label follows the conventional commit prefix in the title, matching how
# maintainers label by hand. The decision reads the pull request's current labels, not the
# event payload, so a type label a maintainer applied before this run started stays and
# a run cut short by a newer push is completed by that push. Dependabot pull requests
# already carry their label.
- name: Label by title prefix
if: github.actor != 'dependabot[bot]'
# maintainers label by hand. The decision reads the pull request's current labels, so a
# type label a maintainer applied before this run started stays. A pull request whose head
# has moved on since the triggering run is skipped: the run for the newer push labels it.
# Dependabot pull requests already carry their label.
- name: Find the pull request and label by title prefix
id: pr
uses: actions/github-script@v9
with:
script: |
const run = context.payload.workflow_run;
const head = run.head_repository;
if (!head) {
core.info('The head repository no longer exists');
return;
}
const repo = { owner: context.repo.owner, repo: context.repo.repo };
const pulls = await github.paginate(github.rest.pulls.list, {
...repo,
state: 'open',
head: `${head.owner.login}:${run.head_branch}`,
per_page: 100,
});
const pr = pulls.find((item) =>
item.head.sha === run.head_sha && item.head.repo?.full_name === head.full_name);
if (!pr) {
core.info(`No open pull request has head ${head.full_name}@${run.head_sha}`);
return;
}
core.setOutput('number', pr.number);
if (pr.user.login === 'dependabot[bot]') {
core.info('Dependabot pull requests already carry their type label');
return;
}
const { typeLabelsToAdd } = await import(
`${process.env.GITHUB_WORKSPACE}/dev/ci/pr-type-label.mjs`
);
const { data: current } = await github.rest.issues.listLabelsOnIssue({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
...repo,
issue_number: pr.number,
per_page: 100,
});
const labels = typeLabelsToAdd(
context.payload.pull_request.title,
current.map((label) => label.name),
);
const labels = typeLabelsToAdd(pr.title, current.map((label) => label.name));
if (labels.length === 0) {
core.info('No type label to add');
return;
}
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels,
});
await github.rest.issues.addLabels({ ...repo, issue_number: pr.number, labels });

- name: Label by changed paths
if: steps.pr.outputs.number != ''
uses: actions/labeler@v7
with:
configuration-path: .github/labeler.yml
pr-number: ${{ steps.pr.outputs.number }}
sync-labels: false
36 changes: 36 additions & 0 deletions .github/workflows/label_prs_trigger.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.


name: Label pull requests trigger

# Starts the labeler for a pull request. This run gets a read-only token and does nothing itself;
# when it completes, label_prs.yml runs from the default branch through workflow_run and writes
# the labels. Kept separate from Comet CI so labels arrive in seconds rather than after CI.
on:
pull_request:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The events reference says pull_request workflows do not run while the PR has a merge conflict, and pull_request_target ones do. A PR opened with a conflict now gets no labels until a push after the conflict is resolved. Could this go in the list of behavior changes, or be covered by a schedule sweep like the one in fork_ci_status.yml?

types: [opened, synchronize, reopened]

permissions: {}

jobs:
trigger:
runs-on: ubuntu-slim
timeout-minutes: 5
steps:
- name: Hand off to label_prs.yml
run: echo "Labels for pull request ${{ github.event.pull_request.number }} are applied by label_prs.yml"