mirror of
https://github.com/LukeHagar/slinky.git
synced 2025-12-06 04:21:20 +00:00
moving action files, adding publishing, adjusted usage
This commit is contained in:
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
||||
|
||||
- name: Build action image
|
||||
run: |
|
||||
docker build -t slinky-action -f .github/actions/slinky/Dockerfile .
|
||||
docker build -t slinky-action -f Dockerfile .
|
||||
|
||||
- name: Run action container (expect nonzero if failures)
|
||||
id: run_action
|
||||
|
||||
2
.github/workflows/example-slinky.yml
vendored
2
.github/workflows/example-slinky.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run Slinky link checker
|
||||
uses: ./\.github/actions/slinky
|
||||
uses: ./
|
||||
with:
|
||||
path: .
|
||||
patterns: "**/*"
|
||||
|
||||
74
.github/workflows/publish.yml
vendored
Normal file
74
.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
name: Publish Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch: {}
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Compute next v1 tag
|
||||
id: compute
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
const tags = await github.paginate(github.rest.repos.listTags, { owner, repo, per_page: 100 });
|
||||
const v1tags = tags
|
||||
.map(t => t.name)
|
||||
.filter(name => /^v1\.\d+\.\d+$/.test(name));
|
||||
let nextPatch = 0;
|
||||
let minor = 0;
|
||||
if (v1tags.length > 0) {
|
||||
let maxPatch = 0;
|
||||
for (const name of v1tags) {
|
||||
const [, mi, pa] = name.match(/^v1\.(\d+)\.(\d+)$/);
|
||||
const m = parseInt(mi, 10);
|
||||
const p = parseInt(pa, 10);
|
||||
if (m > minor) { minor = m; maxPatch = p; }
|
||||
else if (m === minor && p > maxPatch) { maxPatch = p; }
|
||||
}
|
||||
nextPatch = maxPatch + 1;
|
||||
}
|
||||
const newTag = `v1.${minor}.${nextPatch}`;
|
||||
core.setOutput('tag', newTag);
|
||||
|
||||
- name: Create GitHub Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ steps.compute.outputs.tag }}
|
||||
release_name: ${{ steps.compute.outputs.tag }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
- name: Update floating v1 tag to latest
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
const sha = context.sha;
|
||||
const ref = 'tags/v1';
|
||||
try {
|
||||
await github.rest.git.getRef({ owner, repo, ref });
|
||||
await github.rest.git.updateRef({ owner, repo, ref, sha, force: true });
|
||||
} catch (e) {
|
||||
await github.rest.git.createRef({ owner, repo, ref: `refs/${ref}`, sha });
|
||||
}
|
||||
|
||||
|
||||
18
Dockerfile
Normal file
18
Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
||||
FROM golang:1.24 as build
|
||||
WORKDIR /app
|
||||
# Expect the repository root as build context when building this image
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY . .
|
||||
RUN CGO_ENABLED=0 go build -o /usr/local/bin/slinky ./
|
||||
|
||||
FROM alpine:3.20
|
||||
RUN adduser -D -u 10001 appuser \
|
||||
&& apk add --no-cache curl jq ca-certificates
|
||||
COPY --from=build /usr/local/bin/slinky /usr/local/bin/slinky
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
USER appuser
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
|
||||
2
Makefile
2
Makefile
@@ -21,7 +21,7 @@ check: build
|
||||
|
||||
# Build the Docker-based GitHub Action locally
|
||||
action-image:
|
||||
docker build -t slinky-action -f .github/actions/slinky/Dockerfile .
|
||||
docker build -t slinky-action -f Dockerfile .
|
||||
|
||||
# Run the Action container against the current repo
|
||||
action-run: action-image
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Run Slinky
|
||||
uses: ./.github/actions/slinky
|
||||
uses: owner/repo@v1
|
||||
with:
|
||||
path: .
|
||||
patterns: "**/*"
|
||||
|
||||
72
action.yml
Normal file
72
action.yml
Normal file
@@ -0,0 +1,72 @@
|
||||
name: "Slinky Link Checker"
|
||||
description: "Slink through your repository looking for dead links"
|
||||
author: "LukeHagar"
|
||||
branding:
|
||||
icon: "link"
|
||||
color: "blue"
|
||||
|
||||
inputs:
|
||||
path:
|
||||
description: "Root path to scan"
|
||||
required: false
|
||||
default: "."
|
||||
patterns:
|
||||
description: "Comma-separated doublestar patterns. Ex: docs/**/*.md,**/*.go; default **/*"
|
||||
required: false
|
||||
default: "**/*"
|
||||
concurrency:
|
||||
description: "Maximum concurrent requests"
|
||||
required: false
|
||||
default: "16"
|
||||
timeout:
|
||||
description: "HTTP timeout seconds"
|
||||
required: false
|
||||
default: "10"
|
||||
json-out:
|
||||
description: "Optional path to write JSON results"
|
||||
required: false
|
||||
default: "results.json"
|
||||
md-out:
|
||||
description: "Optional path to write Markdown report for PR comment"
|
||||
required: false
|
||||
default: "results.md"
|
||||
repo-blob-base:
|
||||
description: "Override GitHub blob base URL (https://github.com/<owner>/<repo>/blob/<sha>)"
|
||||
required: false
|
||||
default: ""
|
||||
fail-on-failures:
|
||||
description: "Fail the job if any links fail"
|
||||
required: false
|
||||
default: "true"
|
||||
comment-pr:
|
||||
description: "If running on a PR, post a comment with the report"
|
||||
required: false
|
||||
default: "true"
|
||||
step-summary:
|
||||
description: "Append the report to the GitHub Step Summary"
|
||||
required: false
|
||||
default: "true"
|
||||
|
||||
runs:
|
||||
using: "docker"
|
||||
image: "Dockerfile"
|
||||
args: []
|
||||
env:
|
||||
INPUT_PATH: ${{ inputs.path }}
|
||||
INPUT_PATTERNS: ${{ inputs.patterns }}
|
||||
INPUT_CONCURRENCY: ${{ inputs.concurrency }}
|
||||
INPUT_TIMEOUT: ${{ inputs.timeout }}
|
||||
INPUT_JSON_OUT: ${{ inputs["json-out"] }}
|
||||
INPUT_MD_OUT: ${{ inputs["md-out"] }}
|
||||
INPUT_REPO_BLOB_BASE: ${{ inputs["repo-blob-base"] }}
|
||||
INPUT_FAIL_ON_FAILURES: ${{ inputs["fail-on-failures"] }}
|
||||
INPUT_COMMENT_PR: ${{ inputs["comment-pr"] }}
|
||||
INPUT_STEP_SUMMARY: ${{ inputs["step-summary"] }}
|
||||
|
||||
outputs:
|
||||
json-path:
|
||||
description: "Path to JSON results file"
|
||||
md-path:
|
||||
description: "Path to Markdown report file"
|
||||
|
||||
|
||||
89
entrypoint.sh
Normal file
89
entrypoint.sh
Normal file
@@ -0,0 +1,89 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
PATH_ARG="${INPUT_PATH:-.}"
|
||||
PATTERNS_ARG="${INPUT_PATTERNS:-**/*}"
|
||||
CONCURRENCY_ARG="${INPUT_CONCURRENCY:-16}"
|
||||
TIMEOUT_ARG="${INPUT_TIMEOUT:-10}"
|
||||
JSON_OUT_ARG="${INPUT_JSON_OUT:-results.json}"
|
||||
MD_OUT_ARG="${INPUT_MD_OUT:-results.md}"
|
||||
REPO_BLOB_BASE_ARG="${INPUT_REPO_BLOB_BASE:-}"
|
||||
FAIL_ON_FAILURES_ARG="${INPUT_FAIL_ON_FAILURES:-true}"
|
||||
COMMENT_PR_ARG="${INPUT_COMMENT_PR:-true}"
|
||||
STEP_SUMMARY_ARG="${INPUT_STEP_SUMMARY:-true}"
|
||||
|
||||
ARGS="check \"${PATH_ARG}\" --concurrency ${CONCURRENCY_ARG} --timeout ${TIMEOUT_ARG}"
|
||||
if [ "${FAIL_ON_FAILURES_ARG}" = "true" ]; then
|
||||
ARGS="$ARGS --fail-on-failures true"
|
||||
else
|
||||
ARGS="$ARGS --fail-on-failures false"
|
||||
fi
|
||||
if [ -n "${PATTERNS_ARG}" ]; then
|
||||
NORM_PATTERNS=$(printf "%s" "${PATTERNS_ARG}" | sed 's/,\s*/,/g')
|
||||
IFS=','
|
||||
set -- $NORM_PATTERNS
|
||||
unset IFS
|
||||
for pat in "$@"; do
|
||||
ARGS="$ARGS --patterns \"$pat\""
|
||||
done
|
||||
fi
|
||||
if [ -n "${JSON_OUT_ARG}" ]; then
|
||||
ARGS="$ARGS --json-out \"${JSON_OUT_ARG}\""
|
||||
fi
|
||||
if [ -n "${MD_OUT_ARG}" ]; then
|
||||
ARGS="$ARGS --md-out \"${MD_OUT_ARG}\""
|
||||
fi
|
||||
|
||||
# Compute GitHub blob base URL for file links used in the Markdown report
|
||||
if [ -n "${REPO_BLOB_BASE_ARG}" ]; then
|
||||
export SLINKY_REPO_BLOB_BASE_URL="${REPO_BLOB_BASE_ARG}"
|
||||
elif [ -n "${GITHUB_REPOSITORY:-}" ]; then
|
||||
COMMIT_SHA="${GITHUB_SHA:-}"
|
||||
if [ -n "${GITHUB_EVENT_PATH:-}" ] && command -v jq >/dev/null 2>&1; then
|
||||
PR_HEAD_SHA="$(jq -r '.pull_request.head.sha // empty' "$GITHUB_EVENT_PATH" || true)"
|
||||
if [ -n "$PR_HEAD_SHA" ]; then
|
||||
COMMIT_SHA="$PR_HEAD_SHA"
|
||||
fi
|
||||
fi
|
||||
if [ -n "$COMMIT_SHA" ]; then
|
||||
export SLINKY_REPO_BLOB_BASE_URL="https://github.com/${GITHUB_REPOSITORY}/blob/${COMMIT_SHA}"
|
||||
fi
|
||||
fi
|
||||
|
||||
eval slinky ${ARGS}
|
||||
|
||||
# Expose outputs
|
||||
if [ -n "${GITHUB_OUTPUT:-}" ]; then
|
||||
if [ -n "${JSON_OUT_ARG}" ]; then
|
||||
echo "json-path=${JSON_OUT_ARG}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
if [ -n "${MD_OUT_ARG}" ]; then
|
||||
echo "md-path=${MD_OUT_ARG}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Append report to job summary if requested
|
||||
if [ "${STEP_SUMMARY_ARG}" = "true" ] && [ -n "${GITHUB_STEP_SUMMARY:-}" ] && [ -n "${MD_OUT_ARG}" ] && [ -f "${MD_OUT_ARG}" ]; then
|
||||
cat "${MD_OUT_ARG}" >> "$GITHUB_STEP_SUMMARY"
|
||||
fi
|
||||
|
||||
# Post PR comment if this is a PR and requested
|
||||
if [ "${COMMENT_PR_ARG}" = "true" ] && [ -n "${MD_OUT_ARG}" ] && [ -f "${MD_OUT_ARG}" ]; then
|
||||
PR_NUMBER=""
|
||||
if [ -n "${GITHUB_EVENT_PATH:-}" ] && command -v jq >/dev/null 2>&1; then
|
||||
PR_NUMBER="$(jq -r '.pull_request.number // empty' "$GITHUB_EVENT_PATH" || true)"
|
||||
fi
|
||||
if [ -n "${PR_NUMBER}" ] && [ -n "${GITHUB_REPOSITORY:-}" ] && [ -n "${GITHUB_TOKEN:-}" ]; then
|
||||
BODY_CONTENT="$(cat "${MD_OUT_ARG}")"
|
||||
curl -sS -H "Authorization: Bearer ${GITHUB_TOKEN}" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
-X POST "https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" \
|
||||
-d "$(printf '{"body": %s}' "$(jq -Rs . <<EOF
|
||||
${BODY_CONTENT}
|
||||
EOF
|
||||
)" )" >/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user