hackerrank-cli 2026.10.30__tar.gz → 2026.11.7__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.
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/.github/workflows/binaries.yml +1 -1
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/Dockerfile +3 -1
- {hackerrank_cli-2026.10.30/src/hackerrank_cli.egg-info → hackerrank_cli-2026.11.7}/PKG-INFO +27 -2
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/README.rst +25 -0
- hackerrank_cli-2026.11.7/VERSION +1 -0
- hackerrank_cli-2026.11.7/docs/source/changelog/2026.11.7.md +7 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/docs/source/development.rst +1 -1
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/flake.nix +14 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/prek.toml +0 -2
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/pyproject.toml +14 -8
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/spelling_private_dict.txt +6 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/src/hackerrank_cli/__init__.py +3 -3
- hackerrank_cli-2026.11.7/src/hackerrank_cli/_api.py +205 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/src/hackerrank_cli/_version.py +3 -3
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7/src/hackerrank_cli.egg-info}/PKG-INFO +27 -2
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/src/hackerrank_cli.egg-info/SOURCES.txt +3 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/src/hackerrank_cli.egg-info/requires.txt +1 -1
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/src/hackerrank_cli.egg-info/scm_file_list.json +3 -0
- hackerrank_cli-2026.11.7/src/hackerrank_cli.egg-info/scm_version.json +8 -0
- hackerrank_cli-2026.11.7/tests/test_api.py +240 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/tests/test_help/test_help_root_.txt +2 -1
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/uv.lock +307 -306
- hackerrank_cli-2026.10.30/VERSION +0 -1
- hackerrank_cli-2026.10.30/src/hackerrank_cli.egg-info/scm_version.json +0 -8
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/.dockerignore +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/.gitattributes +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/.github/dependabot.yml +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/.github/workflows/autofix.yml +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/.github/workflows/ci.yml +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/.github/workflows/dependabot-merge.yml +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/.github/workflows/docs.yml +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/.github/workflows/lint.yml +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/.github/workflows/nix.yml +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/.github/workflows/publish-site.yml +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/.github/workflows/release.yml +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/.gitignore +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/.vale.ini +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/LICENSE +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/MANIFEST.in +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/bin/__init__.py +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/bin/hackerrank_wrapper.py +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/docs/__init__.py +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/docs/source/__init__.py +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/docs/source/changelog/2026.10.1.1.md +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/docs/source/changelog/2026.10.30.md +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/docs/source/changelog/2026.10.7.md +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/docs/source/changelog/2026.10.8.md +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/docs/source/changelog.md +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/docs/source/cli.rst +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/docs/source/conf.py +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/docs/source/index.rst +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/docs/source/macos-releases.rst +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/docs/source/migration.rst +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/docs/source/usage.rst +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/flake.lock +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/newsfragments/.gitkeep +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/setup.cfg +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/src/hackerrank_cli/__main__.py +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/src/hackerrank_cli/_sources.py +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/src/hackerrank_cli/py.typed +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/src/hackerrank_cli.egg-info/dependency_links.txt +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/src/hackerrank_cli.egg-info/entry_points.txt +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/src/hackerrank_cli.egg-info/not-zip-safe +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/src/hackerrank_cli.egg-info/top_level.txt +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/styles/snapper/LongProseLine.yml +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/styles/snapper/SemanticLineBreaks.yml +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/tests/__init__.py +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/tests/test_archive.py +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/tests/test_cli.py +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/tests/test_help/test_help_questions_.txt +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/tests/test_help/test_help_questions_archive_.txt +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/tests/test_help/test_help_questions_set_system_prompt_.txt +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/tests/test_help/test_help_questions_upload_.txt +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/tests/test_help.py +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/tests/test_http.py +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/tests/test_sources.py +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/tests/test_system_prompt.py +0 -0
- {hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/zizmor.yml +0 -0
|
@@ -67,7 +67,7 @@ jobs:
|
|
|
67
67
|
- name: Import the Developer ID certificate
|
|
68
68
|
id: signing_certificate
|
|
69
69
|
if: runner.os == 'macOS' && inputs.notarize
|
|
70
|
-
uses: Apple-Actions/import-codesign-certs@
|
|
70
|
+
uses: Apple-Actions/import-codesign-certs@288b8ec97b82c66b6f2a6baaf7acc8dfbcbe331c # v7.2.0
|
|
71
71
|
with:
|
|
72
72
|
p12-file-base64: ${{ secrets.DEVELOPER_ID_APP_CERT_P12_BASE64 }}
|
|
73
73
|
p12-password: ${{ secrets.DEVELOPER_ID_APP_CERT_PASSWORD }}
|
|
@@ -4,12 +4,14 @@ COPY --from=ghcr.io/astral-sh/uv:0.13.0 /uv /bin/uv
|
|
|
4
4
|
WORKDIR /build
|
|
5
5
|
COPY . .
|
|
6
6
|
ARG HACKERRANK_CLI_VERSION=0.0.0
|
|
7
|
+
RUN apt-get update && apt-get install -y --no-install-recommends git && rm -rf /var/lib/apt/lists/*
|
|
7
8
|
RUN SETUPTOOLS_SCM_PRETEND_VERSION_FOR_HACKERRANK_CLI=$HACKERRANK_CLI_VERSION uv build --wheel --out-dir /wheels
|
|
9
|
+
RUN uv pip compile pyproject.toml -o /tmp/runtime.txt && uv run --no-project --with pip python -m pip wheel --wheel-dir /wheels -r /tmp/runtime.txt
|
|
8
10
|
|
|
9
11
|
FROM python:3.13-slim
|
|
10
12
|
LABEL org.opencontainers.image.source="https://github.com/adamtheturtle/hackerrank-cli"
|
|
11
13
|
LABEL org.opencontainers.image.description="Upload HackerRank question starter code"
|
|
12
14
|
LABEL org.opencontainers.image.licenses="MIT"
|
|
13
15
|
COPY --from=build /wheels /wheels
|
|
14
|
-
RUN pip install --no-cache-dir /wheels/*.whl && rm -rf /wheels
|
|
16
|
+
RUN pip install --no-cache-dir --no-index --no-deps /wheels/*.whl && rm -rf /wheels
|
|
15
17
|
ENTRYPOINT ["hackerrank"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hackerrank-cli
|
|
3
|
-
Version: 2026.
|
|
3
|
+
Version: 2026.11.7
|
|
4
4
|
Summary: Upload starter files to existing HackerRank project questions.
|
|
5
5
|
Author-email: Adam Dangoor <adamdangoor@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -19,7 +19,7 @@ Requires-Python: >=3.13
|
|
|
19
19
|
Description-Content-Type: text/x-rst
|
|
20
20
|
License-File: LICENSE
|
|
21
21
|
Requires-Dist: click<8.6,>=8.3
|
|
22
|
-
Requires-Dist: hackerrank>=2026.
|
|
22
|
+
Requires-Dist: hackerrank>=2026.11.7
|
|
23
23
|
Requires-Dist: httpx>=0.28
|
|
24
24
|
Requires-Dist: httpx2>=2.12
|
|
25
25
|
Requires-Dist: pathspec>=1
|
|
@@ -184,3 +184,28 @@ Prompts may contain up to 15,000 characters.
|
|
|
184
184
|
Text is sent exactly as read, including whitespace and line endings.
|
|
185
185
|
An empty file explicitly clears the prompt.
|
|
186
186
|
The command reads the question first to preserve its other metadata.
|
|
187
|
+
|
|
188
|
+
Complete API access
|
|
189
|
+
-------------------
|
|
190
|
+
|
|
191
|
+
The ``api`` command group exposes all 76 documented v3, ATS and SCIM
|
|
192
|
+
operations.
|
|
193
|
+
Use ``hackerrank api operations`` to list names and ``api describe OPERATION``
|
|
194
|
+
to inspect parameters and body schemas.
|
|
195
|
+
|
|
196
|
+
.. code-block:: console
|
|
197
|
+
|
|
198
|
+
hackerrank api call api_list_all_tests --query '{"limit": 10}'
|
|
199
|
+
hackerrank api call api_update_interviewer_note --path '{"interview_id": "123"}' --body-file note.json --dry-run
|
|
200
|
+
|
|
201
|
+
``--path`` and ``--query`` accept JSON objects.
|
|
202
|
+
``--body-file`` reads a JSON object from a UTF-8 file, or stdin when set to
|
|
203
|
+
``-``.
|
|
204
|
+
Real v3 requests use ``HACKERRANK_API_TOKEN``.
|
|
205
|
+
SCIM requests use their own ``HACKERRANK_SCIM_API_TOKEN`` and provisioning
|
|
206
|
+
host.
|
|
207
|
+
Dry runs validate requests before reading credentials and make no API calls.
|
|
208
|
+
Responses include status, headers and complete JSON data, including empty and
|
|
209
|
+
pending responses.
|
|
210
|
+
|
|
211
|
+
The complete API commands require ``hackerrank>=2026.11.7``.
|
|
@@ -157,3 +157,28 @@ Prompts may contain up to 15,000 characters.
|
|
|
157
157
|
Text is sent exactly as read, including whitespace and line endings.
|
|
158
158
|
An empty file explicitly clears the prompt.
|
|
159
159
|
The command reads the question first to preserve its other metadata.
|
|
160
|
+
|
|
161
|
+
Complete API access
|
|
162
|
+
-------------------
|
|
163
|
+
|
|
164
|
+
The ``api`` command group exposes all 76 documented v3, ATS and SCIM
|
|
165
|
+
operations.
|
|
166
|
+
Use ``hackerrank api operations`` to list names and ``api describe OPERATION``
|
|
167
|
+
to inspect parameters and body schemas.
|
|
168
|
+
|
|
169
|
+
.. code-block:: console
|
|
170
|
+
|
|
171
|
+
hackerrank api call api_list_all_tests --query '{"limit": 10}'
|
|
172
|
+
hackerrank api call api_update_interviewer_note --path '{"interview_id": "123"}' --body-file note.json --dry-run
|
|
173
|
+
|
|
174
|
+
``--path`` and ``--query`` accept JSON objects.
|
|
175
|
+
``--body-file`` reads a JSON object from a UTF-8 file, or stdin when set to
|
|
176
|
+
``-``.
|
|
177
|
+
Real v3 requests use ``HACKERRANK_API_TOKEN``.
|
|
178
|
+
SCIM requests use their own ``HACKERRANK_SCIM_API_TOKEN`` and provisioning
|
|
179
|
+
host.
|
|
180
|
+
Dry runs validate requests before reading credentials and make no API calls.
|
|
181
|
+
Responses include status, headers and complete JSON data, including empty and
|
|
182
|
+
pending responses.
|
|
183
|
+
|
|
184
|
+
The complete API commands require ``hackerrank>=2026.11.7``.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2026.11.7
|
|
@@ -6,7 +6,7 @@ This standalone repository follows ``coderpad-cli`` main at
|
|
|
6
6
|
It adapts the src layout, Click entry points, setuptools-scm versions, uv
|
|
7
7
|
lockfile, strict checks, 100% branch coverage, Sphinx, Towncrier, and
|
|
8
8
|
distribution workflows.
|
|
9
|
-
The SDK baseline is the released ``hackerrank==2026.
|
|
9
|
+
The SDK baseline is the released ``hackerrank==2026.11.7`` in ``uv.lock``.
|
|
10
10
|
Python 3.13 or later is required by the SDK.
|
|
11
11
|
|
|
12
12
|
The released SDK exposes ``questions.upload_project_zip``.
|
|
@@ -52,6 +52,19 @@
|
|
|
52
52
|
else
|
|
53
53
|
"0.0.0+${self.shortRev or self.dirtyShortRev or "unknown"}";
|
|
54
54
|
|
|
55
|
+
# The pinned SDK is built from source, so supply its build backend.
|
|
56
|
+
hackerrankSourceOverlay = final: prev: {
|
|
57
|
+
hackerrank = prev.hackerrank.overrideAttrs (old: {
|
|
58
|
+
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ final.resolveBuildSystem {
|
|
59
|
+
setuptools = [ ];
|
|
60
|
+
setuptools-scm = [ ];
|
|
61
|
+
};
|
|
62
|
+
env = (old.env or { }) // {
|
|
63
|
+
SETUPTOOLS_SCM_PRETEND_VERSION = old.version;
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
55
68
|
# Override hackerrank-cli to set the version
|
|
56
69
|
hackerrankCliOverlay = final: prev: {
|
|
57
70
|
hackerrank-cli = prev.hackerrank-cli.overrideAttrs (old: {
|
|
@@ -74,6 +87,7 @@
|
|
|
74
87
|
lib.composeManyExtensions [
|
|
75
88
|
pyproject-build-systems.overlays.wheel
|
|
76
89
|
overlay
|
|
90
|
+
hackerrankSourceOverlay
|
|
77
91
|
hackerrankCliOverlay
|
|
78
92
|
]
|
|
79
93
|
)
|
|
@@ -506,8 +506,6 @@ hooks = [
|
|
|
506
506
|
{
|
|
507
507
|
id = "vale-sync",
|
|
508
508
|
name = "vale sync",
|
|
509
|
-
# The Python Vale wrapper may fail transiently while downloading its binary; see
|
|
510
|
-
# https://github.com/daniperez/vale-python-package/issues/77
|
|
511
509
|
entry = "uv run --locked --group=dev vale sync",
|
|
512
510
|
language = "system",
|
|
513
511
|
pass_filenames = false,
|
|
@@ -21,7 +21,13 @@ classifiers = [
|
|
|
21
21
|
"Programming Language :: Python :: 3.15",
|
|
22
22
|
]
|
|
23
23
|
dynamic = [ "version" ]
|
|
24
|
-
dependencies = [
|
|
24
|
+
dependencies = [
|
|
25
|
+
"click>=8.3,<8.6",
|
|
26
|
+
"hackerrank>=2026.11.7",
|
|
27
|
+
"httpx>=0.28",
|
|
28
|
+
"httpx2>=2.12",
|
|
29
|
+
"pathspec>=1",
|
|
30
|
+
]
|
|
25
31
|
urls.Documentation = "https://adamtheturtle.github.io/hackerrank-cli/"
|
|
26
32
|
urls.Issues = "https://github.com/adamtheturtle/hackerrank-cli/issues"
|
|
27
33
|
urls.Source = "https://github.com/adamtheturtle/hackerrank-cli"
|
|
@@ -38,12 +44,12 @@ dev = [
|
|
|
38
44
|
"doccmd==2026.9.16.1",
|
|
39
45
|
"furo==2025.12.19",
|
|
40
46
|
"interrogate==1.7.0",
|
|
41
|
-
"mypy==2.4.
|
|
47
|
+
"mypy==2.4.1",
|
|
42
48
|
"mypy-pytest-parametrize==2026.10.5.1",
|
|
43
49
|
"mypy-strict-kwargs==2026.10.19",
|
|
44
50
|
"myst-parser==5.1.0",
|
|
45
51
|
"no-defaults==2026.9.1",
|
|
46
|
-
"prek==0.5.
|
|
52
|
+
"prek==0.5.9",
|
|
47
53
|
"pydocstringformatter==1.0.0",
|
|
48
54
|
"pylint[spelling]==4.1.3",
|
|
49
55
|
"pylint-per-file-ignores==4.0.0",
|
|
@@ -51,13 +57,13 @@ dev = [
|
|
|
51
57
|
"pyrefly==1.4.0",
|
|
52
58
|
"pyright==1.1.414",
|
|
53
59
|
"pyroma==5.0.1",
|
|
54
|
-
"pytest==9.
|
|
60
|
+
"pytest==9.2.0",
|
|
55
61
|
"pytest-beartype==0.3.0",
|
|
56
62
|
"pytest-cov==7.1",
|
|
57
63
|
"pytest-regressions==2.11.0",
|
|
58
64
|
"pytest-xdist==3.8.0",
|
|
59
65
|
"respx==0.23.1",
|
|
60
|
-
"ruff==0.17.
|
|
66
|
+
"ruff==0.17.3",
|
|
61
67
|
"setuptools>=77",
|
|
62
68
|
"setuptools-scm>=8.1",
|
|
63
69
|
"shellcheck-py==0.11.0.1",
|
|
@@ -70,11 +76,11 @@ dev = [
|
|
|
70
76
|
"strict-kwargs==2026.10.9",
|
|
71
77
|
"towncrier==26.9",
|
|
72
78
|
"twine==7.0.0",
|
|
73
|
-
"ty==0.0.
|
|
74
|
-
"vale==3.
|
|
79
|
+
"ty==0.0.96",
|
|
80
|
+
"vale==3.26.0.1",
|
|
75
81
|
"vulture==2.16",
|
|
76
82
|
"yamlfix==1.19.1",
|
|
77
|
-
"zizmor==1.
|
|
83
|
+
"zizmor==1.32.0",
|
|
78
84
|
]
|
|
79
85
|
binary = [ "pyinstaller>=6.12" ]
|
|
80
86
|
|
|
@@ -23,22 +23,26 @@ Symlinked
|
|
|
23
23
|
Towncrier
|
|
24
24
|
UTF
|
|
25
25
|
Untagged
|
|
26
|
+
api
|
|
26
27
|
autofix
|
|
27
28
|
backend
|
|
28
29
|
backoff
|
|
29
30
|
basename
|
|
30
31
|
bugfix
|
|
32
|
+
catalogue
|
|
31
33
|
changelog
|
|
32
34
|
cli
|
|
33
35
|
dereference
|
|
34
36
|
dereferenced
|
|
35
37
|
dereferences
|
|
36
38
|
dereferencing
|
|
39
|
+
discoverable
|
|
37
40
|
docstrings
|
|
38
41
|
filesystem
|
|
39
42
|
frontend
|
|
40
43
|
fullstack
|
|
41
44
|
hackerrank
|
|
45
|
+
injectable
|
|
42
46
|
jsonschema
|
|
43
47
|
jsonschema's
|
|
44
48
|
keychain
|
|
@@ -50,9 +54,11 @@ nonretryable
|
|
|
50
54
|
prebuilt
|
|
51
55
|
prek
|
|
52
56
|
retryable
|
|
57
|
+
schemas
|
|
53
58
|
scm
|
|
54
59
|
setuptools
|
|
55
60
|
src
|
|
61
|
+
stdin
|
|
56
62
|
symlink
|
|
57
63
|
symlinks
|
|
58
64
|
uploader
|
|
@@ -15,6 +15,7 @@ from hackerrank.client import HackerRank
|
|
|
15
15
|
from hackerrank.exceptions import HackerRankError
|
|
16
16
|
from hackerrank.transports import Transport
|
|
17
17
|
|
|
18
|
+
from hackerrank_cli._api import create_api_cli
|
|
18
19
|
from hackerrank_cli._sources import PreparedSource, prepare_source
|
|
19
20
|
|
|
20
21
|
|
|
@@ -27,9 +28,7 @@ def create_cli(*, transport: Transport | None = None) -> click.Group:
|
|
|
27
28
|
prog_name="hackerrank",
|
|
28
29
|
)
|
|
29
30
|
def cli() -> None:
|
|
30
|
-
"""
|
|
31
|
-
questions.
|
|
32
|
-
"""
|
|
31
|
+
"""Manage HackerRank uploads, prompts and the complete API."""
|
|
33
32
|
|
|
34
33
|
@cli.group()
|
|
35
34
|
def questions() -> None:
|
|
@@ -162,6 +161,7 @@ def create_cli(*, transport: Transport | None = None) -> click.Group:
|
|
|
162
161
|
_ = questions.command()(set_system_prompt)
|
|
163
162
|
_ = questions.command()(archive)
|
|
164
163
|
_ = questions.command()(upload)
|
|
164
|
+
cli.add_command(cmd=create_api_cli(transport=transport))
|
|
165
165
|
return cli
|
|
166
166
|
|
|
167
167
|
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""Expose every documented API operation through the SDK catalogue."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from dataclasses import asdict, dataclass
|
|
6
|
+
from typing import TextIO
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
import httpx
|
|
10
|
+
import httpx2
|
|
11
|
+
from hackerrank.api import (
|
|
12
|
+
api_catalogue,
|
|
13
|
+
api_operations,
|
|
14
|
+
parse_api_object,
|
|
15
|
+
prepare_operation,
|
|
16
|
+
)
|
|
17
|
+
from hackerrank.client import HackerRank
|
|
18
|
+
from hackerrank.exceptions import HackerRankError
|
|
19
|
+
from hackerrank.transports import Transport
|
|
20
|
+
from hackerrank.types import JSONValue
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass(frozen=True, kw_only=True)
|
|
24
|
+
class APICommandRequest:
|
|
25
|
+
"""The request inputs supplied to the API command."""
|
|
26
|
+
|
|
27
|
+
operation: str
|
|
28
|
+
path_json: str
|
|
29
|
+
query_json: str
|
|
30
|
+
body_file: TextIO | None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def create_api_cli(*, transport: Transport | None) -> click.Group:
|
|
34
|
+
"""Create catalogue, schema and execution commands with an injectable
|
|
35
|
+
transport.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
@click.group(name="api")
|
|
39
|
+
def api() -> None:
|
|
40
|
+
"""Call every documented v3, ATS and SCIM operation."""
|
|
41
|
+
|
|
42
|
+
def operations() -> None:
|
|
43
|
+
"""List operation names, methods, paths and summaries without
|
|
44
|
+
credentials.
|
|
45
|
+
"""
|
|
46
|
+
rows = [
|
|
47
|
+
{
|
|
48
|
+
"operation": value.id,
|
|
49
|
+
"method": value.method,
|
|
50
|
+
"path": value.path,
|
|
51
|
+
"summary": value.summary,
|
|
52
|
+
"group": value.group,
|
|
53
|
+
}
|
|
54
|
+
for value in api_operations().values()
|
|
55
|
+
]
|
|
56
|
+
click.echo(message=json.dumps(obj=rows, indent=2))
|
|
57
|
+
|
|
58
|
+
@click.argument("operation")
|
|
59
|
+
def describe(operation: str) -> None:
|
|
60
|
+
"""Show an operation's parameters, body schema and referenced
|
|
61
|
+
definitions.
|
|
62
|
+
"""
|
|
63
|
+
selected = api_operations().get(operation)
|
|
64
|
+
if selected is None:
|
|
65
|
+
raise click.BadParameter(
|
|
66
|
+
message="Unknown API operation.", param_hint="OPERATION"
|
|
67
|
+
)
|
|
68
|
+
click.echo(
|
|
69
|
+
message=json.dumps(
|
|
70
|
+
obj={
|
|
71
|
+
"operation": asdict(obj=selected),
|
|
72
|
+
"definitions": api_catalogue()["definitions"],
|
|
73
|
+
},
|
|
74
|
+
indent=2,
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
@click.argument("operation")
|
|
79
|
+
@click.option(
|
|
80
|
+
"--path",
|
|
81
|
+
"path_json",
|
|
82
|
+
default="{}",
|
|
83
|
+
help="JSON object of path parameters.",
|
|
84
|
+
)
|
|
85
|
+
@click.option(
|
|
86
|
+
"--query",
|
|
87
|
+
"query_json",
|
|
88
|
+
default="{}",
|
|
89
|
+
help="JSON object of query fields; arrays use CSV encoding.",
|
|
90
|
+
)
|
|
91
|
+
@click.option(
|
|
92
|
+
"--body-file",
|
|
93
|
+
type=click.File(mode="r", encoding="utf-8"),
|
|
94
|
+
help="JSON request body file, or - for stdin.",
|
|
95
|
+
)
|
|
96
|
+
@click.option(
|
|
97
|
+
"--dry-run",
|
|
98
|
+
is_flag=True,
|
|
99
|
+
help="Validate without credentials or network access.",
|
|
100
|
+
)
|
|
101
|
+
def call(
|
|
102
|
+
operation: str,
|
|
103
|
+
path_json: str,
|
|
104
|
+
query_json: str,
|
|
105
|
+
body_file: TextIO | None,
|
|
106
|
+
*,
|
|
107
|
+
dry_run: bool,
|
|
108
|
+
) -> None:
|
|
109
|
+
"""Execute OPERATION and print status, headers and complete JSON
|
|
110
|
+
data.
|
|
111
|
+
"""
|
|
112
|
+
_call_api(
|
|
113
|
+
request=APICommandRequest(
|
|
114
|
+
operation=operation,
|
|
115
|
+
path_json=path_json,
|
|
116
|
+
query_json=query_json,
|
|
117
|
+
body_file=body_file,
|
|
118
|
+
),
|
|
119
|
+
dry_run=dry_run,
|
|
120
|
+
transport=transport,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
_ = api.command(name="operations")(operations)
|
|
124
|
+
_ = api.command(name="describe")(describe)
|
|
125
|
+
_ = api.command(name="call")(call)
|
|
126
|
+
return api
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _path_parameters(*, values: dict[str, JSONValue]) -> dict[str, str | int]:
|
|
130
|
+
"""Reject structured values before the SDK encodes path segments."""
|
|
131
|
+
result: dict[str, str | int] = {}
|
|
132
|
+
for name, value in values.items():
|
|
133
|
+
if isinstance(value, bool) or not isinstance(value, str | int):
|
|
134
|
+
message = "Path parameters must be strings or integers."
|
|
135
|
+
raise TypeError(message)
|
|
136
|
+
result[name] = value
|
|
137
|
+
return result
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _call_api(
|
|
141
|
+
*,
|
|
142
|
+
request: APICommandRequest,
|
|
143
|
+
dry_run: bool,
|
|
144
|
+
transport: Transport | None,
|
|
145
|
+
) -> None:
|
|
146
|
+
"""Prepare a request before credential access, then execute it through
|
|
147
|
+
the SDK.
|
|
148
|
+
"""
|
|
149
|
+
operation = request.operation
|
|
150
|
+
path_json = request.path_json
|
|
151
|
+
query_json = request.query_json
|
|
152
|
+
body_file = request.body_file
|
|
153
|
+
try:
|
|
154
|
+
path_values = parse_api_object(text=path_json)
|
|
155
|
+
path_parameters = _path_parameters(values=path_values)
|
|
156
|
+
query = parse_api_object(text=query_json)
|
|
157
|
+
body = (
|
|
158
|
+
None
|
|
159
|
+
if body_file is None
|
|
160
|
+
else parse_api_object(text=body_file.read())
|
|
161
|
+
)
|
|
162
|
+
selected, path, _ = prepare_operation(
|
|
163
|
+
operation=operation,
|
|
164
|
+
path_parameters=path_parameters,
|
|
165
|
+
query=query,
|
|
166
|
+
body=body,
|
|
167
|
+
)
|
|
168
|
+
except (ValueError, TypeError, OSError) as error:
|
|
169
|
+
raise click.BadParameter(
|
|
170
|
+
message=f"Invalid API input: {error}"
|
|
171
|
+
) from None
|
|
172
|
+
if dry_run:
|
|
173
|
+
click.echo(message=f"Would call {selected.method} {path}")
|
|
174
|
+
return
|
|
175
|
+
variable = (
|
|
176
|
+
"HACKERRANK_SCIM_API_TOKEN"
|
|
177
|
+
if selected.scim
|
|
178
|
+
else "HACKERRANK_API_TOKEN"
|
|
179
|
+
)
|
|
180
|
+
credential = os.environ.get(key=variable, default="")
|
|
181
|
+
if not bool(credential.strip()):
|
|
182
|
+
raise click.ClickException(
|
|
183
|
+
message=f"Set {variable} to a nonblank API token."
|
|
184
|
+
)
|
|
185
|
+
try:
|
|
186
|
+
with HackerRank(
|
|
187
|
+
api_key="scim-only" if selected.scim else credential,
|
|
188
|
+
transport=transport,
|
|
189
|
+
) as client:
|
|
190
|
+
response = client.api.call(
|
|
191
|
+
operation=operation,
|
|
192
|
+
path_parameters=path_parameters,
|
|
193
|
+
query=query,
|
|
194
|
+
body=body,
|
|
195
|
+
scim_api_key=credential if selected.scim else None,
|
|
196
|
+
)
|
|
197
|
+
except HackerRankError as error:
|
|
198
|
+
raise click.ClickException(
|
|
199
|
+
message=f"HackerRank request failed (HTTP {error.status_code})."
|
|
200
|
+
) from None
|
|
201
|
+
except (httpx.TransportError, httpx2.TransportError):
|
|
202
|
+
raise click.ClickException(
|
|
203
|
+
message="Could not reach HackerRank."
|
|
204
|
+
) from None
|
|
205
|
+
click.echo(message=json.dumps(obj=asdict(obj=response), indent=2))
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '2026.
|
|
22
|
-
__version_tuple__ = version_tuple = (2026,
|
|
21
|
+
__version__ = version = '2026.11.7'
|
|
22
|
+
__version_tuple__ = version_tuple = (2026, 11, 7)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'gaed479392'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hackerrank-cli
|
|
3
|
-
Version: 2026.
|
|
3
|
+
Version: 2026.11.7
|
|
4
4
|
Summary: Upload starter files to existing HackerRank project questions.
|
|
5
5
|
Author-email: Adam Dangoor <adamdangoor@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -19,7 +19,7 @@ Requires-Python: >=3.13
|
|
|
19
19
|
Description-Content-Type: text/x-rst
|
|
20
20
|
License-File: LICENSE
|
|
21
21
|
Requires-Dist: click<8.6,>=8.3
|
|
22
|
-
Requires-Dist: hackerrank>=2026.
|
|
22
|
+
Requires-Dist: hackerrank>=2026.11.7
|
|
23
23
|
Requires-Dist: httpx>=0.28
|
|
24
24
|
Requires-Dist: httpx2>=2.12
|
|
25
25
|
Requires-Dist: pathspec>=1
|
|
@@ -184,3 +184,28 @@ Prompts may contain up to 15,000 characters.
|
|
|
184
184
|
Text is sent exactly as read, including whitespace and line endings.
|
|
185
185
|
An empty file explicitly clears the prompt.
|
|
186
186
|
The command reads the question first to preserve its other metadata.
|
|
187
|
+
|
|
188
|
+
Complete API access
|
|
189
|
+
-------------------
|
|
190
|
+
|
|
191
|
+
The ``api`` command group exposes all 76 documented v3, ATS and SCIM
|
|
192
|
+
operations.
|
|
193
|
+
Use ``hackerrank api operations`` to list names and ``api describe OPERATION``
|
|
194
|
+
to inspect parameters and body schemas.
|
|
195
|
+
|
|
196
|
+
.. code-block:: console
|
|
197
|
+
|
|
198
|
+
hackerrank api call api_list_all_tests --query '{"limit": 10}'
|
|
199
|
+
hackerrank api call api_update_interviewer_note --path '{"interview_id": "123"}' --body-file note.json --dry-run
|
|
200
|
+
|
|
201
|
+
``--path`` and ``--query`` accept JSON objects.
|
|
202
|
+
``--body-file`` reads a JSON object from a UTF-8 file, or stdin when set to
|
|
203
|
+
``-``.
|
|
204
|
+
Real v3 requests use ``HACKERRANK_API_TOKEN``.
|
|
205
|
+
SCIM requests use their own ``HACKERRANK_SCIM_API_TOKEN`` and provisioning
|
|
206
|
+
host.
|
|
207
|
+
Dry runs validate requests before reading credentials and make no API calls.
|
|
208
|
+
Responses include status, headers and complete JSON data, including empty and
|
|
209
|
+
pending responses.
|
|
210
|
+
|
|
211
|
+
The complete API commands require ``hackerrank>=2026.11.7``.
|
{hackerrank_cli-2026.10.30 → hackerrank_cli-2026.11.7}/src/hackerrank_cli.egg-info/SOURCES.txt
RENAMED
|
@@ -40,9 +40,11 @@ docs/source/changelog/2026.10.1.1.md
|
|
|
40
40
|
docs/source/changelog/2026.10.30.md
|
|
41
41
|
docs/source/changelog/2026.10.7.md
|
|
42
42
|
docs/source/changelog/2026.10.8.md
|
|
43
|
+
docs/source/changelog/2026.11.7.md
|
|
43
44
|
newsfragments/.gitkeep
|
|
44
45
|
src/hackerrank_cli/__init__.py
|
|
45
46
|
src/hackerrank_cli/__main__.py
|
|
47
|
+
src/hackerrank_cli/_api.py
|
|
46
48
|
src/hackerrank_cli/_sources.py
|
|
47
49
|
src/hackerrank_cli/_version.py
|
|
48
50
|
src/hackerrank_cli/py.typed
|
|
@@ -58,6 +60,7 @@ src/hackerrank_cli.egg-info/top_level.txt
|
|
|
58
60
|
styles/snapper/LongProseLine.yml
|
|
59
61
|
styles/snapper/SemanticLineBreaks.yml
|
|
60
62
|
tests/__init__.py
|
|
63
|
+
tests/test_api.py
|
|
61
64
|
tests/test_archive.py
|
|
62
65
|
tests/test_cli.py
|
|
63
66
|
tests/test_help.py
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"docs/source/changelog/2026.10.30.md",
|
|
29
29
|
"docs/source/changelog/2026.10.7.md",
|
|
30
30
|
"docs/source/changelog/2026.10.8.md",
|
|
31
|
+
"docs/source/changelog/2026.11.7.md",
|
|
31
32
|
"docs/source/cli.rst",
|
|
32
33
|
"docs/source/conf.py",
|
|
33
34
|
"docs/source/development.rst",
|
|
@@ -43,11 +44,13 @@
|
|
|
43
44
|
"spelling_private_dict.txt",
|
|
44
45
|
"src/hackerrank_cli/__init__.py",
|
|
45
46
|
"src/hackerrank_cli/__main__.py",
|
|
47
|
+
"src/hackerrank_cli/_api.py",
|
|
46
48
|
"src/hackerrank_cli/_sources.py",
|
|
47
49
|
"src/hackerrank_cli/py.typed",
|
|
48
50
|
"styles/snapper/LongProseLine.yml",
|
|
49
51
|
"styles/snapper/SemanticLineBreaks.yml",
|
|
50
52
|
"tests/__init__.py",
|
|
53
|
+
"tests/test_api.py",
|
|
51
54
|
"tests/test_archive.py",
|
|
52
55
|
"tests/test_cli.py",
|
|
53
56
|
"tests/test_help.py",
|