diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 00000000..4a5d817f --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,6 @@ +changelog: + exclude: + authors: + - dependabot + labels: + - ignore-for-changelog diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 045b73f4..a1eb0645 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,8 +4,7 @@ on: push: branches: [main] tags: ["**"] - pull_request: - branches: ["*"] + pull_request: {} jobs: rust: @@ -33,7 +32,7 @@ jobs: timeout-minutes: 10 - run: cargo publish --package foxglove --dry-run - run: cargo publish --package foxglove - if: startsWith(github.ref, 'refs/tags/rust/v') + if: startsWith(github.ref, 'refs/tags/sdk/v') env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml new file mode 100644 index 00000000..57611b0e --- /dev/null +++ b/.github/workflows/draft-release.yml @@ -0,0 +1,69 @@ +name: Draft Release + +on: + workflow_dispatch: + inputs: + version: + description: "Version (must start with 'v')" + required: true + pull_request: {} + +env: + SDK_VERSION: ${{ github.event.inputs.version || 'v0.2.0' }} + SDK_TAG: sdk/${{ github.event.inputs.version || 'v0.2.0' }} + SDK_BRANCH: release/sdk/${{ github.event.inputs.version || 'v0.2.0' }} + +jobs: + draft: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # needed to get the previous release tag + + - run: corepack enable + + - uses: actions/setup-node@v4 + with: + node-version: 18 + cache: yarn + + - name: Check for existing ${{ env.SDK_TAG }} release + env: + GH_TOKEN: ${{ github.token }} + run: | + if gh release view "${{ env.SDK_TAG }}" --json "name,url"; then + echo "Release ${SDK_TAG} already exists!" + exit 1 + fi + + - run: yarn install --immutable + - run: yarn bump-sdk-version "${{ env.SDK_VERSION }}" + + - name: Detect previous version + id: previous-release + run: | + tag=$(git describe --tags --abbrev=0 --match "sdk/v*") + echo "tag=$tag" | tee -a $GITHUB_OUTPUT + + - name: Commit and push branch + run: | + git config user.name "Foxglove" + git config user.email "support@foxglove.dev" + git checkout -b "${{ env.SDK_BRANCH }}" + git add . + git commit -m "Release SDK version ${{ env.SDK_VERSION }}" + git push -f origin "${{ env.SDK_BRANCH }}" + + - name: Create draft release + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create "${{ env.SDK_TAG }}" \ + --title "${{ env.SDK_TAG }}" \ + --target "${{ env.SDK_BRANCH }}" \ + --generate-notes \ + --notes-start-tag "${{ steps.previous-release.outputs.tag }}" \ + --draft diff --git a/.github/workflows/post-release.yml b/.github/workflows/post-release.yml new file mode 100644 index 00000000..4d306668 --- /dev/null +++ b/.github/workflows/post-release.yml @@ -0,0 +1,27 @@ +name: Post Release + +on: + release: + types: [released] + +env: + SDK_TAG: ${{ github.event.release.tag_name }} + +jobs: + release: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ env.SDK_TAG }} + fetch-depth: 0 + + - name: Git merge into main + run: | + git config user.name "Foxglove" + git config user.email "support@foxglove.dev" + git checkout -b main --track origin/main + git merge --no-ff ${{ github.ref }} + git push origin main diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index d15b9bfe..3888aa53 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -237,7 +237,7 @@ jobs: # them unless the maturin API changes substantially. release: runs-on: ubuntu-latest - if: startsWith(github.ref, 'refs/tags/python/foxglove-sdk/v') + if: startsWith(github.ref, 'refs/tags/sdk/v') needs: [linux, musllinux, windows, macos, sdist] permissions: id-token: write diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 33d2d3e2..00000000 --- a/.npmignore +++ /dev/null @@ -1 +0,0 @@ -ros_foxglove_msgs diff --git a/.vscode/settings.json b/.vscode/settings.json index 87a213ae..a93bea50 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,13 +22,11 @@ "reportUnusedDisableDirectives": "error" }, "jest.jestCommandLine": "yarn test", - "python.analysis.typeCheckingMode": "strict", "[python]": { "editor.defaultFormatter": "ms-python.black-formatter" }, "[rust]": { - "editor.defaultFormatter": "rust-lang.rust-analyzer", - "editor.formatOnSave": true + "editor.defaultFormatter": "rust-lang.rust-analyzer" } } diff --git a/package.json b/package.json index b420fe31..3839a55a 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "lint:ci": "eslint --report-unused-disable-directives .", "lint": "eslint --report-unused-disable-directives --fix .", "test": "jest", + "bump-sdk-version": "ts-node ./scripts/bumpSdkVersion.ts", "update-generated-files": "ts-node --files --project tsconfig.json ./scripts/updateGeneratedFiles.ts --out-dir schemas --ros-out-dir ros_foxglove_msgs && yarn test --updateSnapshot" }, "devDependencies": { @@ -17,6 +18,7 @@ "@foxglove/omgidl-parser": "^0.2.0", "@foxglove/rosmsg": "^4.0.0", "@foxglove/tsconfig": "2.0.0", + "@types/glob": "^8.1.0", "@types/jest": "29.5.14", "@types/node": "22.13.0", "@typescript-eslint/eslint-plugin": "8.22.0", @@ -30,6 +32,7 @@ "eslint-plugin-import": "2.31.0", "eslint-plugin-jest": "28.11.0", "eslint-plugin-prettier": "5.2.3", + "glob": "^10.3.10", "globals": "^15.14.0", "jest": "29.7.0", "prettier": "^3.4.2", diff --git a/scripts/bumpSdkVersion.ts b/scripts/bumpSdkVersion.ts new file mode 100644 index 00000000..c869aa28 --- /dev/null +++ b/scripts/bumpSdkVersion.ts @@ -0,0 +1,76 @@ +#!/usr/bin/env tsx + +import { spawn } from "child_process"; +import fs from "fs/promises"; +import { glob } from "glob"; +import path from "path"; + +const versionRegex = /^version\s*=\s*"[^"]*"/m; + +async function main() { + const newVersion = process.argv[2]; + if (newVersion?.startsWith("v") !== true) { + console.log("Usage: bumpSdkVersion.ts "); + console.log("Version must start with 'v'"); + process.exit(1); + } + + // Remove the 'v' prefix for the actual version string + const versionNumber = newVersion.slice(1); + + // Find all Cargo.toml files from workspace root + const workspaceRoot = path.resolve(__dirname, ".."); + const cargoFiles = await glob("**/Cargo.toml", { + ignore: ["**/target/**", "**/node_modules/**"], + cwd: workspaceRoot, + absolute: true, + }); + + let success = true; + for (const cargoFile of cargoFiles) { + console.log(`Checking ${cargoFile}...`); + const content = await fs.readFile(cargoFile, "utf8"); + + if (!versionRegex.test(content)) { + console.log(` ℹ️ Skipped, does not contain version field`); + continue; + } + + // Only update the main version field, not dependencies + const updatedContent = content.replace(versionRegex, `version = "${versionNumber}"`); + + if (content === updatedContent) { + const oldVersion = versionRegex.exec(content)?.[0] ?? '""'; + console.error(` ❌ Version could not be updated from ${oldVersion} to "${versionNumber}"`); + success = false; + } else { + await fs.writeFile(cargoFile, updatedContent); + console.log(` ✅ Updated version in ${cargoFile} to ${versionNumber}`); + } + } + + if (!success) { + console.error("\n❌ Some versions could not be updated"); + process.exit(1); + } + + // run cargo check + console.log("\nRunning cargo check..."); + const cargoCheck = spawn("cargo", ["check"], { + cwd: workspaceRoot, + stdio: "inherit", + }); + + const exitCode = await new Promise((resolve) => { + cargoCheck.on("close", resolve); + }); + + if (exitCode !== 0) { + process.exit(exitCode); + } +} + +main().catch((err: unknown) => { + console.error(err); + process.exit(1); +}); diff --git a/yarn.lock b/yarn.lock index 5d1daaf8..5a32a787 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1422,6 +1422,16 @@ __metadata: languageName: node linkType: hard +"@types/glob@npm:^8.1.0": + version: 8.1.0 + resolution: "@types/glob@npm:8.1.0" + dependencies: + "@types/minimatch": "npm:^5.1.2" + "@types/node": "npm:*" + checksum: 10c0/ded07aa0d7a1caf3c47b85e262be82989ccd7933b4a14712b79c82fd45a239249811d9fc3a135b3e9457afa163e74a297033d7245b0dc63cd3d032f3906b053f + languageName: node + linkType: hard + "@types/graceful-fs@npm:^4.1.3": version: 4.1.5 resolution: "@types/graceful-fs@npm:4.1.5" @@ -1480,6 +1490,13 @@ __metadata: languageName: node linkType: hard +"@types/minimatch@npm:^5.1.2": + version: 5.1.2 + resolution: "@types/minimatch@npm:5.1.2" + checksum: 10c0/83cf1c11748891b714e129de0585af4c55dd4c2cafb1f1d5233d79246e5e1e19d1b5ad9e8db449667b3ffa2b6c80125c429dbee1054e9efb45758dbc4e118562 + languageName: node + linkType: hard + "@types/node@npm:*, @types/node@npm:>=13.7.0": version: 17.0.31 resolution: "@types/node@npm:17.0.31" @@ -3413,6 +3430,7 @@ __metadata: "@foxglove/omgidl-parser": "npm:^0.2.0" "@foxglove/rosmsg": "npm:^4.0.0" "@foxglove/tsconfig": "npm:2.0.0" + "@types/glob": "npm:^8.1.0" "@types/jest": "npm:29.5.14" "@types/node": "npm:22.13.0" "@typescript-eslint/eslint-plugin": "npm:8.22.0" @@ -3426,6 +3444,7 @@ __metadata: eslint-plugin-import: "npm:2.31.0" eslint-plugin-jest: "npm:28.11.0" eslint-plugin-prettier: "npm:5.2.3" + glob: "npm:^10.3.10" globals: "npm:^15.14.0" jest: "npm:29.7.0" prettier: "npm:^3.4.2"