Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b41a196e1a
|
||
|
|
2b7edc25a5 | ||
|
|
f98d8124f4
|
||
|
|
677f800015 | ||
|
|
56b17b5768
|
||
|
|
ad4a492c31 | ||
|
|
912840a22d
|
||
|
|
db4715c906
|
||
|
|
3fcff49d4f |
No files matched your search
+11
-57
@@ -1,60 +1,14 @@
|
||||
version: 2.1
|
||||
|
||||
setup: true
|
||||
orbs:
|
||||
qqq-orb: kingsrook/qqq-orb@0.6.9
|
||||
|
||||
commands:
|
||||
configure-package-install:
|
||||
steps:
|
||||
- run:
|
||||
name: Keep package installation unattended
|
||||
command: |
|
||||
# These build machines are discarded after the job.
|
||||
sudo install -d /etc/needrestart/conf.d
|
||||
printf '%s\n' '$nrconf{restart} = "l";' | sudo tee /etc/needrestart/conf.d/99-qqq-ci.conf >/dev/null
|
||||
|
||||
qqq-orb: kingsrook/qqq-orb@0.7.11
|
||||
workflows:
|
||||
test_only:
|
||||
jobs:
|
||||
- qqq-orb/mvn_test_only:
|
||||
pre-steps:
|
||||
- configure-package-install
|
||||
context: [qqq-maven-registry-credentials]
|
||||
filters:
|
||||
branches:
|
||||
ignore: /(develop|release\/.*)/
|
||||
|
||||
publish_snapshot:
|
||||
jobs:
|
||||
- qqq-orb/mvn_publish:
|
||||
pre-steps:
|
||||
- configure-package-install
|
||||
context: [qqq-maven-registry-credentials]
|
||||
branch_type: snapshot
|
||||
filters:
|
||||
branches:
|
||||
only: [develop]
|
||||
|
||||
publish_release_candidate:
|
||||
jobs:
|
||||
- qqq-orb/mvn_publish:
|
||||
pre-steps:
|
||||
- configure-package-install
|
||||
context: [qqq-maven-registry-credentials]
|
||||
branch_type: release_candidate
|
||||
filters:
|
||||
branches:
|
||||
only: [/release\/.*/]
|
||||
|
||||
publish_release:
|
||||
jobs:
|
||||
- qqq-orb/mvn_publish:
|
||||
pre-steps:
|
||||
- configure-package-install
|
||||
context: [qqq-maven-registry-credentials]
|
||||
branch_type: release
|
||||
filters:
|
||||
branches:
|
||||
ignore: /.*/
|
||||
tags:
|
||||
only: [/^v\d+\.\d+\.\d+$/]
|
||||
setup:
|
||||
jobs:
|
||||
- qqq-orb/generate_pipeline:
|
||||
orb_version: 0.7.11
|
||||
filters:
|
||||
branches:
|
||||
ignore: automation/qbit-rc-pending
|
||||
tags:
|
||||
only: /^v\d+\.\d+\.\d+$/
|
||||
@@ -21,5 +21,6 @@ jobs:
|
||||
release-rc:
|
||||
if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'release:rc'))
|
||||
uses: QRun-IO/.github/.github/workflows/qbit-release-rc.yml@main
|
||||
secrets: inherit
|
||||
with:
|
||||
dry_run: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run }}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
profile: qbit
|
||||
orb_version: 0.7.11
|
||||
default_branch: develop
|
||||
java_version: '21'
|
||||
browsers: true
|
||||
api_checks: false
|
||||
docs_only: false
|
||||
release_on_main: false
|
||||
release_tag_policy: stable
|
||||
test_branch_policy: non-release
|
||||
publish:
|
||||
snapshot: true
|
||||
release_candidate: true
|
||||
release: true
|
||||
asciidoc: false
|
||||
release_completion: false
|
||||
@@ -16,6 +16,7 @@ All notable changes to this project are documented here. The format follows Keep
|
||||
- **Record developer panel** "SQL Workbench" (`SqlWorkbenchDeveloperPanelProvider`, registered by `SqlWorkbenchDeveloperPanelsMetaDataProducer`): read-only `SELECT`s for the record and its table in the backend's own names, backend details, and links that open them in the Runner as a new cell (`/app/sqlWorkbenchRunner?sql=&backend=`, never run). Requires QQQ 4.1.0-RC.4 (the developer panel contract) and a Next UI with the Runner `?sql=` support.
|
||||
|
||||
### Changed
|
||||
- UI API extension sql-workbench 1.1.0 (requires QQQ 4.1.0-RC.15, UI API 1.6.0): operationIds, standard error responses with BasicErrorResponseV1, extension tags, and deprecated SqlWorkbenchErrorV1 retained for compatibility. Existing operationIds, HTTP statuses and success payloads are preserved.
|
||||
- Require QQQ `4.1.0-RC.6` for the UI API extension contract. Replace the raw Javalin route provider with endpoint specs registered by the qbit producer. `registerRoutes=false` still disables HTTP registration. No existing operation wire changes.
|
||||
- **The nav lists only the main tables**: Notebooks and the execution audit, after the Runner. Cells, versions, pinned results and shares are child lists on a notebook (still standard tables, reachable by URL and API). The app's widget list is now the dashboard, not the `SQL_WORKBENCH` widget; links to `/app/sqlWorkbench` that expected the editor should point at `/app/sqlWorkbenchRunner`.
|
||||
- The notebook record's header shows the description.
|
||||
|
||||
@@ -254,9 +254,9 @@
|
||||
|
||||
<profiles>
|
||||
<!-- Built against qqq 4.1 (QBitMetaDataProducer, runtime services, Javalin 7 -->
|
||||
<!-- specs and help bundles require 4.1.0-RC.7). Until -->
|
||||
<!-- specs and help bundles require 4.1.0-RC.15). Until -->
|
||||
<!-- qbit-build-parent 2.1.0 imports the released 4.1 BOM, this profile is -->
|
||||
<!-- active by default and imports qqq-bom-pom 4.1.0-RC.7 ahead of the -->
|
||||
<!-- active by default and imports qqq-bom-pom 4.1.0-RC.15 ahead of the -->
|
||||
<!-- parent's 4.0.0 BOM (same as qbit-quick-search, ADR-0007). -->
|
||||
<profile>
|
||||
<id>qqq-snapshot</id>
|
||||
@@ -264,7 +264,7 @@
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<properties>
|
||||
<qqq.snapshot.version>4.1.0-RC.7</qqq.snapshot.version>
|
||||
<qqq.snapshot.version>4.1.0-RC.15</qqq.snapshot.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
@@ -43,7 +43,7 @@ public class SqlWorkbenchEndpoints
|
||||
public static MiddlewareSpecExtension extension()
|
||||
{
|
||||
return (new MiddlewareSpecExtension().withName("sql-workbench").withPathPrefix("/sql-workbench")
|
||||
.withSemanticVersion("1.0.0").withDescription("Audited SQL execution and notebooks")
|
||||
.withSemanticVersion("1.1.0").withDescription("Audited SQL execution and notebooks")
|
||||
.withSpec(GetCapabilitiesSpec.class)
|
||||
.withSpec(GetSchemaSpec.class)
|
||||
.withSpec(ExecuteSpec.class)
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.kingsrook.qqq.middleware.javalin.QJavalinUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicOperation;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicResponse;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.extensions.AbstractJsonEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.BasicErrorResponseV1;
|
||||
import com.kingsrook.qqq.openapi.model.HttpMethod;
|
||||
import com.kingsrook.qqq.openapi.model.In;
|
||||
import com.kingsrook.qqq.openapi.model.Method;
|
||||
@@ -155,11 +156,11 @@ public abstract class SqlWorkbenchJsonSpec extends AbstractJsonEndpointSpec
|
||||
*******************************************************************************/
|
||||
static List<BasicResponse> errors()
|
||||
{
|
||||
return (List.of(new BasicResponse(HttpStatus.BAD_REQUEST, "Invalid input or execution limit exceeded", "SqlWorkbenchErrorV1"),
|
||||
new BasicResponse(HttpStatus.UNAUTHORIZED, "Sign in required", "SqlWorkbenchErrorV1"),
|
||||
new BasicResponse(HttpStatus.FORBIDDEN, "Permission denied", "SqlWorkbenchErrorV1"),
|
||||
new BasicResponse(HttpStatus.NOT_FOUND, "Missing or invisible resource", "SqlWorkbenchErrorV1"),
|
||||
new BasicResponse(HttpStatus.CONFLICT, "Execution UUID already used", "SqlWorkbenchErrorV1")));
|
||||
return (List.of(new BasicResponse(HttpStatus.BAD_REQUEST, "Invalid input or execution limit exceeded", BasicErrorResponseV1.class.getSimpleName()),
|
||||
new BasicResponse(HttpStatus.UNAUTHORIZED, "Sign in required", BasicErrorResponseV1.class.getSimpleName()),
|
||||
new BasicResponse(HttpStatus.FORBIDDEN, "Permission denied", BasicErrorResponseV1.class.getSimpleName()),
|
||||
new BasicResponse(HttpStatus.NOT_FOUND, "Missing or invisible resource", BasicErrorResponseV1.class.getSimpleName()),
|
||||
new BasicResponse(HttpStatus.CONFLICT, "Execution UUID already used", BasicErrorResponseV1.class.getSimpleName())));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ public class SqlWorkbenchSchemas
|
||||
{
|
||||
Map<String, Schema> schemas = new LinkedHashMap<>();
|
||||
schemas.put("SqlWorkbenchErrorV1", new Schema().withType(Type.OBJECT)
|
||||
.withDescription("Deprecated since 1.1.0: errors use BasicErrorResponseV1.")
|
||||
.withProperty("error", new Schema().withType(Type.STRING)));
|
||||
schemas.put("SqlWorkbenchEmptyRequestV1", new Schema().withType(Type.OBJECT));
|
||||
schemas.put("SqlWorkbenchDeletedV1", new Schema().withType(Type.OBJECT)
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -22,6 +22,7 @@ import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.MiddlewareVersionV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.BasicErrorResponseV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.tools.UiApiContract;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -50,7 +51,7 @@ class SqlWorkbenchApiContractTest
|
||||
assertThat(UiApiContract.check(generated, Files.readString(path), null, 1,
|
||||
"./mvnw -Dtest=SqlWorkbenchApiContractTest -DsqlWorkbench.openapi.update=true test")).isEmpty();
|
||||
var model = version.generateExtensionOpenAPIModel("qqq", extension);
|
||||
assertThat(model.getComponents().getSchemas().keySet()).allMatch(name -> name.startsWith("SqlWorkbench"));
|
||||
assertThat(model.getComponents().getSchemas().keySet()).allMatch(name -> name.startsWith("SqlWorkbench") || name.equals(BasicErrorResponseV1.class.getSimpleName()));
|
||||
assertThat(model.getPaths().keySet()).allMatch(name -> name.startsWith("/qqq/v1/sql-workbench/"));
|
||||
assertThat(extension.getSpecs()).hasSize(21);
|
||||
assertThat(extension.getEffectivePathPrefix()).isEqualTo("/sql-workbench");
|
||||
|
||||
+26
-2
@@ -98,7 +98,29 @@ class SqlWorkbenchEndpointSpecTest extends BaseSqlWorkbenchTest
|
||||
builder.header("Content-Type", contentType);
|
||||
}
|
||||
builder.method(method, body == null ? HttpRequest.BodyPublishers.noBody() : HttpRequest.BodyPublishers.ofString(body));
|
||||
return (client.send(builder.build(), HttpResponse.BodyHandlers.ofString()));
|
||||
HttpResponse<String> response = client.send(builder.build(), HttpResponse.BodyHandlers.ofString());
|
||||
if(response.statusCode() >= 400)
|
||||
{
|
||||
assertErrorBody(response);
|
||||
}
|
||||
return (response);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** HTTP errors retain their message and include the standard diagnostic fields.
|
||||
*******************************************************************************/
|
||||
private static void assertErrorBody(HttpResponse<String> response) throws Exception
|
||||
{
|
||||
Map<String, Object> body = json(response);
|
||||
assertThat(body).containsKeys("error", "code", "message", "traceId");
|
||||
for(String key : List.of("error", "code", "message", "traceId"))
|
||||
{
|
||||
assertThat(body.get(key)).as(key).isInstanceOf(String.class);
|
||||
assertThat((String) body.get(key)).as(key).isNotBlank();
|
||||
}
|
||||
assertThat(body.get("message")).isEqualTo(body.get("error"));
|
||||
}
|
||||
|
||||
|
||||
@@ -236,7 +258,9 @@ class SqlWorkbenchEndpointSpecTest extends BaseSqlWorkbenchTest
|
||||
HttpRequest unauthenticated = HttpRequest.newBuilder(URI.create(base + path))
|
||||
.header("Authorization", "Bearer Deny")
|
||||
.method(method, HttpRequest.BodyPublishers.noBody()).build();
|
||||
assertThat(client.send(unauthenticated, HttpResponse.BodyHandlers.ofString()).statusCode()).as(method + " authentication").isEqualTo(401);
|
||||
HttpResponse<String> denied = client.send(unauthenticated, HttpResponse.BodyHandlers.ofString());
|
||||
assertThat(denied.statusCode()).as(method + " authentication").isEqualTo(401);
|
||||
assertErrorBody(denied);
|
||||
}
|
||||
assertThat(json(send("GET", "/history", READER, null, null)).get("executions")).asList().isEmpty();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user