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
84 changes: 84 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Dependency updates.
#
# Shaped to keep the updates and drop the noise. Left at Dependabot's defaults it
# opens one pull request per dependency and leads with major bumps, which is how
# a routine week turns into a wall of pull requests nobody reads. This keeps the
# same coverage with a smaller footprint:
#
# * monthly, not weekly
# * grouped, so one pull request carries a whole ecosystem's routine bumps
# * majors kept apart, in their own single pull request, because those are the
# ones that change APIs and want a person
#
# The minor and patch group is merged automatically once CI passes; see
# .github/workflows/dependabot-auto-merge.yml. The major group never is.
#
# `schedule` here is Dependabot's own timer, not a cron in GitHub Actions. The
# only workflow that runs on a schedule in this repository is the issue sweep.
#
# Security updates are a separate mechanism, enabled in the repository settings,
# and are unaffected by any of this: a vulnerable dependency still gets its own
# pull request the day the advisory lands, major or not.

version: 2

updates:
# The Rust crate: the CLI and its library, which share one lockfile. The
# bindings under bindings/ and the fuzz targets are separate crates with their
# own lockfiles and are left out on purpose; they track this crate rather than
# the registry, and a bump that mattered would arrive through it.
- package-ecosystem: cargo
directory: "/"
schedule:
interval: monthly
open-pull-requests-limit: 3
labels: ["dependencies", "rust"]
commit-message:
prefix: "cargo"
groups:
cargo-routine:
patterns: ["*"]
update-types: ["minor", "patch"]
cargo-major:
patterns: ["*"]
update-types: ["major"]

# The documentation site's build dependencies (docs/requirements.txt).
- package-ecosystem: pip
directory: "/docs"
schedule:
interval: monthly
open-pull-requests-limit: 2
labels: ["dependencies", "documentation"]
commit-message:
prefix: "docs"
groups:
docs-routine:
patterns: ["*"]
update-types: ["minor", "patch"]
docs-major:
patterns: ["*"]
update-types: ["major"]

# The actions the workflows themselves pin. These go stale silently: a
# deprecated runner image or a Node version dropped from an action is only
# noticed when a job starts warning, or fails.
#
# The MSRV job in rust.yml pins its compiler through the action's `toolchain`
# input, not through the action's ref, so nothing here can move the minimum
# supported Rust version by "updating" a pin.
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: monthly
open-pull-requests-limit: 2
labels: ["dependencies", "github-actions"]
commit-message:
prefix: "actions"
groups:
actions-routine:
patterns: ["*"]
update-types: ["minor", "patch"]
actions-major:
patterns: ["*"]
update-types: ["major"]
73 changes: 73 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Which part of the project a pull request touches, worked out from the files it
# changes. The labels exist so that "what changed in the VCF path" is a question
# the pull request list can answer; applying them by hand is how they stop being
# applied.
#
# This covers pull requests only. The issue templates here are plain Markdown and
# do not label their own issues, so those are labelled by hand or left bare.
#
# Format is actions/labeler v5, which is not v4's: a bare list of globs under the
# label name silently matches nothing.

core:
- changed-files:
- any-glob-to-any-file:
- "src/main.rs"
- "src/lib.rs"
- "src/scan.rs"
- "src/extract.rs"
- "src/fasta.rs"
- "src/input.rs"
- "src/types.rs"

vcf:
- changed-files:
- any-glob-to-any-file:
- "src/vcf.rs"

filters:
- changed-files:
- any-glob-to-any-file:
- "src/filter.rs"
- "src/audit.rs"
- "src/coords.rs"

bindings:
- changed-files:
- any-glob-to-any-file:
- "bindings/**"

documentation:
- changed-files:
- any-glob-to-any-file:
- "docs/**"
- "overrides/**"
- "mkdocs.yml"
- "README.md"
- "CHANGELOG.md"

packaging:
- changed-files:
- any-glob-to-any-file:
- "Cargo.toml"
- "Dockerfile"
- "snpick.def"
- ".github/workflows/release.yml"
- ".github/workflows/docker.yml"

tests:
- changed-files:
- any-glob-to-any-file:
- "tests/**"
- "benches/**"
- "benchmarks/**"
- "fuzz/**"

# Everything under .github, not a list of the files there. Naming them one by
# one leaves .github/labeler.yml itself uncovered, so the pull request adding a
# rule to this file would arrive with no label, which is a small thing that says
# exactly how the list would have aged.
ci:
- changed-files:
- any-glob-to-any-file:
- ".github/**"
68 changes: 28 additions & 40 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,33 @@
# Pull Request Template for SNPick
<!--
Fill in what applies and delete what does not. A short pull request needs a
short description; nobody is asking for an essay to fix a typo.
-->

## Description
Please include a summary of the changes made in this pull request. Mention any related issues or features that are being addressed.
## What this changes

- **What is the motivation for this change?**
- **Which issue does this address?** (Link to the relevant GitHub issue if applicable)
<!-- One or two sentences. What is different after this is merged? -->

## Type of Change
Please delete options that are not relevant:
- [ ] Bug fix
- [ ] New feature
- [ ] Documentation update
- [ ] Refactor
- [ ] Other (please describe):
## Why

<!-- The problem it solves. Link an issue with "Closes #123" if there is one. -->

## How it was verified

<!--
The important part, and the one a reviewer cannot reconstruct.

Not "it should work", but what you ran and what it printed. For example: the
test you added and the fact that it fails without the fix, the alignment you ran
through it and the VCF or PHYLIP you got before and after, or the benchmark whose
numbers changed.

If it is a change that CI already covers, say which check covers it.
-->

## Checklist
Please ensure your pull request meets the following requirements:

- [ ] My code follows the coding guidelines of this project.
- [ ] I have performed a self-review of my code.
- [ ] I have commented my code, particularly in hard-to-understand areas.
- [ ] I have made corresponding changes to the documentation.
- [ ] My changes do not introduce new warnings or errors.
- [ ] I have added tests that prove my fix is effective or that my feature works.
- [ ] All new and existing tests pass.

## Additional Information
Please provide any additional information that is relevant to this pull request. This can include benchmarking data, notes on design decisions, or information on how to test the changes effectively.

## Screenshots (if applicable)
If your changes involve UI updates, please include screenshots here.

## Related Issues
Link to related issues here:

- Fixes # (issue)
- Resolves # (issue)
- Closes # (issue)

## Reviewer Checklist
For maintainers and reviewers:
- [ ] Code is well-documented and follows project standards.
- [ ] Unit tests and integration tests are sufficient.
- [ ] Changes are in line with the project's overall goals and quality standards.

- [ ] `cargo test` passes and `cargo clippy -- -D warnings` is clean.
- [ ] It still builds on the minimum supported Rust version (1.85).
- [ ] New behaviour has a test, or I have said above why it does not.
- [ ] Output stays byte-for-byte compatible, or the change to it is described above.
- [ ] Documentation under `docs/` and the `CHANGELOG` are updated if the change is user-visible.
68 changes: 68 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: CodeQL

# Static analysis over what this repository is written in. Nothing here looked at
# the code this way before: clippy checks the shape of a line and the test suite
# checks the answer, while these queries follow a value across functions and
# files and ask where an unchecked one arrives somewhere it matters.
#
# Two languages, which is all of them:
#
# rust the extractor, the whole of it
# actions the workflows themselves, including this one
#
# That second one is not a curiosity. These queries know about unsafe uses of
# `pull_request_target`, which is the trigger labeler.yml runs on, and about
# script injection through untrusted context values. Reasoning that a workflow is
# safe is exactly the kind of reasoning worth having checked by something that is
# not the person who wrote it.
#
# On pushes to main and on pull requests, with no schedule. GitHub's own default
# setup adds a weekly run; this does not, in keeping with every other workflow
# here except the issue sweep, which has nothing but time to hang off.
#
# `build-mode: none` reads the source without compiling it. It is what makes this
# take a minute rather than a full release build, and it is the documented mode
# for the languages here.

on:
push:
branches: [main]
pull_request:

# A newer push makes an older analysis irrelevant, the same as CI.
concurrency:
group: codeql-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

permissions:
security-events: write
contents: read
actions: read

jobs:
analyze:
name: Analyse ${{ matrix.language }}
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- language: rust
build-mode: none
- language: actions
build-mode: none

steps:
- uses: actions/checkout@v7

- name: Initialise CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}

- name: Analyse
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{ matrix.language }}"
85 changes: 85 additions & 0 deletions .github/workflows/dependabot-auto-merge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Dependabot auto-merge

# Merges Dependabot's routine updates once CI has passed, and never touches a
# major one.
#
# The point of the split is that a minor or patch bump that survives the whole
# suite (clippy with warnings denied, the test suite on Linux and macOS across
# x86_64 and aarch64, and the minimum-supported-Rust build) has already been
# examined more carefully than a person would examine it by eye, while a major
# bump changes APIs and wants a person to look.
#
# Triggered by the pull request itself, not by a schedule.

on: pull_request

permissions:
contents: write
pull-requests: write

jobs:
auto-merge:
name: Merge routine updates once CI is green
runs-on: ubuntu-latest
timeout-minutes: 10
if: github.event.pull_request.user.login == 'dependabot[bot]'
steps:
- name: Read what this pull request updates
id: metadata
uses: dependabot/fetch-metadata@v3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

# The rule, decided once.
#
# It used to be written twice, once negated for the step that explains
# itself, and the two halves drift the moment the first is edited: a
# grouped patch matches the merge step and the "left alone" step at the
# same time, so it would merge and announce that it had not. One step
# decides, the other two read the answer.
#
# Named rather than excluded: merge when the pull request says in so many
# words that it is a patch or a minor, or when it is a `-routine` group,
# which the configuration already restricts to those two.
#
# Asking instead whether the update was "not major" lets one through. A
# requirement bump can report no update type at all, and an empty string is
# not equal to major, so the rule would say yes to a major on its first
# day. Anything this cannot positively identify still waits for a person.
#
# A group reports "the highest semver change being made by this PR", so a
# group carrying one major is a major here.
- name: Decide whether this one may merge itself
id: decide
env:
GROUP: ${{ steps.metadata.outputs.dependency-group }}
UPDATE_TYPE: ${{ steps.metadata.outputs.update-type }}
run: |
set -euo pipefail
may_merge=false
case "$GROUP" in
*-routine) may_merge=true ;;
esac
case "$UPDATE_TYPE" in
version-update:semver-patch|version-update:semver-minor) may_merge=true ;;
esac
# Printed because a decision nobody can read is a decision nobody can
# correct: this line is what a later surprise gets diagnosed from.
echo "group='${GROUP}' update-type='${UPDATE_TYPE}' -> may-merge=${may_merge}"
echo "may-merge=${may_merge}" >> "$GITHUB_OUTPUT"

- name: Queue the merge
if: steps.decide.outputs.may-merge == 'true'
run: gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Say why this one was left alone
if: steps.decide.outputs.may-merge != 'true'
run: |
gh pr comment "$PR_URL" --body \
"Left for review. Only a \`-routine\` group, or an update that identifies itself as patch or minor, merges on its own once CI passes. This one is a major update or does not say which it is."
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Loading
Loading