diff --git a/.github/renovate.json b/.github/renovate.json index d37c046..6f6032e 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -6,7 +6,7 @@ ":separateMultipleMajorReleases", "helpers:pinGitHubActionDigests" ], - "baseBranchPatterns": ["main"], + "baseBranchPatterns": ["development"], "postUpdateOptions": ["npmDedupe"], "skipInstalls": false, "timezone": "America/New_York", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..990de52 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,31 @@ +name: CI + +on: + pull_request: + branches: [main, development] + push: + branches: [main, development] + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + + - name: Setup Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 + with: + node-version: 24.19.0 + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Lint + run: npm run lint + + - name: Build + run: npm run build diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..c43808c --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,41 @@ +name: CodeQL + +on: + push: + branches: [main, development, nightly, 'feature/**'] + pull_request: + branches: [main, development, nightly] + schedule: + - cron: '30 3 * * 1' # Mondays ~03:30 UTC, off the top of the hour + workflow_dispatch: + +concurrency: + # PRs: cancel the scan for superseded commits on the same PR (the old + # code no longer matters). Pushes: key on the commit SHA, not the branch + # name — otherwise a second push to the same branch before CodeQL + # finishes cancels the first commit's scan and leaves it with a + # permanently cancelled/red check instead of a result. + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }} + cancel-in-progress: true + +permissions: + contents: read + security-events: write + +jobs: + analyze: + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + + - uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4 + with: + languages: javascript-typescript + queries: security-and-quality + + - uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4 + with: + category: /language:javascript-typescript diff --git a/.github/workflows/pr-title-lint.yml b/.github/workflows/pr-title-lint.yml new file mode 100644 index 0000000..ce3cc20 --- /dev/null +++ b/.github/workflows/pr-title-lint.yml @@ -0,0 +1,20 @@ +name: PR title lint + +# release-please derives versions and changelog entries from conventional +# commit prefixes (feat:, fix:, chore:, etc). When a PR is squash-merged, +# the PR title becomes the commit message, so the title has to follow the +# same convention or the release automation silently misses it. +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +permissions: + pull-requests: read + +jobs: + check-title: + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml new file mode 100644 index 0000000..91348ef --- /dev/null +++ b/.github/workflows/prerelease.yml @@ -0,0 +1,72 @@ +name: Publish Pre-Release + +# development is the beta/nightly channel: every push here (an approved dependency +# bump, a feature merge, a main->development sync) publishes a pre-release build +# that users can opt into via "Switch to Pre-Release Version" in the Extensions view. +# +# Version follows VS Code Marketplace's odd/even convention (stable package.json +# version is even-minor, e.g. 1.4.x) so pre-release users are always offered a +# higher version than the current stable one: minor is bumped to the next odd +# number, and patch is the workflow run number so it's always increasing. This is +# computed at publish time only and never committed back to package.json/git. + +on: + push: + branches: [development] + workflow_dispatch: + +permissions: + contents: read + +jobs: + prerelease: + runs-on: ubuntu-latest + env: + VS_MARKETPLACE_TOKEN: ${{ secrets.VS_MARKETPLACE_TOKEN }} + OPEN_VSX_TOKEN: ${{ secrets.OPEN_VSX_TOKEN }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + + - name: Setup Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 + with: + node-version: 24.19.0 + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Compute pre-release version + id: version + run: | + CURRENT=$(node -p "require('./package.json').version") + IFS='.' read -r MAJOR MINOR _PATCH <<< "$CURRENT" + if [ $((MINOR % 2)) -eq 0 ]; then + MINOR=$((MINOR + 1)) + fi + VERSION="${MAJOR}.${MINOR}.${{ github.run_number }}" + echo "Stable version is ${CURRENT}; publishing pre-release ${VERSION}" + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + + - name: Set package version (not committed) + run: npm version ${{ steps.version.outputs.version }} --no-git-tag-version --allow-same-version + + - name: Publish to Visual Studio Marketplace + if: ${{ env.VS_MARKETPLACE_TOKEN != '' }} + continue-on-error: true + uses: HaaLeo/publish-vscode-extension@ca5561daa085dee804bf9f37fe0165785a9b14db # v2 + with: + pat: ${{ env.VS_MARKETPLACE_TOKEN }} + registryUrl: https://marketplace.visualstudio.com + preRelease: true + skipDuplicate: true + + - name: Publish to Open VSX Registry + if: ${{ env.OPEN_VSX_TOKEN != '' }} + continue-on-error: true + uses: HaaLeo/publish-vscode-extension@ca5561daa085dee804bf9f37fe0165785a9b14db # v2 + with: + pat: ${{ env.OPEN_VSX_TOKEN }} + registryUrl: https://open-vsx.org + preRelease: true + skipDuplicate: true diff --git a/.github/workflows/propagate-main-to-development.yml b/.github/workflows/propagate-main-to-development.yml new file mode 100644 index 0000000..ebc3a18 --- /dev/null +++ b/.github/workflows/propagate-main-to-development.yml @@ -0,0 +1,94 @@ +name: Propagate main to development + +# For hotfixes/CI-generated commits pushed straight to main — opens a PR +# carrying those changes down to development so they don't only exist on +# main. Deliberately does NOT also target nightly: nightly picks up +# anything development gets via sync-nightly.yml's daily sync, so a second +# PR there would just be redundant. +# +# Also fires after a routine nightly -> main promotion merge, but that's a +# no-op in practice: main's content after that merge already matches +# development (it came from development via nightly), so the ahead-count +# check below finds nothing to propagate and skips creating a PR. + +on: + push: + branches: [main] + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false + +permissions: + contents: read + pull-requests: write + +jobs: + propagate: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + ref: development + fetch-depth: 0 + + - name: Check for differences + id: diff + run: | + git fetch origin main development + AHEAD=$(git rev-list --count origin/development..origin/main) + echo "main is $AHEAD commits ahead of development" + echo "ahead=$AHEAD" >> "$GITHUB_OUTPUT" + + - name: Create or update propagation PR + if: steps.diff.outputs.ahead != '0' + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + with: + script: | + const { data: existing } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + head: `${context.repo.owner}:main`, + base: 'development', + }); + + if (existing.length > 0) { + core.info(`Existing PR #${existing[0].number} already open for main -> development; leaving it as-is`); + return; + } + + const pr = await github.rest.pulls.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: 'chore: propagate main into development', + head: 'main', + base: 'development', + body: [ + 'Automated PR carrying commits pushed directly to `main` (hotfixes, CI-generated', + 'commits) down into `development`. nightly is intentionally skipped — it picks', + 'these up via the daily development sync instead.', + '', + `Triggered by push ${context.sha} to main.`, + ].join('\n'), + draft: true, + }); + core.info(`Created PR #${pr.data.number}: ${pr.data.html_url}`); + + try { + await github.rest.issues.getLabel({ owner: context.repo.owner, repo: context.repo.repo, name: 'auto-propagate' }); + } catch { + await github.rest.issues.createLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: 'auto-propagate', + color: '7dd3fc', + }); + } + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.data.number, + labels: ['auto-propagate'], + }); diff --git a/package.json b/package.json index e0eece0..12eda4a 100644 --- a/package.json +++ b/package.json @@ -25,12 +25,12 @@ }, "repository": { "type": "git", - "url": "https://github.com/Wikid82/file_bookmarks" + "url": "https://github.com/Wikid82/Workspace-File-Bookmarks" }, "bugs": { - "url": "https://github.com/Wikid82/file_bookmarks/issues" + "url": "https://github.com/Wikid82/Workspace-File-Bookmarks/issues" }, - "homepage": "https://github.com/Wikid82/file_bookmarks#readme", + "homepage": "https://github.com/Wikid82/Workspace-File-Bookmarks#readme", "engines": { "vscode": "^1.132.0" },