mirror of
https://github.com/awalsh128/cache-apt-pkgs-action.git
synced 2026-05-06 10:03:20 +00:00
More stuff
This commit is contained in:
parent
fc79483542
commit
3643802011
|
|
@ -1,37 +0,0 @@
|
|||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
charset = utf-8
|
||||
|
||||
# 2 space indentation
|
||||
[*.{js,json,jsonc,yml,yaml,md,sh}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# Tab indentation (no size specified)
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
# Matches the exact files
|
||||
[{Makefile,makefile,*.mk}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
# Shell scripts
|
||||
[*.sh]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
max_line_length = 100
|
||||
|
||||
# Markdown files
|
||||
[*.md]
|
||||
max_line_length = 100
|
||||
trim_trailing_whitespace = false
|
||||
4
.env
4
.env
|
|
@ -1,3 +1,3 @@
|
|||
GO111MODULE=auto
|
||||
GO_TOOLCHAIN=go1.23.5
|
||||
GO_VERSION=1.23.5
|
||||
GO_TOOLCHAIN=go1.24
|
||||
GO_VERSION=1.24
|
||||
|
|
|
|||
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
|
@ -33,8 +33,8 @@ steps:
|
|||
|
||||
### Environment
|
||||
|
||||
- **Runner OS**: (e.g., ubuntu-22.04, ubuntu-20.04)
|
||||
- **Action version**: (e.g., v1.4.2, latest)
|
||||
- **Runner OS**: (e.g. ubuntu-22.04, ubuntu-20.04)
|
||||
- **Action version**: (e.g. v1.4.2, latest)
|
||||
- **Repository**: (if relevant)
|
||||
|
||||
## Expected vs Actual Behavior
|
||||
|
|
|
|||
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -3,6 +3,3 @@ contact_links:
|
|||
- name: Documentation
|
||||
url: https://github.com/awalsh128/cache-apt-pkgs-action/blob/master/README.md
|
||||
about: Please check the documentation before filing an issue
|
||||
- name: Discussions
|
||||
url: https://github.com/awalsh128/cache-apt-pkgs-action/discussions
|
||||
about: Ask questions and discuss ideas with the community
|
||||
|
|
|
|||
11
.github/ISSUE_TEMPLATE/feature_request.md
vendored
11
.github/ISSUE_TEMPLATE/feature_request.md
vendored
|
|
@ -1,11 +1,9 @@
|
|||
---
|
||||
|
||||
name: Feature Request
|
||||
about: Suggest an idea or enhancement for this action
|
||||
title: "\[FEATURE] "
|
||||
title: "[FEATURE] "
|
||||
labels: enhancement
|
||||
assignees: awalsh128
|
||||
|
||||
---
|
||||
|
||||
## Feature Summary
|
||||
|
|
@ -14,8 +12,8 @@ A clear and concise description of what you want to happen.
|
|||
|
||||
## Problem Statement
|
||||
|
||||
What problem would this feature solve? Is your feature request related to a
|
||||
problem you're experiencing?
|
||||
What problem would this feature solve? Is your feature request related to a problem you're
|
||||
experiencing?
|
||||
|
||||
```txt
|
||||
Example: I'm frustrated when [specific scenario] because [reason]
|
||||
|
|
@ -31,8 +29,7 @@ Describe any alternative solutions or features you've considered.
|
|||
|
||||
## Use Case
|
||||
|
||||
Describe your specific use case and how this feature would benefit you and
|
||||
others.
|
||||
Describe your specific use case and how this feature would benefit you and others.
|
||||
|
||||
```yaml
|
||||
# Example workflow showing how the feature would be used
|
||||
|
|
|
|||
|
|
@ -1,46 +1,38 @@
|
|||
name: Test Action
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
DEBUG: false
|
||||
name: Action Tests
|
||||
on:
|
||||
# Manual trigger (no inputs allowed per Trunk rule)
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
debug:
|
||||
description: "Run in debug mode."
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
repository_dispatch:
|
||||
push:
|
||||
branches: [dev-v2.0] # Test on pushes to dev branch
|
||||
paths:
|
||||
- cmd/** # Only when action code changes
|
||||
- internal/** # Only when action code changes
|
||||
- action.yml
|
||||
- .github/workflows/action_tests.yml
|
||||
pull_request:
|
||||
branches: [dev-v2.0] # Test on PRs to dev branch
|
||||
paths:
|
||||
- cmd/** # Only when action code changes
|
||||
- internal/** # Only when action code changes
|
||||
- action.yml
|
||||
- .github/workflows/action_tests.yml
|
||||
|
||||
env:
|
||||
DEBUG: ${{ github.event.inputs.debug || false }}
|
||||
# Test for overrides in built in shell options (regression issue 98).
|
||||
SHELLOPTS: errexit:pipefail
|
||||
|
||||
jobs:
|
||||
list_all_versions:
|
||||
runs-on: ubuntu-latest
|
||||
name: List all package versions (including deps).
|
||||
steps:
|
||||
# Checkout the code we want to test
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# Use the event ref/sha by default; do not accept user-controlled ref inputs
|
||||
fetch-depth: 0
|
||||
# Run the action from the checked out code
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- name: Execute
|
||||
id: execute
|
||||
uses: ./
|
||||
uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: xdot=1.3-1
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-list_all_versions
|
||||
debug: false
|
||||
debug: ${{ env.DEBUG }}
|
||||
- name: Verify
|
||||
if: "steps.execute.outputs.cache-hit != 'false' || \nsteps.execute.outputs.all-package-version-list != 'fonts-liberation2=1:2.1.5-3,gir1.2-atk-1.0=2.52.0-1build1,gir1.2-freedesktop=1.80.1-1,gir1.2-gdkpixbuf-2.0=2.42.10+dfsg-3ubuntu3.2,gir1.2-gtk-3.0=3.24.41-4ubuntu1.3,gir1.2-harfbuzz-0.0=8.3.0-2build2,gir1.2-pango-1.0=1.52.1+ds-1build1,graphviz=2.42.2-9ubuntu0.1,libann0=1.1.2+doc-9build1,libblas3=3.12.0-3build1.1,libcdt5=2.42.2-9ubuntu0.1,libcgraph6=2.42.2-9ubuntu0.1,libgts-0.7-5t64=0.7.6+darcs121130-5.2build1,libgts-bin=0.7.6+darcs121130-5.2build1,libgvc6=2.42.2-9ubuntu0.1,libgvpr2=2.42.2-9ubuntu0.1,libharfbuzz-gobject0=8.3.0-2build2,liblab-gamut1=2.42.2-9ubuntu0.1,liblapack3=3.12.0-3build1.1,libpangoxft-1.0-0=1.52.1+ds-1build1,libpathplan4=2.42.2-9ubuntu0.1,python3-cairo=1.25.1-2build2,python3-gi-cairo=3.48.2-1,python3-numpy=1:1.26.4+ds-6ubuntu1,xdot=1.3-1'\n"
|
||||
if: |
|
||||
steps.execute.outputs.cache-hit != 'false' ||
|
||||
steps.execute.outputs.all-package-version-list != 'fonts-liberation2=1:2.1.5-3,gir1.2-atk-1.0=2.52.0-1build1,gir1.2-freedesktop=1.80.1-1,gir1.2-gdkpixbuf-2.0=2.42.10+dfsg-3ubuntu3.2,gir1.2-gtk-3.0=3.24.41-4ubuntu1.3,gir1.2-harfbuzz-0.0=8.3.0-2build2,gir1.2-pango-1.0=1.52.1+ds-1build1,graphviz=2.42.2-9ubuntu0.1,libann0=1.1.2+doc-9build1,libblas3=3.12.0-3build1.1,libcdt5=2.42.2-9ubuntu0.1,libcgraph6=2.42.2-9ubuntu0.1,libgts-0.7-5t64=0.7.6+darcs121130-5.2build1,libgts-bin=0.7.6+darcs121130-5.2build1,libgvc6=2.42.2-9ubuntu0.1,libgvpr2=2.42.2-9ubuntu0.1,libharfbuzz-gobject0=8.3.0-2build2,liblab-gamut1=2.42.2-9ubuntu0.1,liblapack3=3.12.0-3build1.1,libpangoxft-1.0-0=1.52.1+ds-1build1,libpathplan4=2.42.2-9ubuntu0.1,python3-cairo=1.25.1-2build2,python3-gi-cairo=3.48.2-1,python3-numpy=1:1.26.4+ds-6ubuntu1,xdot=1.3-1'
|
||||
run: |
|
||||
echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}"
|
||||
echo "package-version-list = ${{ steps.execute.outputs.package-version-list }}"
|
||||
|
|
@ -49,68 +41,81 @@ jobs:
|
|||
diff <(echo "${{ steps.execute.outputs.all-package-version-list }}" ) <(echo "fonts-liberation2=1:2.1.5-3,gir1.2-atk-1.0=2.52.0-1build1,gir1.2-freedesktop=1.80.1-1,gir1.2-gdkpixbuf-2.0=2.42.10+dfsg-3ubuntu3.2,gir1.2-gtk-3.0=3.24.41-4ubuntu1.3,gir1.2-harfbuzz-0.0=8.3.0-2build2,gir1.2-pango-1.0=1.52.1+ds-1build1,graphviz=2.42.2-9ubuntu0.1,libann0=1.1.2+doc-9build1,libblas3=3.12.0-3build1.1,libcdt5=2.42.2-9ubuntu0.1,libcgraph6=2.42.2-9ubuntu0.1,libgts-0.7-5t64=0.7.6+darcs121130-5.2build1,libgts-bin=0.7.6+darcs121130-5.2build1,libgvc6=2.42.2-9ubuntu0.1,libgvpr2=2.42.2-9ubuntu0.1,libharfbuzz-gobject0=8.3.0-2build2,liblab-gamut1=2.42.2-9ubuntu0.1,liblapack3=3.12.0-3build1.1,libpangoxft-1.0-0=1.52.1+ds-1build1,libpathplan4=2.42.2-9ubuntu0.1,python3-cairo=1.25.1-2build2,python3-gi-cairo=3.48.2-1,python3-numpy=1:1.26.4+ds-6ubuntu1,xdot=1.3-1")
|
||||
exit 1
|
||||
shell: bash
|
||||
|
||||
list_versions:
|
||||
runs-on: ubuntu-latest
|
||||
name: List package versions.
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- name: Execute
|
||||
id: execute
|
||||
uses: ./
|
||||
uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: xdot rolldice
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-list_versions
|
||||
debug: false
|
||||
debug: ${{ env.DEBUG }}
|
||||
- name: Verify
|
||||
if: steps.execute.outputs.cache-hit != 'false' || steps.execute.outputs.package-version-list != 'rolldice=1.16-1build3,xdot=1.3-1'
|
||||
run: "echo \"cache-hit = ${{ steps.execute.outputs.cache-hit }}\" \necho \"package-version-list = ${{ steps.execute.outputs.package-version-list }}\"\necho \"diff package-version-list\"\ndiff <(echo \"${{ steps.execute.outputs.package-version-list }}\" ) <(echo \"rolldice=1.16-1build3,xdot=1.3-1\")\nexit 1\n"
|
||||
if:
|
||||
steps.execute.outputs.cache-hit != 'false' || steps.execute.outputs.package-version-list
|
||||
!= 'rolldice=1.16-1build3,xdot=1.3-1'
|
||||
run: |
|
||||
echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}"
|
||||
echo "package-version-list = ${{ steps.execute.outputs.package-version-list }}"
|
||||
echo "diff package-version-list"
|
||||
diff <(echo "${{ steps.execute.outputs.package-version-list }}" ) <(echo "rolldice=1.16-1build3,xdot=1.3-1")
|
||||
exit 1
|
||||
shell: bash
|
||||
|
||||
standard_workflow_install:
|
||||
runs-on: ubuntu-latest
|
||||
name: Standard workflow install package and cache.
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- name: Execute
|
||||
id: execute
|
||||
uses: ./
|
||||
uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: xdot rolldice
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-standard_workflow
|
||||
debug: false
|
||||
debug: ${{ env.DEBUG }}
|
||||
- name: Verify
|
||||
if: steps.execute.outputs.cache-hit != 'false'
|
||||
run: |
|
||||
echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}"
|
||||
exit 1
|
||||
shell: bash
|
||||
|
||||
standard_workflow_install_with_new_version:
|
||||
needs: standard_workflow_install
|
||||
runs-on: ubuntu-latest
|
||||
name: Standard workflow packages with new version.
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- name: Execute
|
||||
id: execute
|
||||
uses: ./
|
||||
uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: xdot rolldice
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-standard_workflow_install_with_new_version
|
||||
debug: false
|
||||
version:
|
||||
${{ github.run_id }}-${{ github.run_attempt
|
||||
}}-standard_workflow_install_with_new_version
|
||||
debug: ${{ env.DEBUG }}
|
||||
- name: Verify
|
||||
if: steps.execute.outputs.cache-hit != 'false'
|
||||
run: |
|
||||
echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}"
|
||||
exit 1
|
||||
shell: bash
|
||||
|
||||
standard_workflow_restore:
|
||||
needs: standard_workflow_install
|
||||
runs-on: ubuntu-latest
|
||||
name: Standard workflow restore cached packages.
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- name: Execute
|
||||
id: execute
|
||||
uses: ./
|
||||
uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: xdot rolldice
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-standard_workflow
|
||||
|
|
@ -121,15 +126,16 @@ jobs:
|
|||
echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}"
|
||||
exit 1
|
||||
shell: bash
|
||||
|
||||
standard_workflow_restore_with_packages_out_of_order:
|
||||
needs: standard_workflow_install
|
||||
runs-on: ubuntu-latest
|
||||
name: Standard workflow restore with packages out of order.
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- name: Execute
|
||||
id: execute
|
||||
uses: ./
|
||||
uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: rolldice xdot
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-standard_workflow
|
||||
|
|
@ -140,15 +146,16 @@ jobs:
|
|||
echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}"
|
||||
exit 1
|
||||
shell: bash
|
||||
|
||||
standard_workflow_add_package:
|
||||
needs: standard_workflow_install
|
||||
runs-on: ubuntu-latest
|
||||
name: Standard workflow add another package.
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- name: Execute
|
||||
id: execute
|
||||
uses: ./
|
||||
uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: xdot rolldice distro-info-data
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-standard_workflow
|
||||
|
|
@ -159,15 +166,16 @@ jobs:
|
|||
echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}"
|
||||
exit 1
|
||||
shell: bash
|
||||
|
||||
standard_workflow_restore_add_package:
|
||||
needs: standard_workflow_add_package
|
||||
runs-on: ubuntu-latest
|
||||
name: Standard workflow restore added package.
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- name: Execute
|
||||
id: execute
|
||||
uses: ./
|
||||
uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: xdot rolldice distro-info-data
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-standard_workflow
|
||||
|
|
@ -178,13 +186,14 @@ jobs:
|
|||
echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}"
|
||||
exit 1
|
||||
shell: bash
|
||||
|
||||
no_packages:
|
||||
runs-on: ubuntu-latest
|
||||
name: No packages passed.
|
||||
steps:
|
||||
- name: Execute
|
||||
id: execute
|
||||
uses: ./
|
||||
uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: ""
|
||||
continue-on-error: true
|
||||
|
|
@ -192,13 +201,14 @@ jobs:
|
|||
if: steps.execute.outcome == 'failure'
|
||||
run: exit 0
|
||||
shell: bash
|
||||
|
||||
package_not_found:
|
||||
runs-on: ubuntu-latest
|
||||
name: Package not found.
|
||||
steps:
|
||||
- name: Execute
|
||||
id: execute
|
||||
uses: ./
|
||||
uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: package_that_doesnt_exist
|
||||
continue-on-error: true
|
||||
|
|
@ -206,13 +216,14 @@ jobs:
|
|||
if: steps.execute.outcome == 'failure'
|
||||
run: exit 0
|
||||
shell: bash
|
||||
|
||||
version_contains_spaces:
|
||||
runs-on: ubuntu-latest
|
||||
name: Version contains spaces.
|
||||
steps:
|
||||
- name: Execute
|
||||
id: execute
|
||||
uses: ./
|
||||
uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: xdot
|
||||
version: 123 abc
|
||||
|
|
@ -222,61 +233,67 @@ jobs:
|
|||
if: steps.execute.outcome == 'failure'
|
||||
run: exit 0
|
||||
shell: bash
|
||||
|
||||
regression_36:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Reinstall existing package (regression issue #36)."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: libgtk-3-dev
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_36
|
||||
debug: ${{ env.DEBUG }}
|
||||
|
||||
regression_37:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Install with reported package dependencies not installed (regression issue #37)."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: libosmesa6-dev libgl1-mesa-dev python3-tk pandoc git-restore-mtime
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_37
|
||||
debug: ${{ env.DEBUG }}
|
||||
|
||||
debug_disabled:
|
||||
runs-on: ubuntu-latest
|
||||
name: Debug disabled.
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: xdot
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-list-all-package-versions
|
||||
debug: false
|
||||
debug: ${{ env.DEBUG }}
|
||||
|
||||
regression_72_1:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Cache Java CA certs package v1 (regression issue #72)."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: openjdk-11-jre
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_72
|
||||
debug: ${{ env.DEBUG }}
|
||||
|
||||
regression_72_2:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Cache Java CA certs package v2 (regression issue #72)."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: default-jre
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_72
|
||||
debug: ${{ env.DEBUG }}
|
||||
|
||||
regression_76:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Cache empty archive (regression issue #76)."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- run: |
|
||||
sudo wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor | tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null;
|
||||
echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list;
|
||||
|
|
@ -284,52 +301,57 @@ jobs:
|
|||
sudo apt-get install -y intel-oneapi-runtime-libs intel-oneapi-runtime-opencl;
|
||||
sudo apt-get install -y opencl-headers ocl-icd-opencl-dev;
|
||||
sudo apt-get install -y libsundials-dev;
|
||||
- uses: ./
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: intel-oneapi-runtime-libs
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_76
|
||||
debug: ${{ env.DEBUG }}
|
||||
|
||||
regression_79:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Tar error with libboost-dev (regression issue #79)."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: libboost-dev
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_79
|
||||
debug: ${{ env.DEBUG }}
|
||||
|
||||
regression_81:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Tar error with alsa-ucm-conf (regression issue #81)."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: libasound2 libatk-bridge2.0-0 libatk1.0-0 libatspi2.0-0 libcups2 libdrm2 libgbm1 libnspr4 libnss3 libxcomposite1 libxdamage1 libxfixes3 libxkbcommon0 libxrandr2
|
||||
packages:
|
||||
libasound2 libatk-bridge2.0-0 libatk1.0-0 libatspi2.0-0 libcups2 libdrm2 libgbm1
|
||||
libnspr4 libnss3 libxcomposite1 libxdamage1 libxfixes3 libxkbcommon0 libxrandr2
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_81
|
||||
debug: ${{ env.DEBUG }}
|
||||
|
||||
regression_84_literal_block_install:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Install multiline package listing using literal block style (regression issue #84)."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: >
|
||||
xdot rolldice distro-info-data
|
||||
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_84_literal_block
|
||||
debug: ${{ env.DEBUG }}
|
||||
|
||||
regression_84_literal_block_restore:
|
||||
needs: regression_84_literal_block_install
|
||||
runs-on: ubuntu-latest
|
||||
name: "Restore multiline package listing using literal block style (regression issue #84)."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- name: Execute
|
||||
id: execute
|
||||
uses: ./
|
||||
uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: xdot rolldice distro-info-data
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_84_literal_block
|
||||
|
|
@ -340,27 +362,29 @@ jobs:
|
|||
echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}"
|
||||
exit 1
|
||||
shell: bash
|
||||
|
||||
regression_84_folded_block_install:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Install multiline package listing using literal block style (regression issue #84)."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: |
|
||||
xdot \
|
||||
rolldice distro-info-data
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_84_folded_block
|
||||
debug: ${{ env.DEBUG }}
|
||||
|
||||
regression_84_folded_block_restore:
|
||||
needs: regression_84_folded_block_install
|
||||
runs-on: ubuntu-latest
|
||||
name: "Restore multiline package listing using literal block style (regression issue #84)."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- name: Execute
|
||||
id: execute
|
||||
uses: ./
|
||||
uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: xdot rolldice distro-info-data
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_84_folded_block
|
||||
|
|
@ -371,73 +395,69 @@ jobs:
|
|||
echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}"
|
||||
exit 1
|
||||
shell: bash
|
||||
|
||||
regression_89:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Upload logs artifact name (regression issue #89)."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: libgtk-3-dev:amd64
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_89
|
||||
debug: ${{ env.DEBUG }}
|
||||
|
||||
regression_98:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Install error due to SHELLOPTS override (regression issue #98)."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: git-restore-mtime libgl1-mesa-dev libosmesa6-dev pandoc
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_98
|
||||
debug: ${{ env.DEBUG }}
|
||||
|
||||
regression_106_install:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Stale apt repo not finding package on restore, install phase (regression issue #106)."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: libtk8.6
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_106
|
||||
debug: ${{ env.DEBUG }}
|
||||
|
||||
regression_106_restore:
|
||||
needs: regression_106_install
|
||||
runs-on: ubuntu-latest
|
||||
name: "Stale apt repo not finding package on restore, restore phase (regression issue #106)."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: libtk8.6
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_106
|
||||
debug: ${{ env.DEBUG }}
|
||||
regression_159_install:
|
||||
runs-on: ubuntu-latest
|
||||
name: apt-show false positive parsing Package line (regression issue #159).
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
with:
|
||||
packages: texlive-latex-extra
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_159
|
||||
debug: ${{ env.DEBUG }}
|
||||
|
||||
multi_arch_cache_key:
|
||||
runs-on: ubuntu-latest
|
||||
name: Cache packages with multi-arch cache key.
|
||||
name: "Cache packages with multi-arch cache key."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: libfuse2
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-multi_arch_cache_key
|
||||
debug: ${{ env.DEBUG }}
|
||||
|
||||
virtual_package:
|
||||
runs-on: ubuntu-latest
|
||||
name: Cache virtual package.
|
||||
name: "Cache virtual package."
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./
|
||||
- uses: actions/checkout@v3.1.0
|
||||
- uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: libvips
|
||||
version: ${{ github.run_id }}-${{ github.run_attempt }}-virtual_package
|
||||
116
.github/workflows/build-distribute.yml
vendored
Normal file
116
.github/workflows/build-distribute.yml
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
name: Build and Release Distribute Artifacts
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v2.*.*"
|
||||
branches:
|
||||
- dev-v2
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
env:
|
||||
VERSION_PREFIX: "commit"
|
||||
jobs:
|
||||
build-and-release:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- goos: linux
|
||||
goarch: amd64
|
||||
arch: x64
|
||||
- goos: linux
|
||||
goarch: arm64
|
||||
arch: arm64
|
||||
- goos: linux
|
||||
goarch: arm
|
||||
goarch_variant: "6"
|
||||
arch: arm
|
||||
- goos: linux
|
||||
goarch: "386"
|
||||
arch: x86
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.24
|
||||
- name: Generate version from commit SHA
|
||||
id: version
|
||||
run: ./scripts/distribute.sh generate-version
|
||||
- name: Create distribute directory
|
||||
run: ./scripts/distribute.sh create-distribute-directory "${{ matrix.arch }}"
|
||||
- name: Clone apt-fast repository
|
||||
run: ./scripts/distribute.sh clone-apt-fast
|
||||
- name: Build binary for ${{ matrix.goos }}/${{ matrix.goarch }}
|
||||
env:
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
GOARM: ${{ matrix.goarch_variant }}
|
||||
CGO_ENABLED: 0
|
||||
run: |
|
||||
./scripts/distribute.sh build-binary \
|
||||
"${{ matrix.goos }}" \
|
||||
"${{ matrix.goarch }}" \
|
||||
"${{ matrix.goarch_variant }}" \
|
||||
"${{ matrix.arch }}"
|
||||
- name: Generate checksums
|
||||
run: ./scripts/distribute.sh generate-checksums "${{ matrix.arch }}"
|
||||
- name: Verify build
|
||||
run: |
|
||||
./scripts/distribute.sh verify-build "${{ matrix.arch }}"
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cache-apt-pkgs-${{ matrix.arch }}-${{ steps.version.outputs.commit_sha }}
|
||||
path: distribute/${{ matrix.arch }}/*
|
||||
retention-days: 30
|
||||
create-release:
|
||||
needs: build-and-release
|
||||
runs-on: ubuntu-latest
|
||||
if: success()
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Generate version from commit SHA
|
||||
id: version
|
||||
run: |
|
||||
COMMIT_SHA="${GITHUB_SHA:0:8}"
|
||||
VERSION="${{ env.VERSION_PREFIX }}-${COMMIT_SHA}"
|
||||
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||
echo "commit_sha=${COMMIT_SHA}" >> $GITHUB_OUTPUT
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: distribute-artifacts
|
||||
- name: Reorganize artifacts
|
||||
run: |
|
||||
./scripts/distribute.sh reorganize-artifacts
|
||||
- name: Create or update release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: ${{ steps.version.outputs.version }}
|
||||
name: "${{ steps.version.outputs.version }}"
|
||||
generate_release_notes: true
|
||||
files: |
|
||||
distribute/x64/*
|
||||
distribute/arm64/*
|
||||
distribute/arm/*
|
||||
distribute/x86/*
|
||||
draft: false
|
||||
prerelease: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Clean up old pre-releases
|
||||
run: |
|
||||
echo "Cleaning up old commit-based releases..."
|
||||
# Keep last 10 commit-based releases, delete older ones
|
||||
gh release list --limit 50 --json tagName,isPrerelease | \
|
||||
jq -r '.[] | select(.isPrerelease == true and (.tagName | startswith("commit-"))) | .tagName' | \
|
||||
tail -n +11 | \
|
||||
xargs -I {} gh release delete {} --yes --cleanup-tag || true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
23
.github/workflows/pr.yml
vendored
Normal file
23
.github/workflows/pr.yml
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
name: Pull Request
|
||||
# trunk-ignore(yamllint/truthy)
|
||||
on: [push, pull_request]
|
||||
concurrency:
|
||||
group: ${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
trunk_check:
|
||||
name: Trunk Code Quality Runner
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
checks: write # For trunk to post annotations
|
||||
contents: read # For repo checkout
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Trunk Code Quality
|
||||
uses: trunk-io/trunk-action@v1
|
||||
|
|
@ -1 +0,0 @@
|
|||
dist/**/*
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
version: "2"
|
||||
formatters:
|
||||
enable:
|
||||
- gofumpt # formats Go code
|
||||
- goimports # formats imports and does everything that gofmt does
|
||||
linters:
|
||||
enable:
|
||||
- asasalint # checks for pass []any as any in variadic func(...any)
|
||||
- asciicheck # checks that your code does not contain non-ASCII identifiers
|
||||
- bidichk # checks for dangerous unicode character sequences
|
||||
- bodyclose # checks whether HTTP response body is closed successfully
|
||||
- containedctx # detects struct contained context.Context field
|
||||
- contextcheck # checks the function whether use a non-inherited context
|
||||
- cyclop # checks function and package cyclomatic complexity
|
||||
- decorder # checks declaration order and count of types, constants, variables and functions
|
||||
- dogsled # checks assignments with too many blank identifiers
|
||||
- dupl # checks code clone duplication
|
||||
- durationcheck # checks for two durations multiplied together
|
||||
- errcheck # checks unchecked errors
|
||||
- errchkjson # checks types passed to encoding/json functions
|
||||
- errname # checks that sentinel errors are prefixed with the Err and error types are suffixed with the Error
|
||||
- errorlint # finds code that will cause problems with the error wrapping scheme
|
||||
- exhaustive # checks exhaustiveness of enum switch statements
|
||||
- forcetypeassert # finds forced type assertions
|
||||
- funlen # checks for long functions
|
||||
- gocheckcompilerdirectives # validates go compiler directive comments
|
||||
- gochecknoglobals # checks that no global variables exist
|
||||
- gochecknoinits # checks that no init functions are present
|
||||
- gocognit # computes and checks the cognitive complexity
|
||||
- goconst # finds repeated strings that could be replaced by a constant
|
||||
- gocritic # provides diagnostics that check for bugs, performance and style issues
|
||||
- gocyclo # checks cyclomatic complexity
|
||||
- godot # checks if comments end in a period
|
||||
- godox # detects FIXME, TODO and other comment keywords
|
||||
- goheader # checks is file header matches to pattern
|
||||
- gomoddirectives # manages the use of 'replace', 'retract', and 'excludes' directives in go.mod
|
||||
- gomodguard # allows to specify a list of forbidden modules
|
||||
- goprintffuncname # checks that printf-like functions are named with f at the end
|
||||
- gosec # inspects source code for security problems
|
||||
- govet # reports suspicious constructs
|
||||
- grouper # analyzes expression groups
|
||||
- importas # enforces consistent import aliases
|
||||
- ineffassign # detects when assignments to existing variables are not used
|
||||
- interfacebloat # checks the number of methods inside an interface
|
||||
- ireturn # accept interfaces, return concrete types
|
||||
- lll # reports long lines
|
||||
- loggercheck # checks key value pairs for common logger libraries
|
||||
- maintidx # measures the maintainability index of each function
|
||||
- makezero # finds slice declarations with non-zero initial length
|
||||
- misspell # finds commonly misspelled English words
|
||||
- nakedret # finds naked returns
|
||||
- nestif # reports deeply nested if statements
|
||||
- nilerr # finds the code that returns nil even if it checks that error is not nil
|
||||
- nilnil # checks that there is no simultaneous return of nil error and an invalid value
|
||||
- nlreturn # checks for a new line before return and branch statements
|
||||
- noctx # finds sending http request without context.Context
|
||||
- nolintlint # reports ill-formed or insufficient nolint directives
|
||||
- nonamedreturns # reports all named returns
|
||||
- nosprintfhostport # checks for misuse of Sprintf to construct a host with port in a URL
|
||||
- paralleltest # detects missing usage of t.Parallel() method in your Go test
|
||||
- prealloc # finds slice declarations that could potentially be pre-allocated
|
||||
- predeclared # finds code that shadows one of Go's predeclared identifiers
|
||||
- promlinter # checks Prometheus metrics naming via promlint
|
||||
- reassign # checks that package variables are not reassigned
|
||||
- revive # fast, configurable, extensible, flexible, and beautiful linter for Go
|
||||
- rowserrcheck # checks whether Err of rows is checked successfully
|
||||
- sqlclosecheck # checks that sql.Rows and sql.Stmt are closed
|
||||
- staticcheck # comprehensive checks for bugs and inefficiencies
|
||||
- testableexamples # checks if examples are testable
|
||||
- testpackage # makes you use a separate _test package
|
||||
- thelper # detects golang test helpers without t.Helper()
|
||||
- tparallel # detects inappropriate usage of t.Parallel()
|
||||
- unconvert # removes unnecessary type conversions
|
||||
- unparam # reports unused function parameters
|
||||
- unused # checks for unused constants, variables, functions and types
|
||||
- usestdlibvars # detects the possibility to use variables/constants from the Go standard library
|
||||
- varnamelen # checks that the length of a variable's name matches its scope
|
||||
- wastedassign # finds wasted assignment statements
|
||||
- whitespace # detects leading and trailing whitespace
|
||||
|
|
@ -1,41 +1,2 @@
|
|||
# Enable all rules by default
|
||||
default: true
|
||||
# Markdown linting configuration with all rules enabled
|
||||
# Prettier friendly markdownlint config (all formatting rules disabled)
|
||||
extends: markdownlint/style/prettier
|
||||
# MD003 heading-style - Header style
|
||||
MD003:
|
||||
style: atx # Use # style headers
|
||||
# MD004 ul-style - Unordered list style
|
||||
MD004:
|
||||
style: consistent # Be consistent with the first list style used
|
||||
# MD012 no-multiple-blanks - No multiple consecutive blank lines
|
||||
MD012:
|
||||
maximum: 1
|
||||
# MD013 line-length - Line length
|
||||
MD013:
|
||||
line_length: 100
|
||||
code_blocks: false
|
||||
tables: false
|
||||
# MD024 no-duplicate-header - No duplicate headers
|
||||
MD024:
|
||||
siblings_only: true # Allow duplicates if they're not siblings
|
||||
# MD026 no-trailing-punctuation - No trailing punctuation in header
|
||||
MD026:
|
||||
punctuation: .,;:!。,;:!
|
||||
# MD029 ol-prefix - Ordered list item prefix
|
||||
MD029:
|
||||
style: one_or_ordered
|
||||
# MD033 no-inline-html - No inline HTML
|
||||
MD033:
|
||||
allowed_elements: []
|
||||
# MD034 no-bare-urls - No bare URLs
|
||||
MD034: true
|
||||
# MD035 hr-style - Horizontal rule style
|
||||
MD035:
|
||||
style: "---"
|
||||
# MD041 first-line-heading - First line should be a top-level header
|
||||
MD041:
|
||||
level: 1
|
||||
# MD046 code-block-style - Code block style
|
||||
MD046:
|
||||
style: fenced
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
plugins:
|
||||
remark-preset-lint-consistent: true
|
||||
remark-preset-lint-recommended: true
|
||||
remark-lint-list-item-indent: true
|
||||
# Allow ATX-style headings (using #). Previously Trunk/remark was expecting
|
||||
# setext-style for certain heading levels which caused the "Unexpected ATX
|
||||
# heading, expected setext" errors. Setting this rule to 'atx' relaxes that.
|
||||
remark-lint-heading-style: [true, "atx"]
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
enable=all
|
||||
source-path=SCRIPTDIR
|
||||
disable=SC1090
|
||||
disable=SC1091
|
||||
disable=SC2154
|
||||
disable=SC2310
|
||||
disable=SC2312
|
||||
|
||||
# If you're having issues with shellcheck following source, disable the errors via:
|
||||
# disable=SC1090
|
||||
# disable=SC1091
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
[formats]
|
||||
markdoc = md
|
||||
# Repo-root Vale configuration for Trunk
|
||||
StylesPath = .trunk/valestyles
|
||||
MinAlertLevel = suggestion
|
||||
|
||||
[*.md]
|
||||
BasedOnStyles = Vale
|
||||
BasedOnStyles = Common, WriteGood, Microsoft
|
||||
Ignore = .github/ISSUE_TEMPLATE/** CLAUDE.md
|
||||
|
||||
[*]
|
||||
vocab = Project
|
||||
|
||||
# Disable spelling checks for technical terms
|
||||
Vale.Spelling = NO
|
||||
# Apply Code style to other files for comments
|
||||
BasedOnStyles = Common
|
||||
Ignore = **/.git/** .trunk/**
|
||||
|
|
|
|||
|
|
@ -1,9 +1,35 @@
|
|||
extends: default
|
||||
|
||||
rules:
|
||||
quoted-strings: disable
|
||||
key-duplicates: {}
|
||||
octal-values:
|
||||
forbid-implicit-octal: true
|
||||
line-length:
|
||||
max: 100
|
||||
level: warning
|
||||
allow-non-breakable-words: true
|
||||
allow-non-breakable-inline-mappings: true
|
||||
|
||||
# Other customizations
|
||||
comments:
|
||||
min-spaces-from-content: 1
|
||||
|
||||
document-start:
|
||||
present: false
|
||||
|
||||
indentation:
|
||||
spaces: 2
|
||||
indent-sequences: consistent
|
||||
|
||||
empty-lines:
|
||||
max: 2
|
||||
max-start: 0
|
||||
max-end: 0
|
||||
|
||||
quoted-strings: disable
|
||||
key-duplicates: {}
|
||||
octal-values:
|
||||
forbid-implicit-octal: true
|
||||
|
||||
# Strict whitespace rules
|
||||
trailing-spaces: enable
|
||||
new-line-at-end-of-file: enable
|
||||
new-lines:
|
||||
type: unix
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
Goroutine
|
||||
goroutines
|
||||
Mutex
|
||||
mutexes
|
||||
heredoc
|
||||
Profiler
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
# Copyright 2021 Praetorian Security, Inc.
|
||||
# Licensed 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.
|
||||
# GoKart analyzers configuration
|
||||
# Uncomment analyzers section below to create a new vulnerability type
|
||||
# analyzers:
|
||||
# # Each entry specifies a vulnerability type.
|
||||
# # Name of the vulnerability:
|
||||
# Test Sink:
|
||||
# # Description of this vulnerability
|
||||
# doc: Writing data to Printf()
|
||||
# # Message displayed when this vulnerability is found
|
||||
# message: Test Sink reachable by user input
|
||||
# # List of vulnerable functions used to identify this vulnerability
|
||||
# vuln_calls:
|
||||
# # Package name
|
||||
# log:
|
||||
# # Function name
|
||||
# - Printf
|
||||
# Each entry specifies a source that should be considered untrusted
|
||||
# If the package already exists in the sources section, add the variable/function/type underneath
|
||||
# Each package can contain multiple vulnerable sources.
|
||||
sources:
|
||||
# Sources that are defined in Go documentation as a variable go here (note: these variables will have an SSA type of Global).
|
||||
variables:
|
||||
os:
|
||||
- Args
|
||||
# Sources that are defined in Go documentation as a function go here.
|
||||
functions:
|
||||
flag:
|
||||
- Arg
|
||||
- Args
|
||||
os:
|
||||
- Environ
|
||||
- File
|
||||
crypto/tls:
|
||||
- LoadX509KeyPair
|
||||
- X509KeyPair
|
||||
os/user:
|
||||
- Lookup
|
||||
- LookupId
|
||||
- Current
|
||||
crypto/x509:
|
||||
- Subjects
|
||||
io:
|
||||
- ReadAtLeast
|
||||
- ReadFull
|
||||
database/sql:
|
||||
- Query
|
||||
- QueryRow
|
||||
bytes:
|
||||
- String
|
||||
- ReadBytes
|
||||
- ReadByte
|
||||
bufio:
|
||||
- Text
|
||||
- Bytes
|
||||
- ReadString
|
||||
- ReadSlice
|
||||
- ReadRune
|
||||
- ReadLine
|
||||
- ReadBytes
|
||||
- ReadByte
|
||||
archive/tar:
|
||||
- Next
|
||||
- FileInfo
|
||||
- Header
|
||||
net/url:
|
||||
- ParseQuery
|
||||
- ParseUriRequest
|
||||
- Parse
|
||||
- Query
|
||||
# Sources that are defined in Go documentation as a type go here (note: adding types will consider all functions that use that type to be tainted).
|
||||
types:
|
||||
net/http:
|
||||
- Request
|
||||
0
.trunk/scripts/fix_vale_suggestions.py
Normal file
0
.trunk/scripts/fix_vale_suggestions.py
Normal file
|
|
@ -6,61 +6,40 @@ cli:
|
|||
# Trunk provides extensibility via plugins. (https://docs.trunk.io/plugins)
|
||||
plugins:
|
||||
sources:
|
||||
- id: configs
|
||||
ref: v1.1.1
|
||||
uri: https://github.com/trunk-io/configs
|
||||
- id: trunk
|
||||
ref: v1.7.3
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
# Many linters and tools depend on runtimes - configure them here. (https://docs.trunk.io/runtimes)
|
||||
runtimes:
|
||||
enabled:
|
||||
- go@1.21.0
|
||||
- node@22.16.0
|
||||
- python@3.10.8
|
||||
- go@1.21.0
|
||||
# This is the section where you manage your linters. (https://docs.trunk.io/check/configuration)
|
||||
lint:
|
||||
disabled:
|
||||
- deno
|
||||
- remark-lint
|
||||
- markdown-table-prettify
|
||||
- biome
|
||||
- cspell
|
||||
- codespell
|
||||
enabled:
|
||||
- vale@3.12.0
|
||||
- checkov@3.2.477
|
||||
- dotenv-linter@3.3.0
|
||||
- git-diff-check
|
||||
- gofmt@1.20.4
|
||||
- gokart@0.5.1
|
||||
- golangci-lint2@2.5.0
|
||||
- markdownlint@0.45.0
|
||||
- osv-scanner@2.2.3
|
||||
- actionlint@1.7.7
|
||||
- checkov@3.2.477
|
||||
- cspell
|
||||
- dotenv-linter@3.3.0
|
||||
- git-diff-check
|
||||
- gitleaks@8.28.0
|
||||
- golangci-lint@1.64.8
|
||||
- isort@6.1.0
|
||||
- kube-linter@0.7.2
|
||||
- ls-lint@2.3.1
|
||||
- markdown-link-check@3.13.7
|
||||
- markdownlint-cli2@0.18.1
|
||||
- oxipng@9.1.5
|
||||
- pre-commit-hooks@6.0.0
|
||||
- prettier@3.6.2
|
||||
- semgrep@1.139.0
|
||||
- shellcheck@0.11.0
|
||||
- shfmt@3.6.0
|
||||
- snyk@1.1295.0
|
||||
- trivy@0.67.1
|
||||
- trunk-toolbox@0.5.4
|
||||
- trufflehog@3.90.8
|
||||
- vale@3.12.0
|
||||
- yamlfmt@0.17.2
|
||||
- yamllint@1.37.1
|
||||
ignore:
|
||||
- linters: [markdownlint-cli2]
|
||||
paths: [".github/ISSUE_TEMPLATE/**"]
|
||||
actions:
|
||||
disabled:
|
||||
- trunk-fmt-pre-commit
|
||||
enabled:
|
||||
- trunk-announce
|
||||
- trunk-check-pre-push
|
||||
# - trunk-fmt-pre-commit
|
||||
- trunk-fmt-pre-commit
|
||||
enabled:
|
||||
- trunk-upgrade-available
|
||||
|
|
|
|||
22
.trunk/valestyles/Common/AllowedWords.txt
Normal file
22
.trunk/valestyles/Common/AllowedWords.txt
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
CLAUDE
|
||||
gRPC
|
||||
apt
|
||||
cache-apt-pkgs
|
||||
trunk
|
||||
Trunk
|
||||
awalsh128
|
||||
pkg
|
||||
EOF
|
||||
|
||||
# Add technical/project tokens
|
||||
pprof
|
||||
cpu.prof
|
||||
mem.prof
|
||||
block.prof
|
||||
mutex
|
||||
goroutine
|
||||
GC
|
||||
cpuprofile
|
||||
|
||||
# Regex fragments
|
||||
lication
|
||||
9
.trunk/valestyles/Microsoft/AMPM.yml
Normal file
9
.trunk/valestyles/Microsoft/AMPM.yml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
extends: existence
|
||||
message: Use 'AM' or 'PM' (preceded by a space).
|
||||
link: https://docs.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/term-collections/date-time-terms
|
||||
level: error
|
||||
nonword: true
|
||||
tokens:
|
||||
- '\d{1,2}[AP]M'
|
||||
- '\d{1,2} ?[ap]m'
|
||||
- '\d{1,2} ?[aApP]\.[mM]\.'
|
||||
30
.trunk/valestyles/Microsoft/Accessibility.yml
Normal file
30
.trunk/valestyles/Microsoft/Accessibility.yml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
extends: existence
|
||||
message: "Don't use language (such as '%s') that defines people by their disability."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/term-collections/accessibility-terms
|
||||
level: suggestion
|
||||
ignorecase: true
|
||||
tokens:
|
||||
- a victim of
|
||||
- able-bodied
|
||||
- an epileptic
|
||||
- birth defect
|
||||
- crippled
|
||||
- differently abled
|
||||
- disabled
|
||||
- dumb
|
||||
- handicapped
|
||||
- handicaps
|
||||
- healthy person
|
||||
- hearing-impaired
|
||||
- lame
|
||||
- maimed
|
||||
- mentally handicapped
|
||||
- missing a limb
|
||||
- mute
|
||||
- non-verbal
|
||||
- normal person
|
||||
- sight-impaired
|
||||
- slow learner
|
||||
- stricken with
|
||||
- suffers from
|
||||
- vision-impaired
|
||||
64
.trunk/valestyles/Microsoft/Acronyms.yml
Normal file
64
.trunk/valestyles/Microsoft/Acronyms.yml
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
extends: conditional
|
||||
message: "'%s' has no definition."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/acronyms
|
||||
level: suggestion
|
||||
ignorecase: false
|
||||
# Ensures that the existence of 'first' implies the existence of 'second'.
|
||||
first: '\b([A-Z]{3,5})\b'
|
||||
second: '(?:\b[A-Z][a-z]+ )+\(([A-Z]{3,5})\)'
|
||||
# ... with the exception of these:
|
||||
exceptions:
|
||||
- API
|
||||
- ASP
|
||||
- CLI
|
||||
- CPU
|
||||
- CSS
|
||||
- CSV
|
||||
- DEBUG
|
||||
- DOM
|
||||
- DPI
|
||||
- FAQ
|
||||
- GCC
|
||||
- GDB
|
||||
- GET
|
||||
- GPU
|
||||
- GTK
|
||||
- GUI
|
||||
- HTML
|
||||
- HTTP
|
||||
- HTTPS
|
||||
- IDE
|
||||
- JAR
|
||||
- JSON
|
||||
- JSX
|
||||
- LESS
|
||||
- LLDB
|
||||
- NET
|
||||
- NOTE
|
||||
- NVDA
|
||||
- OSS
|
||||
- PATH
|
||||
- PDF
|
||||
- PHP
|
||||
- POST
|
||||
- RAM
|
||||
- REPL
|
||||
- RSA
|
||||
- SCM
|
||||
- SCSS
|
||||
- SDK
|
||||
- SQL
|
||||
- SSH
|
||||
- SSL
|
||||
- SVG
|
||||
- TBD
|
||||
- TCP
|
||||
- TODO
|
||||
- URI
|
||||
- URL
|
||||
- USB
|
||||
- UTF
|
||||
- XML
|
||||
- XSS
|
||||
- YAML
|
||||
- ZIP
|
||||
272
.trunk/valestyles/Microsoft/Adverbs.yml
Normal file
272
.trunk/valestyles/Microsoft/Adverbs.yml
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
extends: existence
|
||||
message: "Remove '%s' if it's not important to the meaning of the statement."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/word-choice/use-simple-words-concise-sentences
|
||||
ignorecase: true
|
||||
level: warning
|
||||
action:
|
||||
name: remove
|
||||
tokens:
|
||||
- abnormally
|
||||
- absentmindedly
|
||||
- accidentally
|
||||
- adventurously
|
||||
- anxiously
|
||||
- arrogantly
|
||||
- awkwardly
|
||||
- bashfully
|
||||
- beautifully
|
||||
- bitterly
|
||||
- bleakly
|
||||
- blindly
|
||||
- blissfully
|
||||
- boastfully
|
||||
- boldly
|
||||
- bravely
|
||||
- briefly
|
||||
- brightly
|
||||
- briskly
|
||||
- broadly
|
||||
- busily
|
||||
- calmly
|
||||
- carefully
|
||||
- carelessly
|
||||
- cautiously
|
||||
- cheerfully
|
||||
- cleverly
|
||||
- closely
|
||||
- coaxingly
|
||||
- colorfully
|
||||
- continually
|
||||
- coolly
|
||||
- courageously
|
||||
- crossly
|
||||
- cruelly
|
||||
- curiously
|
||||
- daintily
|
||||
- dearly
|
||||
- deceivingly
|
||||
- deeply
|
||||
- defiantly
|
||||
- deliberately
|
||||
- delightfully
|
||||
- diligently
|
||||
- dimly
|
||||
- doubtfully
|
||||
- dreamily
|
||||
- easily
|
||||
- effectively
|
||||
- elegantly
|
||||
- energetically
|
||||
- enormously
|
||||
- enthusiastically
|
||||
- excitedly
|
||||
- extremely
|
||||
- fairly
|
||||
- faithfully
|
||||
- famously
|
||||
- ferociously
|
||||
- fervently
|
||||
- fiercely
|
||||
- fondly
|
||||
- foolishly
|
||||
- fortunately
|
||||
- frankly
|
||||
- frantically
|
||||
- freely
|
||||
- frenetically
|
||||
- frightfully
|
||||
- furiously
|
||||
- generally
|
||||
- generously
|
||||
- gently
|
||||
- gladly
|
||||
- gleefully
|
||||
- gracefully
|
||||
- gratefully
|
||||
- greatly
|
||||
- greedily
|
||||
- happily
|
||||
- hastily
|
||||
- healthily
|
||||
- heavily
|
||||
- helplessly
|
||||
- honestly
|
||||
- hopelessly
|
||||
- hungrily
|
||||
- innocently
|
||||
- inquisitively
|
||||
- intensely
|
||||
- intently
|
||||
- interestingly
|
||||
- inwardly
|
||||
- irritably
|
||||
- jaggedly
|
||||
- jealously
|
||||
- jovially
|
||||
- joyfully
|
||||
- joyously
|
||||
- jubilantly
|
||||
- judgmentally
|
||||
- justly
|
||||
- keenly
|
||||
- kiddingly
|
||||
- kindheartedly
|
||||
- knavishly
|
||||
- knowingly
|
||||
- knowledgeably
|
||||
- lazily
|
||||
- lightly
|
||||
- limply
|
||||
- lively
|
||||
- loftily
|
||||
- longingly
|
||||
- loosely
|
||||
- loudly
|
||||
- lovingly
|
||||
- loyally
|
||||
- madly
|
||||
- majestically
|
||||
- meaningfully
|
||||
- mechanically
|
||||
- merrily
|
||||
- miserably
|
||||
- mockingly
|
||||
- mortally
|
||||
- mysteriously
|
||||
- naturally
|
||||
- nearly
|
||||
- neatly
|
||||
- nervously
|
||||
- nicely
|
||||
- noisily
|
||||
- obediently
|
||||
- obnoxiously
|
||||
- oddly
|
||||
- offensively
|
||||
- optimistically
|
||||
- overconfidently
|
||||
- painfully
|
||||
- partially
|
||||
- patiently
|
||||
- perfectly
|
||||
- playfully
|
||||
- politely
|
||||
- poorly
|
||||
- positively
|
||||
- potentially
|
||||
- powerfully
|
||||
- promptly
|
||||
- properly
|
||||
- punctually
|
||||
- quaintly
|
||||
- queasily
|
||||
- queerly
|
||||
- questionably
|
||||
- quickly
|
||||
- quietly
|
||||
- quirkily
|
||||
- quite
|
||||
- quizzically
|
||||
- randomly
|
||||
- rapidly
|
||||
- rarely
|
||||
- readily
|
||||
- really
|
||||
- reassuringly
|
||||
- recklessly
|
||||
- regularly
|
||||
- reluctantly
|
||||
- repeatedly
|
||||
- reproachfully
|
||||
- restfully
|
||||
- righteously
|
||||
- rightfully
|
||||
- rigidly
|
||||
- roughly
|
||||
- rudely
|
||||
- safely
|
||||
- scarcely
|
||||
- scarily
|
||||
- searchingly
|
||||
- sedately
|
||||
- seemingly
|
||||
- selfishly
|
||||
- separately
|
||||
- seriously
|
||||
- shakily
|
||||
- sharply
|
||||
- sheepishly
|
||||
- shrilly
|
||||
- shyly
|
||||
- silently
|
||||
- sleepily
|
||||
- slowly
|
||||
- smoothly
|
||||
- softly
|
||||
- solemnly
|
||||
- solidly
|
||||
- speedily
|
||||
- stealthily
|
||||
- sternly
|
||||
- strictly
|
||||
- suddenly
|
||||
- supposedly
|
||||
- surprisingly
|
||||
- suspiciously
|
||||
- sweetly
|
||||
- swiftly
|
||||
- sympathetically
|
||||
- tenderly
|
||||
- tensely
|
||||
- terribly
|
||||
- thankfully
|
||||
- thoroughly
|
||||
- thoughtfully
|
||||
- tightly
|
||||
- tremendously
|
||||
- triumphantly
|
||||
- truthfully
|
||||
- ultimately
|
||||
- unabashedly
|
||||
- unaccountably
|
||||
- unbearably
|
||||
- unethically
|
||||
- unexpectedly
|
||||
- unfortunately
|
||||
- unimpressively
|
||||
- unnaturally
|
||||
- unnecessarily
|
||||
- urgently
|
||||
- usefully
|
||||
- uselessly
|
||||
- utterly
|
||||
- vacantly
|
||||
- vaguely
|
||||
- vainly
|
||||
- valiantly
|
||||
- vastly
|
||||
- verbally
|
||||
- very
|
||||
- viciously
|
||||
- victoriously
|
||||
- violently
|
||||
- vivaciously
|
||||
- voluntarily
|
||||
- warmly
|
||||
- weakly
|
||||
- wearily
|
||||
- wetly
|
||||
- wholly
|
||||
- wildly
|
||||
- willfully
|
||||
- wisely
|
||||
- woefully
|
||||
- wonderfully
|
||||
- worriedly
|
||||
- yawningly
|
||||
- yearningly
|
||||
- yieldingly
|
||||
- youthfully
|
||||
- zealously
|
||||
- zestfully
|
||||
- zestily
|
||||
11
.trunk/valestyles/Microsoft/Auto.yml
Normal file
11
.trunk/valestyles/Microsoft/Auto.yml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
extends: existence
|
||||
message: "In general, don't hyphenate '%s'."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/a/auto
|
||||
ignorecase: true
|
||||
level: error
|
||||
action:
|
||||
name: convert
|
||||
params:
|
||||
- simple
|
||||
tokens:
|
||||
- 'auto-\w+'
|
||||
14
.trunk/valestyles/Microsoft/Avoid.yml
Normal file
14
.trunk/valestyles/Microsoft/Avoid.yml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
extends: existence
|
||||
message: "Don't use '%s'. See the A-Z word list for details."
|
||||
# See the A-Z word list
|
||||
link: https://docs.microsoft.com/en-us/style-guide
|
||||
ignorecase: true
|
||||
level: error
|
||||
tokens:
|
||||
- abortion
|
||||
- and so on
|
||||
- app(?:lication)?s? (?:developer|program)
|
||||
- app(?:lication)? file
|
||||
- backbone
|
||||
- backend
|
||||
- contiguous selection
|
||||
50
.trunk/valestyles/Microsoft/Contractions.yml
Normal file
50
.trunk/valestyles/Microsoft/Contractions.yml
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
extends: substitution
|
||||
message: "Use '%s' instead of '%s'."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/word-choice/use-contractions
|
||||
level: error
|
||||
ignorecase: true
|
||||
action:
|
||||
name: replace
|
||||
swap:
|
||||
are not: aren't
|
||||
cannot: can't
|
||||
could not: couldn't
|
||||
did not: didn't
|
||||
do not: don't
|
||||
does not: doesn't
|
||||
has not: hasn't
|
||||
have not: haven't
|
||||
how is: how's
|
||||
is not: isn't
|
||||
|
||||
'it is(?!\.)': it's
|
||||
'it''s(?=\.)': it is
|
||||
|
||||
should not: shouldn't
|
||||
|
||||
"that is(?![.,])": that's
|
||||
'that''s(?=\.)': that is
|
||||
|
||||
'they are(?!\.)': they're
|
||||
'they''re(?=\.)': they are
|
||||
|
||||
was not: wasn't
|
||||
|
||||
'we are(?!\.)': we're
|
||||
'we''re(?=\.)': we are
|
||||
|
||||
'we have(?!\.)': we've
|
||||
'we''ve(?=\.)': we have
|
||||
|
||||
were not: weren't
|
||||
|
||||
'what is(?!\.)': what's
|
||||
'what''s(?=\.)': what is
|
||||
|
||||
'when is(?!\.)': when's
|
||||
'when''s(?=\.)': when is
|
||||
|
||||
'where is(?!\.)': where's
|
||||
'where''s(?=\.)': where is
|
||||
|
||||
will not: won't
|
||||
13
.trunk/valestyles/Microsoft/Dashes.yml
Normal file
13
.trunk/valestyles/Microsoft/Dashes.yml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
extends: existence
|
||||
message: "Remove the spaces around '%s'."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/punctuation/dashes-hyphens/emes
|
||||
ignorecase: true
|
||||
nonword: true
|
||||
level: error
|
||||
action:
|
||||
name: edit
|
||||
params:
|
||||
- trim
|
||||
- " "
|
||||
tokens:
|
||||
- '\s[—–]\s|\s[—–]|[—–]\s'
|
||||
10
.trunk/valestyles/Microsoft/DateFormat.yml
Normal file
10
.trunk/valestyles/Microsoft/DateFormat.yml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
extends: existence
|
||||
message: Use 'July 31, 2016' format, not '%s'.
|
||||
link: https://docs.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/term-collections/date-time-terms
|
||||
ignorecase: true
|
||||
level: error
|
||||
nonword: true
|
||||
tokens:
|
||||
- '\d{1,2}
|
||||
(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)|May|Jun(?:e)|Jul(?:y)|Aug(?:ust)|Sep(?:tember)?|Oct(?:ober)|Nov(?:ember)?|Dec(?:ember)?)
|
||||
\d{4}'
|
||||
40
.trunk/valestyles/Microsoft/DateNumbers.yml
Normal file
40
.trunk/valestyles/Microsoft/DateNumbers.yml
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
extends: existence
|
||||
message: "Don't use ordinal numbers for dates."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/numbers#numbers-in-dates
|
||||
level: error
|
||||
nonword: true
|
||||
ignorecase: true
|
||||
raw:
|
||||
- \b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)|May|Jun(?:e)|Jul(?:y)|Aug(?:ust)|Sep(?:tember)?|Oct(?:ober)|Nov(?:ember)?|Dec(?:ember)?)\b\s*
|
||||
tokens:
|
||||
- first
|
||||
- second
|
||||
- third
|
||||
- fourth
|
||||
- fifth
|
||||
- sixth
|
||||
- seventh
|
||||
- eighth
|
||||
- ninth
|
||||
- tenth
|
||||
- eleventh
|
||||
- twelfth
|
||||
- thirteenth
|
||||
- fourteenth
|
||||
- fifteenth
|
||||
- sixteenth
|
||||
- seventeenth
|
||||
- eighteenth
|
||||
- nineteenth
|
||||
- twentieth
|
||||
- twenty-first
|
||||
- twenty-second
|
||||
- twenty-third
|
||||
- twenty-fourth
|
||||
- twenty-fifth
|
||||
- twenty-sixth
|
||||
- twenty-seventh
|
||||
- twenty-eighth
|
||||
- twenty-ninth
|
||||
- thirtieth
|
||||
- thirty-first
|
||||
8
.trunk/valestyles/Microsoft/DateOrder.yml
Normal file
8
.trunk/valestyles/Microsoft/DateOrder.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
extends: existence
|
||||
message: "Always spell out the name of the month."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/numbers#numbers-in-dates
|
||||
ignorecase: true
|
||||
level: error
|
||||
nonword: true
|
||||
tokens:
|
||||
- '\b\d{1,2}/\d{1,2}/(?:\d{4}|\d{2})\b'
|
||||
9
.trunk/valestyles/Microsoft/Ellipses.yml
Normal file
9
.trunk/valestyles/Microsoft/Ellipses.yml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
extends: existence
|
||||
message: "In general, don't use an ellipsis."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/punctuation/ellipses
|
||||
nonword: true
|
||||
level: warning
|
||||
action:
|
||||
name: remove
|
||||
tokens:
|
||||
- '\.\.\.'
|
||||
16
.trunk/valestyles/Microsoft/FirstPerson.yml
Normal file
16
.trunk/valestyles/Microsoft/FirstPerson.yml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
extends: existence
|
||||
message: "Use first person (such as '%s') sparingly."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/grammar/person
|
||||
ignorecase: true
|
||||
level: warning
|
||||
nonword: true
|
||||
tokens:
|
||||
- (?:^|\s)I(?=\s)
|
||||
- (?:^|\s)I(?=,\s)
|
||||
- \bI'd\b
|
||||
- \bI'll\b
|
||||
- \bI'm\b
|
||||
- \bI've\b
|
||||
- \bme\b
|
||||
- \bmy\b
|
||||
- \bmine\b
|
||||
13
.trunk/valestyles/Microsoft/Foreign.yml
Normal file
13
.trunk/valestyles/Microsoft/Foreign.yml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
extends: substitution
|
||||
message: "Use '%s' instead of '%s'."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/word-choice/use-us-spelling-avoid-non-english-words
|
||||
ignorecase: true
|
||||
level: error
|
||||
nonword: true
|
||||
action:
|
||||
name: replace
|
||||
swap:
|
||||
'\b(?:eg|e\.g\.)[\s,]': for example
|
||||
'\b(?:ie|i\.e\.)[\s,]': that is
|
||||
'\b(?:viz\.)[\s,]': namely
|
||||
'\b(?:ergo)[\s,]': therefore
|
||||
8
.trunk/valestyles/Microsoft/Gender.yml
Normal file
8
.trunk/valestyles/Microsoft/Gender.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
extends: existence
|
||||
message: "Don't use '%s'."
|
||||
link: https://github.com/MicrosoftDocs/microsoft-style-guide/blob/master/styleguide/grammar/nouns-pronouns.md#pronouns-and-gender
|
||||
level: error
|
||||
ignorecase: true
|
||||
tokens:
|
||||
- he/she
|
||||
- s/he
|
||||
42
.trunk/valestyles/Microsoft/GenderBias.yml
Normal file
42
.trunk/valestyles/Microsoft/GenderBias.yml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
extends: substitution
|
||||
message: "Consider using '%s' instead of '%s'."
|
||||
ignorecase: true
|
||||
level: error
|
||||
action:
|
||||
name: replace
|
||||
swap:
|
||||
(?:alumna|alumnus): graduate
|
||||
(?:alumnae|alumni): graduates
|
||||
air(?:m[ae]n|wom[ae]n): pilot(s)
|
||||
anchor(?:m[ae]n|wom[ae]n): anchor(s)
|
||||
authoress: author
|
||||
camera(?:m[ae]n|wom[ae]n): camera operator(s)
|
||||
door(?:m[ae]|wom[ae]n): concierge(s)
|
||||
draft(?:m[ae]n|wom[ae]n): drafter(s)
|
||||
fire(?:m[ae]n|wom[ae]n): firefighter(s)
|
||||
fisher(?:m[ae]n|wom[ae]n): fisher(s)
|
||||
fresh(?:m[ae]n|wom[ae]n): first-year student(s)
|
||||
garbage(?:m[ae]n|wom[ae]n): waste collector(s)
|
||||
lady lawyer: lawyer
|
||||
ladylike: courteous
|
||||
mail(?:m[ae]n|wom[ae]n): mail carriers
|
||||
man and wife: husband and wife
|
||||
man enough: strong enough
|
||||
mankind: human kind
|
||||
manmade: manufactured
|
||||
manpower: personnel
|
||||
middle(?:m[ae]n|wom[ae]n): intermediary
|
||||
news(?:m[ae]n|wom[ae]n): journalist(s)
|
||||
ombuds(?:man|woman): ombuds
|
||||
oneupmanship: upstaging
|
||||
poetess: poet
|
||||
police(?:m[ae]n|wom[ae]n): police officer(s)
|
||||
repair(?:m[ae]n|wom[ae]n): technician(s)
|
||||
sales(?:m[ae]n|wom[ae]n): salesperson or sales people
|
||||
service(?:m[ae]n|wom[ae]n): soldier(s)
|
||||
steward(?:ess)?: flight attendant
|
||||
tribes(?:m[ae]n|wom[ae]n): tribe member(s)
|
||||
waitress: waiter
|
||||
woman doctor: doctor
|
||||
woman scientist[s]?: scientist(s)
|
||||
work(?:m[ae]n|wom[ae]n): worker(s)
|
||||
11
.trunk/valestyles/Microsoft/GeneralURL.yml
Normal file
11
.trunk/valestyles/Microsoft/GeneralURL.yml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
extends: existence
|
||||
message: "For a general audience, use 'address' rather than 'URL'."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/urls-web-addresses
|
||||
level: warning
|
||||
action:
|
||||
name: replace
|
||||
params:
|
||||
- URL
|
||||
- address
|
||||
tokens:
|
||||
- URL
|
||||
7
.trunk/valestyles/Microsoft/HeadingAcronyms.yml.disabled
Normal file
7
.trunk/valestyles/Microsoft/HeadingAcronyms.yml.disabled
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
extends: existence
|
||||
message: "Avoid using acronyms in a title or heading."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/acronyms#be-careful-with-acronyms-in-titles-and-headings
|
||||
level: warning
|
||||
scope: heading
|
||||
tokens:
|
||||
- '[A-Z]{2,4}'
|
||||
8
.trunk/valestyles/Microsoft/HeadingColons.yml
Normal file
8
.trunk/valestyles/Microsoft/HeadingColons.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
extends: existence
|
||||
message: "Capitalize '%s'."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/punctuation/colons
|
||||
nonword: true
|
||||
level: error
|
||||
scope: heading
|
||||
tokens:
|
||||
- ':\s[a-z]'
|
||||
13
.trunk/valestyles/Microsoft/HeadingPunctuation.yml.disabled
Normal file
13
.trunk/valestyles/Microsoft/HeadingPunctuation.yml.disabled
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
extends: existence
|
||||
message: "Don't use end punctuation in headings."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/punctuation/periods
|
||||
nonword: true
|
||||
level: warning
|
||||
scope: heading
|
||||
action:
|
||||
name: edit
|
||||
params:
|
||||
- trim_right
|
||||
- ".?!"
|
||||
tokens:
|
||||
- "[a-z][.?!]$"
|
||||
28
.trunk/valestyles/Microsoft/Headings.yml.disabled
Normal file
28
.trunk/valestyles/Microsoft/Headings.yml.disabled
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
extends: capitalization
|
||||
message: "'%s' should use sentence-style capitalization."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/capitalization
|
||||
level: suggestion
|
||||
scope: heading
|
||||
match: $sentence
|
||||
indicators:
|
||||
- ':'
|
||||
exceptions:
|
||||
- Azure
|
||||
- CLI
|
||||
- Code
|
||||
- Cosmos
|
||||
- Docker
|
||||
- Emmet
|
||||
- I
|
||||
- Kubernetes
|
||||
- Linux
|
||||
- macOS
|
||||
- Marketplace
|
||||
- MongoDB
|
||||
- REPL
|
||||
- Studio
|
||||
- TypeScript
|
||||
- URLs
|
||||
- Visual
|
||||
- VS
|
||||
- Windows
|
||||
14
.trunk/valestyles/Microsoft/Hyphens.yml
Normal file
14
.trunk/valestyles/Microsoft/Hyphens.yml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
extends: existence
|
||||
message: "'%s' doesn't need a hyphen."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/punctuation/dashes-hyphens/hyphens
|
||||
level: warning
|
||||
ignorecase: false
|
||||
nonword: true
|
||||
action:
|
||||
name: edit
|
||||
params:
|
||||
- regex
|
||||
- "-"
|
||||
- " "
|
||||
tokens:
|
||||
- '\b[^\s-]+ly-\w+\b'
|
||||
2
.trunk/valestyles/Microsoft/Microsoft.ini
Normal file
2
.trunk/valestyles/Microsoft/Microsoft.ini
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# Minimal placeholder for Microsoft-style rules
|
||||
version = 1
|
||||
13
.trunk/valestyles/Microsoft/Negative.yml
Normal file
13
.trunk/valestyles/Microsoft/Negative.yml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
extends: existence
|
||||
message: "Form a negative number with an en dash, not a hyphen."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/numbers
|
||||
nonword: true
|
||||
level: error
|
||||
action:
|
||||
name: edit
|
||||
params:
|
||||
- regex
|
||||
- "-"
|
||||
- "–"
|
||||
tokens:
|
||||
- '(?<=\s)-\d+(?:\.\d+)?\b'
|
||||
13
.trunk/valestyles/Microsoft/Ordinal.yml
Normal file
13
.trunk/valestyles/Microsoft/Ordinal.yml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
extends: existence
|
||||
message: "Don't add -ly to an ordinal number."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/numbers
|
||||
level: error
|
||||
action:
|
||||
name: edit
|
||||
params:
|
||||
- trim
|
||||
- ly
|
||||
tokens:
|
||||
- firstly
|
||||
- secondly
|
||||
- thirdly
|
||||
8
.trunk/valestyles/Microsoft/OxfordComma.yml
Normal file
8
.trunk/valestyles/Microsoft/OxfordComma.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
extends: existence
|
||||
message: "Use the Oxford comma in '%s'."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/punctuation/commas
|
||||
scope: sentence
|
||||
level: suggestion
|
||||
nonword: true
|
||||
tokens:
|
||||
- '(?:[^\s,]+,){1,} \w+ (?:and|or) \w+[.?!]'
|
||||
183
.trunk/valestyles/Microsoft/Passive.yml
Normal file
183
.trunk/valestyles/Microsoft/Passive.yml
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
extends: existence
|
||||
message: "'%s' looks like passive voice."
|
||||
ignorecase: true
|
||||
level: suggestion
|
||||
raw:
|
||||
- \b(am|are|were|being|is|been|was|be)\b\s*
|
||||
tokens:
|
||||
- '[\w]+ed'
|
||||
- awoken
|
||||
- beat
|
||||
- become
|
||||
- been
|
||||
- begun
|
||||
- bent
|
||||
- beset
|
||||
- bet
|
||||
- bid
|
||||
- bidden
|
||||
- bitten
|
||||
- bled
|
||||
- blown
|
||||
- born
|
||||
- bought
|
||||
- bound
|
||||
- bred
|
||||
- broadcast
|
||||
- broken
|
||||
- brought
|
||||
- built
|
||||
- burnt
|
||||
- burst
|
||||
- cast
|
||||
- caught
|
||||
- chosen
|
||||
- clung
|
||||
- come
|
||||
- cost
|
||||
- crept
|
||||
- cut
|
||||
- dealt
|
||||
- dived
|
||||
- done
|
||||
- drawn
|
||||
- dreamt
|
||||
- driven
|
||||
- drunk
|
||||
- dug
|
||||
- eaten
|
||||
- fallen
|
||||
- fed
|
||||
- felt
|
||||
- fit
|
||||
- fled
|
||||
- flown
|
||||
- flung
|
||||
- forbidden
|
||||
- foregone
|
||||
- forgiven
|
||||
- forgotten
|
||||
- forsaken
|
||||
- fought
|
||||
- found
|
||||
- frozen
|
||||
- given
|
||||
- gone
|
||||
- gotten
|
||||
- ground
|
||||
- grown
|
||||
- heard
|
||||
- held
|
||||
- hidden
|
||||
- hit
|
||||
- hung
|
||||
- hurt
|
||||
- kept
|
||||
- knelt
|
||||
- knit
|
||||
- known
|
||||
- laid
|
||||
- lain
|
||||
- leapt
|
||||
- learnt
|
||||
- led
|
||||
- left
|
||||
- lent
|
||||
- let
|
||||
- lighted
|
||||
- lost
|
||||
- made
|
||||
- meant
|
||||
- met
|
||||
- misspelt
|
||||
- mistaken
|
||||
- mown
|
||||
- overcome
|
||||
- overdone
|
||||
- overtaken
|
||||
- overthrown
|
||||
- paid
|
||||
- pled
|
||||
- proven
|
||||
- put
|
||||
- quit
|
||||
- read
|
||||
- rid
|
||||
- ridden
|
||||
- risen
|
||||
- run
|
||||
- rung
|
||||
- said
|
||||
- sat
|
||||
- sawn
|
||||
- seen
|
||||
- sent
|
||||
- set
|
||||
- sewn
|
||||
- shaken
|
||||
- shaven
|
||||
- shed
|
||||
- shod
|
||||
- shone
|
||||
- shorn
|
||||
- shot
|
||||
- shown
|
||||
- shrunk
|
||||
- shut
|
||||
- slain
|
||||
- slept
|
||||
- slid
|
||||
- slit
|
||||
- slung
|
||||
- smitten
|
||||
- sold
|
||||
- sought
|
||||
- sown
|
||||
- sped
|
||||
- spent
|
||||
- spilt
|
||||
- spit
|
||||
- split
|
||||
- spoken
|
||||
- spread
|
||||
- sprung
|
||||
- spun
|
||||
- stolen
|
||||
- stood
|
||||
- stridden
|
||||
- striven
|
||||
- struck
|
||||
- strung
|
||||
- stuck
|
||||
- stung
|
||||
- stunk
|
||||
- sung
|
||||
- sunk
|
||||
- swept
|
||||
- swollen
|
||||
- sworn
|
||||
- swum
|
||||
- swung
|
||||
- taken
|
||||
- taught
|
||||
- thought
|
||||
- thrived
|
||||
- thrown
|
||||
- thrust
|
||||
- told
|
||||
- torn
|
||||
- trodden
|
||||
- understood
|
||||
- upheld
|
||||
- upset
|
||||
- wed
|
||||
- wept
|
||||
- withheld
|
||||
- withstood
|
||||
- woken
|
||||
- won
|
||||
- worn
|
||||
- wound
|
||||
- woven
|
||||
- written
|
||||
- wrung
|
||||
7
.trunk/valestyles/Microsoft/Percentages.yml
Normal file
7
.trunk/valestyles/Microsoft/Percentages.yml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
extends: existence
|
||||
message: "Use a numeral plus the units."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/numbers
|
||||
nonword: true
|
||||
level: error
|
||||
tokens:
|
||||
- '\b[a-zA-z]+\spercent\b'
|
||||
7
.trunk/valestyles/Microsoft/Plurals.yml
Normal file
7
.trunk/valestyles/Microsoft/Plurals.yml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
extends: existence
|
||||
message: "Don't add '%s' to a singular noun. Use plural instead."
|
||||
ignorecase: true
|
||||
level: error
|
||||
link: https://learn.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/s/s-es
|
||||
raw:
|
||||
- '\(s\)|\(es\)'
|
||||
7
.trunk/valestyles/Microsoft/Quotes.yml
Normal file
7
.trunk/valestyles/Microsoft/Quotes.yml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
extends: existence
|
||||
message: "Punctuation should be inside the quotes."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/punctuation/quotation-marks
|
||||
level: error
|
||||
nonword: true
|
||||
tokens:
|
||||
- '["“][^"”“]+["”][.,]'
|
||||
13
.trunk/valestyles/Microsoft/RangeTime.yml
Normal file
13
.trunk/valestyles/Microsoft/RangeTime.yml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
extends: existence
|
||||
message: "Use 'to' instead of a dash in '%s'."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/numbers
|
||||
nonword: true
|
||||
level: error
|
||||
action:
|
||||
name: edit
|
||||
params:
|
||||
- regex
|
||||
- "[-–]"
|
||||
- "to"
|
||||
tokens:
|
||||
- '\b(?:AM|PM)\s?[-–]\s?.+(?:AM|PM)\b'
|
||||
8
.trunk/valestyles/Microsoft/Semicolon.yml
Normal file
8
.trunk/valestyles/Microsoft/Semicolon.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
extends: existence
|
||||
message: "Try to simplify this sentence."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/punctuation/semicolons
|
||||
nonword: true
|
||||
scope: sentence
|
||||
level: suggestion
|
||||
tokens:
|
||||
- ";"
|
||||
6
.trunk/valestyles/Microsoft/SentenceLength.yml
Normal file
6
.trunk/valestyles/Microsoft/SentenceLength.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
extends: occurrence
|
||||
message: "Try to keep sentences short (< 30 words)."
|
||||
scope: sentence
|
||||
level: suggestion
|
||||
max: 30
|
||||
token: \b(\w+)\b
|
||||
8
.trunk/valestyles/Microsoft/Spacing.yml
Normal file
8
.trunk/valestyles/Microsoft/Spacing.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
extends: existence
|
||||
message: "'%s' should have one space."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/punctuation/periods
|
||||
level: error
|
||||
nonword: true
|
||||
tokens:
|
||||
- "[a-z][.?!] {2,}[A-Z]"
|
||||
- "[a-z][.?!][A-Z]"
|
||||
7
.trunk/valestyles/Microsoft/Suspended.yml
Normal file
7
.trunk/valestyles/Microsoft/Suspended.yml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
extends: existence
|
||||
message: "Don't use '%s' unless space is limited."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/punctuation/dashes-hyphens/hyphens
|
||||
ignorecase: true
|
||||
level: warning
|
||||
tokens:
|
||||
- '\w+- and \w+-'
|
||||
42
.trunk/valestyles/Microsoft/Terms.yml
Normal file
42
.trunk/valestyles/Microsoft/Terms.yml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
extends: substitution
|
||||
message: "Prefer '%s' over '%s'."
|
||||
# term preference should be based on microsoft style guide, such as
|
||||
link: https://learn.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/a/adapter
|
||||
level: warning
|
||||
ignorecase: true
|
||||
action:
|
||||
name: replace
|
||||
swap:
|
||||
"(?:agent|virtual assistant|intelligent personal assistant)": personal digital assistant
|
||||
"(?:assembler|machine language)": assembly language
|
||||
"(?:drive C:|drive C>|C: drive)": drive C
|
||||
"(?:internet bot|web robot)s?": bot(s)
|
||||
"(?:microsoft cloud|the cloud)": cloud
|
||||
"(?:mobile|smart) ?phone": phone
|
||||
"24/7": every day
|
||||
"audio(?:-| )book": audiobook
|
||||
"back(?:-| )light": backlight
|
||||
"chat ?bots?": chatbot(s)
|
||||
adaptor: adapter
|
||||
administrate: administer
|
||||
afterwards: afterward
|
||||
alphabetic: alphabetical
|
||||
alphanumerical: alphanumeric
|
||||
an URL: a URL
|
||||
anti-aliasing: antialiasing
|
||||
anti-malware: antimalware
|
||||
anti-spyware: antispyware
|
||||
anti-virus: antivirus
|
||||
appendixes: appendices
|
||||
artificial intelligence: AI
|
||||
caap: CaaP
|
||||
conversation-as-a-platform: conversation as a platform
|
||||
eb: EB
|
||||
gb: GB
|
||||
gbps: Gbps
|
||||
kb: KB
|
||||
keypress: keystroke
|
||||
mb: MB
|
||||
pb: PB
|
||||
tb: TB
|
||||
zb: ZB
|
||||
9
.trunk/valestyles/Microsoft/URLFormat.yml
Normal file
9
.trunk/valestyles/Microsoft/URLFormat.yml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
extends: substitution
|
||||
message: Use 'of' (not 'for') to describe the relationship of the word URL to a resource.
|
||||
ignorecase: true
|
||||
link: https://learn.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/u/url
|
||||
level: suggestion
|
||||
action:
|
||||
name: replace
|
||||
swap:
|
||||
URL for: URL of
|
||||
16
.trunk/valestyles/Microsoft/Units.yml
Normal file
16
.trunk/valestyles/Microsoft/Units.yml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
extends: existence
|
||||
message: "Don't spell out the number in '%s'."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/term-collections/units-of-measure-terms
|
||||
level: error
|
||||
raw:
|
||||
- '[a-zA-Z]+\s'
|
||||
tokens:
|
||||
- "(?:centi|milli)?meters"
|
||||
- "(?:kilo)?grams"
|
||||
- "(?:kilo)?meters"
|
||||
- "(?:mega)?pixels"
|
||||
- cm
|
||||
- inches
|
||||
- lb
|
||||
- miles
|
||||
- pounds
|
||||
25
.trunk/valestyles/Microsoft/Vocab.yml
Normal file
25
.trunk/valestyles/Microsoft/Vocab.yml
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
extends: existence
|
||||
message: "Verify your use of '%s' with the A-Z word list."
|
||||
link: "https://docs.microsoft.com/en-us/style-guide"
|
||||
level: suggestion
|
||||
ignorecase: true
|
||||
tokens:
|
||||
- above
|
||||
- accessible
|
||||
- actionable
|
||||
- against
|
||||
- alarm
|
||||
- alert
|
||||
- alias
|
||||
- allows?
|
||||
- and/or
|
||||
- as well as
|
||||
- assure
|
||||
- author
|
||||
- avg
|
||||
- beta
|
||||
- ensure
|
||||
- he
|
||||
- insure
|
||||
- sample
|
||||
- she
|
||||
11
.trunk/valestyles/Microsoft/We.yml
Normal file
11
.trunk/valestyles/Microsoft/We.yml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
extends: existence
|
||||
message: "Try to avoid using first-person plural like '%s'."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/grammar/person#avoid-first-person-plural
|
||||
level: warning
|
||||
ignorecase: true
|
||||
tokens:
|
||||
- we
|
||||
- we'(?:ve|re)
|
||||
- ours?
|
||||
- us
|
||||
- let's
|
||||
127
.trunk/valestyles/Microsoft/Wordiness.yml
Normal file
127
.trunk/valestyles/Microsoft/Wordiness.yml
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
extends: substitution
|
||||
message: "Consider using '%s' instead of '%s'."
|
||||
link: https://docs.microsoft.com/en-us/style-guide/word-choice/use-simple-words-concise-sentences
|
||||
ignorecase: true
|
||||
level: suggestion
|
||||
action:
|
||||
name: replace
|
||||
swap:
|
||||
"sufficient number(?: of)?": enough
|
||||
(?:extract|take away|eliminate): remove
|
||||
(?:in order to|as a means to): to
|
||||
(?:inform|let me know): tell
|
||||
(?:previous|prior) to: before
|
||||
(?:utilize|make use of): use
|
||||
a (?:large)? majority of: most
|
||||
a (?:large)? number of: many
|
||||
a myriad of: myriad
|
||||
adversely impact: hurt
|
||||
all across: across
|
||||
all of a sudden: suddenly
|
||||
all of these: these
|
||||
all of(?! a sudden| these): all
|
||||
all-time record: record
|
||||
almost all: most
|
||||
almost never: seldom
|
||||
along the lines of: similar to
|
||||
an adequate number of: enough
|
||||
an appreciable number of: many
|
||||
an estimated: about
|
||||
any and all: all
|
||||
are in agreement: agree
|
||||
as a matter of fact: in fact
|
||||
as a means of: to
|
||||
as a result of: because of
|
||||
as of yet: yet
|
||||
as per: per
|
||||
at a later date: later
|
||||
at all times: always
|
||||
at the present time: now
|
||||
at this point in time: at this point
|
||||
based in large part on: based on
|
||||
based on the fact that: because
|
||||
basic necessity: necessity
|
||||
because of the fact that: because
|
||||
came to a realization: realized
|
||||
came to an abrupt end: ended abruptly
|
||||
carry out an evaluation of: evaluate
|
||||
close down: close
|
||||
closed down: closed
|
||||
complete stranger: stranger
|
||||
completely separate: separate
|
||||
concerning the matter of: regarding
|
||||
conduct a review of: review
|
||||
conduct an investigation: investigate
|
||||
conduct experiments: experiment
|
||||
continue on: continue
|
||||
despite the fact that: although
|
||||
disappear from sight: disappear
|
||||
doomed to fail: doomed
|
||||
drag and drop: drag
|
||||
drag-and-drop: drag
|
||||
due to the fact that: because
|
||||
during the period of: during
|
||||
during the time that: while
|
||||
emergency situation: emergency
|
||||
establish connectivity: connect
|
||||
except when: unless
|
||||
excessive number: too many
|
||||
extend an invitation: invite
|
||||
fall down: fall
|
||||
fell down: fell
|
||||
for the duration of: during
|
||||
gather together: gather
|
||||
has the ability to: can
|
||||
has the capacity to: can
|
||||
has the opportunity to: could
|
||||
hold a meeting: meet
|
||||
if this is not the case: if not
|
||||
in a careful manner: carefully
|
||||
in a thoughtful manner: thoughtfully
|
||||
in a timely manner: timely
|
||||
in addition: also
|
||||
in an effort to: to
|
||||
in between: between
|
||||
in lieu of: instead of
|
||||
in many cases: often
|
||||
in most cases: usually
|
||||
in order to: to
|
||||
in some cases: sometimes
|
||||
in spite of the fact that: although
|
||||
in spite of: despite
|
||||
in the (?:very)? near future: soon
|
||||
in the event that: if
|
||||
in the neighborhood of: roughly
|
||||
in the vicinity of: close to
|
||||
it would appear that: apparently
|
||||
lift up: lift
|
||||
made reference to: referred to
|
||||
make reference to: refer to
|
||||
mix together: mix
|
||||
none at all: none
|
||||
not in a position to: unable
|
||||
not possible: impossible
|
||||
of major importance: important
|
||||
perform an assessment of: assess
|
||||
pertaining to: about
|
||||
place an order: order
|
||||
plays a key role in: is essential to
|
||||
present time: now
|
||||
readily apparent: apparent
|
||||
some of the: some
|
||||
span across: span
|
||||
subsequent to: after
|
||||
successfully complete: complete
|
||||
take action: act
|
||||
take into account: consider
|
||||
the question as to whether: whether
|
||||
there is no doubt but that: doubtless
|
||||
this day and age: this age
|
||||
this is a subject that: this subject
|
||||
time (?:frame|period): time
|
||||
under the provisions of: under
|
||||
until such time as: until
|
||||
used for fuel purposes: used for fuel
|
||||
whether or not: whether
|
||||
with regard to: regarding
|
||||
with the exception of: except for
|
||||
4
.trunk/valestyles/Microsoft/meta.json
Normal file
4
.trunk/valestyles/Microsoft/meta.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"feed": "https://github.com/errata-ai/Microsoft/releases.atom",
|
||||
"vale_version": ">=1.0.0"
|
||||
}
|
||||
702
.trunk/valestyles/WriteGood/Cliches.yml
Normal file
702
.trunk/valestyles/WriteGood/Cliches.yml
Normal file
|
|
@ -0,0 +1,702 @@
|
|||
extends: existence
|
||||
message: "Try to avoid using clichés like '%s'."
|
||||
ignorecase: true
|
||||
level: warning
|
||||
tokens:
|
||||
- a chip off the old block
|
||||
- a clean slate
|
||||
- a dark and stormy night
|
||||
- a far cry
|
||||
- a fine kettle of fish
|
||||
- a loose cannon
|
||||
- a penny saved is a penny earned
|
||||
- a tough row to hoe
|
||||
- a word to the wise
|
||||
- ace in the hole
|
||||
- acid test
|
||||
- add insult to injury
|
||||
- against all odds
|
||||
- air your dirty laundry
|
||||
- all fun and games
|
||||
- all in a day's work
|
||||
- all talk, no action
|
||||
- all thumbs
|
||||
- all your eggs in one basket
|
||||
- all's fair in love and war
|
||||
- all's well that ends well
|
||||
- almighty dollar
|
||||
- American as apple pie
|
||||
- an axe to grind
|
||||
- another day, another dollar
|
||||
- armed to the teeth
|
||||
- as luck would have it
|
||||
- as old as time
|
||||
- as the crow flies
|
||||
- at loose ends
|
||||
- at my wits end
|
||||
- avoid like the plague
|
||||
- babe in the woods
|
||||
- back against the wall
|
||||
- back in the saddle
|
||||
- back to square one
|
||||
- back to the drawing board
|
||||
- bad to the bone
|
||||
- badge of honor
|
||||
- bald faced liar
|
||||
- ballpark figure
|
||||
- banging your head against a brick wall
|
||||
- baptism by fire
|
||||
- barking up the wrong tree
|
||||
- bat out of hell
|
||||
- be all and end all
|
||||
- beat a dead horse
|
||||
- beat around the bush
|
||||
- been there, done that
|
||||
- beggars can't be choosers
|
||||
- behind the eight ball
|
||||
- bend over backwards
|
||||
- benefit of the doubt
|
||||
- bent out of shape
|
||||
- best thing since sliced bread
|
||||
- bet your bottom dollar
|
||||
- better half
|
||||
- better late than never
|
||||
- better mousetrap
|
||||
- better safe than sorry
|
||||
- between a rock and a hard place
|
||||
- beyond the pale
|
||||
- bide your time
|
||||
- big as life
|
||||
- big cheese
|
||||
- big fish in a small pond
|
||||
- big man on campus
|
||||
- bigger they are the harder they fall
|
||||
- bird in the hand
|
||||
- bird's eye view
|
||||
- birds and the bees
|
||||
- birds of a feather flock together
|
||||
- bit the hand that feeds you
|
||||
- bite the bullet
|
||||
- bite the dust
|
||||
- bitten off more than he can chew
|
||||
- black as coal
|
||||
- black as pitch
|
||||
- black as the ace of spades
|
||||
- blast from the past
|
||||
- bleeding heart
|
||||
- blessing in disguise
|
||||
- blind ambition
|
||||
- blind as a bat
|
||||
- blind leading the blind
|
||||
- blood is thicker than water
|
||||
- blood sweat and tears
|
||||
- blow off steam
|
||||
- blow your own horn
|
||||
- blushing bride
|
||||
- boils down to
|
||||
- bolt from the blue
|
||||
- bone to pick
|
||||
- bored stiff
|
||||
- bored to tears
|
||||
- bottomless pit
|
||||
- boys will be boys
|
||||
- bright and early
|
||||
- brings home the bacon
|
||||
- broad across the beam
|
||||
- broken record
|
||||
- brought back to reality
|
||||
- bull by the horns
|
||||
- bull in a china shop
|
||||
- burn the midnight oil
|
||||
- burning question
|
||||
- burning the candle at both ends
|
||||
- burst your bubble
|
||||
- bury the hatchet
|
||||
- busy as a bee
|
||||
- by hook or by crook
|
||||
- call a spade a spade
|
||||
- called onto the carpet
|
||||
- calm before the storm
|
||||
- can of worms
|
||||
- can't cut the mustard
|
||||
- can't hold a candle to
|
||||
- case of mistaken identity
|
||||
- cat got your tongue
|
||||
- cat's meow
|
||||
- caught in the crossfire
|
||||
- caught red-handed
|
||||
- checkered past
|
||||
- chomping at the bit
|
||||
- cleanliness is next to godliness
|
||||
- clear as a bell
|
||||
- clear as mud
|
||||
- close to the vest
|
||||
- cock and bull story
|
||||
- cold shoulder
|
||||
- come hell or high water
|
||||
- cool as a cucumber
|
||||
- cool, calm, and collected
|
||||
- cost a king's ransom
|
||||
- count your blessings
|
||||
- crack of dawn
|
||||
- crash course
|
||||
- creature comforts
|
||||
- cross that bridge when you come to it
|
||||
- crushing blow
|
||||
- cry like a baby
|
||||
- cry me a river
|
||||
- cry over spilt milk
|
||||
- crystal clear
|
||||
- curiosity killed the cat
|
||||
- cut and dried
|
||||
- cut through the red tape
|
||||
- cut to the chase
|
||||
- cute as a bugs ear
|
||||
- cute as a button
|
||||
- cute as a puppy
|
||||
- cuts to the quick
|
||||
- dark before the dawn
|
||||
- day in, day out
|
||||
- dead as a doornail
|
||||
- devil is in the details
|
||||
- dime a dozen
|
||||
- divide and conquer
|
||||
- dog and pony show
|
||||
- dog days
|
||||
- dog eat dog
|
||||
- dog tired
|
||||
- don't burn your bridges
|
||||
- don't count your chickens
|
||||
- don't look a gift horse in the mouth
|
||||
- don't rock the boat
|
||||
- don't step on anyone's toes
|
||||
- don't take any wooden nickels
|
||||
- down and out
|
||||
- down at the heels
|
||||
- down in the dumps
|
||||
- down the hatch
|
||||
- down to earth
|
||||
- draw the line
|
||||
- dressed to kill
|
||||
- dressed to the nines
|
||||
- drives me up the wall
|
||||
- dull as dishwater
|
||||
- dyed in the wool
|
||||
- eagle eye
|
||||
- ear to the ground
|
||||
- early bird catches the worm
|
||||
- easier said than done
|
||||
- easy as pie
|
||||
- eat your heart out
|
||||
- eat your words
|
||||
- eleventh hour
|
||||
- even the playing field
|
||||
- every dog has its day
|
||||
- every fiber of my being
|
||||
- everything but the kitchen sink
|
||||
- eye for an eye
|
||||
- face the music
|
||||
- facts of life
|
||||
- fair weather friend
|
||||
- fall by the wayside
|
||||
- fan the flames
|
||||
- feast or famine
|
||||
- feather your nest
|
||||
- feathered friends
|
||||
- few and far between
|
||||
- fifteen minutes of fame
|
||||
- filthy vermin
|
||||
- fine kettle of fish
|
||||
- fish out of water
|
||||
- fishing for a compliment
|
||||
- fit as a fiddle
|
||||
- fit the bill
|
||||
- fit to be tied
|
||||
- flash in the pan
|
||||
- flat as a pancake
|
||||
- flip your lid
|
||||
- flog a dead horse
|
||||
- fly by night
|
||||
- fly the coop
|
||||
- follow your heart
|
||||
- for all intents and purposes
|
||||
- for the birds
|
||||
- for what it's worth
|
||||
- force of nature
|
||||
- force to be reckoned with
|
||||
- forgive and forget
|
||||
- fox in the henhouse
|
||||
- free and easy
|
||||
- free as a bird
|
||||
- fresh as a daisy
|
||||
- full steam ahead
|
||||
- fun in the sun
|
||||
- garbage in, garbage out
|
||||
- gentle as a lamb
|
||||
- get a kick out of
|
||||
- get a leg up
|
||||
- get down and dirty
|
||||
- get the lead out
|
||||
- get to the bottom of
|
||||
- get your feet wet
|
||||
- gets my goat
|
||||
- gilding the lily
|
||||
- give and take
|
||||
- go against the grain
|
||||
- go at it tooth and nail
|
||||
- go for broke
|
||||
- go him one better
|
||||
- go the extra mile
|
||||
- go with the flow
|
||||
- goes without saying
|
||||
- good as gold
|
||||
- good deed for the day
|
||||
- good things come to those who wait
|
||||
- good time was had by all
|
||||
- good times were had by all
|
||||
- greased lightning
|
||||
- greek to me
|
||||
- green thumb
|
||||
- green-eyed monster
|
||||
- grist for the mill
|
||||
- growing like a weed
|
||||
- hair of the dog
|
||||
- hand to mouth
|
||||
- happy as a clam
|
||||
- happy as a lark
|
||||
- hasn't a clue
|
||||
- have a nice day
|
||||
- have high hopes
|
||||
- have the last laugh
|
||||
- haven't got a row to hoe
|
||||
- head honcho
|
||||
- head over heels
|
||||
- hear a pin drop
|
||||
- heard it through the grapevine
|
||||
- heart's content
|
||||
- heavy as lead
|
||||
- hem and haw
|
||||
- high and dry
|
||||
- high and mighty
|
||||
- high as a kite
|
||||
- hit paydirt
|
||||
- hold your head up high
|
||||
- hold your horses
|
||||
- hold your own
|
||||
- hold your tongue
|
||||
- honest as the day is long
|
||||
- horns of a dilemma
|
||||
- horse of a different color
|
||||
- hot under the collar
|
||||
- hour of need
|
||||
- I beg to differ
|
||||
- icing on the cake
|
||||
- if the shoe fits
|
||||
- if the shoe were on the other foot
|
||||
- in a jam
|
||||
- in a jiffy
|
||||
- in a nutshell
|
||||
- in a pig's eye
|
||||
- in a pinch
|
||||
- in a word
|
||||
- in hot water
|
||||
- in the gutter
|
||||
- in the nick of time
|
||||
- in the thick of it
|
||||
- in your dreams
|
||||
- it ain't over till the fat lady sings
|
||||
- it goes without saying
|
||||
- it takes all kinds
|
||||
- it takes one to know one
|
||||
- it's a small world
|
||||
- it's only a matter of time
|
||||
- ivory tower
|
||||
- Jack of all trades
|
||||
- jockey for position
|
||||
- jog your memory
|
||||
- joined at the hip
|
||||
- judge a book by its cover
|
||||
- jump down your throat
|
||||
- jump in with both feet
|
||||
- jump on the bandwagon
|
||||
- jump the gun
|
||||
- jump to conclusions
|
||||
- just a hop, skip, and a jump
|
||||
- just the ticket
|
||||
- justice is blind
|
||||
- keep a stiff upper lip
|
||||
- keep an eye on
|
||||
- keep it simple, stupid
|
||||
- keep the home fires burning
|
||||
- keep up with the Joneses
|
||||
- keep your chin up
|
||||
- keep your fingers crossed
|
||||
- kick the bucket
|
||||
- kick up your heels
|
||||
- kick your feet up
|
||||
- kid in a candy store
|
||||
- kill two birds with one stone
|
||||
- kiss of death
|
||||
- knock it out of the park
|
||||
- knock on wood
|
||||
- knock your socks off
|
||||
- know him from Adam
|
||||
- know the ropes
|
||||
- know the score
|
||||
- knuckle down
|
||||
- knuckle sandwich
|
||||
- knuckle under
|
||||
- labor of love
|
||||
- ladder of success
|
||||
- land on your feet
|
||||
- lap of luxury
|
||||
- last but not least
|
||||
- last hurrah
|
||||
- last-ditch effort
|
||||
- law of the jungle
|
||||
- law of the land
|
||||
- lay down the law
|
||||
- leaps and bounds
|
||||
- let sleeping dogs lie
|
||||
- let the cat out of the bag
|
||||
- let the good times roll
|
||||
- let your hair down
|
||||
- let's talk turkey
|
||||
- letter perfect
|
||||
- lick your wounds
|
||||
- lies like a rug
|
||||
- life's a bitch
|
||||
- life's a grind
|
||||
- light at the end of the tunnel
|
||||
- lighter than a feather
|
||||
- lighter than air
|
||||
- like clockwork
|
||||
- like father like son
|
||||
- like taking candy from a baby
|
||||
- like there's no tomorrow
|
||||
- lion's share
|
||||
- live and learn
|
||||
- live and let live
|
||||
- long and short of it
|
||||
- long lost love
|
||||
- look before you leap
|
||||
- look down your nose
|
||||
- look what the cat dragged in
|
||||
- looking a gift horse in the mouth
|
||||
- looks like death warmed over
|
||||
- loose cannon
|
||||
- lose your head
|
||||
- lose your temper
|
||||
- loud as a horn
|
||||
- lounge lizard
|
||||
- loved and lost
|
||||
- low man on the totem pole
|
||||
- luck of the draw
|
||||
- luck of the Irish
|
||||
- make hay while the sun shines
|
||||
- make money hand over fist
|
||||
- make my day
|
||||
- make the best of a bad situation
|
||||
- make the best of it
|
||||
- make your blood boil
|
||||
- man of few words
|
||||
- man's best friend
|
||||
- mark my words
|
||||
- meaningful dialogue
|
||||
- missed the boat on that one
|
||||
- moment in the sun
|
||||
- moment of glory
|
||||
- moment of truth
|
||||
- money to burn
|
||||
- more power to you
|
||||
- more than one way to skin a cat
|
||||
- movers and shakers
|
||||
- moving experience
|
||||
- naked as a jaybird
|
||||
- naked truth
|
||||
- neat as a pin
|
||||
- needle in a haystack
|
||||
- needless to say
|
||||
- neither here nor there
|
||||
- never look back
|
||||
- never say never
|
||||
- nip and tuck
|
||||
- nip it in the bud
|
||||
- no guts, no glory
|
||||
- no love lost
|
||||
- no pain, no gain
|
||||
- no skin off my back
|
||||
- no stone unturned
|
||||
- no time like the present
|
||||
- no use crying over spilled milk
|
||||
- nose to the grindstone
|
||||
- not a hope in hell
|
||||
- not a minute's peace
|
||||
- not in my backyard
|
||||
- not playing with a full deck
|
||||
- not the end of the world
|
||||
- not written in stone
|
||||
- nothing to sneeze at
|
||||
- nothing ventured nothing gained
|
||||
- now we're cooking
|
||||
- off the top of my head
|
||||
- off the wagon
|
||||
- off the wall
|
||||
- old hat
|
||||
- older and wiser
|
||||
- older than dirt
|
||||
- older than Methuselah
|
||||
- on a roll
|
||||
- on cloud nine
|
||||
- on pins and needles
|
||||
- on the bandwagon
|
||||
- on the money
|
||||
- on the nose
|
||||
- on the rocks
|
||||
- on the spot
|
||||
- on the tip of my tongue
|
||||
- on the wagon
|
||||
- on thin ice
|
||||
- once bitten, twice shy
|
||||
- one bad apple doesn't spoil the bushel
|
||||
- one born every minute
|
||||
- one brick short
|
||||
- one foot in the grave
|
||||
- one in a million
|
||||
- one red cent
|
||||
- only game in town
|
||||
- open a can of worms
|
||||
- open and shut case
|
||||
- open the flood gates
|
||||
- opportunity doesn't knock twice
|
||||
- out of pocket
|
||||
- out of sight, out of mind
|
||||
- out of the frying pan into the fire
|
||||
- out of the woods
|
||||
- out on a limb
|
||||
- over a barrel
|
||||
- over the hump
|
||||
- pain and suffering
|
||||
- pain in the
|
||||
- panic button
|
||||
- par for the course
|
||||
- part and parcel
|
||||
- party pooper
|
||||
- pass the buck
|
||||
- patience is a virtue
|
||||
- pay through the nose
|
||||
- penny pincher
|
||||
- perfect storm
|
||||
- pig in a poke
|
||||
- pile it on
|
||||
- pillar of the community
|
||||
- pin your hopes on
|
||||
- pitter patter of little feet
|
||||
- plain as day
|
||||
- plain as the nose on your face
|
||||
- play by the rules
|
||||
- play your cards right
|
||||
- playing the field
|
||||
- playing with fire
|
||||
- pleased as punch
|
||||
- plenty of fish in the sea
|
||||
- point with pride
|
||||
- poor as a church mouse
|
||||
- pot calling the kettle black
|
||||
- pretty as a picture
|
||||
- pull a fast one
|
||||
- pull your punches
|
||||
- pulling your leg
|
||||
- pure as the driven snow
|
||||
- put it in a nutshell
|
||||
- put one over on you
|
||||
- put the cart before the horse
|
||||
- put the pedal to the metal
|
||||
- put your best foot forward
|
||||
- put your foot down
|
||||
- quick as a bunny
|
||||
- quick as a lick
|
||||
- quick as a wink
|
||||
- quick as lightning
|
||||
- quiet as a dormouse
|
||||
- rags to riches
|
||||
- raining buckets
|
||||
- raining cats and dogs
|
||||
- rank and file
|
||||
- rat race
|
||||
- reap what you sow
|
||||
- red as a beet
|
||||
- red herring
|
||||
- reinvent the wheel
|
||||
- rich and famous
|
||||
- rings a bell
|
||||
- ripe old age
|
||||
- ripped me off
|
||||
- rise and shine
|
||||
- road to hell is paved with good intentions
|
||||
- rob Peter to pay Paul
|
||||
- roll over in the grave
|
||||
- rub the wrong way
|
||||
- ruled the roost
|
||||
- running in circles
|
||||
- sad but true
|
||||
- sadder but wiser
|
||||
- salt of the earth
|
||||
- scared stiff
|
||||
- scared to death
|
||||
- sealed with a kiss
|
||||
- second to none
|
||||
- see eye to eye
|
||||
- seen the light
|
||||
- seize the day
|
||||
- set the record straight
|
||||
- set the world on fire
|
||||
- set your teeth on edge
|
||||
- sharp as a tack
|
||||
- shoot for the moon
|
||||
- shoot the breeze
|
||||
- shot in the dark
|
||||
- shoulder to the wheel
|
||||
- sick as a dog
|
||||
- sigh of relief
|
||||
- signed, sealed, and delivered
|
||||
- sink or swim
|
||||
- six of one, half a dozen of another
|
||||
- skating on thin ice
|
||||
- slept like a log
|
||||
- slinging mud
|
||||
- slippery as an eel
|
||||
- slow as molasses
|
||||
- smart as a whip
|
||||
- smooth as a baby's bottom
|
||||
- sneaking suspicion
|
||||
- snug as a bug in a rug
|
||||
- sow wild oats
|
||||
- spare the rod, spoil the child
|
||||
- speak of the devil
|
||||
- spilled the beans
|
||||
- spinning your wheels
|
||||
- spitting image of
|
||||
- spoke with relish
|
||||
- spread like wildfire
|
||||
- spring to life
|
||||
- squeaky wheel gets the grease
|
||||
- stands out like a sore thumb
|
||||
- start from scratch
|
||||
- stick in the mud
|
||||
- still waters run deep
|
||||
- stitch in time
|
||||
- stop and smell the roses
|
||||
- straight as an arrow
|
||||
- straw that broke the camel's back
|
||||
- strong as an ox
|
||||
- stubborn as a mule
|
||||
- stuff that dreams are made of
|
||||
- stuffed shirt
|
||||
- sweating blood
|
||||
- sweating bullets
|
||||
- take a load off
|
||||
- take one for the team
|
||||
- take the bait
|
||||
- take the bull by the horns
|
||||
- take the plunge
|
||||
- takes one to know one
|
||||
- takes two to tango
|
||||
- the more the merrier
|
||||
- the real deal
|
||||
- the real McCoy
|
||||
- the red carpet treatment
|
||||
- the same old story
|
||||
- there is no accounting for taste
|
||||
- thick as a brick
|
||||
- thick as thieves
|
||||
- thin as a rail
|
||||
- think outside of the box
|
||||
- third time's the charm
|
||||
- this day and age
|
||||
- this hurts me worse than it hurts you
|
||||
- this point in time
|
||||
- three sheets to the wind
|
||||
- through thick and thin
|
||||
- throw in the towel
|
||||
- tie one on
|
||||
- tighter than a drum
|
||||
- time and time again
|
||||
- time is of the essence
|
||||
- tip of the iceberg
|
||||
- tired but happy
|
||||
- to coin a phrase
|
||||
- to each his own
|
||||
- to make a long story short
|
||||
- to the best of my knowledge
|
||||
- toe the line
|
||||
- tongue in cheek
|
||||
- too good to be true
|
||||
- too hot to handle
|
||||
- too numerous to mention
|
||||
- touch with a ten foot pole
|
||||
- tough as nails
|
||||
- trial and error
|
||||
- trials and tribulations
|
||||
- tried and true
|
||||
- trip down memory lane
|
||||
- twist of fate
|
||||
- two cents worth
|
||||
- two peas in a pod
|
||||
- ugly as sin
|
||||
- under the counter
|
||||
- under the gun
|
||||
- under the same roof
|
||||
- under the weather
|
||||
- until the cows come home
|
||||
- unvarnished truth
|
||||
- up the creek
|
||||
- uphill battle
|
||||
- upper crust
|
||||
- upset the applecart
|
||||
- vain attempt
|
||||
- vain effort
|
||||
- vanquish the enemy
|
||||
- vested interest
|
||||
- waiting for the other shoe to drop
|
||||
- wakeup call
|
||||
- warm welcome
|
||||
- watch your p's and q's
|
||||
- watch your tongue
|
||||
- watching the clock
|
||||
- water under the bridge
|
||||
- weather the storm
|
||||
- weed them out
|
||||
- week of Sundays
|
||||
- went belly up
|
||||
- wet behind the ears
|
||||
- what goes around comes around
|
||||
- what you see is what you get
|
||||
- when it rains, it pours
|
||||
- when push comes to shove
|
||||
- when the cat's away
|
||||
- when the going gets tough, the tough get going
|
||||
- white as a sheet
|
||||
- whole ball of wax
|
||||
- whole hog
|
||||
- whole nine yards
|
||||
- wild goose chase
|
||||
- will wonders never cease?
|
||||
- wisdom of the ages
|
||||
- wise as an owl
|
||||
- wolf at the door
|
||||
- words fail me
|
||||
- work like a dog
|
||||
- world weary
|
||||
- worst nightmare
|
||||
- worth its weight in gold
|
||||
- wrong side of the bed
|
||||
- yanking your chain
|
||||
- yappy as a dog
|
||||
- years young
|
||||
- you are what you eat
|
||||
- you can run but you can't hide
|
||||
- you only live once
|
||||
- you're the boss
|
||||
- young and foolish
|
||||
- young and vibrant
|
||||
32
.trunk/valestyles/WriteGood/E-Prime.yml
Normal file
32
.trunk/valestyles/WriteGood/E-Prime.yml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
extends: existence
|
||||
message: "Try to avoid using '%s'."
|
||||
ignorecase: true
|
||||
level: suggestion
|
||||
tokens:
|
||||
- am
|
||||
- are
|
||||
- aren't
|
||||
- be
|
||||
- been
|
||||
- being
|
||||
- he's
|
||||
- here's
|
||||
- here's
|
||||
- how's
|
||||
- i'm
|
||||
- is
|
||||
- isn't
|
||||
- it's
|
||||
- she's
|
||||
- that's
|
||||
- there's
|
||||
- they're
|
||||
- was
|
||||
- wasn't
|
||||
- we're
|
||||
- were
|
||||
- weren't
|
||||
- what's
|
||||
- where's
|
||||
- who's
|
||||
- you're
|
||||
11
.trunk/valestyles/WriteGood/Illusions.yml
Normal file
11
.trunk/valestyles/WriteGood/Illusions.yml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
extends: repetition
|
||||
message: "'%s' is repeated!"
|
||||
level: warning
|
||||
alpha: true
|
||||
action:
|
||||
name: edit
|
||||
params:
|
||||
- truncate
|
||||
- " "
|
||||
tokens:
|
||||
- '[^\s]+'
|
||||
183
.trunk/valestyles/WriteGood/Passive.yml
Normal file
183
.trunk/valestyles/WriteGood/Passive.yml
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
extends: existence
|
||||
message: "'%s' may be passive voice. Use active voice if you can."
|
||||
ignorecase: true
|
||||
level: warning
|
||||
raw:
|
||||
- \b(am|are|were|being|is|been|was|be)\b\s*
|
||||
tokens:
|
||||
- '[\w]+ed'
|
||||
- awoken
|
||||
- beat
|
||||
- become
|
||||
- been
|
||||
- begun
|
||||
- bent
|
||||
- beset
|
||||
- bet
|
||||
- bid
|
||||
- bidden
|
||||
- bitten
|
||||
- bled
|
||||
- blown
|
||||
- born
|
||||
- bought
|
||||
- bound
|
||||
- bred
|
||||
- broadcast
|
||||
- broken
|
||||
- brought
|
||||
- built
|
||||
- burnt
|
||||
- burst
|
||||
- cast
|
||||
- caught
|
||||
- chosen
|
||||
- clung
|
||||
- come
|
||||
- cost
|
||||
- crept
|
||||
- cut
|
||||
- dealt
|
||||
- dived
|
||||
- done
|
||||
- drawn
|
||||
- dreamt
|
||||
- driven
|
||||
- drunk
|
||||
- dug
|
||||
- eaten
|
||||
- fallen
|
||||
- fed
|
||||
- felt
|
||||
- fit
|
||||
- fled
|
||||
- flown
|
||||
- flung
|
||||
- forbidden
|
||||
- foregone
|
||||
- forgiven
|
||||
- forgotten
|
||||
- forsaken
|
||||
- fought
|
||||
- found
|
||||
- frozen
|
||||
- given
|
||||
- gone
|
||||
- gotten
|
||||
- ground
|
||||
- grown
|
||||
- heard
|
||||
- held
|
||||
- hidden
|
||||
- hit
|
||||
- hung
|
||||
- hurt
|
||||
- kept
|
||||
- knelt
|
||||
- knit
|
||||
- known
|
||||
- laid
|
||||
- lain
|
||||
- leapt
|
||||
- learnt
|
||||
- led
|
||||
- left
|
||||
- lent
|
||||
- let
|
||||
- lighted
|
||||
- lost
|
||||
- made
|
||||
- meant
|
||||
- met
|
||||
- misspelt
|
||||
- mistaken
|
||||
- mown
|
||||
- overcome
|
||||
- overdone
|
||||
- overtaken
|
||||
- overthrown
|
||||
- paid
|
||||
- pled
|
||||
- proven
|
||||
- put
|
||||
- quit
|
||||
- read
|
||||
- rid
|
||||
- ridden
|
||||
- risen
|
||||
- run
|
||||
- rung
|
||||
- said
|
||||
- sat
|
||||
- sawn
|
||||
- seen
|
||||
- sent
|
||||
- set
|
||||
- sewn
|
||||
- shaken
|
||||
- shaven
|
||||
- shed
|
||||
- shod
|
||||
- shone
|
||||
- shorn
|
||||
- shot
|
||||
- shown
|
||||
- shrunk
|
||||
- shut
|
||||
- slain
|
||||
- slept
|
||||
- slid
|
||||
- slit
|
||||
- slung
|
||||
- smitten
|
||||
- sold
|
||||
- sought
|
||||
- sown
|
||||
- sped
|
||||
- spent
|
||||
- spilt
|
||||
- spit
|
||||
- split
|
||||
- spoken
|
||||
- spread
|
||||
- sprung
|
||||
- spun
|
||||
- stolen
|
||||
- stood
|
||||
- stridden
|
||||
- striven
|
||||
- struck
|
||||
- strung
|
||||
- stuck
|
||||
- stung
|
||||
- stunk
|
||||
- sung
|
||||
- sunk
|
||||
- swept
|
||||
- swollen
|
||||
- sworn
|
||||
- swum
|
||||
- swung
|
||||
- taken
|
||||
- taught
|
||||
- thought
|
||||
- thrived
|
||||
- thrown
|
||||
- thrust
|
||||
- told
|
||||
- torn
|
||||
- trodden
|
||||
- understood
|
||||
- upheld
|
||||
- upset
|
||||
- wed
|
||||
- wept
|
||||
- withheld
|
||||
- withstood
|
||||
- woken
|
||||
- won
|
||||
- worn
|
||||
- wound
|
||||
- woven
|
||||
- written
|
||||
- wrung
|
||||
28
.trunk/valestyles/WriteGood/README.md
Normal file
28
.trunk/valestyles/WriteGood/README.md
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
Based on [write-good](https://github.com/btford/write-good).
|
||||
|
||||
> Naive linter for English prose for developers who can't write good and wanna learn to do other
|
||||
> stuff good too.
|
||||
|
||||
```
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Brian Ford
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
5
.trunk/valestyles/WriteGood/So.yml
Normal file
5
.trunk/valestyles/WriteGood/So.yml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
extends: existence
|
||||
message: "Don't start a sentence with '%s'."
|
||||
level: error
|
||||
raw:
|
||||
- '(?:[;-]\s)so[\s,]|\bSo[\s,]'
|
||||
6
.trunk/valestyles/WriteGood/ThereIs.yml
Normal file
6
.trunk/valestyles/WriteGood/ThereIs.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
extends: existence
|
||||
message: "Don't start a sentence with '%s'."
|
||||
ignorecase: false
|
||||
level: error
|
||||
raw:
|
||||
- '(?:[;-]\s)There\s(is|are)|\bThere\s(is|are)\b'
|
||||
221
.trunk/valestyles/WriteGood/TooWordy.yml
Normal file
221
.trunk/valestyles/WriteGood/TooWordy.yml
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
extends: existence
|
||||
message: "'%s' is too wordy."
|
||||
ignorecase: true
|
||||
level: warning
|
||||
tokens:
|
||||
- a number of
|
||||
- abundance
|
||||
- accede to
|
||||
- accelerate
|
||||
- accentuate
|
||||
- accompany
|
||||
- accomplish
|
||||
- accorded
|
||||
- accrue
|
||||
- acquiesce
|
||||
- acquire
|
||||
- additional
|
||||
- adjacent to
|
||||
- adjustment
|
||||
- admissible
|
||||
- advantageous
|
||||
- adversely impact
|
||||
- advise
|
||||
- aforementioned
|
||||
- aggregate
|
||||
- aircraft
|
||||
- all of
|
||||
- all things considered
|
||||
- alleviate
|
||||
- allocate
|
||||
- along the lines of
|
||||
- already existing
|
||||
- alternatively
|
||||
- amazing
|
||||
- ameliorate
|
||||
- anticipate
|
||||
- apparent
|
||||
- appreciable
|
||||
- as a matter of fact
|
||||
- as a means of
|
||||
- as far as I'm concerned
|
||||
- as of yet
|
||||
- as to
|
||||
- as yet
|
||||
- ascertain
|
||||
- assistance
|
||||
- at the present time
|
||||
- at this time
|
||||
- attain
|
||||
- attributable to
|
||||
- authorize
|
||||
- because of the fact that
|
||||
- belated
|
||||
- benefit from
|
||||
- bestow
|
||||
- by means of
|
||||
- by virtue of
|
||||
- by virtue of the fact that
|
||||
- cease
|
||||
- close proximity
|
||||
- commence
|
||||
- comply with
|
||||
- concerning
|
||||
- consequently
|
||||
- consolidate
|
||||
- constitutes
|
||||
- demonstrate
|
||||
- depart
|
||||
- designate
|
||||
- discontinue
|
||||
- due to the fact that
|
||||
- each and every
|
||||
- economical
|
||||
- eliminate
|
||||
- elucidate
|
||||
- employ
|
||||
- endeavor
|
||||
- enumerate
|
||||
- equitable
|
||||
- equivalent
|
||||
- evaluate
|
||||
- evidenced
|
||||
- exclusively
|
||||
- expedite
|
||||
- expend
|
||||
- expiration
|
||||
- facilitate
|
||||
- factual evidence
|
||||
- feasible
|
||||
- finalize
|
||||
- first and foremost
|
||||
- for all intents and purposes
|
||||
- for the most part
|
||||
- for the purpose of
|
||||
- forfeit
|
||||
- formulate
|
||||
- have a tendency to
|
||||
- honest truth
|
||||
- however
|
||||
- if and when
|
||||
- impacted
|
||||
- implement
|
||||
- in a manner of speaking
|
||||
- in a timely manner
|
||||
- in a very real sense
|
||||
- in accordance with
|
||||
- in addition
|
||||
- in all likelihood
|
||||
- in an effort to
|
||||
- in between
|
||||
- in excess of
|
||||
- in lieu of
|
||||
- in light of the fact that
|
||||
- in many cases
|
||||
- in my opinion
|
||||
- in order to
|
||||
- in regard to
|
||||
- in some instances
|
||||
- in terms of
|
||||
- in the case of
|
||||
- in the event that
|
||||
- in the final analysis
|
||||
- in the nature of
|
||||
- in the near future
|
||||
- in the process of
|
||||
- inception
|
||||
- incumbent upon
|
||||
- indicate
|
||||
- indication
|
||||
- initiate
|
||||
- irregardless
|
||||
- is applicable to
|
||||
- is authorized to
|
||||
- is responsible for
|
||||
- it is
|
||||
- it is essential
|
||||
- it seems that
|
||||
- it was
|
||||
- magnitude
|
||||
- maximum
|
||||
- methodology
|
||||
- minimize
|
||||
- minimum
|
||||
- modify
|
||||
- monitor
|
||||
- multiple
|
||||
- necessitate
|
||||
- nevertheless
|
||||
- not certain
|
||||
- not many
|
||||
- not often
|
||||
- not unless
|
||||
- not unlike
|
||||
- notwithstanding
|
||||
- null and void
|
||||
- numerous
|
||||
- objective
|
||||
- obligate
|
||||
- obtain
|
||||
- on the contrary
|
||||
- on the other hand
|
||||
- one particular
|
||||
- optimum
|
||||
- overall
|
||||
- owing to the fact that
|
||||
- participate
|
||||
- particulars
|
||||
- pass away
|
||||
- pertaining to
|
||||
- point in time
|
||||
- portion
|
||||
- possess
|
||||
- preclude
|
||||
- previously
|
||||
- prior to
|
||||
- prioritize
|
||||
- procure
|
||||
- proficiency
|
||||
- provided that
|
||||
- purchase
|
||||
- put simply
|
||||
- readily apparent
|
||||
- refer back
|
||||
- regarding
|
||||
- relocate
|
||||
- remainder
|
||||
- remuneration
|
||||
- requirement
|
||||
- reside
|
||||
- residence
|
||||
- retain
|
||||
- satisfy
|
||||
- shall
|
||||
- should you wish
|
||||
- similar to
|
||||
- solicit
|
||||
- span across
|
||||
- strategize
|
||||
- subsequent
|
||||
- substantial
|
||||
- successfully complete
|
||||
- sufficient
|
||||
- terminate
|
||||
- the month of
|
||||
- the point I am trying to make
|
||||
- therefore
|
||||
- time period
|
||||
- took advantage of
|
||||
- transmit
|
||||
- transpire
|
||||
- type of
|
||||
- until such time as
|
||||
- utilization
|
||||
- utilize
|
||||
- validate
|
||||
- various different
|
||||
- what I mean to say is
|
||||
- whether or not
|
||||
- with respect to
|
||||
- with the exception of
|
||||
- witnessed
|
||||
29
.trunk/valestyles/WriteGood/Weasel.yml
Normal file
29
.trunk/valestyles/WriteGood/Weasel.yml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
extends: existence
|
||||
message: "'%s' is a weasel word!"
|
||||
ignorecase: true
|
||||
level: warning
|
||||
tokens:
|
||||
- clearly
|
||||
- completely
|
||||
- exceedingly
|
||||
- excellent
|
||||
- extremely
|
||||
- fairly
|
||||
- huge
|
||||
- interestingly
|
||||
- is a number
|
||||
- largely
|
||||
- mostly
|
||||
- obviously
|
||||
- quite
|
||||
- relatively
|
||||
- remarkably
|
||||
- several
|
||||
- significantly
|
||||
- substantially
|
||||
- surprisingly
|
||||
- tiny
|
||||
- usually
|
||||
- various
|
||||
- vast
|
||||
- very
|
||||
3
.trunk/valestyles/WriteGood/WriteGood.ini
Normal file
3
.trunk/valestyles/WriteGood/WriteGood.ini
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Minimal placeholder for WriteGood-style rules
|
||||
# This folder acts as a vendored style. Add rules here if desired.
|
||||
version = 1
|
||||
4
.trunk/valestyles/WriteGood/meta.json
Normal file
4
.trunk/valestyles/WriteGood/meta.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"feed": "https://github.com/errata-ai/write-good/releases.atom",
|
||||
"vale_version": ">=1.0.0"
|
||||
}
|
||||
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
|
|
@ -3,7 +3,6 @@
|
|||
"golang.go", // Official Go extension
|
||||
"trunk.io", // trunk.io Linters
|
||||
"wayou.vscode-todo-highlight", // Highlight TODOs
|
||||
"eamodio.gitlens", // Git integration
|
||||
"github.vscode-github-actions" // GitHub Actions support
|
||||
"eamodio.gitlens" // Git integration
|
||||
]
|
||||
}
|
||||
|
|
|
|||
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
|
|
@ -2,11 +2,13 @@
|
|||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
// keep-sorted start
|
||||
"name": "Launch Package",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "${fileDirname}"
|
||||
// keep-sorted end
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
47
.vscode/settings.json
vendored
47
.vscode/settings.json
vendored
|
|
@ -1,41 +1,22 @@
|
|||
{
|
||||
"editor.tabSize": 2,
|
||||
"editor.insertSpaces": true,
|
||||
"editor.defaultFormatter": "trunk.io",
|
||||
"editor.detectIndentation": false,
|
||||
"editor.rulers": [100],
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnPaste": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnType": true,
|
||||
"editor.rulers": [100],
|
||||
"editor.tabSize": 2,
|
||||
"editor.wordWrap": "wordWrapColumn",
|
||||
"editor.wordWrapColumn": 100,
|
||||
"editor.wrappingIndent": "indent",
|
||||
"[go]": {
|
||||
"editor.defaultFormatter": "golang.go"
|
||||
},
|
||||
"[shellscript]": {
|
||||
"editor.defaultFormatter": "trunk.io"
|
||||
},
|
||||
"[bash]": {
|
||||
"editor.defaultFormatter": "trunk.io"
|
||||
},
|
||||
"[json,jsonc]": {
|
||||
"editor.defaultFormatter": "vscode.json-language-features"
|
||||
},
|
||||
"[shfmt]": {
|
||||
"editor.defaultFormatter": "trunk.io"
|
||||
},
|
||||
"[yaml]": {
|
||||
"editor.defaultFormatter": "trunk.io"
|
||||
},
|
||||
"cSpell.enabled": false,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.shellcheck": "explicit"
|
||||
},
|
||||
"workbench.editorAssociations": {
|
||||
"git-index": "default",
|
||||
"git-show": "default"
|
||||
},
|
||||
"files.readonlyInclude": {},
|
||||
"workbench.editor.defaultBinaryEditor": "default",
|
||||
"workbench.editor.enablePreviewFromCodeNavigation": false
|
||||
"editor.insertSpaces": true,
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimFinalNewlines": true,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"git.ignoreLimitWarning": true,
|
||||
"git.enableSmartCommit": true,
|
||||
"gitlens.advanced.fileHistoryFollowsRenames": true,
|
||||
"gitlens.codeLens.enabled": false,
|
||||
"terminal.integrated.scrollback": 100000,
|
||||
"workbench.list.horizontalScrolling": true
|
||||
}
|
||||
|
|
|
|||
9
.vscode/tasks.json
vendored
9
.vscode/tasks.json
vendored
|
|
@ -39,14 +39,7 @@
|
|||
"label": "go: test with coverage",
|
||||
"type": "shell",
|
||||
"command": "go",
|
||||
"args": [
|
||||
"test",
|
||||
"-v",
|
||||
"-race",
|
||||
"-coverprofile=coverage.txt",
|
||||
"-covermode=atomic",
|
||||
"./..."
|
||||
],
|
||||
"args": ["test", "-v", "-race", "-coverprofile=coverage.txt", "-covermode=atomic", "./..."],
|
||||
"problemMatcher": ["$go"],
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
|
|
|
|||
171
CLAUDE.md
171
CLAUDE.md
|
|
@ -1,4 +1,4 @@
|
|||
# Code Improvements by Claude
|
||||
# Code improvements by claude
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
|
@ -59,32 +59,32 @@
|
|||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
## General Code Organization Principles
|
||||
## General code organization principles
|
||||
|
||||
### 1. Package Structure
|
||||
### 1 . package structure
|
||||
|
||||
- Keep packages focused and single-purpose
|
||||
- Use internal packages for code not meant to be imported
|
||||
- Organize by feature/domain rather than by type
|
||||
- Follow Go standard layout conventions
|
||||
|
||||
### 2. Code Style and Formatting
|
||||
### 2 . code style and formatting
|
||||
|
||||
- Use 2 spaces for indentation, never tabs
|
||||
- Consistent naming conventions (e.g., CamelCase for exported names)
|
||||
- Consistent naming conventions (for example, CamelCase for exported names)
|
||||
- Keep functions small and focused
|
||||
- Use meaningful variable names
|
||||
- Follow standard Go formatting guidelines
|
||||
- Use comments to explain "why" not "what"
|
||||
|
||||
### 3. Error Handling
|
||||
### 3 . error handling
|
||||
|
||||
- Return errors rather than using panics
|
||||
- Wrap errors with context when crossing package boundaries
|
||||
- Create custom error types only when needed for client handling
|
||||
- Use sentinel errors sparingly
|
||||
|
||||
### 4. API Design
|
||||
### 4 . API design
|
||||
|
||||
- Make zero values useful
|
||||
- Keep interfaces small and focused, observing the
|
||||
|
|
@ -98,9 +98,9 @@
|
|||
- Use option patterns for complex configurations
|
||||
- Make dependencies explicit
|
||||
|
||||
### 5. Documentation Practices
|
||||
### 5 . documentation practices
|
||||
|
||||
#### Go Code Documentation Standards
|
||||
#### Go code documentation standards
|
||||
|
||||
Following the official [Go Documentation Guidelines](https://go.dev/blog/godoc):
|
||||
|
||||
|
|
@ -170,7 +170,7 @@ Following the official [Go Documentation Guidelines](https://go.dev/blog/godoc):
|
|||
- Keep examples up to date and passing
|
||||
- Update docs when changing behavior
|
||||
|
||||
#### Code Documentation
|
||||
#### Code documentation
|
||||
|
||||
- Write package documentation with examples
|
||||
- Document exported symbols comprehensively
|
||||
|
|
@ -201,7 +201,7 @@ Example:
|
|||
package cache
|
||||
```
|
||||
|
||||
#### Project Documentation
|
||||
#### Project documentation
|
||||
|
||||
- Maintain a comprehensive README
|
||||
- Include getting started guide
|
||||
|
|
@ -210,9 +210,9 @@ package cache
|
|||
- Keep changelog updated
|
||||
- Include contribution guidelines
|
||||
|
||||
### 6. Testing Strategy
|
||||
### 6 . testing strategy
|
||||
|
||||
#### Types of Tests
|
||||
#### Types of tests
|
||||
|
||||
1. **Unit Tests**
|
||||
- Test individual components
|
||||
|
|
@ -229,7 +229,7 @@ package cache
|
|||
- Use real external services
|
||||
- Verify key user scenarios
|
||||
|
||||
#### Test Coverage Strategy
|
||||
#### Test coverage strategy
|
||||
|
||||
- Aim for high but meaningful coverage
|
||||
- Focus on critical paths
|
||||
|
|
@ -237,9 +237,9 @@ package cache
|
|||
- Balance cost vs benefit of testing
|
||||
- Document untested scenarios
|
||||
|
||||
### 7. Security Best Practices
|
||||
### 7 . security best practices
|
||||
|
||||
#### Input Validation
|
||||
#### Input validation
|
||||
|
||||
- Validate all external input
|
||||
- Use strong types over strings
|
||||
|
|
@ -247,7 +247,7 @@ package cache
|
|||
- Assert array bounds
|
||||
- Validate file paths
|
||||
|
||||
#### Secure Coding
|
||||
#### Secure coding
|
||||
|
||||
- Use latest dependencies
|
||||
- Implement proper error handling
|
||||
|
|
@ -255,7 +255,7 @@ package cache
|
|||
- Use secure random numbers
|
||||
- Follow principle of least privilege
|
||||
|
||||
#### Secrets Management
|
||||
#### Secrets management
|
||||
|
||||
- Never commit secrets
|
||||
- Use environment variables
|
||||
|
|
@ -263,7 +263,7 @@ package cache
|
|||
- Rotate credentials regularly
|
||||
- Log access to sensitive operations
|
||||
|
||||
### 8. Performance Considerations
|
||||
### 8 . performance considerations
|
||||
|
||||
- Minimize allocations in hot paths
|
||||
- Use `sync.Pool` for frequently allocated objects
|
||||
|
|
@ -271,9 +271,9 @@ package cache
|
|||
- Profile before optimizing
|
||||
- Document performance characteristics
|
||||
|
||||
### 9. Profiling and Benchmarking
|
||||
### 9 . profiling and benchmarking
|
||||
|
||||
#### CPU Profiling
|
||||
#### CPU profiling
|
||||
|
||||
```go
|
||||
import "runtime/pprof"
|
||||
|
|
@ -295,7 +295,7 @@ View with:
|
|||
go tool pprof cpu.prof
|
||||
```
|
||||
|
||||
#### Memory Profiling
|
||||
#### Memory profiling
|
||||
|
||||
```go
|
||||
import "runtime/pprof"
|
||||
|
|
@ -333,7 +333,7 @@ Run with:
|
|||
go test -bench=. -benchmem
|
||||
```
|
||||
|
||||
#### Trace Profiling
|
||||
#### Trace profiling
|
||||
|
||||
```go
|
||||
import "runtime/trace"
|
||||
|
|
@ -354,7 +354,7 @@ View with:
|
|||
go tool trace trace.out
|
||||
```
|
||||
|
||||
#### Common Profiling Tasks
|
||||
#### Common profiling tasks
|
||||
|
||||
1. **CPU Usage**
|
||||
|
||||
|
|
@ -388,7 +388,7 @@ go tool trace trace.out
|
|||
go tool pprof mutex.prof
|
||||
```
|
||||
|
||||
#### `pprof` Web Interface
|
||||
#### `pprof` web interface
|
||||
|
||||
For visual analysis:
|
||||
|
||||
|
|
@ -396,7 +396,7 @@ For visual analysis:
|
|||
go tool pprof -http=:8080 cpu.prof
|
||||
```
|
||||
|
||||
#### Key Metrics to Watch
|
||||
#### Key metrics to watch
|
||||
|
||||
1. **CPU Profile**
|
||||
- Hot functions
|
||||
|
|
@ -422,7 +422,7 @@ go tool pprof -http=:8080 cpu.prof
|
|||
- Goroutine scheduling
|
||||
- Network/syscall blocking
|
||||
|
||||
### 10. Concurrency Patterns
|
||||
### 10 . concurrency patterns
|
||||
|
||||
- Use channels for coordination, mutexes for state
|
||||
- Keep critical sections small
|
||||
|
|
@ -430,7 +430,7 @@ go tool pprof -http=:8080 cpu.prof
|
|||
- Use context for cancellation
|
||||
- Consider rate limiting and load shedding
|
||||
|
||||
### 11. Configuration Management
|
||||
### 11 . configuration management
|
||||
|
||||
- Use environment variables for deployment-specific values
|
||||
- Validate configuration at startup
|
||||
|
|
@ -438,7 +438,7 @@ go tool pprof -http=:8080 cpu.prof
|
|||
- Support multiple configuration sources
|
||||
- Document all configuration options
|
||||
|
||||
### 12. Logging and Observability
|
||||
### 12 . logging and observability
|
||||
|
||||
- Use structured logging
|
||||
- Include relevant context in logs
|
||||
|
|
@ -446,11 +446,11 @@ go tool pprof -http=:8080 cpu.prof
|
|||
- Add tracing for complex operations
|
||||
- Include metrics for important operations
|
||||
|
||||
## Non-Go Files
|
||||
## Non - go files
|
||||
|
||||
### GitHub Actions
|
||||
### Github actions
|
||||
|
||||
#### Action File Formatting
|
||||
#### Action file formatting
|
||||
|
||||
- Minimize the amount of shell code and put complex logic in the Go code
|
||||
- Use clear step `id` names that use dashes between words and active verbs
|
||||
|
|
@ -458,38 +458,38 @@ go tool pprof -http=:8080 cpu.prof
|
|||
for REST API, GITHUB_GRAPHQL_URL for GraphQL) or the @actions/github toolkit for dynamic URL
|
||||
handling
|
||||
|
||||
##### Release Management
|
||||
##### Release management
|
||||
|
||||
- Use semantic versioning for releases (e.g., v1.0.0)
|
||||
- Use semantic versioning for releases (for example, v1.0.0)
|
||||
- Recommend users reference major version tags (v1) instead of the default branch for stability.
|
||||
- Update major version tags to point to the latest release
|
||||
|
||||
##### Create a README File
|
||||
##### Create a README file
|
||||
|
||||
Include a detailed description, required/optional inputs and outputs, secrets, environment
|
||||
variables, and usage examples
|
||||
|
||||
##### Testing and Automation
|
||||
##### Testing and automation
|
||||
|
||||
- Add workflows to test your action on feature branches and pull requests
|
||||
- Automate releases using workflows triggered by publishing or editing a release.
|
||||
|
||||
##### Community Engagement
|
||||
##### Community engagement
|
||||
|
||||
- Maintain a clear README with examples.
|
||||
- Add community health files like CODE_OF_CONDUCT and CONTRIBUTING.
|
||||
- Use badges to display workflow status.
|
||||
|
||||
##### Further Guidance
|
||||
##### Further guidance
|
||||
|
||||
For more details, visit:
|
||||
|
||||
- <https://docs.github.com/en/actions/how-tos/create-and-publish-actions/manage-custom-actions>
|
||||
- <https://docs.github.com/en/actions/how-tos/create-and-publish-actions/release-and-maintain-actions>
|
||||
|
||||
### YAML Formatting
|
||||
### YAML formatting
|
||||
|
||||
#### Quoting Guidelines
|
||||
#### Quoting guidelines
|
||||
|
||||
Follow these rules for consistent YAML formatting:
|
||||
|
||||
|
|
@ -515,7 +515,7 @@ value: "null" # String "null", not null value
|
|||
enable: "false" # String "false", not boolean false
|
||||
```
|
||||
|
||||
**DO NOT quote simple values:**
|
||||
**do not quote simple values:**
|
||||
|
||||
```yaml
|
||||
# Booleans
|
||||
|
|
@ -531,7 +531,7 @@ name: ubuntu-latest
|
|||
step: checkout
|
||||
action: setup-node
|
||||
|
||||
# GitHub Actions expressions (never quote these)
|
||||
# Github actions expressions ( never quote these )
|
||||
if: github.event_name == 'push'
|
||||
with: ${{ secrets.TOKEN }}
|
||||
```
|
||||
|
|
@ -543,7 +543,7 @@ with: ${{ secrets.TOKEN }}
|
|||
uses: actions/checkout@v4
|
||||
uses: ./path/to/local/action
|
||||
|
||||
# Boolean inputs - don't quote
|
||||
# Boolean inputs - don ' t quote
|
||||
debug: false
|
||||
cache: true
|
||||
|
||||
|
|
@ -555,7 +555,7 @@ if: ${{ github.ref == 'refs/heads/main' }}
|
|||
run: echo "${{ github.actor }}"
|
||||
```
|
||||
|
||||
#### Formatting Standards
|
||||
#### Formatting standards
|
||||
|
||||
- Use 2 spaces for indentation
|
||||
- Use `-` for list items with proper indentation
|
||||
|
|
@ -587,11 +587,11 @@ jobs:
|
|||
DEBUG: false
|
||||
```
|
||||
|
||||
### Bash Scripts
|
||||
### Bash scripts
|
||||
|
||||
Project scripts should follow these guidelines:
|
||||
|
||||
#### File and Directory Structure
|
||||
#### File and directory structure
|
||||
|
||||
All scripts must go into the project's script directory with specific guidance below
|
||||
|
||||
|
|
@ -626,11 +626,15 @@ scripts
|
|||
- Add new development script functionality to the `scripts/dev/menu.sh` script for easy access
|
||||
- Always use `template.sh` when creating a script
|
||||
|
||||
#### Style and Format Rules
|
||||
#### Style and format rules
|
||||
|
||||
- **MANDATORY:** All Bash scripts must strictly follow the [Google Bash Style Guide](https://google.github.io/styleguide/shellguide) for naming, formatting, comments, and best practices.
|
||||
- **MANDATORY:** All Bash scripts must pass [ShellCheck](https://github.com/koalaman/shellcheck/wiki) with no warnings or errors.
|
||||
- **MANDATORY:** All script comments and header blocks must wrap at a maximum line length of 80 characters.
|
||||
- **MANDATORY:** All Bash scripts must strictly follow the
|
||||
[Google Bash Style Guide](https://google.github.io/styleguide/shellguide) for naming, formatting,
|
||||
comments, and best practices.
|
||||
- **MANDATORY:** All Bash scripts must pass
|
||||
[ShellCheck](https://github.com/koalaman/shellcheck/wiki) with no warnings or errors.
|
||||
- **MANDATORY:** All script comments and header blocks must wrap at a maximum line length of 80
|
||||
characters.
|
||||
- Use the `function` keyword before all function definitions: `function my_function() {`
|
||||
- Use imperative verb form for script names:
|
||||
- Good: `export_version.sh`, `build_package.sh`, `run_tests.sh`
|
||||
|
|
@ -649,33 +653,33 @@ For functions:
|
|||
- Always follow the format described in
|
||||
[Google Bash Style Guide: Function Comments](https://google.github.io/styleguide/shellguide#function-comments)
|
||||
|
||||
#### Script Header Requirements (MANDATORY)
|
||||
#### Script header requirements ( MANDATORY )
|
||||
|
||||
Every Bash script must begin with a standardized header block, formatted as follows:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
#==============================================================================
|
||||
# <script_name>.sh
|
||||
# < script_name > . sh
|
||||
#==============================================================================
|
||||
#
|
||||
# DESCRIPTION:
|
||||
# <Detailed description of the script's purpose and functionality>
|
||||
# DESCRIPTION :
|
||||
# < detailed description of the script ' s purpose and functionality >
|
||||
#
|
||||
# USAGE:
|
||||
# <script_name>.sh <command> [args]
|
||||
# USAGE :
|
||||
# < script_name > . sh < command > [ args ]
|
||||
#
|
||||
# COMMANDS:
|
||||
# <command_1> <Description of command_1>
|
||||
# <command_2> <Description of command_2>
|
||||
# ...
|
||||
# COMMANDS :
|
||||
# < command_1 > < description of command_1 >
|
||||
# < command_2 > < description of command_2 >
|
||||
# . . .
|
||||
#
|
||||
# OPTIONS:
|
||||
# -h, --help Show this help message
|
||||
# ... <Other options and their descriptions>
|
||||
# OPTIONS :
|
||||
# - h , - - help show this help message
|
||||
# . . . < other options and their descriptions >
|
||||
#
|
||||
# DEPENDENCIES:
|
||||
# <List required dependencies, e.g. external tools, environment variables>
|
||||
# DEPENDENCIES :
|
||||
# < list required dependencies , e . g . external tools , environment variables >
|
||||
#==============================================================================
|
||||
```
|
||||
|
||||
|
|
@ -687,9 +691,10 @@ Checklist for script headers:
|
|||
- Command and option documentation
|
||||
- Required dependencies
|
||||
|
||||
All new and updated scripts must comply with this format. Non-compliant scripts will be flagged in code review and CI.
|
||||
All new and updated scripts must comply with this format. Non-compliant scripts will be flagged in
|
||||
code review and CI.
|
||||
|
||||
#### Script Testing
|
||||
#### Script testing
|
||||
|
||||
All scripts must have corresponding tests in the `tests` sub-directory using the common test
|
||||
library:
|
||||
|
|
@ -717,7 +722,7 @@ library:
|
|||
- Test execution is part of the validate-scripts job
|
||||
- Test failures block PR merges
|
||||
|
||||
##### Test Framework Architecture Pattern
|
||||
##### Test framework architecture pattern
|
||||
|
||||
All tests must start with `scripts/template_test.sh`
|
||||
|
||||
|
|
@ -732,7 +737,7 @@ All tests must start with `scripts/template_test.sh`
|
|||
- **Framework Integration**: Call `start_tests "$@"` before running tests to handle argument parsing
|
||||
and setup
|
||||
|
||||
##### Centralized Configuration Management
|
||||
##### Centralized configuration management
|
||||
|
||||
The project implements centralized version management using the `.env` file as a single source of
|
||||
truth:
|
||||
|
|
@ -740,7 +745,7 @@ truth:
|
|||
**Configuration Structure:**
|
||||
|
||||
```bash
|
||||
# .env file contents
|
||||
# . env file contents
|
||||
GO_VERSION=1.23.4
|
||||
GO_TOOLCHAIN=go1.23.4
|
||||
```
|
||||
|
|
@ -748,7 +753,7 @@ GO_TOOLCHAIN=go1.23.4
|
|||
**GitHub Actions Integration:**
|
||||
|
||||
```yaml
|
||||
# .github/workflows/ci.yml pattern
|
||||
# . github / workflows / ci . yml pattern
|
||||
jobs:
|
||||
setup:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -776,9 +781,9 @@ jobs:
|
|||
- Ensures consistency between environment configuration and Go module requirements
|
||||
- Can be extended for other configuration synchronization needs
|
||||
|
||||
## Testing Principles
|
||||
## Testing principles
|
||||
|
||||
### 1. Test Organization Strategy
|
||||
### 1 . test organization strategy
|
||||
|
||||
We established a balanced approach to test organization:
|
||||
|
||||
|
|
@ -787,9 +792,9 @@ We established a balanced approach to test organization:
|
|||
cannot be shared amongst other cases
|
||||
- Group related test cases that operate on the same API method / function
|
||||
|
||||
### 2. Code Structure
|
||||
### 2 . code structure
|
||||
|
||||
#### Constants and Variables
|
||||
#### Constants and variables
|
||||
|
||||
```go
|
||||
const (
|
||||
|
|
@ -809,7 +814,7 @@ var (
|
|||
- Group related constants and variables together
|
||||
- Do not prefix constants or variables with `test`
|
||||
|
||||
#### Helper Functions
|
||||
#### Helper functions
|
||||
|
||||
Simple examples of factory and assert functions.
|
||||
|
||||
|
|
@ -892,9 +897,9 @@ func TestAddPrefixToDescription_WithValidInput_AddsPrefix(t *testing.T) {
|
|||
- Keep helpers focused and single-purpose
|
||||
- Helper functions that require logic should go into their own file and have tests
|
||||
|
||||
### 3. Test Case Patterns
|
||||
### 3 . test case patterns
|
||||
|
||||
#### Table-Driven Tests (for simple cases)
|
||||
#### Table - driven tests ( for simple cases )
|
||||
|
||||
```go
|
||||
// Each test case is its own function - no loops or conditionals in test body
|
||||
|
|
@ -948,7 +953,7 @@ func assertFormatError(t *testing.T, actual string, err error, expectedErrMsg st
|
|||
}
|
||||
```
|
||||
|
||||
#### Individual Tests (for complex cases)
|
||||
#### Individual tests ( for complex cases )
|
||||
|
||||
```go
|
||||
func TestProcessTransaction_WithConcurrentUpdates_PreservesConsistency(t *testing.T) {
|
||||
|
|
@ -1001,7 +1006,7 @@ func assertBalanceEquals(t *testing.T, expected, actual decimal.Decimal) {
|
|||
}
|
||||
```
|
||||
|
||||
### 4. Best Practices Applied
|
||||
### 4 . best practices applied
|
||||
|
||||
1. **Clear Naming**
|
||||
- Name test data clearly and meaningfully
|
||||
|
|
@ -1009,7 +1014,7 @@ func assertBalanceEquals(t *testing.T, expected, actual decimal.Decimal) {
|
|||
- Use `expected` for expected values
|
||||
- Use `actual` for function results
|
||||
- Keep test variables consistent across all tests
|
||||
- Always use "Arrange", "Act", "Assert" as step comments in tests
|
||||
- Always use "Arrange," "Act," "Assert" as step comments in tests
|
||||
- Use descriptive test name arrangement and expectation parts
|
||||
- Use test name formats in a 3 part structure
|
||||
- `Test<function>_<arrangement>_<expectation>` for free functions, and
|
||||
|
|
@ -1084,7 +1089,7 @@ func assertBalanceEquals(t *testing.T, expected, actual decimal.Decimal) {
|
|||
- Group related assertions logically
|
||||
- Test one concept per assertion
|
||||
|
||||
### 5. Examples of Improvements
|
||||
### 5 . examples of improvements
|
||||
|
||||
#### Before
|
||||
|
||||
|
|
@ -1156,7 +1161,7 @@ func TestValidateConfig_WithEmptyPath_ReturnsError(t *testing.T) {
|
|||
}
|
||||
```
|
||||
|
||||
## Key Benefits
|
||||
## Key benefits
|
||||
|
||||
1. **Maintainability**
|
||||
- Easier to update and modify tests
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
# Command Line Usage Guide
|
||||
|
||||
This document provides information about using the `cache-apt-pkgs` command line
|
||||
tool.
|
||||
This document provides information about using the `cache-apt-pkgs` command line tool.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
|
|
@ -24,8 +23,7 @@ cache-apt-pkgs install [flags] [packages]
|
|||
#### Flags for Install
|
||||
|
||||
- `--version`: Cache version identifier (optional)
|
||||
- `--execute-scripts`: Execute package install scripts (optional, default:
|
||||
false)
|
||||
- `--execute-scripts`: Execute package install scripts (optional, default: false)
|
||||
|
||||
#### Install Examples
|
||||
|
||||
|
|
@ -76,8 +74,7 @@ cache-apt-pkgs restore [flags] [packages]
|
|||
#### Flags for Restore
|
||||
|
||||
- `--version`: Cache version to restore from (optional)
|
||||
- `--execute-scripts`: Execute package install scripts (optional, default:
|
||||
false)
|
||||
- `--execute-scripts`: Execute package install scripts (optional, default: false)
|
||||
|
||||
#### Restore Examples
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +1,19 @@
|
|||
# 🤝 Contributing to cache-apt-pkgs-action
|
||||
|
||||
Thank you for your interest in contributing to cache-apt-pkgs-action! This
|
||||
document provides guidelines and instructions for contributing to the project.
|
||||
Thank you for your interest in contributing to cache-apt-pkgs-action! This document provides
|
||||
guidelines and instructions for contributing to the project.
|
||||
|
||||
[](https://github.com/awalsh128/cache-apt-pkgs-action/actions/workflows/ci.yml?query=branch%3Adev-v2.0)
|
||||
[](https://goreportcard.com/report/github.com/awalsh128/cache-apt-pkgs-action)
|
||||
[](https://pkg.go.dev/github.com/awalsh128/cache-apt-pkgs-action)
|
||||
[](https://github.com/awalsh128/cache-apt-pkgs-action/blob/dev-v2.0/LICENSE)
|
||||
[](https://github.com/awalsh128/cache-apt-pkgs-action/releases)
|
||||
|
||||
⚠️ **IMPORTANT**: This is a very unstable branch and will be introduced as
|
||||
version 2.0 once in beta.
|
||||
⚠️ **IMPORTANT**: This is a very unstable branch and will be introduced as version 2.0 once in beta.
|
||||
|
||||
## 🔗 Useful Links
|
||||
|
||||
- 📖
|
||||
[GitHub Action Documentation](https://github.com/awalsh128/cache-apt-pkgs-action#readme)
|
||||
- 📦
|
||||
[Go Package Documentation](https://pkg.go.dev/github.com/awalsh128/cache-apt-pkgs-action)
|
||||
- 🔄
|
||||
[GitHub Actions Workflow Status](https://github.com/awalsh128/cache-apt-pkgs-action/actions)
|
||||
- 📖 [GitHub Action Documentation](https://github.com/awalsh128/cache-apt-pkgs-action#readme)
|
||||
- 🔄 [GitHub Actions Workflow Status](https://github.com/awalsh128/cache-apt-pkgs-action/actions)
|
||||
- 🐛 [Issues](https://github.com/awalsh128/cache-apt-pkgs-action/issues)
|
||||
- 🛠️ [Pull Requests](https://github.com/awalsh128/cache-apt-pkgs-action/pulls)
|
||||
|
||||
|
|
@ -99,14 +93,13 @@ There are two ways to test the GitHub Action workflows:
|
|||
1. ☁️ **Using GitHub Actions**:
|
||||
- Push your changes to a branch
|
||||
- Create a PR to trigger the
|
||||
[test workflow](https://github.com/awalsh128/cache-apt-pkgs-action/blob/dev-v2.0/.github/workflows/test-action.yml)
|
||||
[test workflow](https://github.com/awalsh128/cache-apt-pkgs-action/blob/dev-v2.0/.github/workflows/action-tests.yml)
|
||||
- Or manually trigger the workflow from the
|
||||
[Actions tab](https://github.com/awalsh128/cache-apt-pkgs-action/actions/workflows/test-action.yml)
|
||||
|
||||
2. 🐳 **Running Tests Locally** (requires Docker):
|
||||
- Install Docker
|
||||
- 🪟 WSL users install
|
||||
[Docker Desktop](https://www.docker.com/products/docker-desktop/)
|
||||
- 🪟 WSL users install [Docker Desktop](https://www.docker.com/products/docker-desktop/)
|
||||
- 🐧 Non-WSL users (native Linux)
|
||||
|
||||
```bash
|
||||
|
|
@ -116,8 +109,7 @@ There are two ways to test the GitHub Action workflows:
|
|||
sudo systemctl start docker
|
||||
```
|
||||
|
||||
- 🎭 Install [`act`](https://github.com/nektos/act) for local GitHub Actions
|
||||
testing:
|
||||
- 🎭 Install [`act`](https://github.com/nektos/act) for local GitHub Actions testing:
|
||||
|
||||
- ▶️ Run `act` on any action test in the following ways:
|
||||
|
||||
|
|
@ -159,14 +151,13 @@ There are two ways to test the GitHub Action workflows:
|
|||
1. **Using GitHub Actions**:
|
||||
- Push your changes to a branch
|
||||
- Create a PR to trigger the
|
||||
[test workflow](https://github.com/awalsh128/cache-apt-pkgs-action/blob/dev-v2.0/.github/workflows/test-action.yml)
|
||||
[test workflow](https://github.com/awalsh128/cache-apt-pkgs-action/blob/dev-v2.0/.github/workflows/action-tests.yml)
|
||||
- Or manually trigger the workflow from the
|
||||
[Actions tab](https://github.com/awalsh128/cache-apt-pkgs-action/actions/workflows/test-action.yml)
|
||||
|
||||
2. **Running Tests Locally** (requires Docker):
|
||||
- Install Docker
|
||||
- WSL users install
|
||||
[Docker Desktop](https://www.docker.com/products/docker-desktop/)
|
||||
- WSL users install [Docker Desktop](https://www.docker.com/products/docker-desktop/)
|
||||
- Non-WSL users (native Linux)
|
||||
|
||||
```bash
|
||||
|
|
@ -176,8 +167,7 @@ There are two ways to test the GitHub Action workflows:
|
|||
sudo systemctl start docker
|
||||
```
|
||||
|
||||
- Install [`act`](https://github.com/nektos/act) for local GitHub Actions
|
||||
testing:
|
||||
- Install [`act`](https://github.com/nektos/act) for local GitHub Actions testing:
|
||||
|
||||
- Run `act` on any action test in the following ways:
|
||||
|
||||
|
|
@ -197,14 +187,12 @@ There are two ways to test the GitHub Action workflows:
|
|||
```
|
||||
|
||||
2. ✏️ Make your changes, following these guidelines:
|
||||
- 📚 Follow Go coding
|
||||
[standards and conventions](https://go.dev/doc/effective_go)
|
||||
- 📚 Follow Go coding [standards and conventions](https://go.dev/doc/effective_go)
|
||||
- ✅ Add tests for new features
|
||||
- 🎯 Test behaviors on the public interface not implementation
|
||||
- 🔍 Keep tests for each behavior separate
|
||||
- 🏭 Use constants and factory functions to keep testing arrangement and
|
||||
asserts clear. Not a lot of boilerplate not directly relevant to the
|
||||
test.
|
||||
- 🏭 Use constants and factory functions to keep testing arrangement and asserts clear. Not a
|
||||
lot of boilerplate not directly relevant to the test.
|
||||
- 📖 Update documentation as needed
|
||||
- 🎯 Keep commits focused and atomic
|
||||
- 📝 Write clear commit messages
|
||||
|
|
@ -230,11 +218,8 @@ There are two ways to test the GitHub Action workflows:
|
|||
|
||||
## 💻 Code Style Guidelines
|
||||
|
||||
- 📏 Follow
|
||||
[standard Go formatting](https://golang.org/doc/effective_go#formatting) (use
|
||||
`gofmt`)
|
||||
- 📖 Follow
|
||||
[Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments)
|
||||
- 📏 Follow [standard Go formatting](https://golang.org/doc/effective_go#formatting) (use `gofmt`)
|
||||
- 📖 Follow [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments)
|
||||
- 🔍 Write clear, self-documenting code
|
||||
- 📚 Add [GoDoc](https://blog.golang.org/godoc) comments for complex logic
|
||||
- 🏷️ Use meaningful variable and function names
|
||||
|
|
@ -247,8 +232,7 @@ There are two ways to test the GitHub Action workflows:
|
|||
📚 For more details on Go best practices, refer to:
|
||||
|
||||
- 📖 [Effective Go](https://golang.org/doc/effective_go)
|
||||
- 🔍
|
||||
[Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments)
|
||||
- 🔍 [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments)
|
||||
|
||||
## Documentation
|
||||
|
||||
|
|
@ -265,49 +249,15 @@ There are two ways to test the GitHub Action workflows:
|
|||
|
||||
## Questions or Problems?
|
||||
|
||||
- Open an [issue](https://github.com/awalsh128/cache-apt-pkgs-action/issues/new)
|
||||
for bugs or feature requests
|
||||
- Use
|
||||
[discussions](https://github.com/awalsh128/cache-apt-pkgs-action/discussions)
|
||||
for questions or ideas
|
||||
- Open an [issue](https://github.com/awalsh128/cache-apt-pkgs-action/issues/new) for bugs or feature
|
||||
requests
|
||||
- Reference the
|
||||
[GitHub Action documentation](https://github.com/awalsh128/cache-apt-pkgs-action#readme)
|
||||
- Check existing
|
||||
[issues](https://github.com/awalsh128/cache-apt-pkgs-action/issues) and
|
||||
- Check existing [issues](https://github.com/awalsh128/cache-apt-pkgs-action/issues) and
|
||||
[pull requests](https://github.com/awalsh128/cache-apt-pkgs-action/pulls)
|
||||
- Tag maintainers for urgent issues
|
||||
|
||||
## License
|
||||
|
||||
By contributing to this project, you agree that your contributions will be
|
||||
licensed under the same license as the project.
|
||||
|
||||
## 📦 Publishing to pkg.go.dev
|
||||
|
||||
NOTE: This is done by the maintainers
|
||||
|
||||
To make the library available on [pkg.go.dev](https://pkg.go.dev):
|
||||
|
||||
1. 🏷️ Ensure your code is tagged with a version:
|
||||
|
||||
```bash
|
||||
git tag v2.0.0 # Use semantic versioning
|
||||
git push origin v2.0.0
|
||||
```
|
||||
|
||||
2. 🔄 Trigger pkg.go.dev to fetch your module:
|
||||
- Visit
|
||||
[pkg.go.dev for this module](https://pkg.go.dev/github.com/awalsh128/cache-apt-pkgs-action@v2.0.0)
|
||||
- Or fetch via command line:
|
||||
|
||||
```bash
|
||||
GOPROXY=https://proxy.golang.org GO111MODULE=on go get github.com/awalsh128/cache-apt-pkgs-action@v2.0.0
|
||||
```
|
||||
|
||||
3. 📝 Best practices for publishing:
|
||||
- Add comprehensive `godoc` comments
|
||||
- Include examples in your documentation
|
||||
- Use semantic versioning for tags
|
||||
- Keep the module path consistent
|
||||
- Update go.mod with the correct module path
|
||||
- [Go Best Practices](https://golang.org/doc/effective_go#names)
|
||||
By contributing to this project, you agree that your contributions will be licensed under the same
|
||||
license as the project.
|
||||
|
|
|
|||
79
README.md
79
README.md
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
[](https://github.com/awalsh128/cache-apt-pkgs-action/actions/workflows/ci.yml?query=branch%3Adev-v2.0)
|
||||
[](https://goreportcard.com/report/github.com/awalsh128/cache-apt-pkgs-action)
|
||||
[](https://pkg.go.dev/github.com/awalsh128/cache-apt-pkgs-action)
|
||||
[](https://github.com/awalsh128/cache-apt-pkgs-action/blob/dev-v2.0/LICENSE)
|
||||
[](https://github.com/awalsh128/cache-apt-pkgs-action/releases)
|
||||
|
||||
|
|
@ -36,14 +35,12 @@
|
|||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
Speed up your GitHub Actions workflows by caching APT package dependencies. This
|
||||
action integrates with [actions/cache](https://github.com/actions/cache/) to
|
||||
provide efficient package caching, significantly reducing workflow execution
|
||||
time by avoiding repeated package installations.
|
||||
Speed up your GitHub Actions workflows by caching APT package dependencies. This action integrates
|
||||
with [actions/cache](https://github.com/actions/cache/) to provide efficient package caching,
|
||||
significantly reducing workflow execution time by avoiding repeated package installations.
|
||||
|
||||
> **Important:** We're looking for co-maintainers to help review changes and
|
||||
> investigate issues. If you're interested in contributing to this project,
|
||||
> please reach out.
|
||||
> **Important:** We're looking for co-maintainers to help review changes and investigate issues. If
|
||||
> you're interested in contributing to this project, please reach out.
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
|
|
@ -92,10 +89,9 @@ steps:
|
|||
|
||||
### Version Selection
|
||||
|
||||
> ⚠️ The action enforces immutable references. Workflows must pin
|
||||
> `awalsh128/cache-apt-pkgs-action` to a release tag or commit SHA. Referencing
|
||||
> a branch (for example `@main`) will now fail during the `setup` step. For more
|
||||
> information on blocking and SHA pinning actions, see the
|
||||
> ⚠️ The action enforces immutable references. Workflows must pin `awalsh128/cache-apt-pkgs-action`
|
||||
> to a release tag or commit SHA. Referencing a branch (for example `@main`) will now fail during
|
||||
> the `setup` step. For more information on blocking and SHA pinning actions, see the
|
||||
> [announcement on the GitHub changelog](https://github.blog/changelog/2025-08-15-github-actions-policy-now-supports-blocking-and-sha-pinning-actions).
|
||||
|
||||
Recommended options:
|
||||
|
|
@ -103,9 +99,8 @@ Recommended options:
|
|||
- `@v2` or any other published release tag.
|
||||
- A full commit SHA such as `@4f5c863ba5ce9f1784c8ad7d8f63a9cfd3f1ab2c`.
|
||||
|
||||
Avoid floating references such as `@latest`, `@master`, or `@dev`. The action
|
||||
will refuse to run when a branch reference is detected to protect consumers from
|
||||
involuntary updates.
|
||||
Avoid floating references such as `@latest`, `@master`, or `@dev`. The action will refuse to run
|
||||
when a branch reference is detected to protect consumers from involuntary updates.
|
||||
|
||||
### Example Workflows
|
||||
|
||||
|
|
@ -210,39 +205,34 @@ permissions:
|
|||
|
||||
## 🤝 Contributing
|
||||
|
||||
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md)
|
||||
for details.
|
||||
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
||||
|
||||
## 📜 License
|
||||
|
||||
This project is licensed under the Apache License 2.0 - see the
|
||||
[LICENSE](LICENSE) file for details.
|
||||
This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
## Caveats
|
||||
|
||||
### Edge Cases
|
||||
|
||||
This action is able to speed up installs by skipping the number of steps that
|
||||
`apt` uses.
|
||||
This action is able to speed up installs by skipping the number of steps that `apt` uses.
|
||||
|
||||
- This means there will be certain cases that it may not be able to handle like
|
||||
state management of other file configurations outside the package scope.
|
||||
- In cases that can't be immediately addressed or run counter to the approach of
|
||||
this action, the packages affected should go into their own action `step` and
|
||||
using the normal `apt` utility.
|
||||
- This means there will be certain cases that it may not be able to handle like state management of
|
||||
other file configurations outside the package scope.
|
||||
- In cases that can't be immediately addressed or run counter to the approach of this action, the
|
||||
packages affected should go into their own action `step` and using the normal `apt` utility.
|
||||
|
||||
### Non-file Dependencies
|
||||
|
||||
This action is based on the principle that most packages can be cached as a set
|
||||
of files. There are situations though where this is not enough.
|
||||
This action is based on the principle that most packages can be cached as a set of files. There are
|
||||
situations though where this is not enough.
|
||||
|
||||
- Pre and post installation scripts need to be run from
|
||||
- Pre-installation and post-installation scripts need to be run from
|
||||
`/var/lib/dpkg/info/{package name}.[preinst, postinst]`.
|
||||
- The Debian package database needs to be queried for scripts above (i.e.
|
||||
`dpkg-query`).
|
||||
- The Debian package database needs to be queried for scripts above (i.e. `dpkg-query`).
|
||||
|
||||
The `execute_install_scripts` argument can be used to attempt to execute the
|
||||
install scripts but they are no guaranteed to resolve the issue.
|
||||
The `execute_install_scripts` argument can be used to attempt to execute the install scripts but
|
||||
they are no guaranteed to resolve the issue.
|
||||
|
||||
```yaml
|
||||
- uses: awalsh128/cache-apt-pkgs-action@latest
|
||||
|
|
@ -252,19 +242,18 @@ install scripts but they are no guaranteed to resolve the issue.
|
|||
execute_install_scripts: true
|
||||
```
|
||||
|
||||
If this does not solve your issue, you will need to run `apt-get install` as a
|
||||
separate step for that particular package unfortunately.
|
||||
If this does not solve your issue, you will need to run `apt-get install` as a separate step for
|
||||
that particular package unfortunately.
|
||||
|
||||
```yaml
|
||||
run: apt-get install mypackage
|
||||
shell: bash
|
||||
```
|
||||
|
||||
Please reach out if you have found a workaround for your scenario and it can be
|
||||
generalized. There is only so much this action can do and can't get into the
|
||||
area of reverse engineering Debian package manager. It would be beyond the scope
|
||||
of this action and may result in a lot of extended support and brittleness.
|
||||
Also, it would be better to contribute to Debian packager instead at that point.
|
||||
Please reach out if you have found a workaround for your scenario and it can be generalized. There
|
||||
is only so much this action can do and can't get into the area of reverse engineering Debian package
|
||||
manager. It would be beyond the scope of this action and may result in a lot of extended support and
|
||||
brittleness. Also, it would be better to contribute to Debian packager instead at that point.
|
||||
|
||||
For more context and information see
|
||||
[issue #57](https://github.com/awalsh128/cache-apt-pkgs-action/issues/57#issuecomment-1321024283)
|
||||
|
|
@ -272,14 +261,12 @@ which contains the investigation and conclusion.
|
|||
|
||||
### Cache Limits
|
||||
|
||||
A repository can have up to 5GB of caches. Once the 5GB limit is reached, older
|
||||
caches will be evicted based on when the cache was last accessed. Caches that
|
||||
are not accessed within the last week will also be evicted. To get more
|
||||
information on how to access and manage your actions's caches, see
|
||||
A repository can have up to 5GB of caches. Once the 5GB limit is reached, older caches will be
|
||||
evicted based on when the cache was last accessed. Caches that are not accessed within the last week
|
||||
will also be evicted. To get more information on how to access and manage your actions's caches, see
|
||||
[GitHub Actions / Using workflows / Cache dependencies](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#viewing-cache-entries).
|
||||
|
||||
## 🌟 Acknowledgements
|
||||
|
||||
- [actions/cache](https://github.com/actions/cache/) team
|
||||
- All our
|
||||
[contributors](https://github.com/awalsh128/cache-apt-pkgs-action/graphs/contributors)
|
||||
- All our [contributors](https://github.com/awalsh128/cache-apt-pkgs-action/graphs/contributors)
|
||||
|
|
|
|||
25
action.yml
25
action.yml
|
|
@ -7,19 +7,22 @@ branding:
|
|||
inputs:
|
||||
packages:
|
||||
description: >
|
||||
Space delimited list of packages to install. Version can be specified optionally using APT command syntax of <name>=<version> (e.g. xdot=1.2-2).
|
||||
Space delimited list of packages to install. Version can be specified optionally using APT
|
||||
command syntax of <name>=<version> (e.g. xdot=1.2-2).
|
||||
|
||||
required: true
|
||||
default: ""
|
||||
version:
|
||||
description: >
|
||||
Version of cache to load. Each version will have its own cache. Note, all characters except spaces are allowed.
|
||||
Version of cache to load. Each version will have its own cache. Note, all characters except
|
||||
spaces are allowed.
|
||||
|
||||
required: false
|
||||
default: ""
|
||||
execute_install_scripts:
|
||||
description: >
|
||||
Execute Debian package pre and post install script upon restore. See README.md caveats for more information.
|
||||
Execute Debian package pre and post install script upon restore. See README.md caveats
|
||||
for more information.
|
||||
|
||||
required: false
|
||||
default: "false"
|
||||
|
|
@ -35,14 +38,22 @@ outputs:
|
|||
value: ${{ steps.load-cache.outputs.cache-hit || false }}
|
||||
package-version-list:
|
||||
description: >
|
||||
The main requested packages and versions that are installed. Represented as a comma delimited list with equals delimit on the package version (i.e. <package>:<version,<package>:<version>).
|
||||
The main requested packages and versions that are installed. Represented as a comma
|
||||
delimited list with equals delimit on the package version (i.e.
|
||||
<package>:<version,<package>:<version>).
|
||||
|
||||
value: ${{ steps.install-pkgs.outputs.package-version-list || steps.restore-pkgs.outputs.package-version-list }}
|
||||
value:
|
||||
${{ steps.install-pkgs.outputs.package-version-list ||
|
||||
steps.restore-pkgs.outputs.package-version-list }}
|
||||
all-package-version-list:
|
||||
description: >
|
||||
All the pulled in packages and versions, including dependencies, that are installed. Represented as a comma delimited list with equals delimit on the package version (i.e. <package>:<version,<package>:<version>).
|
||||
All the pulled in packages and versions, including dependencies, that are
|
||||
installed. Represented as a comma delimited list with equals delimit on the package version
|
||||
(i.e. <package>:<version,<package>:<version>).
|
||||
|
||||
value: ${{ steps.install-pkgs.outputs.all-package-version-list || steps.restore-pkgs.outputs.all-package-version-list }}
|
||||
value:
|
||||
${{ steps.install-pkgs.outputs.all-package-version-list ||
|
||||
steps.restore-pkgs.outputs.all-package-version-list }}
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
|
|
|
|||
117
cmd/cache_apt_pkgs/cmdflags/cmd.go
Normal file
117
cmd/cache_apt_pkgs/cmdflags/cmd.go
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// Package cmdflags provides types and utilities for parsing command-line flags
|
||||
// and managing subcommands in the cache-apt-pkgs CLI tool.
|
||||
package cmdflags
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"awalsh128.com/cache-apt-pkgs-action/internal/cio"
|
||||
"awalsh128.com/cache-apt-pkgs-action/internal/logging"
|
||||
"awalsh128.com/cache-apt-pkgs-action/internal/pkgs"
|
||||
)
|
||||
|
||||
// Cmd represents a command-line subcommand with its associated flags and behavior.
|
||||
// Each command has a name, description, set of flags, and a function to execute the command.
|
||||
type Cmd struct {
|
||||
// Name is the command identifier used in CLI arguments
|
||||
Name string
|
||||
// Description explains what the command does
|
||||
Description string
|
||||
// Flags contains the command-specific command-line flags
|
||||
Flags *flag.FlagSet
|
||||
// Run executes the command with the given packages and returns any errors
|
||||
Run func(cmd *Cmd, pkgArgs pkgs.Packages) error
|
||||
// GhioPrinter provides an interface for GitHub Actions output printing that supports testing
|
||||
// locally and in Action workflows
|
||||
GhioPrinter cio.GhPrinter
|
||||
// Examples provides example usage strings for the command
|
||||
Examples []string
|
||||
// ExamplePackages provides example package arguments for documentation and testing
|
||||
ExamplePackages pkgs.Packages
|
||||
}
|
||||
|
||||
// NewCmd creates a new command with the given name, description, examples, and run function.
|
||||
// It automatically includes global flags and sets up the usage documentation.
|
||||
// The returned Cmd is ready to be used as a subcommand in the CLI.
|
||||
func NewCmd(name, description string, examples []string, runFunc func(cmd *Cmd, pkgArgs pkgs.Packages) error) *Cmd {
|
||||
flags := flag.NewFlagSet(name, flag.ExitOnError)
|
||||
globalFlags.VisitAll(func(f *flag.Flag) {
|
||||
flags.Var(f.Value, f.Name, f.Usage)
|
||||
})
|
||||
flags.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "usage: %s %s [flags] [packages]\n\n%s\n\n", binaryName, name, description)
|
||||
fmt.Fprintf(os.Stderr, "flags:\n")
|
||||
flags.VisitAll(func(f *flag.Flag) {
|
||||
fmt.Fprintf(os.Stderr, " -%s: %s\n", f.Name, f.Usage)
|
||||
})
|
||||
fmt.Fprintf(os.Stderr, "\nexamples:\n")
|
||||
for _, example := range examples {
|
||||
fmt.Fprintf(os.Stderr, " %s %s %s\n", binaryName, name, example)
|
||||
}
|
||||
}
|
||||
wrappedRunFunc := func(cmd *Cmd, pkgArgs pkgs.Packages) error {
|
||||
// If any command args include help flag, print usage and don't execute command.
|
||||
if helpFlagSet(cmd.Flags) {
|
||||
cmd.Flags.Usage()
|
||||
return nil
|
||||
}
|
||||
return runFunc(cmd, pkgArgs)
|
||||
}
|
||||
return &Cmd{
|
||||
Name: name,
|
||||
Description: description,
|
||||
Flags: flags,
|
||||
Run: wrappedRunFunc,
|
||||
GhioPrinter: cio.NewGhPrinter(),
|
||||
Examples: examples,
|
||||
ExamplePackages: ExamplePackages,
|
||||
}
|
||||
}
|
||||
|
||||
// StringFlag returns the string value of a flag by name.
|
||||
// It panics if the flag does not exist, so ensure the flag exists before calling.
|
||||
func (c *Cmd) StringFlag(name string) string {
|
||||
return c.Flags.Lookup(name).Value.String()
|
||||
}
|
||||
|
||||
// parseFlags processes command line arguments for the command.
|
||||
// It validates required flags and parses package arguments.
|
||||
// Returns the parsed package arguments or exits with an error if validation fails.
|
||||
func (c *Cmd) parseFlags() (pkgs.Packages, error) {
|
||||
logging.Debug("Parsing flags for command %q with args: %v", c.Name, os.Args[2:])
|
||||
if len(os.Args) < 3 {
|
||||
return nil, fmt.Errorf("command %q requires arguments", c.Name)
|
||||
}
|
||||
// Parse the command line flags
|
||||
if err := c.Flags.Parse(os.Args[2:]); err != nil {
|
||||
return nil, fmt.Errorf("unable to parse flags for command %q: %v", c.Name, err)
|
||||
}
|
||||
|
||||
// Check for missing required flags
|
||||
missingFlagNames := []string{}
|
||||
c.Flags.VisitAll(func(f *flag.Flag) {
|
||||
// Skip all global flags since they are considered optional
|
||||
if gf := globalFlags.Lookup(f.Name); gf != nil {
|
||||
return
|
||||
}
|
||||
if f.DefValue == "" && f.Value.String() == "" {
|
||||
logging.Info("Missing required flag: %s", f.Name)
|
||||
missingFlagNames = append(missingFlagNames, f.Name)
|
||||
}
|
||||
})
|
||||
if len(missingFlagNames) > 0 {
|
||||
return nil, fmt.Errorf("missing required flags for command %q: %s", c.Name, missingFlagNames)
|
||||
}
|
||||
logging.Debug("Parsed flags successfully")
|
||||
|
||||
// Parse the remaining arguments as package arguments
|
||||
pkgArgs, err := pkgs.ParsePackageArgs(c.Flags.Args())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse package arguments for command %q: %v", c.Name, err)
|
||||
}
|
||||
logging.Debug("Parsed package arguments:\n%s", strings.Join(c.Flags.Args(), "\n "))
|
||||
return pkgArgs, nil
|
||||
}
|
||||
105
cmd/cache_apt_pkgs/cmdflags/cmd_test.go
Normal file
105
cmd/cache_apt_pkgs/cmdflags/cmd_test.go
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
package cmdflags
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"testing"
|
||||
|
||||
"awalsh128.com/cache-apt-pkgs-action/internal/pkgs"
|
||||
)
|
||||
|
||||
const (
|
||||
flagSetName = "test_flag_set_name"
|
||||
flagName = "test-flag"
|
||||
flagValue = "test_flag_value"
|
||||
flagDefaultValue = "test_default_flag_value"
|
||||
flagDescription = "This is a test flag"
|
||||
cmdName = "test-command-name"
|
||||
argExample = "test-package"
|
||||
requiredFlagName = "required-flag"
|
||||
)
|
||||
|
||||
func TestCmd_StringFlag(t *testing.T) {
|
||||
cmd := &Cmd{
|
||||
Name: cmdName,
|
||||
Flags: flag.NewFlagSet(flagSetName, flag.ContinueOnError),
|
||||
}
|
||||
cmd.Flags.String(flagName, flagDefaultValue, flagDescription)
|
||||
|
||||
// Parse some args to set the flag value
|
||||
cmd.Flags.Set(flagName, flagValue)
|
||||
|
||||
result := cmd.StringFlag(flagName)
|
||||
if result != flagValue {
|
||||
t.Errorf("Expected %q, got %q", flagValue, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewCmd(t *testing.T) {
|
||||
runCalled := false
|
||||
runFunc := func(cmd *Cmd, pkgArgs pkgs.Packages) error {
|
||||
runCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := NewCmd(cmdName, "test description", []string{argExample}, runFunc)
|
||||
|
||||
if cmd == nil {
|
||||
t.Fatal("NewCmd returned nil")
|
||||
}
|
||||
if cmd.Name != cmdName {
|
||||
t.Errorf("Expected name %q, got %q", cmdName, cmd.Name)
|
||||
}
|
||||
if cmd.Description == "" {
|
||||
t.Error("Expected non-empty description")
|
||||
}
|
||||
if cmd.Flags == nil {
|
||||
t.Error("Expected flags to be initialized")
|
||||
}
|
||||
if cmd.Run == nil {
|
||||
t.Error("Expected Run function to be set")
|
||||
}
|
||||
if len(cmd.Examples) != 1 {
|
||||
t.Errorf("Expected 1 example, got %d", len(cmd.Examples))
|
||||
}
|
||||
|
||||
// Test that Run function works
|
||||
err := cmd.Run(cmd, pkgs.NewPackages())
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error calling Run: %v", err)
|
||||
}
|
||||
if !runCalled {
|
||||
t.Error("Expected run function to be called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCmd_ParseFlagsLogic(t *testing.T) {
|
||||
t.Run("missing required flags", func(t *testing.T) {
|
||||
cmd := NewCmd(cmdName, "test description", []string{argExample}, func(cmd *Cmd, pkgArgs pkgs.Packages) error {
|
||||
return nil
|
||||
})
|
||||
cmd.Flags.String(requiredFlagName, "", "required flag description")
|
||||
|
||||
// Test that the flag was added
|
||||
requiredFlag := cmd.Flags.Lookup(requiredFlagName)
|
||||
if requiredFlag == nil {
|
||||
t.Error("Expected required-flag to be registered")
|
||||
}
|
||||
if requiredFlag.DefValue != "" {
|
||||
t.Error("Expected required-flag to have empty default value")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("flag registration", func(t *testing.T) {
|
||||
cmd := NewCmd(cmdName, "test description", []string{}, func(cmd *Cmd, pkgArgs pkgs.Packages) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
// Check that global flags are inherited
|
||||
if cmd.Flags.Lookup("verbose") == nil {
|
||||
t.Error("Expected verbose flag to be inherited from global flags")
|
||||
}
|
||||
if cmd.Flags.Lookup("help") == nil {
|
||||
t.Error("Expected help flag to be inherited from global flags")
|
||||
}
|
||||
})
|
||||
}
|
||||
87
cmd/cache_apt_pkgs/cmdflags/cmds.go
Normal file
87
cmd/cache_apt_pkgs/cmdflags/cmds.go
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
package cmdflags
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"awalsh128.com/cache-apt-pkgs-action/internal/pkgs"
|
||||
)
|
||||
|
||||
// Cmds is a collection of subcommands indexed by their names.
|
||||
// It provides methods for managing and executing CLI subcommands.
|
||||
type Cmds map[string]*Cmd
|
||||
|
||||
// Add registers a new command to the command set.
|
||||
// Returns an error if a command with the same name already exists.
|
||||
func (c *Cmds) Add(cmd *Cmd) error {
|
||||
if _, exists := (*c)[cmd.Name]; exists {
|
||||
return fmt.Errorf("command %q already exists", cmd.Name)
|
||||
}
|
||||
(*c)[cmd.Name] = cmd
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get retrieves a command by name.
|
||||
// Returns the command and true if found, or nil and false if not found.
|
||||
func (c *Cmds) Get(name string) (*Cmd, bool) {
|
||||
cmd, ok := (*c)[name]
|
||||
return cmd, ok
|
||||
}
|
||||
|
||||
// usage prints the overall usage help for all commands.
|
||||
func (c *Cmds) usage() {
|
||||
fmt.Fprintf(os.Stderr, "usage: %s <command> [flags] [packages]\n\n", binaryName)
|
||||
fmt.Fprintf(os.Stderr, "commands:\n")
|
||||
for _, cmd := range *c {
|
||||
fmt.Fprintf(os.Stderr, " %s: %s\n", cmd.Name, cmd.Description)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "\nflags:\n")
|
||||
// Print global flags (from any command, since they are the same)
|
||||
globalFlags.VisitAll(func(f *flag.Flag) {
|
||||
fmt.Fprintf(os.Stderr, " -%s: %s\n", f.Name, f.Usage)
|
||||
})
|
||||
fmt.Fprintf(os.Stderr, "\nUse \"%s <command> --help\" for more information about a command.\n", binaryName)
|
||||
}
|
||||
|
||||
// Parse processes the command line arguments to determine the command to run
|
||||
// and its package arguments. Handles help requests and invalid commands.
|
||||
// Returns the command, package arguments, and any error encountered.
|
||||
func (c *Cmds) Parse() (*Cmd, pkgs.Packages, error) {
|
||||
if len(os.Args) < 2 {
|
||||
c.usage()
|
||||
return nil, nil, fmt.Errorf("no command specified")
|
||||
}
|
||||
|
||||
cmdName := os.Args[1]
|
||||
if cmdName == "--"+helpFlagName || cmdName == "-"+helpShortFlagName {
|
||||
c.usage()
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
cmd, ok := c.Get(cmdName)
|
||||
if !ok {
|
||||
c.usage()
|
||||
return nil, nil, fmt.Errorf("unknown command %q", cmdName)
|
||||
}
|
||||
|
||||
pkgArgs, err := cmd.parseFlags()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if pkgArgs == nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse package arguments for command %q", cmd.Name)
|
||||
}
|
||||
|
||||
return cmd, pkgArgs, nil
|
||||
}
|
||||
|
||||
// CreateCmds initializes a new command set with the provided commands.
|
||||
// Each command is added to the set, and the resulting set is returned.
|
||||
func CreateCmds(cmd ...*Cmd) *Cmds {
|
||||
commands := &Cmds{}
|
||||
for _, c := range cmd {
|
||||
commands.Add(c)
|
||||
}
|
||||
return commands
|
||||
}
|
||||
141
cmd/cache_apt_pkgs/cmdflags/cmds_test.go
Normal file
141
cmd/cache_apt_pkgs/cmdflags/cmds_test.go
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
package cmdflags
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"awalsh128.com/cache-apt-pkgs-action/internal/pkgs"
|
||||
)
|
||||
|
||||
const (
|
||||
cmdName1 = "test-command-1"
|
||||
cmdName2 = "test-command-2"
|
||||
)
|
||||
|
||||
func TestCmds_Add(t *testing.T) {
|
||||
cmds := make(Cmds)
|
||||
cmd := NewCmd(cmdName, "test description", []string{argExample}, func(cmd *Cmd, pkgArgs pkgs.Packages) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
err := cmds.Add(cmd)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if len(cmds) != 1 {
|
||||
t.Errorf("Expected 1 command, got %d", len(cmds))
|
||||
}
|
||||
if _, exists := cmds[cmdName]; !exists {
|
||||
t.Errorf("Expected command %q to be added", cmdName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCmds_Get(t *testing.T) {
|
||||
cmds := make(Cmds)
|
||||
expectedCmd := NewCmd(cmdName, "test description", []string{argExample}, func(cmd *Cmd, pkgArgs pkgs.Packages) error {
|
||||
return nil
|
||||
})
|
||||
cmds.Add(expectedCmd)
|
||||
|
||||
t.Run("existing command", func(t *testing.T) {
|
||||
cmd, ok := cmds.Get(cmdName)
|
||||
if !ok {
|
||||
t.Error("Expected to find command")
|
||||
}
|
||||
if cmd != expectedCmd {
|
||||
t.Error("Expected to get the same command instance")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("non-existing command", func(t *testing.T) {
|
||||
_, ok := cmds.Get("non-existent-command")
|
||||
if ok {
|
||||
t.Error("Expected not to find non-existent command")
|
||||
}
|
||||
})
|
||||
|
||||
// Test multiple commands
|
||||
cmd1 := NewCmd(cmdName1, "description 1", []string{}, func(cmd *Cmd, pkgArgs pkgs.Packages) error { return nil })
|
||||
cmd2 := NewCmd(cmdName2, "description 2", []string{}, func(cmd *Cmd, pkgArgs pkgs.Packages) error { return nil })
|
||||
|
||||
cmds2 := make(Cmds)
|
||||
cmds2.Add(cmd1)
|
||||
cmds2.Add(cmd2)
|
||||
|
||||
if _, ok := cmds2.Get(cmdName1); !ok {
|
||||
t.Errorf("Expected to find %s", cmdName1)
|
||||
}
|
||||
if _, ok := cmds2.Get(cmdName2); !ok {
|
||||
t.Errorf("Expected to find %s", cmdName2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateCmds(t *testing.T) {
|
||||
cmds := CreateCmds()
|
||||
|
||||
expectedCommands := []string{"install", "restore", "validate", "setup", "cleanup", "createkey"}
|
||||
|
||||
if len(*cmds) != len(expectedCommands) {
|
||||
t.Errorf("Expected %d commands, got %d", len(expectedCommands), len(*cmds))
|
||||
}
|
||||
|
||||
for _, cmdName := range expectedCommands {
|
||||
cmd, ok := cmds.Get(cmdName)
|
||||
if !ok {
|
||||
t.Errorf("Expected command %q to exist", cmdName)
|
||||
continue
|
||||
}
|
||||
if cmd.Name != cmdName {
|
||||
t.Errorf("Expected command name %q, got %q", cmdName, cmd.Name)
|
||||
}
|
||||
if cmd.Description == "" {
|
||||
t.Errorf("Expected non-empty description for command %q", cmdName)
|
||||
}
|
||||
if cmd.Flags == nil {
|
||||
t.Errorf("Expected flags to be initialized for command %q", cmdName)
|
||||
}
|
||||
if cmd.Run == nil {
|
||||
t.Errorf("Expected Run function to be set for command %q", cmdName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCmds_Parse(t *testing.T) {
|
||||
// Note: These tests don't call Parse() directly as it calls os.Exit
|
||||
// Instead they test the Parse method's logic through integration with os.Args
|
||||
|
||||
origArgs := os.Args
|
||||
defer func() { os.Args = origArgs }()
|
||||
|
||||
t.Run("missing command", func(t *testing.T) {
|
||||
// Test the condition that would trigger the missing command error
|
||||
os.Args = []string{binaryName}
|
||||
// Can't actually call Parse() here as it will exit the test process
|
||||
// Just verify the setup
|
||||
if len(os.Args) < 2 {
|
||||
t.Log("Command would be missing, Parse() would show usage")
|
||||
}
|
||||
})
|
||||
|
||||
const pkgArg1 = "test-package=1.1-beta"
|
||||
const pkgArg2 = "test-package=2.0"
|
||||
|
||||
t.Run("valid command with packages", func(t *testing.T) {
|
||||
os.Args = []string{binaryName, cmdName, pkgArg1, pkgArg2}
|
||||
|
||||
if len(os.Args) >= 4 {
|
||||
actualCmdName := os.Args[1]
|
||||
actualPkgArgs := os.Args[2:]
|
||||
|
||||
if actualCmdName != cmdName {
|
||||
t.Errorf("Expected command '%s', got %s", cmdName, actualCmdName)
|
||||
}
|
||||
if len(actualPkgArgs) != 2 {
|
||||
t.Errorf("Expected 2 package args, got %d", len(actualPkgArgs))
|
||||
}
|
||||
} else {
|
||||
t.Error("Expected at least 4 args for this test")
|
||||
}
|
||||
})
|
||||
}
|
||||
6
cmd/cache_apt_pkgs/cmdflags/doc.go
Normal file
6
cmd/cache_apt_pkgs/cmdflags/doc.go
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// Package cmdflags provides command-line flag handling and command management for cache-apt-pkgs.
|
||||
//
|
||||
// The package is responsible for parsing and validating command-line arguments used
|
||||
// to control the action's behavior. It is an extension of the standard flag package with support
|
||||
// for subcommands and shared global flags.
|
||||
package cmdflags
|
||||
48
cmd/cache_apt_pkgs/cmdflags/shared.go
Normal file
48
cmd/cache_apt_pkgs/cmdflags/shared.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
// Package cmdflags provides types and utilities for parsing command-line flags
|
||||
// and managing subcommands in the cache-apt-pkgs CLI tool.
|
||||
package cmdflags
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"awalsh128.com/cache-apt-pkgs-action/internal/pkgs"
|
||||
)
|
||||
|
||||
// ExamplePackages provides a set of sample packages used for testing and documentation.
|
||||
// It includes rolldice, xdot with a specific version, and libgtk-3-dev.
|
||||
var ExamplePackages = pkgs.NewPackages(
|
||||
pkgs.Package{Name: "rolldice"},
|
||||
pkgs.Package{Name: "xdot", Version: "1.1-2"},
|
||||
pkgs.Package{Name: "libgtk-3-dev"},
|
||||
)
|
||||
|
||||
// binaryName is the base name of the command executable, used in usage and error messages.
|
||||
var binaryName = filepath.Base(os.Args[0])
|
||||
|
||||
const (
|
||||
helpFlagName = "help"
|
||||
helpShortFlagName = "h"
|
||||
)
|
||||
|
||||
// globalFlags defines the command-line flags that apply to all commands.
|
||||
// It includes options for verbosity and help documentation.
|
||||
var globalFlags = func() *flag.FlagSet {
|
||||
flags := flag.NewFlagSet("global", flag.ExitOnError)
|
||||
flags.BoolVar(new(bool), "verbose", false, "Enable verbose logging")
|
||||
flags.BoolVar(new(bool), "v", false, "Enable verbose logging (shorthand)")
|
||||
flags.BoolVar(new(bool), helpFlagName, false, "Show help")
|
||||
flags.BoolVar(new(bool), helpShortFlagName, false, "Show help (shorthand)")
|
||||
return flags
|
||||
}()
|
||||
|
||||
// helpFlagSet checks if the help flag is set in the given flag set.
|
||||
func helpFlagSet(flags *flag.FlagSet) bool {
|
||||
for _, name := range []string{helpFlagName, helpShortFlagName} {
|
||||
if f := flags.Lookup(name); f != nil && f.Value.String() == "true" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
4
cmd/cache_apt_pkgs/doc.go
Normal file
4
cmd/cache_apt_pkgs/doc.go
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// Package main implements the cache-apt-pkgs GitHub Action.
|
||||
// This action caches APT packages to speed up CI/CD workflows by avoiding
|
||||
// repeated package downloads and installations.
|
||||
package main
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
|
@ -8,11 +9,43 @@ import (
|
|||
|
||||
"awalsh128.com/cache-apt-pkgs-action/internal/logging"
|
||||
atesting "awalsh128.com/cache-apt-pkgs-action/internal/testing"
|
||||
"github.com/awalsh128/syspkg"
|
||||
"github.com/awalsh128/syspkg/manager"
|
||||
)
|
||||
|
||||
func installAptFastIfMissing(t *testing.T) error {
|
||||
t.Helper()
|
||||
registry, err := syspkg.New(syspkg.IncludeOptions{Apt: true})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize syspkg: %v", err)
|
||||
}
|
||||
|
||||
// Get APT package manager (if available)
|
||||
aptManager, err := registry.GetPackageManager("apt-fast")
|
||||
if err != nil {
|
||||
return fmt.Errorf("APT package manager not available: %v", err)
|
||||
}
|
||||
|
||||
_, err = aptManager.ListInstalledFiles("apt-fast")
|
||||
if err != nil {
|
||||
logging.Info("apt-fast not installed, attempting installation.")
|
||||
_, err := aptManager.Install(
|
||||
[]string{"apt-fast"}, &manager.Options{AssumeYes: true, Verbose: true},
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to install apt-fast: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetupTest performs per-test initialization and registers cleanup hooks.
|
||||
func SetupTest(t *testing.T) {
|
||||
logging.Init(true)
|
||||
err := installAptFastIfMissing(t)
|
||||
if err != nil {
|
||||
t.Fatalf("Aborting testt: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
logging.InitDefault()
|
||||
})
|
||||
|
|
|
|||
357
internal/actions/action.go
Normal file
357
internal/actions/action.go
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
package actions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const parserIndentSize = 2
|
||||
|
||||
// Action represents a complete GitHub Action configuration with all its metadata,
|
||||
// inputs, outputs, and execution details.
|
||||
//
|
||||
// Action corresponds to the structure of an action.yml file and contains all
|
||||
// necessary information to define a GitHub Action including:
|
||||
// - Metadata (name, description, author)
|
||||
// - Branding (icon, color for GitHub marketplace)
|
||||
// - Inputs (parameters that can be passed to the action)
|
||||
// - Outputs (values the action produces)
|
||||
// - Runs (execution configuration and steps)
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// action := &Action{
|
||||
// Name: "My Action",
|
||||
// Description: "Does something useful",
|
||||
// Author: "username",
|
||||
// Inputs: Inputs{...},
|
||||
// Outputs: Outputs{...},
|
||||
// Runs: Runs{...},
|
||||
// }
|
||||
//
|
||||
// Actions can be loaded from YAML files:
|
||||
//
|
||||
// action := &Action{}
|
||||
// err := action.LoadFromFile("action.yml")
|
||||
type Action struct {
|
||||
Name string `yaml:"name"`
|
||||
Description string `yaml:"description"`
|
||||
Author string `yaml:"author"`
|
||||
Branding Branding `yaml:"branding"`
|
||||
Inputs Inputs `yaml:"inputs"`
|
||||
Outputs Outputs `yaml:"outputs"`
|
||||
Runs Runs `yaml:"runs"`
|
||||
}
|
||||
|
||||
// Branding represents the action's branding configuration for display in the
|
||||
// GitHub marketplace.
|
||||
//
|
||||
// The branding information controls how the action appears visually:
|
||||
// - Icon: The feather icon to use (see GitHub's supported icons)
|
||||
// - Color: The background color (white, yellow, blue, green, orange, red, purple, gray-dark)
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// branding := Branding{
|
||||
// Icon: "archive",
|
||||
// Color: "gray-dark",
|
||||
// }
|
||||
type Branding struct {
|
||||
Icon string `yaml:"icon"`
|
||||
Color string `yaml:"color"`
|
||||
}
|
||||
|
||||
// Inputs represents all input parameters for the action as a map of input names
|
||||
// to their configurations.
|
||||
//
|
||||
// Each key in the map is the input name, and the value is the Input configuration
|
||||
// that defines the parameter's properties.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// inputs := Inputs{
|
||||
// "key": Input{
|
||||
// Description: "Cache key",
|
||||
// Required: true,
|
||||
// },
|
||||
// "path": Input{
|
||||
// Description: "Files to cache",
|
||||
// Required: true,
|
||||
// },
|
||||
// }
|
||||
type Inputs map[string]Input
|
||||
|
||||
// Input represents a single input parameter configuration for an action.
|
||||
//
|
||||
// An input defines a parameter that can be passed to the action when it's used.
|
||||
// It includes:
|
||||
// - Description: Human-readable description of the parameter
|
||||
// - Required: Whether the parameter must be provided
|
||||
// - Default: Default value if not provided (only valid if Required is false)
|
||||
// - DeprecationMessage: Optional message if the input is deprecated
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// input := Input{
|
||||
// Description: "An explicit key for a cache entry",
|
||||
// Required: true,
|
||||
// }
|
||||
//
|
||||
// inputWithDefault := Input{
|
||||
// Description: "Enable debug mode",
|
||||
// Required: false,
|
||||
// Default: "false",
|
||||
// }
|
||||
type Input struct {
|
||||
Description string `yaml:"description"`
|
||||
Required bool `yaml:"required"`
|
||||
Default string `yaml:"default"`
|
||||
DeprecationMessage string `yaml:"deprecationMessage,omitempty"`
|
||||
}
|
||||
|
||||
// Outputs represents all output parameters from the action as a map of output
|
||||
// names to their configurations.
|
||||
//
|
||||
// Each key in the map is the output name, and the value is the Output configuration
|
||||
// that defines what the output represents and how it's computed.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// outputs := Outputs{
|
||||
// "cache-hit": Output{
|
||||
// Description: "Whether cache was found",
|
||||
// Value: "${{ steps.cache.outputs.cache-hit }}",
|
||||
// },
|
||||
// }
|
||||
type Outputs map[string]Output
|
||||
|
||||
// Output represents a single output parameter configuration from an action.
|
||||
//
|
||||
// An output defines a value that the action produces which can be used by
|
||||
// subsequent steps in a workflow.
|
||||
// - Description: Human-readable description of the output
|
||||
// - Value: Expression that computes the output value (uses GitHub Actions expression syntax)
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// output := Output{
|
||||
// Description: "A boolean value to indicate an exact match was found",
|
||||
// Value: "${{ steps.restore.outputs.cache-hit }}",
|
||||
// }
|
||||
type Output struct {
|
||||
Description string `yaml:"description"`
|
||||
Value string `yaml:"value"`
|
||||
}
|
||||
|
||||
// Runs represents the action's execution configuration.
|
||||
//
|
||||
// This defines how the action executes, including:
|
||||
// - Using: The runtime environment (e.g., "composite", "node20", "docker")
|
||||
// - Env: Environment variables available during execution
|
||||
// - Steps: Sequence of steps to execute (for composite actions)
|
||||
//
|
||||
// For composite actions, Steps contains the commands to run.
|
||||
// For other action types, this may reference a main entry point.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// runs := Runs{
|
||||
// Using: "composite",
|
||||
// Steps: []Step{
|
||||
// {ID: "install", Run: "npm install"},
|
||||
// {ID: "test", Run: "npm test"},
|
||||
// },
|
||||
// }
|
||||
type Runs struct {
|
||||
Using string `yaml:"using"`
|
||||
Main string `yaml:"main,omitempty"`
|
||||
Env map[string]string `yaml:"env"`
|
||||
Steps []Step `yaml:"steps"`
|
||||
}
|
||||
|
||||
// Step represents a single step in the action's execution sequence.
|
||||
//
|
||||
// A step can either:
|
||||
// - Run a shell command (via Run field)
|
||||
// - Use another action (via Uses field)
|
||||
//
|
||||
// Fields:
|
||||
// - ID: Unique identifier for the step
|
||||
// - Uses: Reference to another action (e.g., "actions/checkout@v4")
|
||||
// - With: Input parameters for the referenced action
|
||||
// - Shell: Shell to use for execution (e.g., "bash", "pwsh")
|
||||
// - Run: Shell command to execute
|
||||
// - Env: Environment variables for this step
|
||||
//
|
||||
// Example (running a command):
|
||||
//
|
||||
// step := Step{
|
||||
// ID: "build",
|
||||
// Shell: "bash",
|
||||
// Run: "go build -v ./...",
|
||||
// }
|
||||
//
|
||||
// Example (using another action):
|
||||
//
|
||||
// step := Step{
|
||||
// ID: "cache-restore",
|
||||
// Uses: "actions/cache/restore@v4",
|
||||
// With: map[string]string{
|
||||
// "key": "my-cache-key",
|
||||
// "path": "/tmp/cache",
|
||||
// },
|
||||
// }
|
||||
type Step struct {
|
||||
ID string `yaml:"id"`
|
||||
Uses string `yaml:"uses"`
|
||||
With map[string]string `yaml:"with"`
|
||||
Shell string `yaml:"shell"`
|
||||
Run string `yaml:"run"`
|
||||
Env map[string]string `yaml:"env"`
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer for Action
|
||||
func (a Action) String() string {
|
||||
var b strings.Builder
|
||||
b.WriteString(a.ShortString())
|
||||
|
||||
b.WriteString("\nRuns:\n")
|
||||
b.WriteString(indent(a.Runs.String(), 1))
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// ShortString implements fmt.Stringer for Action but with runs trimmed out
|
||||
func (a Action) ShortString() string {
|
||||
var b strings.Builder
|
||||
b.WriteString(fmt.Sprintf("Name: %s\n", a.Name))
|
||||
b.WriteString(fmt.Sprintf("Description: %s\n", a.Description))
|
||||
b.WriteString(fmt.Sprintf("Author: %s\n", a.Author))
|
||||
|
||||
b.WriteString("\nBranding:\n")
|
||||
b.WriteString(indent(a.Branding.String(), 1))
|
||||
|
||||
b.WriteString("\nInputs:\n")
|
||||
b.WriteString(indent(a.Inputs.String(), 1))
|
||||
|
||||
b.WriteString("\nOutputs:\n")
|
||||
b.WriteString(indent(a.Outputs.String(), 1))
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer for Branding
|
||||
func (b Branding) String() string {
|
||||
return fmt.Sprintf("Icon: %s\nColor: %s", b.Icon, b.Color)
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer for Inputs
|
||||
func (i Inputs) String() string {
|
||||
var b strings.Builder
|
||||
for k, v := range i {
|
||||
b.WriteString(fmt.Sprintf("%s:\n", k))
|
||||
b.WriteString(indent(v.String(), 1))
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer for Input
|
||||
func (i Input) String() string {
|
||||
var b strings.Builder
|
||||
b.WriteString(fmt.Sprintf("Description: %s\n", i.Description))
|
||||
b.WriteString(fmt.Sprintf("Required: %v\n", i.Required))
|
||||
b.WriteString(fmt.Sprintf("Default: %s", i.Default))
|
||||
if i.DeprecationMessage != "" {
|
||||
b.WriteString(fmt.Sprintf("\nDeprecation Message: %s", i.DeprecationMessage))
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer for Outputs
|
||||
func (o Outputs) String() string {
|
||||
var b strings.Builder
|
||||
for k, v := range o {
|
||||
b.WriteString(fmt.Sprintf("%s:\n", k))
|
||||
b.WriteString(indent(v.String(), 1))
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer for Output
|
||||
func (o Output) String() string {
|
||||
return fmt.Sprintf("Description: %s\nValue: %s", o.Description, o.Value)
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer for Runs
|
||||
func (r Runs) String() string {
|
||||
var b strings.Builder
|
||||
b.WriteString(fmt.Sprintf("Using: %s\n", r.Using))
|
||||
|
||||
b.WriteString("Environment:\n")
|
||||
for k, v := range r.Env {
|
||||
b.WriteString(indent(fmt.Sprintf("%s: %s\n", k, v), 1))
|
||||
}
|
||||
|
||||
b.WriteString("Steps:\n")
|
||||
for _, step := range r.Steps {
|
||||
b.WriteString(indent(step.String()+"\n", 1))
|
||||
}
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer for Step
|
||||
func (s Step) String() string {
|
||||
var b strings.Builder
|
||||
if s.ID != "" {
|
||||
b.WriteString(fmt.Sprintf("ID: %s\n", s.ID))
|
||||
}
|
||||
if len(s.With) > 0 {
|
||||
b.WriteString("With:\n")
|
||||
for k, v := range s.With {
|
||||
b.WriteString(fmt.Sprintf("%s: %s\n", k, v))
|
||||
}
|
||||
}
|
||||
if s.Shell != "" {
|
||||
b.WriteString(fmt.Sprintf("Shell: %s\n", s.Shell))
|
||||
}
|
||||
if s.Run != "" {
|
||||
b.WriteString(fmt.Sprintf("Run:\n%s", indent(s.Run, 1)))
|
||||
}
|
||||
return strings.TrimSuffix(b.String(), "\n")
|
||||
}
|
||||
|
||||
// indent adds the specified number of indentation levels to each line of the input string
|
||||
func indent(s string, level int) string {
|
||||
if s == "" {
|
||||
return s
|
||||
}
|
||||
|
||||
prefix := strings.Repeat(" ", level*parserIndentSize)
|
||||
lines := strings.Split(s, "\n")
|
||||
for i, line := range lines {
|
||||
if line != "" {
|
||||
lines[i] = prefix + line
|
||||
}
|
||||
}
|
||||
return strings.Join(lines, "\n") + "\n"
|
||||
}
|
||||
|
||||
func Parse(yamlFilePath string) (Action, error) {
|
||||
// Read the action.yml file
|
||||
data, err := os.ReadFile(yamlFilePath)
|
||||
if err != nil {
|
||||
return Action{}, fmt.Errorf("Error reading %s: %v", yamlFilePath, err)
|
||||
}
|
||||
|
||||
// Parse the YAML into our Action struct
|
||||
var action Action
|
||||
if err := yaml.Unmarshal(data, &action); err != nil {
|
||||
return Action{}, fmt.Errorf("Error parsing YAML: %v", err)
|
||||
}
|
||||
|
||||
return action, nil
|
||||
}
|
||||
172
internal/actions/cache_actions_test.go
Normal file
172
internal/actions/cache_actions_test.go
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
package actions
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewCacheRestoreAction(t *testing.T) {
|
||||
action := NewCacheRestoreAction()
|
||||
|
||||
// Test basic properties
|
||||
if action.Name != "Cache restore" {
|
||||
t.Errorf("Expected name 'Cache restore', got '%s'", action.Name)
|
||||
}
|
||||
|
||||
if action.Description != "Restore cache without saving it" {
|
||||
t.Errorf(
|
||||
"Expected description 'Restore cache without saving it', got '%s'",
|
||||
action.Description,
|
||||
)
|
||||
}
|
||||
|
||||
if action.Author != "GitHub" {
|
||||
t.Errorf("Expected author 'GitHub', got '%s'", action.Author)
|
||||
}
|
||||
|
||||
// Test branding
|
||||
if action.Branding.Icon != "archive" {
|
||||
t.Errorf("Expected icon 'archive', got '%s'", action.Branding.Icon)
|
||||
}
|
||||
|
||||
if action.Branding.Color != "gray-dark" {
|
||||
t.Errorf("Expected color 'gray-dark', got '%s'", action.Branding.Color)
|
||||
}
|
||||
|
||||
// Test required inputs
|
||||
if !action.Inputs["key"].Required {
|
||||
t.Error("Expected 'key' input to be required")
|
||||
}
|
||||
|
||||
if !action.Inputs["path"].Required {
|
||||
t.Error("Expected 'path' input to be required")
|
||||
}
|
||||
|
||||
// Test optional inputs with defaults
|
||||
if action.Inputs["fail-on-cache-miss"].Required {
|
||||
t.Error("Expected 'fail-on-cache-miss' input to be optional")
|
||||
}
|
||||
|
||||
if action.Inputs["fail-on-cache-miss"].Default != "false" {
|
||||
t.Errorf(
|
||||
"Expected 'fail-on-cache-miss' default to be 'false', got '%s'",
|
||||
action.Inputs["fail-on-cache-miss"].Default,
|
||||
)
|
||||
}
|
||||
|
||||
// Test outputs
|
||||
expectedOutputs := []string{"cache-hit", "cache-primary-key", "cache-matched-key"}
|
||||
for _, expectedOutput := range expectedOutputs {
|
||||
if _, exists := action.Outputs[expectedOutput]; !exists {
|
||||
t.Errorf("Expected output '%s' to exist", expectedOutput)
|
||||
}
|
||||
}
|
||||
|
||||
// Test runs configuration
|
||||
if action.Runs.Using != "node20" {
|
||||
t.Errorf("Expected runs.using 'node20', got '%s'", action.Runs.Using)
|
||||
}
|
||||
|
||||
if action.Runs.Main != "dist/restore/index.js" {
|
||||
t.Errorf("Expected runs.main 'dist/restore/index.js', got '%s'", action.Runs.Main)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewCacheSaveAction(t *testing.T) {
|
||||
action := NewCacheSaveAction()
|
||||
|
||||
// Test basic properties
|
||||
if action.Name != "Cache save" {
|
||||
t.Errorf("Expected name 'Cache save', got '%s'", action.Name)
|
||||
}
|
||||
|
||||
if action.Description != "Save cache with key and path" {
|
||||
t.Errorf(
|
||||
"Expected description 'Save cache with key and path', got '%s'",
|
||||
action.Description,
|
||||
)
|
||||
}
|
||||
|
||||
if action.Author != "GitHub" {
|
||||
t.Errorf("Expected author 'GitHub', got '%s'", action.Author)
|
||||
}
|
||||
|
||||
// Test branding
|
||||
if action.Branding.Icon != "archive" {
|
||||
t.Errorf("Expected icon 'archive', got '%s'", action.Branding.Icon)
|
||||
}
|
||||
|
||||
if action.Branding.Color != "gray-dark" {
|
||||
t.Errorf("Expected color 'gray-dark', got '%s'", action.Branding.Color)
|
||||
}
|
||||
|
||||
// Test required inputs
|
||||
if !action.Inputs["key"].Required {
|
||||
t.Error("Expected 'key' input to be required")
|
||||
}
|
||||
|
||||
if !action.Inputs["path"].Required {
|
||||
t.Error("Expected 'path' input to be required")
|
||||
}
|
||||
|
||||
// Test optional inputs
|
||||
if action.Inputs["upload-chunk-size"].Required {
|
||||
t.Error("Expected 'upload-chunk-size' input to be optional")
|
||||
}
|
||||
|
||||
if action.Inputs["enableCrossOsArchive"].Required {
|
||||
t.Error("Expected 'enableCrossOsArchive' input to be optional")
|
||||
}
|
||||
|
||||
if action.Inputs["enableCrossOsArchive"].Default != "false" {
|
||||
t.Errorf(
|
||||
"Expected 'enableCrossOsArchive' default to be 'false', got '%s'",
|
||||
action.Inputs["enableCrossOsArchive"].Default,
|
||||
)
|
||||
}
|
||||
|
||||
// Test that save action has no outputs (as per documentation)
|
||||
if len(action.Outputs) != 0 {
|
||||
t.Errorf("Expected no outputs for save action, got %d", len(action.Outputs))
|
||||
}
|
||||
|
||||
// Test runs configuration
|
||||
if action.Runs.Using != "node20" {
|
||||
t.Errorf("Expected runs.using 'node20', got '%s'", action.Runs.Using)
|
||||
}
|
||||
|
||||
if action.Runs.Main != "dist/save/index.js" {
|
||||
t.Errorf("Expected runs.main 'dist/save/index.js', got '%s'", action.Runs.Main)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCacheRestoreActionString(t *testing.T) {
|
||||
action := NewCacheRestoreAction()
|
||||
|
||||
// Test that String() method works without panicking
|
||||
result := action.String()
|
||||
if result == "" {
|
||||
t.Error("Expected non-empty string representation")
|
||||
}
|
||||
|
||||
// Test that ShortString() method works without panicking
|
||||
shortResult := action.ShortString()
|
||||
if shortResult == "" {
|
||||
t.Error("Expected non-empty short string representation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCacheSaveActionString(t *testing.T) {
|
||||
action := NewCacheSaveAction()
|
||||
|
||||
// Test that String() method works without panicking
|
||||
result := action.String()
|
||||
if result == "" {
|
||||
t.Error("Expected non-empty string representation")
|
||||
}
|
||||
|
||||
// Test that ShortString() method works without panicking
|
||||
shortResult := action.ShortString()
|
||||
if shortResult == "" {
|
||||
t.Error("Expected non-empty short string representation")
|
||||
}
|
||||
}
|
||||
113
internal/actions/cache_restore.go
Normal file
113
internal/actions/cache_restore.go
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
package actions
|
||||
|
||||
// NewCacheRestoreAction creates a new cache restore action with default configuration
|
||||
func NewCacheRestoreAction() *Action {
|
||||
return &Action{
|
||||
Name: "Cache restore",
|
||||
Description: "Restore cache without saving it",
|
||||
Author: "GitHub",
|
||||
Branding: Branding{
|
||||
Icon: "archive",
|
||||
Color: "gray-dark",
|
||||
},
|
||||
Inputs: Inputs{
|
||||
"key": Input{
|
||||
Description: "An explicit key for a cache entry",
|
||||
Required: true,
|
||||
},
|
||||
"path": Input{
|
||||
Description: "A list of files, directories, and wildcard patterns to restore",
|
||||
Required: true,
|
||||
},
|
||||
"restore-keys": Input{
|
||||
Description: "An ordered list of prefix-matched keys to use for restoring stale cache if no cache hit occurred for key",
|
||||
Required: false,
|
||||
},
|
||||
"fail-on-cache-miss": Input{
|
||||
Description: "Fail the workflow if cache entry is not found",
|
||||
Required: false,
|
||||
Default: "false",
|
||||
},
|
||||
"lookup-only": Input{
|
||||
Description: "If true, only checks if cache entry exists and skips download",
|
||||
Required: false,
|
||||
Default: "false",
|
||||
},
|
||||
"enableCrossOsArchive": Input{
|
||||
Description: "An optional boolean when enabled, allows Windows runners to restore caches from other platforms",
|
||||
Required: false,
|
||||
Default: "false",
|
||||
},
|
||||
},
|
||||
Outputs: Outputs{
|
||||
"cache-hit": Output{
|
||||
Description: "A boolean value to indicate an exact match was found for the key",
|
||||
},
|
||||
"cache-primary-key": Output{
|
||||
Description: "Cache primary key passed in the input to use in subsequent steps of the workflow",
|
||||
},
|
||||
"cache-matched-key": Output{
|
||||
Description: "Key of the cache that was restored, it could either be the primary key on cache-hit or a partial/complete match of one of the restore keys",
|
||||
},
|
||||
},
|
||||
Runs: Runs{
|
||||
// Actual values for GitHub action.
|
||||
// Using: "node20",
|
||||
// Main: "dist/restore/index.js",
|
||||
Steps: []Step{
|
||||
{
|
||||
ID: "Restore cache",
|
||||
Uses: "actions/cache@v3",
|
||||
With: map[string]string{
|
||||
"key": "${{ inputs.key }}",
|
||||
"restore-keys": "${{ inputs.restore-keys }}",
|
||||
"path": "${{ inputs.path }}",
|
||||
},
|
||||
Shell: "bash",
|
||||
Run: `
|
||||
if [ "${{ inputs.lookup-only }}" = "true" ]; then
|
||||
echo "Lookup only mode enabled. Skipping cache restore."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
CACHE_DIR="/tmp/cache-apt-pkgs-action-test"
|
||||
mkdir -p "$CACHE_DIR"
|
||||
|
||||
if [ -d "$CACHE_DIR/${{ inputs.key }}" ]; then
|
||||
echo "Cache hit for key '${{ inputs.key }}'. Restoring cache..."
|
||||
find "$CACHE_DIR/${{ inputs.key }}" -type f -exec cp --parents -r {} ./ \;
|
||||
echo "Cache restored from $CACHE_DIR/${{ inputs.key }}"
|
||||
echo "cache-hit=true" >> $GITHUB_OUTPUT
|
||||
echo "cache-primary-key=${{ inputs.key }}" >> $GITHUB_OUTPUT
|
||||
echo "cache-matched-key=${{ inputs.key }}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
if [ -n "${{ inputs.restore-keys }}" ]; then
|
||||
IFS=',' read -ra RESTORE_KEYS <<< "${{ inputs.restore-keys }}"
|
||||
for KEY in "${RESTORE_KEYS[@]}"; do
|
||||
if [ -d "$CACHE_DIR/$KEY" ]; then
|
||||
echo "Partial cache hit for restore key '$KEY'. Restoring cache..."
|
||||
find "$CACHE_DIR/$KEY" -type f -exec cp --parents -r {} ./ \;
|
||||
echo "Cache restored from $CACHE_DIR/$KEY"
|
||||
echo "cache-hit=false" >> $GITHUB_OUTPUT
|
||||
echo "cache-primary-key=${{ inputs.key }}" >> $GITHUB_OUTPUT
|
||||
echo "cache-matched-key=$KEY" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
fi
|
||||
echo "No cache found for key '${{ inputs.key }}' or restore keys. Continuing without cache."
|
||||
echo "cache-hit=false" >> $GITHUB_OUTPUT
|
||||
echo "cache-primary-key=${{ inputs.key }}" >> $GITHUB_OUTPUT
|
||||
echo "cache-matched-key=" >> $GITHUB_OUTPUT
|
||||
|
||||
if [ "${{ inputs.fail-on-cache-miss }}" = "true" ]; then
|
||||
echo "Cache miss and 'fail-on-cache-miss' is set to true. Failing the workflow."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
`,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
57
internal/actions/cache_save.go
Normal file
57
internal/actions/cache_save.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package actions
|
||||
|
||||
// NewCacheSaveAction creates a new cache save action with default configuration
|
||||
func NewCacheSaveAction() *Action {
|
||||
return &Action{
|
||||
Name: "Cache save",
|
||||
Description: "Save cache with key and path",
|
||||
Author: "GitHub",
|
||||
Branding: Branding{
|
||||
Icon: "archive",
|
||||
Color: "gray-dark",
|
||||
},
|
||||
Inputs: Inputs{
|
||||
"key": Input{
|
||||
Description: "An explicit key for a cache entry",
|
||||
Required: true,
|
||||
},
|
||||
"path": Input{
|
||||
Description: "A list of files, directories, and wildcard patterns to cache",
|
||||
Required: true,
|
||||
},
|
||||
"upload-chunk-size": Input{
|
||||
Description: "The chunk size used to split up large files during upload, in bytes",
|
||||
Required: false,
|
||||
},
|
||||
"enableCrossOsArchive": Input{
|
||||
Description: "An optional boolean when enabled, allows Windows runners to save caches that can be restored on other platforms",
|
||||
Required: false,
|
||||
Default: "false",
|
||||
},
|
||||
},
|
||||
Outputs: Outputs{
|
||||
// Cache save action has no outputs according to the documentation
|
||||
},
|
||||
Runs: Runs{
|
||||
// Actual values for GitHub action.
|
||||
// Using: "node20",
|
||||
// Main: "dist/save/index.js",
|
||||
Steps: []Step{
|
||||
{
|
||||
ID: "Save cache",
|
||||
Uses: "actions/cache@v3",
|
||||
With: map[string]string{
|
||||
"key": "${{ inputs.key }}",
|
||||
"path": "${{ inputs.path }}",
|
||||
},
|
||||
Shell: "bash",
|
||||
Run: `
|
||||
mkdir -p /tmp/cache-apt-pkgs-action-test/${key}
|
||||
find ${path} -type f -exec cp --parents -r {} /tmp/cache-apt-pkgs-action-test/${key} \;
|
||||
echo "Cache saved to /tmp/cache-apt-pkgs-action-test/${key}"
|
||||
`,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
70
internal/actions/doc.go
Normal file
70
internal/actions/doc.go
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
// Package actions provides data structures for GitHub Actions configurations
|
||||
// and factory functions for creating pre-configured cache actions.
|
||||
//
|
||||
// This package defines the structure of GitHub Actions (action.yml format) and provides some action
|
||||
// templates for external action dependencies. At this point it is very minimal and just used by the
|
||||
// cache-apt-pkgs-action.
|
||||
//
|
||||
// # YAML Parsing
|
||||
//
|
||||
// Actions can be loaded from YAML files:
|
||||
//
|
||||
// action := &Action{}
|
||||
// err := action.LoadFromFile("action.yml")
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// Or parsed from YAML data:
|
||||
//
|
||||
// yamlData := []byte(`
|
||||
// name: My Action
|
||||
// description: Does something useful
|
||||
// inputs:
|
||||
// key:
|
||||
// description: Cache key
|
||||
// required: true
|
||||
// `)
|
||||
//
|
||||
// action := &Action{}
|
||||
// err := yaml.Unmarshal(yamlData, action)
|
||||
//
|
||||
// # Usage Examples
|
||||
//
|
||||
// Accessing action metadata:
|
||||
//
|
||||
// action := NewCacheRestoreAction()
|
||||
// fmt.Println(action.Name) // "Cache restore"
|
||||
// fmt.Println(action.Description) // "Restore cache without saving it"
|
||||
// fmt.Println(action.Author) // "GitHub"
|
||||
//
|
||||
// Working with inputs:
|
||||
//
|
||||
// keyInput := action.Inputs["key"]
|
||||
// fmt.Println(keyInput.Required) // true
|
||||
// fmt.Println(keyInput.Description) // "An explicit key for a cache entry"
|
||||
//
|
||||
// // Check if input has a default value
|
||||
// lookupInput := action.Inputs["lookup-only"]
|
||||
// if lookupInput.Default != "" {
|
||||
// fmt.Println("Default:", lookupInput.Default) // "false"
|
||||
// }
|
||||
//
|
||||
// Examining outputs:
|
||||
//
|
||||
// cacheHitOutput := action.Outputs["cache-hit"]
|
||||
// fmt.Println(cacheHitOutput.Description)
|
||||
//
|
||||
// # Integration
|
||||
//
|
||||
// This package is designed to be used by the parent action2sh package for
|
||||
// converting GitHub Actions to bash scripts. The action structures provide
|
||||
// the metadata needed for script generation and validation.
|
||||
//
|
||||
// # Compatibility
|
||||
//
|
||||
// Action definitions are compatible with:
|
||||
// - GitHub Actions specification (action.yml format)
|
||||
//
|
||||
// All YAML tags follow GitHub Actions conventions for proper serialization.
|
||||
package actions
|
||||
94
internal/cio/ghio.go
Normal file
94
internal/cio/ghio.go
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
package cio
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"awalsh128.com/cache-apt-pkgs-action/internal/pkgs"
|
||||
"github.com/sethvargo/go-githubactions"
|
||||
)
|
||||
|
||||
const localPrintPrefix = "ghio::"
|
||||
|
||||
// formatPackages formats a Packages collection as a comma-delimited list with = delimiter
|
||||
// Format: package1=version1,package2=version2,...
|
||||
func formatPackages(packages pkgs.Packages) string {
|
||||
if packages.Len() == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
var parts []string
|
||||
for i := 0; i < packages.Len(); i++ {
|
||||
pkg := packages.Get(i)
|
||||
parts = append(parts, fmt.Sprintf("%s=%s", pkg.Name, pkg.Version))
|
||||
}
|
||||
|
||||
return strings.Join(parts, ",")
|
||||
}
|
||||
|
||||
// GhPrinter defines an interface for printing outputs in GitHub Actions or locally
|
||||
type GhPrinter interface {
|
||||
// SetOutput sets an output variable name and value
|
||||
SetOutput(name string, value any)
|
||||
}
|
||||
|
||||
// ghActionEnvPrinter implements GhPrinter for GitHub Actions environment
|
||||
type ghActionEnvPrinter struct {
|
||||
}
|
||||
|
||||
// localPrinter implements GhPrinter for local (non-GitHub Actions) environment
|
||||
// Used in local testing and debugging
|
||||
type localPrinter struct {
|
||||
}
|
||||
|
||||
// isGitHubActions checks if the code is running in a GitHub Actions environment
|
||||
func NewGhPrinter() GhPrinter {
|
||||
if os.Getenv("GITHUB_ACTIONS") == "true" {
|
||||
return &ghActionEnvPrinter{}
|
||||
}
|
||||
return &localPrinter{}
|
||||
}
|
||||
|
||||
func (p *ghActionEnvPrinter) SetOutput(name string, value any) {
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
githubactions.SetOutput(name, v)
|
||||
case bool:
|
||||
githubactions.SetOutput(name, fmt.Sprintf("%t", v))
|
||||
case pkgs.Packages:
|
||||
githubactions.SetOutput(name, formatPackages(v))
|
||||
default:
|
||||
githubactions.SetOutput(name, fmt.Sprintf("%v", v))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *localPrinter) SetOutput(name string, value any) {
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
fmt.Printf("%s%s=%v\n", localPrintPrefix, name, v)
|
||||
case bool:
|
||||
fmt.Printf("%s%s=%v\n", localPrintPrefix, name, fmt.Sprintf("%t", v))
|
||||
case pkgs.Packages:
|
||||
fmt.Printf("%s%s=%v\n", localPrintPrefix, name, formatPackages(v))
|
||||
default:
|
||||
fmt.Printf("%s%s=%v\n", localPrintPrefix, name, fmt.Sprintf("%v", v))
|
||||
}
|
||||
}
|
||||
|
||||
// ReadLocalPrinterOutputs reads outputs printed by localPrinter from the given text.
|
||||
// It returns a map of output names to their values.
|
||||
// Lines not starting with the localPrintPrefix are ignored.
|
||||
func ReadLocalPrinterOutputs(text string) map[string]string {
|
||||
outputs := make(map[string]string)
|
||||
lines := strings.Split(text, "\n")
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, localPrintPrefix) {
|
||||
parts := strings.SplitN(line[len(localPrintPrefix):], "=", 2)
|
||||
if len(parts) == 2 {
|
||||
outputs[parts[0]] = parts[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
return outputs
|
||||
}
|
||||
148
internal/cio/print_scanner.go
Normal file
148
internal/cio/print_scanner.go
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
package cio
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// PrintScanner scans stdout and stderr for local print prefixes while allowing
|
||||
// normal terminal output to continue. This is useful for detecting and handling local
|
||||
// print statements in a non-blocking way.
|
||||
type PrintScanner struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
origStdout *os.File
|
||||
origStderr *os.File
|
||||
rOut, wOut *os.File
|
||||
rErr, wErr *os.File
|
||||
prefix string
|
||||
matches []string
|
||||
mu sync.Mutex
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
// NewPrintScanner creates a new scanner that monitors stdout and stderr for the given prefix.
|
||||
// It sets up pipe redirection while maintaining terminal output.
|
||||
func NewPrintScanner(prefix string) (*PrintScanner, error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
// Save original file descriptors
|
||||
origStdout := os.Stdout
|
||||
origStderr := os.Stderr
|
||||
|
||||
// Create pipes for stdout and stderr
|
||||
rOut, wOut, err := os.Pipe()
|
||||
if err != nil {
|
||||
cancel()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rErr, wErr, err := os.Pipe()
|
||||
if err != nil {
|
||||
cancel()
|
||||
rOut.Close()
|
||||
wOut.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
scanner := &PrintScanner{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
origStdout: origStdout,
|
||||
origStderr: origStderr,
|
||||
rOut: rOut,
|
||||
wOut: wOut,
|
||||
rErr: rErr,
|
||||
wErr: wErr,
|
||||
prefix: prefix,
|
||||
}
|
||||
|
||||
return scanner, nil
|
||||
}
|
||||
|
||||
// Start begins monitoring stdout and stderr in the background.
|
||||
// It sets up the necessary pipes and starts goroutines for scanning.
|
||||
func (s *PrintScanner) Start() error {
|
||||
// Redirect stdout and stderr
|
||||
os.Stdout = s.wOut
|
||||
os.Stderr = s.wErr
|
||||
|
||||
// Start monitoring stdout
|
||||
s.wg.Add(1)
|
||||
go func() {
|
||||
defer s.wg.Done()
|
||||
s.monitorStream(s.rOut, s.origStdout)
|
||||
}()
|
||||
|
||||
// Start monitoring stderr
|
||||
s.wg.Add(1)
|
||||
go func() {
|
||||
defer s.wg.Done()
|
||||
s.monitorStream(s.rErr, s.origStderr)
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop terminates the monitoring and restores original stdout/stderr.
|
||||
// It waits for all goroutines to complete before returning.
|
||||
func (s *PrintScanner) Stop() error {
|
||||
s.cancel()
|
||||
|
||||
// Restore original stdout and stderr
|
||||
os.Stdout = s.origStdout
|
||||
os.Stderr = s.origStderr
|
||||
|
||||
// Close write ends of pipes
|
||||
s.wOut.Close()
|
||||
s.wErr.Close()
|
||||
|
||||
// Wait for monitoring goroutines to finish
|
||||
s.wg.Wait()
|
||||
|
||||
// Close read ends of pipes
|
||||
s.rOut.Close()
|
||||
s.rErr.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMatches returns all captured lines that matched the prefix.
|
||||
// It's safe to call this method concurrently.
|
||||
func (s *PrintScanner) GetMatches() []string {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
result := make([]string, len(s.matches))
|
||||
copy(result, s.matches)
|
||||
return result
|
||||
}
|
||||
|
||||
// monitorStream reads from the pipe and writes to the original file descriptor
|
||||
// while scanning for the prefix. This is run in a goroutine for each stream.
|
||||
func (s *PrintScanner) monitorStream(r *os.File, orig *os.File) {
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
// Write to original file descriptor for normal output
|
||||
io.WriteString(orig, line+"\n")
|
||||
|
||||
// Check for prefix and store match
|
||||
if strings.HasPrefix(line, s.prefix) {
|
||||
s.mu.Lock()
|
||||
s.matches = append(s.matches, line)
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
// Check if we should stop
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
95
internal/cio/print_scanner_test.go
Normal file
95
internal/cio/print_scanner_test.go
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
package cio
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestPrintScanner(t *testing.T) {
|
||||
const prefix = "::local::"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
writes []string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "No matching lines",
|
||||
writes: []string{
|
||||
"regular output",
|
||||
"another line",
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "Some matching lines",
|
||||
writes: []string{
|
||||
"regular output",
|
||||
"::local::matched line 1",
|
||||
"another regular line",
|
||||
"::local::matched line 2",
|
||||
},
|
||||
expected: []string{
|
||||
"::local::matched line 1",
|
||||
"::local::matched line 2",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Mixed stdout and stderr",
|
||||
writes: []string{
|
||||
"stdout regular",
|
||||
"::local::stdout match",
|
||||
"stderr regular",
|
||||
"::local::stderr match",
|
||||
},
|
||||
expected: []string{
|
||||
"::local::stdout match",
|
||||
"::local::stderr match",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
scanner, err := NewPrintScanner(prefix)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create scanner: %v", err)
|
||||
}
|
||||
|
||||
err = scanner.Start()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start scanner: %v", err)
|
||||
}
|
||||
|
||||
// Write test lines
|
||||
for _, line := range tt.writes {
|
||||
println(line)
|
||||
time.Sleep(10 * time.Millisecond) // Small delay to ensure processing
|
||||
}
|
||||
|
||||
// Give scanner time to process
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
err = scanner.Stop()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to stop scanner: %v", err)
|
||||
}
|
||||
|
||||
// Compare results
|
||||
matches := scanner.GetMatches()
|
||||
if len(matches) != len(tt.expected) {
|
||||
t.Errorf("Got %d matches, want %d", len(matches), len(tt.expected))
|
||||
}
|
||||
|
||||
for i, match := range matches {
|
||||
if i >= len(tt.expected) {
|
||||
t.Errorf("Extra match: %s", match)
|
||||
continue
|
||||
}
|
||||
if match != tt.expected[i] {
|
||||
t.Errorf("Match %d: got %s, want %s", i, match, tt.expected[i])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
83
scripts/dev/export_version.sh
Executable file
83
scripts/dev/export_version.sh
Executable file
|
|
@ -0,0 +1,83 @@
|
|||
#!/bin/bash
|
||||
|
||||
#==============================================================================
|
||||
# export_version.sh
|
||||
#==============================================================================
|
||||
#
|
||||
# DESCRIPTION:
|
||||
# Script to export Go library version information for package development.
|
||||
# Extracts and exports version information from go.mod including Go version,
|
||||
# toolchain version, and syspkg version.
|
||||
#
|
||||
# USAGE:
|
||||
# export_version.sh [OPTIONS]
|
||||
#
|
||||
# OPTIONS:
|
||||
# -v, --verbose Enable verbose output
|
||||
# -h, --help Show this help message
|
||||
#==============================================================================
|
||||
|
||||
source "$(git rev-parse --show-toplevel)/scripts/lib.sh"
|
||||
parse_common_args "$@" >/dev/null # prevent return from echo'ng
|
||||
|
||||
# Function to extract Go version from go.mod
|
||||
function get_go_version() {
|
||||
local go_version
|
||||
go_version=$(grep "^go " "${PROJECT_ROOT}/go.mod" | awk '{print $2}')
|
||||
log_debug "Extracted Go version: ${go_version}"
|
||||
echo "${go_version}"
|
||||
}
|
||||
|
||||
# Function to extract toolchain version from go.mod
|
||||
function get_toolchain_version() {
|
||||
local toolchain_version
|
||||
toolchain_version=$(grep "^toolchain " "${PROJECT_ROOT}/go.mod" | awk '{print $2}')
|
||||
log_debug "Extracted toolchain version: ${toolchain_version}"
|
||||
echo "${toolchain_version}"
|
||||
}
|
||||
|
||||
# Function to extract syspkg version from go.mod
|
||||
function get_syspkg_version() {
|
||||
local syspkg_version
|
||||
syspkg_version=$(grep "github.com/awalsh128/syspkg" "${PROJECT_ROOT}/go.mod" | awk '{print $2}')
|
||||
log_debug "Extracted syspkg version: ${syspkg_version}"
|
||||
echo "${syspkg_version}"
|
||||
}
|
||||
|
||||
# Export versions as environment variables
|
||||
log_info "Exporting version information..."
|
||||
GO_VERSION=$(get_go_version)
|
||||
export GO_VERSION
|
||||
TOOLCHAIN_VERSION=$(get_toolchain_version)
|
||||
export TOOLCHAIN_VERSION
|
||||
SYSPKG_VERSION=$(get_syspkg_version)
|
||||
export SYSPKG_VERSION
|
||||
|
||||
# Create a version info file
|
||||
VERSION_FILE="${PROJECT_ROOT}/.version-info"
|
||||
log_debug "Creating version file: ${VERSION_FILE}"
|
||||
cat >"${VERSION_FILE}" <<EOF
|
||||
# Version information for cache-apt-pkgs-action
|
||||
GO_VERSION=${GO_VERSION}
|
||||
TOOLCHAIN_VERSION=${TOOLCHAIN_VERSION}
|
||||
SYSPKG_VERSION=${SYSPKG_VERSION}
|
||||
EXPORT_DATE=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
EOF
|
||||
|
||||
echo "Version information has been exported to ${VERSION_FILE}"
|
||||
echo "Go Version: ${GO_VERSION}"
|
||||
echo "Toolchain Version: ${TOOLCHAIN_VERSION}"
|
||||
echo "Syspkg Version: ${SYSPKG_VERSION}"
|
||||
|
||||
# Also create a JSON format for tools that prefer it
|
||||
VERSION_JSON="${PROJECT_ROOT}/.version-info.json"
|
||||
cat >"${VERSION_JSON}" <<EOF
|
||||
{
|
||||
"goVersion": "${GO_VERSION}",
|
||||
"toolchainVersion": "${TOOLCHAIN_VERSION}",
|
||||
"syspkgVersion": "${SYSPKG_VERSION}",
|
||||
"exportDate": "$(date '+%Y-%m-%d %H:%M:%S')"
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "Version information also exported in JSON format to ${VERSION_JSON}"
|
||||
36
scripts/dev/fix_and_update.sh
Executable file
36
scripts/dev/fix_and_update.sh
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
#!/bin/bash
|
||||
|
||||
#==============================================================================
|
||||
# fix_and_update.sh
|
||||
#==============================================================================
|
||||
#
|
||||
# DESCRIPTION:
|
||||
# Runs lint fixes and updates to code based on changes in the repository.
|
||||
# Intended to help maintain code quality and formatting consistency.
|
||||
#
|
||||
# USAGE:
|
||||
# fix_and_update.sh
|
||||
#
|
||||
# OPTIONS:
|
||||
# -v, --verbose Enable verbose output
|
||||
# -h, --help Show this help message
|
||||
#==============================================================================
|
||||
|
||||
REPO_DIR="$(git rev-parse --show-toplevel)"
|
||||
|
||||
source "${REPO_DIR}/scripts/lib.sh"
|
||||
parse_common_args "$@" >/dev/null # prevent return from echo'ng
|
||||
|
||||
print_status "Running trunk format and code check..."
|
||||
if ! command_exists trunk; then
|
||||
print_status "Installing trunk..."
|
||||
# trunk-ignore(semgrep/bash.curl.security.curl-pipe-bash.curl-pipe-bash)
|
||||
curl https://get.trunk.io -fsSL | bash
|
||||
fi
|
||||
trunk check --all --ci
|
||||
trunk fmt --all --ci
|
||||
|
||||
print_status "Checking for table of content updates in markdown files..."
|
||||
"${REPO_DIR}"/scripts/dev/update_md_tocs.sh
|
||||
|
||||
log_success "All fixes applied and checks complete."
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue