-
Notifications
You must be signed in to change notification settings - Fork 1
sdk%lint: enable CodeCov comments, define ignorelist, track test runner results, add Justfile, repair cargo test --doc violations, broaden lint_cargo to include license checks
#55
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
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
27226c5
sdk%lint: shave down CodeCov config, enable comments, specify ignorelist
kwvg 825d28f
sdk%lint: move CodeRabbit definitions from UI to source tree
kwvg b7f1732
sdk%lint: use `nextest` to generate test failure coverage for CodeCov
kwvg acc043f
sdk%lint: use `--locked` for `taplo-cli`, move config to `maint/`
kwvg 95c3705
sdk%fix(doc): repair `cargo doc` violations
kwvg c4f5572
sdk%build: add `Justfile`, update docs, run `cargo test --doc`
kwvg 7ce1ed8
sdk%doc: refine agentic guidance
kwvg ab0593b
sdk%lint: broaden `lint_cargo` to include license rejection
kwvg 43fa4da
sdk%ci: reconcile pull request labels with the project boards
kwvg 5c5f0da
sdk%lint: `lint_unconv` -> `lint_commit`, set maximum width and height
kwvg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| comment: | ||
| behavior: "default" | ||
| layout: "condensed_header, condensed_files, condensed_footer" | ||
| hide_project_coverage: true | ||
| require_changes: false | ||
| show_carryforward_flags: true | ||
| coverage: | ||
| status: | ||
| project: | ||
| default: | ||
| target: auto | ||
| patch: | ||
| default: | ||
| target: auto | ||
| flags: | ||
| dash-num: | ||
| paths: | ||
| - pkgs/num/ | ||
| dash-script: | ||
| paths: | ||
| - pkgs/script/ | ||
| dash-p2p-core: | ||
| paths: | ||
| - pkgs/p2p_core/ | ||
| dash-params: | ||
| paths: | ||
| - pkgs/params/ | ||
| dash-pkc: | ||
| paths: | ||
| - pkgs/pkc/ | ||
| dash-pow: | ||
| paths: | ||
| - pkgs/pow/ | ||
| dash-primitives: | ||
| paths: | ||
| - pkgs/primitives/ | ||
| dash-types: | ||
| paths: | ||
| - pkgs/types/ | ||
| - pkgs/types/marker/ | ||
| flag_management: | ||
| default_rules: | ||
| carryforward: true | ||
| ignore: | ||
| - "**/bench/**" | ||
| - "**/corpus/**" | ||
| - "**/tests/**" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json | ||
|
|
||
| early_access: false | ||
| enable_free_tier: true | ||
| inheritance: false | ||
| chat: | ||
| allow_non_org_members: false | ||
| auto_reply: true | ||
| art: false | ||
| issue_enrichment: | ||
| auto_enrich: | ||
| enabled: false | ||
| planning: | ||
| enabled: false | ||
| labeling: | ||
| enabled: false | ||
| knowledge_base: | ||
| code_guidelines: | ||
| enabled: true | ||
| filePatterns: | ||
| - "AGENTS.md" | ||
| - "docs/dev/guide_rust.md" | ||
| language: en-US | ||
| reviews: | ||
| auto_apply_labels: false | ||
| auto_assign_reviewers: false | ||
| auto_review: | ||
| enabled: true | ||
| base_branches: | ||
| - "develop" | ||
| drafts: false | ||
| changed_files_summary: false | ||
| collapse_walkthrough: true | ||
| estimate_code_review_effort: false | ||
| finishing_touches: | ||
| docstrings: | ||
| enabled: false | ||
| unit_tests: | ||
| enabled: false | ||
| high_level_summary_in_walkthrough: true | ||
| in_progress_fortune: false | ||
| path_filters: | ||
| - "!**/*.json" | ||
| - "!**/*.json5" | ||
| - "!**/*.lock" | ||
| poem: false | ||
| pre_merge_checks: | ||
| docstrings: | ||
| mode: "off" | ||
| profile: chill | ||
| related_issues: false | ||
| related_prs: false | ||
| request_changes_workflow: false | ||
| sequence_diagrams: true | ||
| suggested_labels: false | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,3 +13,6 @@ indent_size = 4 | |
|
|
||
| [*.md] | ||
| trim_trailing_whitespace = false | ||
|
|
||
| [Justfile] | ||
| indent_size = 4 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| { | ||
| "projects": { | ||
| "defaults": { | ||
| "owner": "dashpay", | ||
| "field": "Status" | ||
| }, | ||
| "allow": [ | ||
| { "number": 13 }, | ||
| { "number": 14 } | ||
| ] | ||
| }, | ||
| "topics": [ | ||
| "Build/CI", | ||
| "Codec", | ||
| "Crypto", | ||
| "Documentation", | ||
| "FFI", | ||
| "P2P", | ||
| "Primitives" | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,232 @@ | ||
| /*! | ||
| * Copyright (c) 2026-present, The Dash Core developers | ||
| * SPDX-License-Identifier: MIT | ||
| * See the accompanying file LICENSE or https://opensource.org/license/MIT | ||
| */ | ||
|
|
||
| // @ts-check | ||
|
|
||
| // Syncs pull request topic labels with the project board buckets, with the | ||
| // board as the source of truth. Boards and topics come from `board.json`. | ||
|
|
||
| const fs = require("node:fs"); | ||
| const path = require("node:path"); | ||
|
|
||
| const { listOpenPulls } = require("./util"); | ||
|
|
||
| const CONFIG_PATH = path.join(__dirname, "..", "board.json"); | ||
|
|
||
| // Color of newly created topic labels. | ||
| const TOPIC_COLOR = "1d76db"; | ||
|
|
||
| const BOARD_QUERY = ` | ||
| query($owner: String!, $number: Int!, $field: String!, $cursor: String) { | ||
| organization(login: $owner) { | ||
| projectV2(number: $number) { | ||
| id | ||
| field(name: $field) { | ||
| ... on ProjectV2SingleSelectField { id options { id name } } | ||
| } | ||
| items(first: 100, after: $cursor) { | ||
| pageInfo { hasNextPage endCursor } | ||
| nodes { | ||
| id | ||
| fieldValueByName(name: $field) { | ||
| ... on ProjectV2ItemFieldSingleSelectValue { name } | ||
| } | ||
| content { | ||
| ... on PullRequest { | ||
| number | ||
| repository { nameWithOwner } | ||
| labels(first: 50) { nodes { name } } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| `; | ||
|
|
||
| const SET_TOPIC = ` | ||
| mutation($project: ID!, $item: ID!, $field: ID!, $option: String!) { | ||
| updateProjectV2ItemFieldValue(input: { | ||
| projectId: $project, itemId: $item, fieldId: $field, | ||
| value: { singleSelectOptionId: $option } | ||
| }) { projectV2Item { id } } | ||
| } | ||
| `; | ||
|
|
||
| // `github` always sends the workflow token, which cannot reach organization | ||
| // projects, so board queries use `PROJECT_TOKEN` directly. | ||
| async function graphql(token, query, variables) { | ||
| const response = await fetch("https://api.github.com/graphql", { | ||
| method: "POST", | ||
| headers: { authorization: `Bearer ${token}`, "content-type": "application/json" }, | ||
| body: JSON.stringify({ query, variables }), | ||
| }); | ||
| const body = await response.json().catch(() => ({})); | ||
| if (body.errors?.length) { | ||
| throw new Error(body.errors.map((e) => e.message).join("; ")); | ||
| } | ||
| if (!response.ok) { | ||
| throw new Error(`board refused the query with ${response.status}`); | ||
| } | ||
| return body.data; | ||
| } | ||
|
|
||
| // Returns topic option ids and the *slug* pull requests on the board by number. | ||
| // Throws if the board lacks a topic option. | ||
| async function readBoard(token, { owner, number, field }, topics, slug, core) { | ||
| const where = `${owner}/${number}`; | ||
| const options = new Map(); | ||
| const items = new Map(); | ||
| let board; | ||
| let cursor = null; | ||
| do { | ||
| const data = await graphql(token, BOARD_QUERY, { owner, number, field, cursor }); | ||
| board = data.organization?.projectV2; | ||
| if (!board) { | ||
| throw new Error(`${owner} states no project ${number}`); | ||
| } | ||
| if (!board.field?.id) { | ||
| throw new Error(`${field} is not a single-select field on ${where}`); | ||
| } | ||
| for (const { id, fieldValueByName, content } of board.items.nodes) { | ||
| // Skip issues, drafts and other repositories. | ||
| if (content?.number && content.repository.nameWithOwner === slug) { | ||
| items.set(content.number, { | ||
| itemId: id, | ||
| bucket: fieldValueByName?.name ?? null, | ||
| labels: content.labels.nodes.map((l) => l.name), | ||
| }); | ||
| } | ||
| } | ||
| const { hasNextPage, endCursor } = board.items.pageInfo; | ||
| cursor = hasNextPage ? endCursor : null; | ||
| } while (cursor); | ||
|
|
||
| for (const { id, name } of board.field.options) { | ||
| if (topics.has(name)) { | ||
| options.set(name, id); | ||
| } else { | ||
| core.notice(`${where}: option ${name} is not a topic`); | ||
| } | ||
| } | ||
| for (const topic of topics) { | ||
| if (!options.has(topic)) { | ||
| throw new Error(`${where}: topic ${topic} is not offered by ${field}`); | ||
| } | ||
| } | ||
| return { where, id: board.id, fieldId: board.field.id, options, items }; | ||
| } | ||
|
|
||
| // Runs a write, returning false when the target is no longer available | ||
| async function settle(write, core, what) { | ||
| try { | ||
| await write; | ||
| return true; | ||
| } catch (error) { | ||
| if (error.status !== 404) { | ||
| throw error; | ||
| } | ||
| core.info(`${what} no longer exists`); | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| // Creates missing topic labels. GitHub label names are case-insensitive, so a | ||
| // label differing only in case is renamed to the topic. | ||
| async function mintLabels(github, owner, repo, topics, core) { | ||
| const labels = await github.paginate(github.rest.issues.listLabelsForRepo, { owner, repo, per_page: 100 }); | ||
| const held = new Map(labels.map((l) => [l.name.toLowerCase(), l.name])); | ||
| for (const name of topics) { | ||
| const present = held.get(name.toLowerCase()); | ||
| if (present === name) { | ||
| continue; | ||
| } | ||
| if (present === undefined) { | ||
| const description = `Pull requests concerning ${name}`; | ||
| await github.rest.issues.createLabel({ owner, repo, name, color: TOPIC_COLOR, description }); | ||
| core.info(`minted label ${name}`); | ||
| } else { | ||
| const call = github.rest.issues.updateLabel({ owner, repo, name: present, new_name: name }); | ||
| if (await settle(call, core, `label ${present}`)) { | ||
| core.info(`renamed label ${present} to ${name}`); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @param {{ github: any, context: import("@actions/github").context, core: any }} params | ||
| */ | ||
| module.exports = async ({ github, context, core }) => { | ||
| const token = process.env.PROJECT_TOKEN; | ||
| if (!token) { | ||
| throw new Error("PROJECT_TOKEN reaches the boards; it is unset"); | ||
| } | ||
| const { owner, repo } = context.repo; | ||
|
|
||
| // Allowed order breaks ties between boards. | ||
| const config = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf8")); | ||
| const topics = new Set(config.topics); | ||
| const boards = []; | ||
| for (const entry of config.projects.allow) { | ||
| const project = { ...config.projects.defaults, ...entry }; | ||
| boards.push(await readBoard(token, project, topics, `${owner}/${repo}`, core)); | ||
| } | ||
|
|
||
| await mintLabels(github, owner, repo, topics, core); | ||
|
|
||
| // Apply board buckets to labels for all pull requests, open or not. | ||
| const settled = new Map(); | ||
| for (const { where, items } of boards) { | ||
| for (const [number, { bucket, labels }] of items) { | ||
| if (!topics.has(bucket)) { | ||
| continue; | ||
| } | ||
| const prior = settled.get(number); | ||
| if (prior !== undefined) { | ||
| if (prior !== bucket) { | ||
| core.warning(`PR #${number}: ${where} buckets ${bucket}, an earlier board ${prior}`); | ||
| } | ||
| continue; | ||
| } | ||
| settled.set(number, bucket); | ||
| if (!labels.includes(bucket)) { | ||
| const call = github.rest.issues.addLabels({ owner, repo, issue_number: number, labels: [bucket] }); | ||
| if (await settle(call, core, `PR #${number}`)) { | ||
| core.info(`PR #${number}: labelled ${bucket}`); | ||
| } | ||
| } | ||
| for (const name of labels) { | ||
| if (name !== bucket && topics.has(name)) { | ||
| const call = github.rest.issues.removeLabel({ owner, repo, issue_number: number, name }); | ||
| if (await settle(call, core, `PR #${number} label ${name}`)) { | ||
| core.info(`PR #${number}: pruned ${name}`); | ||
| } | ||
| } | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
| } | ||
|
|
||
| // Bucket unbucketed board items from their label. Never add items to a board. | ||
| for (const pr of await listOpenPulls({ github, owner, repo })) { | ||
| const unbucketed = boards.filter((b) => b.items.get(pr.number)?.bucket === null); | ||
| if (unbucketed.length === 0) { | ||
| continue; | ||
| } | ||
| const held = pr.labels.map((l) => l.name).filter((n) => topics.has(n)); | ||
| const topic = settled.get(pr.number) ?? (held.length === 1 ? held[0] : undefined); | ||
| if (topic === undefined) { | ||
| core.warning(`PR #${pr.number} is unbucketed and names ${held.length} topics`); | ||
| continue; | ||
| } | ||
| for (const { where, id, fieldId, options, items } of unbucketed) { | ||
| const item = items.get(pr.number).itemId; | ||
| await graphql(token, SET_TOPIC, { project: id, item, field: fieldId, option: options.get(topic) }); | ||
| core.info(`PR #${pr.number}: bucketed ${topic} on ${where}`); | ||
| } | ||
| } | ||
| }; | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.