Skip to content

Commit 45cdb22

Browse files
committed
Release v0.3.0: CI, ensure-yang.sh --help and GITHUB_TOKEN support, changelog
1 parent f969429 commit 45cdb22

7 files changed

Lines changed: 144 additions & 20 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
{
1010
"name": "nokia-sr-skills",
1111
"description": "Learn how to inspect and operate Nokia SR network OSes - SR OS (SROS) and SR Linux (SRL).",
12-
"version": "0.2.1",
12+
"version": "0.3.0",
1313
"source": "./",
1414
"author": {
1515
"name": "Antoine Keranflec'h",

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "nokia-sr-skills",
33
"description": "Learn how to inspect and operate Nokia SR network OSes - SR OS (SROS) and SR Linux (SRL): tell the two apart, fetch YANG models on demand, read the software version, understand config formats, and apply NETCONF / MD-CLI / gNMI behaviors.",
4-
"version": "0.2.1",
4+
"version": "0.3.0",
55
"author": {
66
"name": "Antoine Keranflec'h",
77
"email": "antoine.keranflech@gmail.com"

.github/workflows/ci.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [master]
6+
pull_request:
7+
8+
jobs:
9+
test:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v6
13+
- name: ShellCheck
14+
run: shellcheck skills/nokia-sr/scripts/ensure-yang.sh tests/*.sh
15+
- name: Run tests
16+
run: bash tests/test_ensure_yang.sh

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Changelog
2+
3+
## v0.3.0 - 2026-06-09
4+
5+
### Added
6+
7+
- CI workflow (GitHub Actions): ShellCheck and the offline test suite run on every push and pull request.
8+
- `ensure-yang.sh`: `-h`/`--help` handler backed by a single `usage()` function, also printed on the missing-argument error path.
9+
- `ensure-yang.sh`: `GITHUB_TOKEN` / `GH_TOKEN` are sent as an Authorization header when set, lifting the unauthenticated api.github.com rate limit (60 requests/hour per IP); transient download failures are retried (`curl --retry 3`).
10+
- This changelog, and a release checklist in the README (the plugin version lives in both `plugin.json` and `marketplace.json`).
11+
12+
### Fixed
13+
14+
- Test suite: failures inside subshell tests were not counted, so the suite could print `FAIL` lines yet still exit 0 ("all tests passed"). Failures are now tracked in a file so they propagate from subshells.
15+
16+
## v0.2.1 - 2026-06-04
17+
18+
### Fixed
19+
20+
- Quote the SKILL.md `description` to fix invalid YAML frontmatter.
21+
22+
## v0.2.0 - 2026-06-04
23+
24+
- Initial release: `nokia-sr` skill - NOS detection (SR OS vs SR Linux), on-demand YANG models via `ensure-yang.sh`, per-NOS version detection, config formats, NETCONF / MD-CLI / gNMI operations, and srpls language server pointers.

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ A Claude Code skill plugin that teaches Claude how to inspect and operate Nokia'
2323
| Environment variable | Default | Purpose |
2424
|----------------------|---------|---------|
2525
| `NOKIA_SR_YANG_DIR` | `${XDG_CACHE_HOME:-~/.cache}/nokia-sr/yang` | Override the directory where YANG releases are cached and looked up. |
26+
| `GITHUB_TOKEN` / `GH_TOKEN` | unset | Sent as an Authorization header on GitHub API requests; lifts the unauthenticated rate limit (60 requests/hour per IP). |
2627

2728
## Layout
2829

@@ -42,6 +43,16 @@ skills/nokia-sr/
4243
bash tests/test_ensure_yang.sh
4344
```
4445

46+
CI runs ShellCheck and this suite on every push and pull request.
47+
48+
## Releasing
49+
50+
The plugin version is duplicated in two files that must stay in sync:
51+
52+
1. Bump `version` in `.claude-plugin/plugin.json` **and** `.claude-plugin/marketplace.json`.
53+
2. Move the `## Unreleased` entries of `CHANGELOG.md` into a new `## vX.Y.Z - <date>` block.
54+
3. Commit and tag `vX.Y.Z`.
55+
4556
## Attribution
4657

4758
YANG models are downloaded from Nokia's public [7x50_YangModels](https://github.com/nokia/7x50_YangModels) and [srlinux-yang-models](https://github.com/nokia/srlinux-yang-models) repositories and are subject to Nokia's license. This plugin does not redistribute them.

skills/nokia-sr/scripts/ensure-yang.sh

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,50 @@
11
#!/bin/bash
22
# ensure-yang.sh - make Nokia SR YANG models available locally.
3-
#
4-
# Usage: ensure-yang.sh <nos> <version>
5-
# nos sros | srlinux
6-
# version sros: MAJOR.MINOR.Rn e.g. 25.10.R4 (a revision is required)
7-
# srlinux: [v]MAJOR.MINOR.PATCH e.g. 25.10.3 or v25.10.3
8-
# either: latest resolve the newest release from GitHub
3+
# Run with --help (or see usage() below) for arguments, environment, and sources.
94
#
105
# Downloads the matching release as a GitHub tarball - the same source the
116
# srpls language server / vscode-sr extension use - and caches it locally.
127
# Prints the local YANG release directory on stdout (grep it recursively).
13-
#
14-
# sros -> github.com/nokia/7x50_YangModels tag sros_<mm>.r<n> (branch sros_<mm> fallback)
15-
# srlinux -> github.com/nokia/srlinux-yang-models tag v<maj>.<min>.<patch>
168

179
GITHUB_API="https://api.github.com/repos"
18-
CURL_OPTS=(-fsSL -H "Accept: application/vnd.github+json" -A "nokia-sr-skill")
10+
CURL_OPTS=(-fsSL --retry 3 -H "Accept: application/vnd.github+json" -A "nokia-sr-skill")
11+
# Unauthenticated api.github.com allows only 60 requests/hour per IP; a token lifts that.
12+
if [[ -n ${GITHUB_TOKEN:-${GH_TOKEN:-}} ]]; then
13+
CURL_OPTS+=(-H "Authorization: Bearer ${GITHUB_TOKEN:-$GH_TOKEN}")
14+
fi
15+
16+
usage() {
17+
cat << 'EOF'
18+
Usage: ensure-yang.sh <nos> <version>
19+
20+
Make Nokia SR YANG models available locally: check the cache and download the
21+
matching GitHub release tarball only if missing. Prints the local YANG release
22+
directory on stdout (grep it recursively).
23+
24+
Arguments:
25+
nos sros | srlinux
26+
version sros: MAJOR.MINOR.Rn e.g. 25.10.R4 (a revision is required)
27+
srlinux: [v]MAJOR.MINOR.PATCH e.g. 25.10.3 or v25.10.3
28+
either: latest resolve the newest release from GitHub
29+
30+
Options:
31+
-h, --help Show this help and exit.
32+
33+
Environment:
34+
NOKIA_SR_YANG_DIR Cache directory (default: ${XDG_CACHE_HOME:-~/.cache}/nokia-sr/yang).
35+
GITHUB_TOKEN / GH_TOKEN GitHub token sent as an Authorization header; lifts the
36+
unauthenticated api.github.com rate limit (60 requests/hour per IP).
37+
38+
Sources:
39+
sros -> github.com/nokia/7x50_YangModels tag sros_<mm>.r<n> (branch sros_<mm> fallback)
40+
srlinux -> github.com/nokia/srlinux-yang-models tag v<maj>.<min>.<patch>
41+
42+
Examples:
43+
ensure-yang.sh sros 25.10.R4
44+
ensure-yang.sh srlinux 25.10.3
45+
ensure-yang.sh sros latest
46+
EOF
47+
}
1948

2049
# set_repo <nos> -> sets REPO. Returns 2 for an unknown nos.
2150
set_repo() {
@@ -154,9 +183,12 @@ fetch_yang() {
154183

155184
main() {
156185
set -euo pipefail
186+
case ${1:-} in
187+
-h|--help) usage; exit 0 ;;
188+
esac
157189
local nos=${1:-} version=${2:-}
158190
if [[ -z $nos || -z $version ]]; then
159-
echo "usage: ensure-yang.sh <nos> <version> e.g. sros 25.10.R4 | srlinux 25.10.3 | sros latest" >&2
191+
usage >&2
160192
exit 2
161193
fi
162194
if ! set_repo "$nos"; then
@@ -190,7 +222,8 @@ main() {
190222
exit 0
191223
fi
192224

193-
local manual="curl -fsSL $GITHUB_API/$REPO/tarball/${REFS[0]} -o /tmp/yang.tar.gz && mkdir -p $(version_dir "$nos") && tar -xz --strip-components=1 -f /tmp/yang.tar.gz -C $(version_dir "$nos")"
225+
local manual
226+
manual="curl -fsSL $GITHUB_API/$REPO/tarball/${REFS[0]} -o /tmp/yang.tar.gz && mkdir -p $(version_dir "$nos") && tar -xz --strip-components=1 -f /tmp/yang.tar.gz -C $(version_dir "$nos")"
194227
if ! command -v curl > /dev/null 2>&1 || ! command -v tar > /dev/null 2>&1; then
195228
echo "error: need both 'curl' and 'tar'. Install them, or fetch manually:" >&2
196229
echo " $manual" >&2

tests/test_ensure_yang.sh

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
#!/bin/bash
22
# Plain-bash test suite for ensure-yang.sh. Sources the script for unit tests and
33
# execs it (with stubbed curl + tar on PATH) for integration tests. No network, no bats.
4+
#
5+
# shellcheck disable=SC2015,SC2030,SC2031
6+
# SC2015: '&& pass || fail' is safe here - pass() never fails.
7+
# SC2030/SC2031: env changes being local to each ( ) subshell is the point - it is
8+
# how tests stay isolated from each other.
49
set -uo pipefail
510

611
TEST_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
712
SUT="$TEST_DIR/../skills/nokia-sr/scripts/ensure-yang.sh"
8-
FAILS=0
13+
# Failures are recorded in a file, not a counter: most tests run in ( ) subshells,
14+
# where a counter increment would be lost and the suite would wrongly exit 0.
15+
FAIL_FLAG=$(mktemp)
16+
trap 'rm -f "$FAIL_FLAG"' EXIT
917

1018
pass() { printf 'ok - %s\n' "$1"; }
11-
fail() { printf 'FAIL - %s (expected [%s] got [%s])\n' "$1" "$3" "$2"; FAILS=$((FAILS + 1)); }
19+
fail() { printf 'FAIL - %s (expected [%s] got [%s])\n' "$1" "$3" "$2"; echo "$1" >> "$FAIL_FLAG"; }
1220
assert_eq() { [[ $2 == "$3" ]] && pass "$1" || fail "$1" "$2" "$3"; }
1321

1422
# Fresh sandbox HOME + stubbed curl/tar on PATH for one integration run.
@@ -20,10 +28,11 @@ make_sandbox() {
2028
chmod +x "$SANDBOX/bin/curl" "$SANDBOX/bin/tar"
2129
export CURL_STUB_LOG="$SANDBOX/curl.log"
2230
: > "$CURL_STUB_LOG"
23-
unset CURL_STUB_FAIL_REFS TAR_STUB_NOS
31+
unset CURL_STUB_FAIL_REFS TAR_STUB_NOS GITHUB_TOKEN GH_TOKEN
2432
}
2533

2634
# --- unit: source the script, call pure functions directly ---
35+
unset GITHUB_TOKEN GH_TOKEN # keep CURL_OPTS deterministic regardless of caller env
2736
# shellcheck disable=SC1090
2837
source "$SUT"
2938

@@ -191,11 +200,41 @@ set_repo frobnos; assert_eq "set_repo unknown nos returns 2" "$?" "2"
191200
( bash "$SUT" frobnos 25.10.R4 > /dev/null 2>&1; rc=$?
192201
assert_eq "e2e: exit 2 on unknown nos" "$rc" "2" )
193202

194-
# missing args -> exit 2
203+
# missing args -> exit 2, usage on stderr
195204
( bash "$SUT" sros > /dev/null 2>&1; rc=$?
196205
assert_eq "e2e: exit 2 on missing version" "$rc" "2" )
197-
( bash "$SUT" > /dev/null 2>&1; rc=$?
198-
assert_eq "e2e: exit 2 on no args" "$rc" "2" )
206+
( err=$(bash "$SUT" 2>&1 >/dev/null); rc=$?
207+
assert_eq "e2e: exit 2 on no args" "$rc" "2"
208+
case "$err" in
209+
*"Usage: ensure-yang.sh"*) pass "e2e: no args prints usage on stderr" ;;
210+
*) fail "e2e: no args prints usage on stderr" "$err" "contains 'Usage: ensure-yang.sh'" ;;
211+
esac )
212+
213+
# --help / -h -> usage on stdout, exit 0
214+
( out=$(bash "$SUT" --help); rc=$?
215+
assert_eq "e2e: --help exits 0" "$rc" "0"
216+
case "$out" in
217+
*"Usage: ensure-yang.sh"*) pass "e2e: --help prints usage" ;;
218+
*) fail "e2e: --help prints usage" "$out" "contains 'Usage: ensure-yang.sh'" ;;
219+
esac )
220+
( bash "$SUT" -h > /dev/null; rc=$?
221+
assert_eq "e2e: -h exits 0" "$rc" "0" )
222+
223+
# GITHUB_TOKEN -> Authorization header on every GitHub request
224+
( make_sandbox; export HOME="$SANDBOX" PATH="$SANDBOX/bin:$PATH" GITHUB_TOKEN="t0ken"
225+
unset NOKIA_SR_YANG_DIR XDG_CACHE_HOME
226+
bash "$SUT" sros 25.10.R4 > /dev/null
227+
grep -q -- "Authorization: Bearer t0ken" "$CURL_STUB_LOG" \
228+
&& pass "e2e: token sent as Authorization header" \
229+
|| fail "e2e: token sent as Authorization header" "missing" "present" )
230+
231+
# no token -> no Authorization header
232+
( make_sandbox; export HOME="$SANDBOX" PATH="$SANDBOX/bin:$PATH"
233+
unset NOKIA_SR_YANG_DIR XDG_CACHE_HOME
234+
bash "$SUT" sros 25.10.R4 > /dev/null
235+
grep -q -- "Authorization:" "$CURL_STUB_LOG" \
236+
&& fail "e2e: no Authorization header without token" "present" "absent" \
237+
|| pass "e2e: no Authorization header without token" )
199238

200239
# relative cache dir is rejected (rm -rf safety guard)
201240
( export NOKIA_SR_YANG_DIR="relative/cache"
@@ -223,6 +262,7 @@ set_repo frobnos; assert_eq "set_repo unknown nos returns 2" "$?" "2"
223262
esac )
224263

225264
echo
265+
FAILS=$(wc -l < "$FAIL_FLAG")
226266
if (( FAILS > 0 )); then
227267
printf '%d test(s) failed\n' "$FAILS"; exit 1
228268
fi

0 commit comments

Comments
 (0)