diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cf786c1..2bef69d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,21 +39,13 @@ jobs: run: | set -euo pipefail - latest_tag="$(git tag --list 'v*' --sort=-v:refname | head -n 1 || true)" - if [[ -z "$latest_tag" ]]; then - version="1.0.0" - else - current_version="${latest_tag#v}" - IFS='.' read -r major minor patch <<< "$current_version" - - if [[ -z "${major:-}" || -z "${minor:-}" || -z "${patch:-}" ]]; then - echo "Latest tag '$latest_tag' is not in vX.Y.Z format." >&2 - exit 1 - fi - - version="${major}.${minor}.$((patch + 1))" + current_version="$(node -p "require('./package.json').version")" + IFS='.' read -r major minor patch <<< "$current_version" + if [[ -z "${major:-}" || -z "${minor:-}" || -z "${patch:-}" ]]; then + echo "package.json version '$current_version' is not in X.Y.Z format." >&2 + exit 1 fi - + version="${major}.${minor}.$((patch + 1))" echo "version=$version" >> "$GITHUB_OUTPUT" echo "release_tag=v${version}" >> "$GITHUB_OUTPUT" @@ -67,6 +59,7 @@ jobs: echo "owner=$lower_owner" >> "$GITHUB_OUTPUT" verify: + needs: prepare name: Verify Bun / TypeScript / Coverage runs-on: ubuntu-latest timeout-minutes: 20 @@ -107,9 +100,38 @@ jobs: - name: Build Next.js app run: bun run build + commit_version: + needs: + - prepare + - verify + runs-on: ubuntu-latest + outputs: + commit_sha: ${{ steps.commit.outputs.commit_sha }} + steps: + - name: Checkout repository + uses: actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Commit package version + id: commit + shell: bash + env: + VERSION: ${{ needs.prepare.outputs.version }} + run: | + set -euo pipefail + node -e "const fs=require('fs'); const path='package.json'; const pkg=JSON.parse(fs.readFileSync(path,'utf8')); pkg.version=process.argv[1]; fs.writeFileSync(path, JSON.stringify(pkg,null,2)+'\\n');" "$VERSION" + git config user.name 'github-actions[bot]' + git config user.email '41898282+github-actions[bot]@users.noreply.github.com' + git add package.json + git commit -m "chore: bump version to v${VERSION}" + git push origin "HEAD:${GITHUB_REF_NAME}" + echo "commit_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + publish-image: needs: - prepare + - commit_version - verify name: Publish ${{ matrix.arch }} image runs-on: ${{ matrix.runs_on }} @@ -128,6 +150,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v7 + with: + ref: ${{ needs.commit_version.outputs.commit_sha }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 @@ -204,6 +228,7 @@ jobs: merge-image-manifests: needs: - prepare + - commit_version - publish-image name: Merge multi-arch manifests runs-on: ubuntu-latest @@ -269,6 +294,7 @@ jobs: release: needs: - prepare + - commit_version - merge-image-manifests runs-on: ubuntu-latest timeout-minutes: 15 @@ -278,6 +304,7 @@ jobs: uses: actions/checkout@v7 with: fetch-depth: 0 + ref: ${{ needs.commit_version.outputs.commit_sha }} - name: Create GitHub release env: @@ -291,10 +318,10 @@ jobs: set -euo pipefail latest_tag="$(git tag --list 'v*' --sort=-v:refname | grep -Fxv "${RELEASE_TAG}" | head -n 1 || true)" - commit_range="${GITHUB_SHA}" + commit_range="${{ needs.commit_version.outputs.commit_sha }}" if [[ -n "${latest_tag}" ]]; then - commit_range="${latest_tag}..${GITHUB_SHA}" + commit_range="${latest_tag}..${{ needs.commit_version.outputs.commit_sha }}" fi commit_notes="$(git log "${commit_range}" --pretty=format:'- %s (%h)' || true)" @@ -312,7 +339,7 @@ jobs: release_notes="${release_notes}"$'\n\n'"## Commits"$'\n'"${commit_notes}" gh release create "$RELEASE_TAG" \ - --target "$GITHUB_SHA" \ + --target "${{ needs.commit_version.outputs.commit_sha }}" \ --title "$RELEASE_TITLE" \ --latest \ --notes "$release_notes" diff --git a/.husky/pre-push b/.husky/pre-push index 6eb4199..39477c2 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -5,8 +5,3 @@ set -eu bun run lint bun run format:check bun run typecheck -bun run test:ci - -base_sha="$(git merge-base HEAD origin/main)" -bun run test:patch-branches --base "$base_sha" -bun run build diff --git a/app/credentials/credential-card.tsx b/app/credentials/credential-card.tsx index d39ee5d..d87a79b 100644 --- a/app/credentials/credential-card.tsx +++ b/app/credentials/credential-card.tsx @@ -70,6 +70,7 @@ export const CredentialCard = ({ return ( { ))} +
+ + + orangeboyChen/codebuddy2api + + v{packageJson.version} +
); }; diff --git a/app/globals.scss b/app/globals.scss index ed2ab7f..c40363a 100644 --- a/app/globals.scss +++ b/app/globals.scss @@ -195,6 +195,12 @@ textarea { margin-left: 24px; max-width: none; min-width: 0; + overflow-x: auto; + scrollbar-width: none; +} + +.admin-header-navigation::-webkit-scrollbar { + display: none; } .admin-header-navigation-compact { @@ -205,6 +211,8 @@ textarea { background: transparent !important; border-color: transparent !important; box-shadow: none !important; + flex: 0 0 auto; + white-space: nowrap; } .admin-header-tab[data-active] { @@ -219,7 +227,9 @@ textarea { } .admin-header-controls { + flex: 0 0 auto; margin-left: auto; + min-width: 0; } .admin-header-select > *:last-child { @@ -312,6 +322,31 @@ textarea { background: var(--lobe-color-fill); } +.dashboard-github-link { + align-items: center; + align-self: center; + display: inline-flex; + gap: 8px; + justify-content: center; +} + +.dashboard-github-repository { + align-items: center; + color: var(--lobe-color-text-secondary); + display: inline-flex; + gap: 8px; + transition: color 160ms ease; +} + +.dashboard-github-repository:hover { + color: var(--lobe-color-text); +} + +.dashboard-version { + color: var(--lobe-color-text); + font-variant-numeric: tabular-nums; +} + .account-status-card-busy { opacity: 0.72; } diff --git a/e2e/account-status.spec.ts b/e2e/account-status.spec.ts index 14fce8f..60bfeda 100644 --- a/e2e/account-status.spec.ts +++ b/e2e/account-status.spec.ts @@ -73,7 +73,7 @@ test.describe('Account Status tab', () => { await context.grantPermissions(['clipboard-read', 'clipboard-write'], { origin: 'http://127.0.0.1:8001', }); - const filename = 'account-status-copy.json'; + const filename = `account-status-copy-${process.pid}.json`; const createResponse = await page.request.post('/admin-api/credentials', { data: { bearer_token: 'e2e-token', diff --git a/e2e/admin-console.spec.ts b/e2e/admin-console.spec.ts index 56796fd..59808d8 100644 --- a/e2e/admin-console.spec.ts +++ b/e2e/admin-console.spec.ts @@ -1,6 +1,6 @@ import { expect, test } from '@playwright/test'; -const filename = 'admin-console-e2e.json'; +const filename = `admin-console-e2e-${process.pid}.json`; const json = (body: unknown) => ({ data: body, headers: { 'Content-Type': 'application/json' }, @@ -165,12 +165,9 @@ test.describe('Admin console essentials', () => { }); expect(createResponse.ok()).toBe(true); await page.goto('/credentials'); - const credentialCard = page - .locator('.credential-card') - .filter({ - hasText: filename, - }) - .last(); + const credentialCard = page.locator( + `[data-credential-filename="${filename}"]`, + ); await expect(credentialCard).toBeVisible(); await credentialCard.getByRole('button', { name: 'Edit' }).click(); const saveButton = credentialCard.getByRole('button', { diff --git a/package.json b/package.json index 4c86621..ef5ae22 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codebuddy2api", - "version": "2.0.0", + "version": "1.0.31", "private": true, "scripts": { "dev": "next dev",