osdlc-kit 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- osdlc_kit-0.3.0/.github/dependabot.yml +20 -0
- osdlc_kit-0.3.0/.github/workflows/codeql.yml +27 -0
- osdlc_kit-0.3.0/.github/workflows/lint.yml +36 -0
- osdlc_kit-0.3.0/.github/workflows/opencode.yml +235 -0
- osdlc_kit-0.3.0/.github/workflows/pr-check.yml +62 -0
- osdlc_kit-0.3.0/.github/workflows/release.yml +156 -0
- osdlc_kit-0.3.0/.gitignore +9 -0
- osdlc_kit-0.3.0/AGENTS.md +67 -0
- osdlc_kit-0.3.0/OSDLC Icon.png +0 -0
- osdlc_kit-0.3.0/PKG-INFO +472 -0
- osdlc_kit-0.3.0/README.md +447 -0
- osdlc_kit-0.3.0/opencode.json +32 -0
- osdlc_kit-0.3.0/pyproject.toml +48 -0
- osdlc_kit-0.3.0/pytest.ini +4 -0
- osdlc_kit-0.3.0/run.py +10 -0
- osdlc_kit-0.3.0/src/osdlc/__init__.py +0 -0
- osdlc_kit-0.3.0/src/osdlc/__main__.py +5 -0
- osdlc_kit-0.3.0/src/osdlc/cli.py +188 -0
- osdlc_kit-0.3.0/src/osdlc/detector.py +67 -0
- osdlc_kit-0.3.0/src/osdlc/scaffold.py +206 -0
- osdlc_kit-0.3.0/src/osdlc/templates.py +615 -0
- osdlc_kit-0.3.0/src/osdlc/version.py +303 -0
- osdlc_kit-0.3.0/tests/__init__.py +0 -0
- osdlc_kit-0.3.0/tests/conftest.py +44 -0
- osdlc_kit-0.3.0/tests/test_cli.py +83 -0
- osdlc_kit-0.3.0/tests/test_detector.py +147 -0
- osdlc_kit-0.3.0/tests/test_integration.py +287 -0
- osdlc_kit-0.3.0/tests/test_scaffold.py +115 -0
- osdlc_kit-0.3.0/tests/test_templates.py +122 -0
- osdlc_kit-0.3.0/tests/test_version.py +206 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "pip"
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "weekly"
|
|
7
|
+
day: "monday"
|
|
8
|
+
open-pull-requests-limit: 5
|
|
9
|
+
commit-message:
|
|
10
|
+
prefix: "fix"
|
|
11
|
+
prefix-development: "chore"
|
|
12
|
+
|
|
13
|
+
- package-ecosystem: "github-actions"
|
|
14
|
+
directory: "/"
|
|
15
|
+
schedule:
|
|
16
|
+
interval: "weekly"
|
|
17
|
+
day: "monday"
|
|
18
|
+
open-pull-requests-limit: 5
|
|
19
|
+
commit-message:
|
|
20
|
+
prefix: "chore"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: CodeQL
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: '0 12 * * 1'
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
analyze:
|
|
13
|
+
name: Analyze
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
permissions:
|
|
16
|
+
actions: read
|
|
17
|
+
contents: read
|
|
18
|
+
security-events: write
|
|
19
|
+
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v6
|
|
22
|
+
|
|
23
|
+
- uses: github/codeql-action/init@v4
|
|
24
|
+
|
|
25
|
+
- uses: github/codeql-action/autobuild@v4
|
|
26
|
+
|
|
27
|
+
- uses: github/codeql-action/analyze@v4
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: Lint
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
pull-requests: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
super-linter:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout
|
|
17
|
+
uses: actions/checkout@v6
|
|
18
|
+
with:
|
|
19
|
+
fetch-depth: 0
|
|
20
|
+
|
|
21
|
+
- name: Super-Linter
|
|
22
|
+
uses: super-linter/super-linter@v8.6.0
|
|
23
|
+
env:
|
|
24
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
25
|
+
VALIDATE_ALL_CODEBASE: false
|
|
26
|
+
DEFAULT_BRANCH: main
|
|
27
|
+
VALIDATE_JAVA: true
|
|
28
|
+
VALIDATE_KOTLIN_KT_LINT: true
|
|
29
|
+
VALIDATE_KOTLIN_BIOME: true
|
|
30
|
+
VALIDATE_YAML: true
|
|
31
|
+
VALIDATE_JSON: true
|
|
32
|
+
VALIDATE_XML: true
|
|
33
|
+
VALIDATE_MARKDOWN: true
|
|
34
|
+
VALIDATE_PROPERTIES: true
|
|
35
|
+
VALIDATE_GITHUB_ACTIONS: true
|
|
36
|
+
FILTER_REGEX_EXCLUDE: \.jks$|\.jar$|\.keystore$
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: opencode
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
issue_comment:
|
|
6
|
+
types: [created]
|
|
7
|
+
pull_request_review:
|
|
8
|
+
types: [submitted]
|
|
9
|
+
workflow_run:
|
|
10
|
+
workflows: ["PR Check"]
|
|
11
|
+
types: [completed]
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: opencode-${{ github.event_name }}-${{
|
|
15
|
+
github.event.issue.number ||
|
|
16
|
+
github.event.pull_request.number ||
|
|
17
|
+
github.event.workflow_run.pull_requests[0].number ||
|
|
18
|
+
github.event.reply_to_id }}-${{
|
|
19
|
+
github.event_name == 'workflow_run' && 'auto' ||
|
|
20
|
+
contains(github.event.comment.body, '/oc') && 'cmd' ||
|
|
21
|
+
'other' }}
|
|
22
|
+
cancel-in-progress: true
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
opencode:
|
|
26
|
+
if: |
|
|
27
|
+
github.event_name != 'workflow_run' &&
|
|
28
|
+
github.event.comment != null &&
|
|
29
|
+
github.event.comment.author_association == 'OWNER' &&
|
|
30
|
+
github.actor == 'andreaschiona' &&
|
|
31
|
+
(
|
|
32
|
+
contains(github.event.comment.body, ' /oc') ||
|
|
33
|
+
startsWith(github.event.comment.body, '/oc') ||
|
|
34
|
+
contains(github.event.comment.body, ' /opencode') ||
|
|
35
|
+
startsWith(github.event.comment.body, '/opencode')
|
|
36
|
+
)
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
timeout-minutes: 180
|
|
39
|
+
permissions:
|
|
40
|
+
id-token: write
|
|
41
|
+
contents: write
|
|
42
|
+
pull-requests: write
|
|
43
|
+
issues: write
|
|
44
|
+
steps:
|
|
45
|
+
- name: Checkout repository
|
|
46
|
+
uses: actions/checkout@v6
|
|
47
|
+
with:
|
|
48
|
+
persist-credentials: false
|
|
49
|
+
fetch-depth: 0
|
|
50
|
+
|
|
51
|
+
- name: Install jq
|
|
52
|
+
shell: bash
|
|
53
|
+
run: sudo apt-get update -qq && sudo apt-get install -y -qq jq
|
|
54
|
+
|
|
55
|
+
- name: Setup Python
|
|
56
|
+
uses: actions/setup-python@v5
|
|
57
|
+
with:
|
|
58
|
+
python-version: '3.x'
|
|
59
|
+
|
|
60
|
+
- name: Get opencode version
|
|
61
|
+
id: version
|
|
62
|
+
shell: bash
|
|
63
|
+
run: |
|
|
64
|
+
VERSION=$(curl -sf https://api.github.com/repos/anomalyco/opencode/releases/latest |
|
|
65
|
+
grep -o '"tag_name": *"[^"]*"' | cut -d'"' -f4 || true)
|
|
66
|
+
echo "version=${VERSION:-v1.15.10}" >> "$GITHUB_OUTPUT"
|
|
67
|
+
|
|
68
|
+
- name: Cache opencode
|
|
69
|
+
id: cache
|
|
70
|
+
uses: actions/cache@v5
|
|
71
|
+
with:
|
|
72
|
+
path: ~/.opencode/bin
|
|
73
|
+
key: opencode-${{ runner.os }}-${{ runner.arch }}-${{ steps.version.outputs.version }}
|
|
74
|
+
|
|
75
|
+
- name: Install opencode
|
|
76
|
+
if: steps.cache.outputs.cache-hit != 'true'
|
|
77
|
+
shell: bash
|
|
78
|
+
run: curl -fsSL https://opencode.ai/install.sh | sh -s -- ${{ steps.version.outputs.version }}
|
|
79
|
+
|
|
80
|
+
- name: Add opencode to PATH
|
|
81
|
+
shell: bash
|
|
82
|
+
run: echo "$HOME/.opencode/bin" >> "$GITHUB_PATH"
|
|
83
|
+
|
|
84
|
+
- name: Determine model from comment
|
|
85
|
+
id: model_select
|
|
86
|
+
shell: bash
|
|
87
|
+
env:
|
|
88
|
+
COMMENT: ${{ github.event.comment.body }}
|
|
89
|
+
run: |
|
|
90
|
+
if echo "$COMMENT" | grep -qi "GEMINI"; then
|
|
91
|
+
echo "model=google/gemini-2.5-flash" >> "$GITHUB_OUTPUT"
|
|
92
|
+
elif echo "$COMMENT" | grep -qi "BIGPICKLE"; then
|
|
93
|
+
echo "model=opencode/big-pickle" >> "$GITHUB_OUTPUT"
|
|
94
|
+
elif echo "$COMMENT" | grep -qi "NEMOTRON"; then
|
|
95
|
+
echo "model=opencode/nemotron-3-super-free" >> "$GITHUB_OUTPUT"
|
|
96
|
+
else
|
|
97
|
+
echo "model=opencode/deepseek-v4-flash-free" >> "$GITHUB_OUTPUT"
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
- name: Run opencode (with retry)
|
|
101
|
+
shell: bash
|
|
102
|
+
id: run_opencode
|
|
103
|
+
env:
|
|
104
|
+
MODEL: ${{ steps.model_select.outputs.model }}
|
|
105
|
+
OPENCODE_TELEMETRY: false
|
|
106
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
107
|
+
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
|
108
|
+
run: |
|
|
109
|
+
echo "Selected model: $MODEL"
|
|
110
|
+
|
|
111
|
+
jq --arg model "$MODEL" '.model = $model' opencode.json > opencode.tmp.json && mv opencode.tmp.json opencode.json
|
|
112
|
+
echo "Injected model '$MODEL' into opencode.json"
|
|
113
|
+
|
|
114
|
+
MAX_RETRIES=3
|
|
115
|
+
RETRY_DELAY=15
|
|
116
|
+
for i in $(seq 1 "$MAX_RETRIES"); do
|
|
117
|
+
echo "opencode run attempt $i of $MAX_RETRIES"
|
|
118
|
+
if opencode github run; then
|
|
119
|
+
echo "opencode completed successfully"
|
|
120
|
+
exit 0
|
|
121
|
+
fi
|
|
122
|
+
exit_code=$?
|
|
123
|
+
echo "opencode exit code: $exit_code"
|
|
124
|
+
if [ "$i" -eq "$MAX_RETRIES" ]; then
|
|
125
|
+
echo "All $MAX_RETRIES attempts failed, last exit code: $exit_code"
|
|
126
|
+
exit 1
|
|
127
|
+
fi
|
|
128
|
+
echo "Attempt $i failed (exit code: $exit_code), retrying in ${RETRY_DELAY}s..."
|
|
129
|
+
sleep "$RETRY_DELAY"
|
|
130
|
+
done
|
|
131
|
+
|
|
132
|
+
auto-analyze-failure:
|
|
133
|
+
if: |
|
|
134
|
+
github.event_name == 'workflow_run' &&
|
|
135
|
+
github.event.workflow_run.conclusion == 'failure' &&
|
|
136
|
+
github.event.workflow_run.pull_requests[0] != null &&
|
|
137
|
+
github.event.workflow_run.head_repository.fork == false
|
|
138
|
+
runs-on: ubuntu-latest
|
|
139
|
+
timeout-minutes: 30
|
|
140
|
+
permissions:
|
|
141
|
+
contents: read
|
|
142
|
+
pull-requests: write
|
|
143
|
+
checks: read
|
|
144
|
+
steps:
|
|
145
|
+
- name: Checkout PR head
|
|
146
|
+
uses: actions/checkout@v6
|
|
147
|
+
with:
|
|
148
|
+
ref: ${{ github.event.workflow_run.head_sha }}
|
|
149
|
+
fetch-depth: 0
|
|
150
|
+
persist-credentials: false
|
|
151
|
+
|
|
152
|
+
- name: Get PR number
|
|
153
|
+
id: pr
|
|
154
|
+
shell: bash
|
|
155
|
+
run: |
|
|
156
|
+
{
|
|
157
|
+
echo "number=${{ github.event.workflow_run.pull_requests[0].number }}"
|
|
158
|
+
echo "head_branch=${{ github.event.workflow_run.head_branch }}"
|
|
159
|
+
echo "head_sha=${{ github.event.workflow_run.head_sha }}"
|
|
160
|
+
} >> "$GITHUB_OUTPUT"
|
|
161
|
+
|
|
162
|
+
- name: Collect failure context
|
|
163
|
+
shell: bash
|
|
164
|
+
run: |
|
|
165
|
+
mkdir -p /tmp/ci-context
|
|
166
|
+
URL="/repos/${{ github.repository }}/commits/${{ github.event.workflow_run.head_sha }}/check-runs"
|
|
167
|
+
gh api "$URL" --jq '
|
|
168
|
+
.check_runs[] | select(.conclusion == "failure") |
|
|
169
|
+
"## \(.name)\n\n**Title:** \(.output.title // "failed")\n\n**Summary:**\n\(.output.summary // "N/A")\n\n**Text:**\n\(.output.text // "N/A")\n"
|
|
170
|
+
' > /tmp/ci-context/check-failures.md
|
|
171
|
+
gh pr diff ${{ steps.pr.outputs.number }} > /tmp/ci-context/pr-diff.diff
|
|
172
|
+
echo "Failure context collected ($(wc -l < /tmp/ci-context/check-failures.md) lines)"
|
|
173
|
+
env:
|
|
174
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
175
|
+
|
|
176
|
+
- name: Get opencode version
|
|
177
|
+
id: version
|
|
178
|
+
shell: bash
|
|
179
|
+
run: |
|
|
180
|
+
VERSION=$(curl -sf https://api.github.com/repos/anomalyco/opencode/releases/latest |
|
|
181
|
+
grep -o '"tag_name": *"[^"]*"' | cut -d'"' -f4 || true)
|
|
182
|
+
echo "version=${VERSION:-v1.15.10}" >> "$GITHUB_OUTPUT"
|
|
183
|
+
|
|
184
|
+
- name: Cache opencode
|
|
185
|
+
id: cache
|
|
186
|
+
uses: actions/cache@v5
|
|
187
|
+
with:
|
|
188
|
+
path: ~/.opencode/bin
|
|
189
|
+
key: opencode-auto-${{ runner.os }}-${{ runner.arch }}-${{ steps.version.outputs.version }}
|
|
190
|
+
|
|
191
|
+
- name: Install opencode
|
|
192
|
+
if: steps.cache.outputs.cache-hit != 'true'
|
|
193
|
+
shell: bash
|
|
194
|
+
run: curl -fsSL https://opencode.ai/install.sh | sh -s -- ${{ steps.version.outputs.version }}
|
|
195
|
+
|
|
196
|
+
- name: Add opencode to PATH
|
|
197
|
+
shell: bash
|
|
198
|
+
run: echo "$HOME/.opencode/bin" >> "$GITHUB_PATH"
|
|
199
|
+
|
|
200
|
+
- name: Analyze failures with opencode
|
|
201
|
+
shell: bash
|
|
202
|
+
continue-on-error: true
|
|
203
|
+
env:
|
|
204
|
+
OPENCODE_TELEMETRY: false
|
|
205
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
206
|
+
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
|
207
|
+
run: |
|
|
208
|
+
opencode run --model opencode/deepseek-v4-flash-free \
|
|
209
|
+
--file /tmp/ci-context/check-failures.md \
|
|
210
|
+
--file /tmp/ci-context/pr-diff.diff \
|
|
211
|
+
"I CI check su questa PR (#${{ steps.pr.outputs.number }}) sono falliti. \
|
|
212
|
+
I file allegati contengono i dettagli dei check falliti e il diff della PR. \
|
|
213
|
+
Analizza i fallimenti e proponi correzioni specifiche. \
|
|
214
|
+
Fornisci un'analisi dettagliata in italiano." \
|
|
215
|
+
> /tmp/ci-context/analysis.md 2>&1
|
|
216
|
+
|
|
217
|
+
- name: Post analysis to PR
|
|
218
|
+
if: always() && steps.pr.outputs.number != ''
|
|
219
|
+
shell: bash
|
|
220
|
+
env:
|
|
221
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
222
|
+
run: |
|
|
223
|
+
{
|
|
224
|
+
echo '## Analisi automatica CI'
|
|
225
|
+
echo ''
|
|
226
|
+
if [ -s /tmp/ci-context/analysis.md ]; then
|
|
227
|
+
echo 'OpenCode ha analizzato i fallimenti dei check su questo PR.'
|
|
228
|
+
echo ''
|
|
229
|
+
cat /tmp/ci-context/analysis.md
|
|
230
|
+
else
|
|
231
|
+
echo "L'analisi automatica non ha prodotto risultati."
|
|
232
|
+
echo "Per analizzare manualmente, commenta con /oc analizza i fallimenti CI su questa PR."
|
|
233
|
+
fi
|
|
234
|
+
} > /tmp/ci-context/body.md
|
|
235
|
+
gh pr comment ${{ steps.pr.outputs.number }} --body-file /tmp/ci-context/body.md
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: PR Check
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize, reopened]
|
|
6
|
+
branches: [main]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
pull-requests: write
|
|
11
|
+
checks: write
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
check:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v6
|
|
18
|
+
with:
|
|
19
|
+
fetch-depth: 0
|
|
20
|
+
|
|
21
|
+
- name: Setup Python
|
|
22
|
+
uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: '3.x'
|
|
25
|
+
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: pip install pytest pytest-cov
|
|
28
|
+
|
|
29
|
+
- name: Lint
|
|
30
|
+
run: python -m py_compile run.py src/osdlc/*.py
|
|
31
|
+
|
|
32
|
+
- name: Test with coverage
|
|
33
|
+
run: python -m pytest --cov=src/osdlc --cov-report=xml --cov-report=term-missing -v
|
|
34
|
+
|
|
35
|
+
- name: Build
|
|
36
|
+
run: python -m py_compile run.py src/osdlc/*.py
|
|
37
|
+
|
|
38
|
+
- name: Upload coverage artifact
|
|
39
|
+
if: always()
|
|
40
|
+
uses: actions/upload-artifact@v7
|
|
41
|
+
with:
|
|
42
|
+
name: coverage-report
|
|
43
|
+
path: coverage.xml
|
|
44
|
+
retention-days: 7
|
|
45
|
+
|
|
46
|
+
- name: PR comment with results
|
|
47
|
+
if: always() && github.event_name == 'pull_request'
|
|
48
|
+
uses: actions/github-script@v9
|
|
49
|
+
with:
|
|
50
|
+
script: |
|
|
51
|
+
const { data: checks } = await github.rest.checks.listForRef({
|
|
52
|
+
...context.repo,
|
|
53
|
+
ref: context.sha,
|
|
54
|
+
});
|
|
55
|
+
const summary = checks.check_runs.map(c =>
|
|
56
|
+
`- **${c.name}**: ${c.conclusion || 'in_progress'}`
|
|
57
|
+
).join('\n');
|
|
58
|
+
github.rest.issues.createComment({
|
|
59
|
+
...context.repo,
|
|
60
|
+
issue_number: context.issue.number,
|
|
61
|
+
body: `## PR Check Results\n\n${summary}\n\n_Updated at ${new Date().toISOString()}_`,
|
|
62
|
+
});
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths-ignore:
|
|
7
|
+
- '**.md'
|
|
8
|
+
- '.gitignore'
|
|
9
|
+
- '.github/**'
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
issues: write
|
|
14
|
+
id-token: write # needed for PyPI trusted publishing
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
release:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
outputs:
|
|
20
|
+
new_version: ${{ steps.resolve.outputs.new_version }}
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v6
|
|
23
|
+
with:
|
|
24
|
+
fetch-depth: 0
|
|
25
|
+
|
|
26
|
+
- name: Setup Python
|
|
27
|
+
uses: actions/setup-python@v5
|
|
28
|
+
with:
|
|
29
|
+
python-version: '3.x'
|
|
30
|
+
|
|
31
|
+
- name: Determine bump
|
|
32
|
+
id: bump
|
|
33
|
+
run: |
|
|
34
|
+
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true)
|
|
35
|
+
if [ -z "$LAST_TAG" ]; then
|
|
36
|
+
COMMITS=$(git log --format="%s")
|
|
37
|
+
else
|
|
38
|
+
COMMITS=$(git log "$LAST_TAG..HEAD" --format="%s")
|
|
39
|
+
fi
|
|
40
|
+
if echo "$COMMITS" | grep -q "BREAKING CHANGE"; then
|
|
41
|
+
echo "BUMP_TYPE=major" >> "$GITHUB_ENV"
|
|
42
|
+
elif echo "$COMMITS" | grep -q "^feat"; then
|
|
43
|
+
echo "BUMP_TYPE=minor" >> "$GITHUB_ENV"
|
|
44
|
+
else
|
|
45
|
+
echo "BUMP_TYPE=patch" >> "$GITHUB_ENV"
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
- name: Bump version
|
|
49
|
+
id: version
|
|
50
|
+
shell: bash
|
|
51
|
+
run: |
|
|
52
|
+
OUTPUT=$(python src/osdlc/version.py update --root . 2>&1)
|
|
53
|
+
echo "update_output=$OUTPUT" >> "$GITHUB_OUTPUT"
|
|
54
|
+
NEW_VERSION=$(echo "$OUTPUT" | sed -n 's/.*-> \([0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/p')
|
|
55
|
+
echo "new_version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
|
|
56
|
+
echo "$OUTPUT"
|
|
57
|
+
|
|
58
|
+
- name: Install dependencies
|
|
59
|
+
run: pip install pytest
|
|
60
|
+
|
|
61
|
+
- name: Lint
|
|
62
|
+
run: python -m py_compile run.py src/osdlc/*.py
|
|
63
|
+
|
|
64
|
+
- name: Run tests
|
|
65
|
+
id: tests
|
|
66
|
+
continue-on-error: true
|
|
67
|
+
run: python -m pytest -v || test $? -eq 5
|
|
68
|
+
|
|
69
|
+
- name: Build
|
|
70
|
+
run: python -m py_compile run.py src/osdlc/*.py
|
|
71
|
+
|
|
72
|
+
- name: Create issue on test failure
|
|
73
|
+
if: steps.tests.outcome == 'failure'
|
|
74
|
+
uses: actions/github-script@v9
|
|
75
|
+
with:
|
|
76
|
+
script: |
|
|
77
|
+
github.rest.issues.create({
|
|
78
|
+
owner: context.repo.owner,
|
|
79
|
+
repo: context.repo.repo,
|
|
80
|
+
title: 'Release tests failed',
|
|
81
|
+
body: 'Tests failed during release for version ${{ steps.version.outputs.new_version }}. Check the release workflow run for details.',
|
|
82
|
+
labels: ['bug', 'auto-reported']
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
- name: Fail if tests failed
|
|
86
|
+
if: steps.tests.outcome == 'failure'
|
|
87
|
+
run: exit 1
|
|
88
|
+
|
|
89
|
+
- name: Resolve version (increment if tag exists)
|
|
90
|
+
id: resolve
|
|
91
|
+
run: |
|
|
92
|
+
VERSION_FILE="VERSION"
|
|
93
|
+
[ -f "pyproject.toml" ] && VERSION_FILE="pyproject.toml"
|
|
94
|
+
NEW_VERSION="${{ steps.version.outputs.new_version }}"
|
|
95
|
+
while git tag -l "v$NEW_VERSION" | grep -q .; do
|
|
96
|
+
echo "Tag v$NEW_VERSION already exists — incrementing"
|
|
97
|
+
IFS='.' read -r MAJOR MINOR PATCH <<< "$NEW_VERSION"
|
|
98
|
+
case "$BUMP_TYPE" in
|
|
99
|
+
major) MAJOR=$((MAJOR+1)); MINOR=0; PATCH=0 ;;
|
|
100
|
+
minor) MINOR=$((MINOR+1)); PATCH=0 ;;
|
|
101
|
+
patch) PATCH=$((PATCH+1)) ;;
|
|
102
|
+
esac
|
|
103
|
+
NEW_VERSION="$MAJOR.$MINOR.$PATCH"
|
|
104
|
+
done
|
|
105
|
+
echo "new_version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
|
|
106
|
+
if [ -f "pyproject.toml" ]; then
|
|
107
|
+
sed -i "s/version = \"[0-9.]*\"/version = \"$NEW_VERSION\"/" pyproject.toml
|
|
108
|
+
else
|
|
109
|
+
echo "version=$NEW_VERSION" > "$VERSION_FILE"
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
- name: Commit version bump
|
|
113
|
+
run: |
|
|
114
|
+
git config user.name "github-actions"
|
|
115
|
+
git config user.email "actions@github.com"
|
|
116
|
+
VERSION_FILE=$(python src/osdlc/version.py detect --root . | cut -d' ' -f1)
|
|
117
|
+
[ -z "$VERSION_FILE" ] && VERSION_FILE="VERSION"
|
|
118
|
+
git add "$VERSION_FILE"
|
|
119
|
+
git commit -m "chore: bump version to ${{ steps.resolve.outputs.new_version }} [skip ci]"
|
|
120
|
+
git tag v${{ steps.resolve.outputs.new_version }}
|
|
121
|
+
|
|
122
|
+
- name: Push changes
|
|
123
|
+
run: |
|
|
124
|
+
git push origin main
|
|
125
|
+
git push origin v${{ steps.resolve.outputs.new_version }}
|
|
126
|
+
|
|
127
|
+
- name: Create Release
|
|
128
|
+
uses: softprops/action-gh-release@v3
|
|
129
|
+
with:
|
|
130
|
+
tag_name: v${{ steps.resolve.outputs.new_version }}
|
|
131
|
+
generate_release_notes: true
|
|
132
|
+
make_latest: true
|
|
133
|
+
|
|
134
|
+
publish:
|
|
135
|
+
needs: release
|
|
136
|
+
runs-on: ubuntu-latest
|
|
137
|
+
permissions:
|
|
138
|
+
id-token: write
|
|
139
|
+
steps:
|
|
140
|
+
- uses: actions/checkout@v6
|
|
141
|
+
with:
|
|
142
|
+
ref: v${{ needs.release.outputs.new_version }}
|
|
143
|
+
fetch-depth: 0
|
|
144
|
+
|
|
145
|
+
- name: Setup Python
|
|
146
|
+
uses: actions/setup-python@v5
|
|
147
|
+
with:
|
|
148
|
+
python-version: '3.x'
|
|
149
|
+
|
|
150
|
+
- name: Build wheel
|
|
151
|
+
run: |
|
|
152
|
+
pip install hatchling
|
|
153
|
+
python -m hatchling build
|
|
154
|
+
|
|
155
|
+
- name: Publish to PyPI
|
|
156
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# AI Open SDLC Kit -- Agent Instructions
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
|
|
5
|
+
This project uses Python with a manual build system (manual).
|
|
6
|
+
|
|
7
|
+
## Verified Commands
|
|
8
|
+
|
|
9
|
+
- **Build:** `python -m py_compile run.py src/osdlc/*.py`
|
|
10
|
+
- **Test:** `python -m pytest --cov=src/osdlc --cov-report=xml --cov-report=term-missing -v`
|
|
11
|
+
- **Lint:** `python -m py_compile run.py src/osdlc/*.py`
|
|
12
|
+
|
|
13
|
+
## Environment
|
|
14
|
+
|
|
15
|
+
Python 3.x. Install dependencies with `pip install pytest pytest-cov`.
|
|
16
|
+
|
|
17
|
+
## OpenCode Protocol
|
|
18
|
+
|
|
19
|
+
The agent MUST handle slash-commands found in issue or PR comments.
|
|
20
|
+
|
|
21
|
+
### Parsing
|
|
22
|
+
|
|
23
|
+
When opencode is triggered by a comment:
|
|
24
|
+
1. Read the comment body from the triggering event.
|
|
25
|
+
2. If the comment starts with `/oc` or `/opencode`, extract the first whitespace-delimited token immediately following the prefix.
|
|
26
|
+
3. The remainder of the comment (after the command token) is the **instruction payload**.
|
|
27
|
+
4. Route to the appropriate behaviour based on the command token.
|
|
28
|
+
|
|
29
|
+
### Commands
|
|
30
|
+
|
|
31
|
+
- **`/oc fix`** (Issue) - Apply a quick corrective change. Analyse the issue, create a throwaway fix branch from `main`, apply the fix, commit with `fix:`, and push. Do NOT create a PR. The payload may describe the fix intent.
|
|
32
|
+
- **`/oc analyze`** (Issue) - Read the issue body and all comments. Perform a critical analysis, then post a detailed functional requirement as a new issue comment. Include: problem statement, affected areas, acceptance criteria, and open questions.
|
|
33
|
+
- **`/oc plan`** (Issue) - Requires prior analyze. Read the analysed requirement, produce a technical implementation plan with file-level breakdown, and post it as a new issue comment.
|
|
34
|
+
- **`/oc implement`** (Issue) - Requires prior plan. Create branch `issue-{{number}}` from `main`. Implement file-by-file, commit each unit conventionally. Open a PR targeting `main` with `Closes #{{number}}`.
|
|
35
|
+
- **`/oc fixCheck`** (PR) - Read automated check results. For each failure, apply a fix, amend the PR branch, and re-trigger checks. Repeat up to 3 retries. Post a status comment when done.
|
|
36
|
+
|
|
37
|
+
### Instruction Payload
|
|
38
|
+
|
|
39
|
+
Any text after the command token is the instruction payload. The agent MAY use it for additional context:
|
|
40
|
+
- `/oc fix add null guard` -> command `fix`, payload `add null guard`
|
|
41
|
+
- `/oc analyze` -> command `analyze`, payload empty
|
|
42
|
+
|
|
43
|
+
### Model Overrides
|
|
44
|
+
|
|
45
|
+
The workflow sets the model based on keywords anywhere in the comment (case-insensitive):
|
|
46
|
+
|
|
47
|
+
- `GEMINI` -> `google/gemini-2.5-flash`
|
|
48
|
+
- `BIGPICKLE` -> `opencode/big-pickle`
|
|
49
|
+
- `NEMOTRON` -> `opencode/nemotron-3-super-free`
|
|
50
|
+
- (default) -> `opencode/deepseek-v4-flash-free`
|
|
51
|
+
|
|
52
|
+
## Commit Convention
|
|
53
|
+
|
|
54
|
+
Every commit MUST follow the Conventional Commits specification:
|
|
55
|
+
- `feat: ...` -- a new feature
|
|
56
|
+
- `fix: ...` -- a bug fix
|
|
57
|
+
- `chore: ...` -- maintenance, dependencies, tooling
|
|
58
|
+
- `BREAKING CHANGE: ...` or `feat!: ...` -- incompatible API changes
|
|
59
|
+
|
|
60
|
+
## Branch Naming
|
|
61
|
+
|
|
62
|
+
Feature branches MUST follow the pattern: `issue-{{number}}`
|
|
63
|
+
Always branch from `main`.
|
|
64
|
+
|
|
65
|
+
## Version Configuration
|
|
66
|
+
|
|
67
|
+
Version is stored in: `VERSION`
|
|
Binary file
|