ci: remove dead inherited .github/workflows (pwn-request + cruft)
Some checks failed
gitleaks / scan (push) Failing after 3s
Some checks failed
gitleaks / scan (push) Failing after 3s
CI security audit finding. These are all inherited NewPipe GitHub workflows, none functional on Forgejo — the real pipeline is .forgejo/workflows/. Highest risk: pr-labeler.yml ran on pull_request_target with pull-requests:write and called a mutable @main third-party action with GITHUB_TOKEN — a textbook pwn-request on a public repo (base-repo write token, triggerable by any fork PR). image-minimizer.yml ran arbitrary JS with issues/PR write perms. The rest (no-response, backport-pr, ci, build-release-apk) are dead + were spamming a red X on every push. Removing the lot drops third-party supply-chain surface to zero. Also dropped changed-lines-count-labeler.yml (dead config for the deleted labeler).
This commit is contained in:
parent
e34fbd457b
commit
7ff1546d31
8 changed files with 0 additions and 470 deletions
17
.github/changed-lines-count-labeler.yml
vendored
17
.github/changed-lines-count-labeler.yml
vendored
|
|
@ -1,17 +0,0 @@
|
||||||
# Add 'size/small' label to any changes with less than 50 lines
|
|
||||||
size/small:
|
|
||||||
max: 49
|
|
||||||
|
|
||||||
# Add 'size/medium' label to any changes between 50 and 249 lines
|
|
||||||
size/medium:
|
|
||||||
min: 50
|
|
||||||
max: 249
|
|
||||||
|
|
||||||
# Add 'size/large' label to any changes between 250 and 749 lines
|
|
||||||
size/large:
|
|
||||||
min: 250
|
|
||||||
max: 749
|
|
||||||
|
|
||||||
# Add 'size/giant' label to any changes for more than 749 lines
|
|
||||||
size/giant:
|
|
||||||
min: 750
|
|
||||||
48
.github/workflows/backport-pr.yml
vendored
48
.github/workflows/backport-pr.yml
vendored
|
|
@ -1,48 +0,0 @@
|
||||||
name: Backport merged pull request
|
|
||||||
on:
|
|
||||||
issue_comment:
|
|
||||||
types: [created]
|
|
||||||
permissions:
|
|
||||||
contents: write # for comment creation on original PR
|
|
||||||
pull-requests: write
|
|
||||||
jobs:
|
|
||||||
backport:
|
|
||||||
name: Backport pull request
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
# Only run when the comment starts with the `/backport` command on a PR and
|
|
||||||
# the commenter has write access to the repository. We do not want to allow
|
|
||||||
# everybody to trigger backports and create branches in our repository.
|
|
||||||
if: >
|
|
||||||
github.event.issue.pull_request &&
|
|
||||||
startsWith(github.event.comment.body, '/backport ') &&
|
|
||||||
(
|
|
||||||
github.event.comment.author_association == 'OWNER' ||
|
|
||||||
github.event.comment.author_association == 'COLLABORATOR' ||
|
|
||||||
github.event.comment.author_association == 'MEMBER'
|
|
||||||
)
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
- name: Get backport metadata
|
|
||||||
# the target branch is the first argument after `/backport`
|
|
||||||
env:
|
|
||||||
COMMENT_BODY: ${{ github.event.comment.body }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
body="$COMMENT_BODY"
|
|
||||||
|
|
||||||
line=${body%%$'\n'*} # Get the first line
|
|
||||||
if [[ $line =~ ^/backport[[:space:]]+([^[:space:]]+) ]]; then
|
|
||||||
echo "BACKPORT_TARGET=${BASH_REMATCH[1]}" >> "$GITHUB_ENV"
|
|
||||||
else
|
|
||||||
echo "Usage: /backport <target-branch>" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Create backport pull request
|
|
||||||
uses: korthout/backport-action@v4
|
|
||||||
with:
|
|
||||||
add_labels: 'backport'
|
|
||||||
copy_labels_pattern: '.*'
|
|
||||||
label_pattern: ''
|
|
||||||
target_branches: ${{ env.BACKPORT_TARGET }}
|
|
||||||
38
.github/workflows/build-release-apk.yml
vendored
38
.github/workflows/build-release-apk.yml
vendored
|
|
@ -1,38 +0,0 @@
|
||||||
name: "Build unsigned release APK on master"
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
ref: 'master'
|
|
||||||
|
|
||||||
- uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: '21'
|
|
||||||
cache: 'gradle'
|
|
||||||
|
|
||||||
- name: "Build release APK"
|
|
||||||
run: ./gradlew assembleRelease --stacktrace
|
|
||||||
|
|
||||||
- name: "Rename APK"
|
|
||||||
run: |
|
|
||||||
VERSION_NAME="$(jq -r ".elements[0].versionName" "app/build/outputs/apk/release/output-metadata.json")"
|
|
||||||
echo "Version name: $VERSION_NAME" >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
echo '```json' >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
cat "app/build/outputs/apk/release/output-metadata.json" >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
echo >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
echo '```' >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
# assume there is only one APK in that folder
|
|
||||||
mv app/build/outputs/apk/release/*.apk "app/build/outputs/apk/release/NewPipe_v$VERSION_NAME.apk"
|
|
||||||
|
|
||||||
- name: "Upload APK"
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: app
|
|
||||||
path: app/build/outputs/apk/release/*.apk
|
|
||||||
143
.github/workflows/ci.yml
vendored
143
.github/workflows/ci.yml
vendored
|
|
@ -1,143 +0,0 @@
|
||||||
name: CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
- master
|
|
||||||
- refactor
|
|
||||||
- release**
|
|
||||||
paths-ignore:
|
|
||||||
- 'README.md'
|
|
||||||
- 'doc/**'
|
|
||||||
- 'fastlane/**'
|
|
||||||
- 'assets/**'
|
|
||||||
- '.github/**/*.md'
|
|
||||||
- '.github/FUNDING.yml'
|
|
||||||
- '.github/ISSUE_TEMPLATE/**'
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
- master
|
|
||||||
paths-ignore:
|
|
||||||
- 'README.md'
|
|
||||||
- 'doc/**'
|
|
||||||
- 'fastlane/**'
|
|
||||||
- 'assets/**'
|
|
||||||
- '.github/**/*.md'
|
|
||||||
- '.github/FUNDING.yml'
|
|
||||||
- '.github/ISSUE_TEMPLATE/**'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-and-test-jvm:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
- uses: gradle/actions/wrapper-validation@v6
|
|
||||||
|
|
||||||
- name: create and checkout branch
|
|
||||||
# push events already checked out the branch
|
|
||||||
if: github.event_name == 'pull_request'
|
|
||||||
env:
|
|
||||||
BRANCH: ${{ github.head_ref }}
|
|
||||||
run: git checkout -B "$BRANCH"
|
|
||||||
|
|
||||||
- name: set up JDK
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
java-version: 21
|
|
||||||
distribution: "temurin"
|
|
||||||
cache: 'gradle'
|
|
||||||
|
|
||||||
- name: Build debug APK and run jvm tests
|
|
||||||
run: ./gradlew assembleDebug lintDebug testDebugUnitTest --stacktrace -DskipFormatKtlint
|
|
||||||
|
|
||||||
- name: Upload APK
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: app
|
|
||||||
path: app/build/outputs/apk/debug/*.apk
|
|
||||||
|
|
||||||
test-android:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 20
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- api-level: 23
|
|
||||||
target: default
|
|
||||||
arch: x86
|
|
||||||
- api-level: 35
|
|
||||||
target: default
|
|
||||||
arch: x86_64
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Enable KVM
|
|
||||||
run: |
|
|
||||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
|
||||||
sudo udevadm control --reload-rules
|
|
||||||
sudo udevadm trigger --name-match=kvm
|
|
||||||
|
|
||||||
- name: set up JDK
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
java-version: 21
|
|
||||||
distribution: "temurin"
|
|
||||||
cache: 'gradle'
|
|
||||||
|
|
||||||
- name: Run android tests
|
|
||||||
uses: reactivecircus/android-emulator-runner@v2
|
|
||||||
with:
|
|
||||||
api-level: ${{ matrix.api-level }}
|
|
||||||
target: ${{ matrix.target }}
|
|
||||||
arch: ${{ matrix.arch }}
|
|
||||||
script: ./gradlew connectedCheck --stacktrace
|
|
||||||
|
|
||||||
- name: Upload test report when tests fail # because the printed out stacktrace (console) is too short, see also #7553
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
if: failure()
|
|
||||||
with:
|
|
||||||
name: android-test-report-api${{ matrix.api-level }}
|
|
||||||
path: app/build/reports/androidTests/connected/**
|
|
||||||
|
|
||||||
sonar:
|
|
||||||
if: ${{ false }} # the key has expired and needs to be regenerated by the sonar admins
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
|
||||||
|
|
||||||
- name: Set up JDK
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
java-version: 21
|
|
||||||
distribution: "temurin"
|
|
||||||
cache: 'gradle'
|
|
||||||
|
|
||||||
- name: Cache SonarCloud packages
|
|
||||||
uses: actions/cache@v5
|
|
||||||
with:
|
|
||||||
path: ~/.sonar/cache
|
|
||||||
key: ${{ runner.os }}-sonar
|
|
||||||
restore-keys: ${{ runner.os }}-sonar
|
|
||||||
|
|
||||||
- name: Build and analyze
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
|
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
||||||
run: ./gradlew build sonar --info
|
|
||||||
147
.github/workflows/image-minimizer.js
vendored
147
.github/workflows/image-minimizer.js
vendored
|
|
@ -1,147 +0,0 @@
|
||||||
/*
|
|
||||||
* Script for minimizing big images (jpg,gif,png) when they are uploaded to GitHub and not edited otherwise
|
|
||||||
*/
|
|
||||||
module.exports = async ({github, context}) => {
|
|
||||||
const IGNORE_KEY = '<!-- IGNORE IMAGE MINIFY -->';
|
|
||||||
const IGNORE_ALT_NAME_END = 'ignoreImageMinify';
|
|
||||||
// Targeted maximum height
|
|
||||||
const IMG_MAX_HEIGHT_PX = 600;
|
|
||||||
// maximum width of GitHub issues/comments
|
|
||||||
const IMG_MAX_WIDTH_PX = 800;
|
|
||||||
// all images that have a lower aspect ratio (-> have a smaller width) than this will be minimized
|
|
||||||
const MIN_ASPECT_RATIO = IMG_MAX_WIDTH_PX / IMG_MAX_HEIGHT_PX
|
|
||||||
|
|
||||||
// Get the body of the image
|
|
||||||
let initialBody = null;
|
|
||||||
if (context.eventName == 'issue_comment') {
|
|
||||||
initialBody = context.payload.comment.body;
|
|
||||||
} else if (context.eventName == 'issues') {
|
|
||||||
initialBody = context.payload.issue.body;
|
|
||||||
} else if (context.eventName == 'pull_request') {
|
|
||||||
initialBody = context.payload.pull_request.body;
|
|
||||||
} else {
|
|
||||||
console.log('Aborting: No body found');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log(`Found body: \n${initialBody}\n`);
|
|
||||||
|
|
||||||
// Check if we should ignore the currently processing element
|
|
||||||
if (initialBody.includes(IGNORE_KEY)) {
|
|
||||||
console.log('Ignoring: Body contains IGNORE_KEY');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regex for finding images (simple variant) 
|
|
||||||
const REGEX_USER_CONTENT_IMAGE_LOOKUP = /\!\[([^\]]*)\]\((https:\/\/[-a-z0-9]+\.githubusercontent\.com\/\d+\/[-0-9a-f]{32,512}\.(jpg|gif|png))\)/gm;
|
|
||||||
const REGEX_ASSETS_IMAGE_LOOKUP = /\!\[([^\]]*)\]\((https:\/\/github\.com\/(?:user-attachments\/assets|[-\w\d]+\/[-\w\d]+\/assets\/\d+)\/[\-0-9a-f]{32,512})\)/gm;
|
|
||||||
|
|
||||||
// Check if we found something
|
|
||||||
let foundSimpleImages = REGEX_USER_CONTENT_IMAGE_LOOKUP.test(initialBody)
|
|
||||||
|| REGEX_ASSETS_IMAGE_LOOKUP.test(initialBody);
|
|
||||||
if (!foundSimpleImages) {
|
|
||||||
console.log('Found no simple images to process');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Found at least one simple image to process');
|
|
||||||
|
|
||||||
// Require the probe lib for getting the image dimensions
|
|
||||||
const probe = require('probe-image-size');
|
|
||||||
|
|
||||||
var wasMatchModified = false;
|
|
||||||
|
|
||||||
// Try to find and replace the images with minimized ones
|
|
||||||
let newBody = await replaceAsync(initialBody, REGEX_USER_CONTENT_IMAGE_LOOKUP, minimizeAsync);
|
|
||||||
newBody = await replaceAsync(newBody, REGEX_ASSETS_IMAGE_LOOKUP, minimizeAsync);
|
|
||||||
|
|
||||||
if (!wasMatchModified) {
|
|
||||||
console.log('Nothing was modified. Skipping update');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the corresponding element
|
|
||||||
if (context.eventName == 'issue_comment') {
|
|
||||||
console.log('Updating comment with id', context.payload.comment.id);
|
|
||||||
await github.rest.issues.updateComment({
|
|
||||||
comment_id: context.payload.comment.id,
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
body: newBody
|
|
||||||
})
|
|
||||||
} else if (context.eventName == 'issues') {
|
|
||||||
console.log('Updating issue', context.payload.issue.number);
|
|
||||||
await github.rest.issues.update({
|
|
||||||
issue_number: context.payload.issue.number,
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
body: newBody
|
|
||||||
});
|
|
||||||
} else if (context.eventName == 'pull_request') {
|
|
||||||
console.log('Updating pull request', context.payload.pull_request.number);
|
|
||||||
await github.rest.pulls.update({
|
|
||||||
pull_number: context.payload.pull_request.number,
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
body: newBody
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Async replace function from https://stackoverflow.com/a/48032528
|
|
||||||
async function replaceAsync(str, regex, asyncFn) {
|
|
||||||
const promises = [];
|
|
||||||
str.replace(regex, (match, ...args) => {
|
|
||||||
const promise = asyncFn(match, ...args);
|
|
||||||
promises.push(promise);
|
|
||||||
});
|
|
||||||
const data = await Promise.all(promises);
|
|
||||||
return str.replace(regex, () => data.shift());
|
|
||||||
}
|
|
||||||
|
|
||||||
async function minimizeAsync(match, g1, g2) {
|
|
||||||
console.log(`Found match '${match}'`);
|
|
||||||
|
|
||||||
if (g1.endsWith(IGNORE_ALT_NAME_END)) {
|
|
||||||
console.log(`Ignoring match '${match}': IGNORE_ALT_NAME_END`);
|
|
||||||
return match;
|
|
||||||
}
|
|
||||||
|
|
||||||
let probeAspectRatio = 0;
|
|
||||||
let shouldModify = false;
|
|
||||||
try {
|
|
||||||
console.log(`Probing ${g2}`);
|
|
||||||
let probeResult = await probe(g2);
|
|
||||||
if (probeResult == null) {
|
|
||||||
throw 'No probeResult';
|
|
||||||
}
|
|
||||||
if (probeResult.hUnits != 'px') {
|
|
||||||
throw `Unexpected probeResult.hUnits (expected px but got ${probeResult.hUnits})`;
|
|
||||||
}
|
|
||||||
if (probeResult.height <= 0) {
|
|
||||||
throw `Unexpected probeResult.height (height is invalid: ${probeResult.height})`;
|
|
||||||
}
|
|
||||||
if (probeResult.wUnits != 'px') {
|
|
||||||
throw `Unexpected probeResult.wUnits (expected px but got ${probeResult.wUnits})`;
|
|
||||||
}
|
|
||||||
if (probeResult.width <= 0) {
|
|
||||||
throw `Unexpected probeResult.width (width is invalid: ${probeResult.width})`;
|
|
||||||
}
|
|
||||||
console.log(`Probing resulted in ${probeResult.width}x${probeResult.height}px`);
|
|
||||||
|
|
||||||
probeAspectRatio = probeResult.width / probeResult.height;
|
|
||||||
shouldModify = probeResult.height > IMG_MAX_HEIGHT_PX && probeAspectRatio < MIN_ASPECT_RATIO;
|
|
||||||
} catch(e) {
|
|
||||||
console.log('Probing failed:', e);
|
|
||||||
// Immediately abort
|
|
||||||
return match;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldModify) {
|
|
||||||
wasMatchModified = true;
|
|
||||||
console.log(`Modifying match '${match}'`);
|
|
||||||
return `<img alt="${g1}" src="${g2}" width=${Math.min(600, Math.floor(IMG_MAX_HEIGHT_PX * probeAspectRatio))} />`;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Match '${match}' is ok/will not be modified`);
|
|
||||||
return match;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
35
.github/workflows/image-minimizer.yml
vendored
35
.github/workflows/image-minimizer.yml
vendored
|
|
@ -1,35 +0,0 @@
|
||||||
name: Image Minimizer
|
|
||||||
|
|
||||||
on:
|
|
||||||
issue_comment:
|
|
||||||
types: [created, edited]
|
|
||||||
issues:
|
|
||||||
types: [opened, edited]
|
|
||||||
pull_request:
|
|
||||||
types: [opened, edited]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
try-minimize:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
|
|
||||||
- name: Install probe-image-size
|
|
||||||
run: npm i probe-image-size@7.2.3 --ignore-scripts
|
|
||||||
|
|
||||||
- name: Minimize simple images
|
|
||||||
uses: actions/github-script@v9
|
|
||||||
timeout-minutes: 3
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const script = require('.github/workflows/image-minimizer.js');
|
|
||||||
await script({github, context});
|
|
||||||
24
.github/workflows/no-response.yml
vendored
24
.github/workflows/no-response.yml
vendored
|
|
@ -1,24 +0,0 @@
|
||||||
name: No Response
|
|
||||||
|
|
||||||
# Both `issue_comment` and `scheduled` event types are required for this Action
|
|
||||||
# to work properly.
|
|
||||||
on:
|
|
||||||
issue_comment:
|
|
||||||
types: [created]
|
|
||||||
schedule:
|
|
||||||
# Run daily at midnight.
|
|
||||||
- cron: '0 0 * * *'
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
noResponse:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: lee-dohm/no-response@v0.5.0
|
|
||||||
with:
|
|
||||||
token: ${{ github.token }}
|
|
||||||
daysUntilClose: 14
|
|
||||||
responseRequiredLabel: waiting for author
|
|
||||||
18
.github/workflows/pr-labeler.yml
vendored
18
.github/workflows/pr-labeler.yml
vendored
|
|
@ -1,18 +0,0 @@
|
||||||
name: "PR size labeler"
|
|
||||||
on: [pull_request_target]
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
changed-lines-count-labeler:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Automatically labelling pull requests based on the changed lines count
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
steps:
|
|
||||||
- name: Set a label
|
|
||||||
uses: TeamNewPipe/changed-lines-count-labeler@main
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
configuration-path: .github/changed-lines-count-labeler.yml
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue