Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/assets/project-lockup.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions .github/assets/project-mark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/readme-header.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/social-preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Set up Node 22
uses: actions/setup-node@v4
with:
node-version: '22'

- name: Verify O11 brand sources
run: node scripts/check-brand-assets.mjs

- name: Set up JDK 21
uses: actions/setup-java@v4
with:
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Set up Node 22
uses: actions/setup-node@v4
with:
node-version: '22'

- name: Verify O11 brand sources
run: node scripts/check-brand-assets.mjs

- name: Set up JDK 21
uses: actions/setup-java@v4
with:
Expand Down
4 changes: 3 additions & 1 deletion README.ko.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[![DataLinq](.github/assets/readme-header.png)](https://devslab.kr/brand/open-source/)

# DataLinq

[English](README.md) | **한국어**
Expand All @@ -11,7 +13,7 @@ MariaDB/MySQL, PostgreSQL 드라이버는 **번들**되어 있고, 그 외(Oracl
명령 한 줄로 내려받습니다. 연결은 **DB 종류 + host/port/database**(또는 raw URL)로 설정하며,
`application.yml` 에 적거나 DB 연결 화면에서 바로 편집·저장할 수 있습니다.

> **DevsLab Co., Ltd.** (주식회사 데브스랩) 제작 · https://devslab.kr · Apache-2.0
> [DevsLab 오픈소스](https://devslab.kr/brand/open-source/) · **DevsLab Co., Ltd.** (주식회사 데브스랩) 제작 · https://devslab.kr · Apache-2.0

## 빠른 시작

Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[![DataLinq](.github/assets/readme-header.png)](https://devslab.kr/brand/open-source/)

# DataLinq

**English** | [한국어](README.ko.md)
Expand All @@ -11,7 +13,7 @@ MariaDB/MySQL and PostgreSQL drivers are **bundled**; others (Oracle, H2, SQLite
one-line `driver` download away. Connections are configured by **DB type + host/port/database**
(or a raw URL), in `application.yml` or live from the DB Connection screen.

> By **DevsLab Co., Ltd.** (주식회사 데브스랩) · https://devslab.kr · Apache-2.0
> [Open source by DevsLab](https://devslab.kr/brand/open-source/) · By **DevsLab Co., Ltd.** (주식회사 데브스랩) · https://devslab.kr · Apache-2.0

## Quick start

Expand Down
55 changes: 55 additions & 0 deletions scripts/check-brand-assets.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import assert from 'node:assert/strict';
import { createHash } from 'node:crypto';
import { readFile } from 'node:fs/promises';
import { resolve } from 'node:path';

const root = resolve(import.meta.dirname, '..');
const guide = 'https://devslab.kr/brand/open-source/';
const terminalLogo = 'DataLinq\n========\n[ source ] ===> [ target ]\nOpen source by DevsLab\n';
const assets = new Map([
['.github/assets/project-mark.svg', '6a5ddb30c2f0c6251d60a96f78b88f026e946aa7c5cda31284b29194f8482309'],
['.github/assets/project-lockup.svg', '123d4746b874a955b6f4c4a9f1373a2b312b01016028703ff3257fcc0e0e2c6d'],
['.github/assets/readme-header.png', 'cc5b10846a31c4c458ccd784fe158c83616368df0ffb645015561b059343267d'],
['.github/assets/social-preview.png', '9b83784be89547d512a174853e7e8bbd56ea43975b076530ce930839b7067c3a'],
['src/main/resources/branding/logo.txt', 'aa4aa8c9bcc2b07257f96854a481496b8229d28bc27057eedbadbce4fa1cc6d7'],
]);

const file = (relative) => resolve(root, relative);
const text = (relative) => readFile(file(relative), 'utf8');
const hash = async (relative) => createHash('sha256').update(await readFile(file(relative))).digest('hex');

for (const [relative, expected] of assets) {
assert.equal(await hash(relative), expected, `${relative} must match the oss-brand v0.1.1 O11 asset`);
}

const mark = await text('.github/assets/project-mark.svg');
assert.match(mark, /data-oss-project="O11"/, 'project mark must identify O11');
assert.match(mark, /M5 6H11V12H5Z/, 'project mark must retain O11 source column geometry');
assert.match(mark, /M17 12L21 16L17 20/, 'project mark must retain O11 transfer path geometry');

assert.equal(await text('src/main/resources/branding/logo.txt'), terminalLogo, 'bundled terminal logo must be the stable UTF-8 no-color O11 asset');
assert.ok(!terminalLogo.includes('\u001b'), 'bundled terminal logo must contain no ANSI escape character');
assert.deepEqual(terminalLogo.trimEnd().split('\n').map((line) => line.length), [8, 8, 26, 22], 'terminal logo line widths must remain stable');

for (const [relative, endorsement] of [
['README.md', 'Open source by DevsLab'],
['README.ko.md', 'DevsLab 오픈소스'],
]) {
const readme = await text(relative);
assert.match(readme, /\.github\/assets\/readme-header\.png/, `${relative} must use the vendored O11 README header`);
assert.ok(readme.includes(guide), `${relative} must link to the canonical OSS brand guide`);
assert.ok(readme.includes(endorsement), `${relative} must include its localized DevsLab endorsement`);
}

const brandCommand = 'run: node scripts/check-brand-assets.mjs';
for (const [relative, gradleCommand] of [
['.github/workflows/ci.yml', 'run: ./gradlew build'],
['.github/workflows/release.yml', 'run: ./gradlew shadowJar'],
]) {
const workflow = await text(relative);
const brandIndex = workflow.indexOf(brandCommand);
assert.ok(workflow.includes('actions/setup-node@v4') && workflow.includes("node-version: '22'"), `${relative} must provide Node 22 for the brand checker`);
assert.ok(brandIndex >= 0 && brandIndex < workflow.indexOf(gradleCommand), `${relative} must verify O11 brand sources before Gradle`);
}

console.log(`O11 brand contract passed (${assets.size} exact v0.1.1 assets, terminal, README, CI, and release).`);
10 changes: 4 additions & 6 deletions src/main/resources/branding/logo.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
____ __ __ _
/ __ \____ _/ /_____ _/ / (_)___ ____ _
/ / / / __ `/ __/ __ `/ / / / __ \/ __ `/
/ /_/ / /_/ / /_/ /_/ / /___/ / / / / /_/ /
/_____/\__,_/\__/\__,_/_____/_/_/ /_/\__, /
/_/
DataLinq
========
[ source ] ===> [ target ]
Open source by DevsLab
37 changes: 37 additions & 0 deletions src/test/java/kr/devslab/datalinq/ui/LogoTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2026 DevsLab Co., Ltd.
* SPDX-License-Identifier: Apache-2.0
*/
package kr.devslab.datalinq.ui;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

class LogoTest {

@Test
void bundledNoColorLogoUsesStableAsciiUtf8Output(@TempDir Path tempDir) throws Exception {
List<String> lines = Logo.load(tempDir.resolve("missing-logo.txt"));

assertEquals(List.of(
"DataLinq",
"========",
"[ source ] ===> [ target ]",
"Open source by DevsLab"), lines);
assertEquals(List.of(8, 8, 26, 22), lines.stream().map(String::length).toList());
assertEquals(26, lines.stream().mapToInt(String::length).max().orElseThrow());
assertTrue(lines.stream().flatMapToInt(String::chars).allMatch(codePoint -> codePoint <= 0x7f));
assertFalse(lines.stream().anyMatch(line -> line.indexOf('\u001b') >= 0));

String bundled = new String(Logo.class.getResourceAsStream("/branding/logo.txt").readAllBytes(), StandardCharsets.UTF_8);
assertEquals(String.join("\n", lines) + "\n", bundled);
}
}
Loading