-
Notifications
You must be signed in to change notification settings - Fork 7
ENG-2099 Test and fix Obsidian Linear release pipeline #1311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
2f7a0ce
7b33e2d
510f658
8d68b05
5eb6721
571007e
8776c60
1bb10ac
07180a4
2dc6982
c4a86fc
409589d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,7 +17,10 @@ concurrency: | |
| cancel-in-progress: false | ||
|
|
||
| env: | ||
| OBSIDIAN_PLUGIN_REPO_TOKEN: ${{ secrets.OBSIDIAN_PLUGIN_REPO_TOKEN }} | ||
| # TODO(ENG-2099): REVERT BEFORE MERGE, restore secrets.OBSIDIAN_PLUGIN_REPO_TOKEN. | ||
| OBSIDIAN_PLUGIN_REPO_TOKEN: ${{ secrets.OBSIDIAN_TEST_REPO_TOKEN }} | ||
| # TODO(ENG-2099): REVERT BEFORE MERGE, restore DiscourseGraphs/discourse-graph-obsidian. | ||
| PUBLISH_REPO: DiscourseGraphs/discourse-graph-obsidian-test | ||
| SUPABASE_URL: ${{ secrets.SUPABASE_URL }} | ||
| SUPABASE_PUBLISHABLE_KEY: ${{ secrets.SUPABASE_PUBLISHABLE_KEY }} | ||
| GH_TOKEN: ${{ github.token }} | ||
|
|
@@ -48,17 +51,17 @@ jobs: | |
|
|
||
| - name: Compute next beta version | ||
| id: version | ||
| env: | ||
| # Releases exist only in the publish repo, never in the monorepo, so the | ||
| # lookup needs an explicit --repo and a token that can read that repo. | ||
| GH_TOKEN: ${{ env.OBSIDIAN_PLUGIN_REPO_TOKEN }} | ||
| run: | | ||
| STABLE_VERSION=$(node -p "require('./apps/obsidian/package.json').version" | sed 's/-beta\.[0-9]*//') | ||
| LATEST_N=$(gh release list --limit 50 --json tagName --jq '.[].tagName' \ | ||
| STABLE_VERSION=$(node -p "require('./apps/obsidian/package.json').version") | ||
| LATEST_N=$(gh release list --repo "$PUBLISH_REPO" --limit 100 --json tagName --jq '.[].tagName' \ | ||
| | grep "^${STABLE_VERSION}-beta\." \ | ||
| | sed "s/^${STABLE_VERSION}-beta\.//" \ | ||
| | sort -n | tail -1) | ||
| if [ -n "$LATEST_N" ]; then | ||
| NEXT_BETA="${STABLE_VERSION}-beta.$((LATEST_N + 1))" | ||
| else | ||
| NEXT_BETA="${STABLE_VERSION}-beta.1" | ||
| fi | ||
| NEXT_BETA="${STABLE_VERSION}-beta.$(( ${LATEST_N:-0} + 1 ))" | ||
| echo "Stable version: $STABLE_VERSION, next beta: $NEXT_BETA" | ||
| echo "version=$NEXT_BETA" >> "$GITHUB_OUTPUT" | ||
|
|
||
|
|
@@ -68,5 +71,5 @@ jobs: | |
| - name: Sync Linear release | ||
| uses: linear/linear-release-action@v0 | ||
| with: | ||
| access_key: ${{ secrets.OBSIDIAN_LINEAR_RELEASE_KEY }} | ||
| access_key: ${{ secrets.LINEAR_RELEASES_ACCESS_KEY_OBSIDIAN }} | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug B: every run on This referenced The name was correct on Worth noting the step runs last, after |
||
| include_paths: "apps/obsidian/**,packages/database/**,packages/utils/**" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,7 +12,8 @@ permissions: | |
|
|
||
| env: | ||
| VERSION: ${{ inputs.version }} | ||
| OBSIDIAN_PLUGIN_REPO_TOKEN: ${{ secrets.OBSIDIAN_PLUGIN_REPO_TOKEN }} | ||
| # TODO(ENG-2099): REVERT BEFORE MERGE, restore secrets.OBSIDIAN_PLUGIN_REPO_TOKEN. | ||
| OBSIDIAN_PLUGIN_REPO_TOKEN: ${{ secrets.OBSIDIAN_TEST_REPO_TOKEN }} | ||
| SUPABASE_URL: ${{ secrets.SUPABASE_URL }} | ||
| SUPABASE_PUBLISHABLE_KEY: ${{ secrets.SUPABASE_PUBLISHABLE_KEY }} | ||
|
|
||
|
|
@@ -50,27 +51,32 @@ jobs: | |
| - name: Publish stable release | ||
| run: cd apps/obsidian && npx tsx scripts/publish.ts --version "$VERSION" | ||
|
|
||
| - name: Commit version bump | ||
| run: | | ||
| if ! git diff --quiet -- apps/obsidian/package.json apps/obsidian/manifest.json; then | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git add apps/obsidian/package.json apps/obsidian/manifest.json | ||
| git commit -m "chore: release obsidian ${VERSION} [skip ci]" | ||
| git push | ||
| fi | ||
| # Disabled: the default-branch ruleset requires a pull request and does not | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug E: this step could never succeed on The The step sits after publishing, so a real stable release would create the GitHub release, push the publish repo, then fail here and never reach the Linear steps. Retrying does not help: The two green runs on 24 May prove nothing. They ran on a branch, where The step's own |
||
| # grant github-actions[bot] a bypass, so this push is always rejected on main. | ||
| # Bump apps/obsidian/package.json and manifest.json in the release PR instead. | ||
| # To re-enable, add github-actions[bot] as a ruleset bypass actor. | ||
| # | ||
| # - name: Commit version bump | ||
| # run: | | ||
| # if ! git diff --quiet -- apps/obsidian/package.json apps/obsidian/manifest.json; then | ||
| # git config user.name "github-actions[bot]" | ||
| # git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| # git add apps/obsidian/package.json apps/obsidian/manifest.json | ||
| # git commit -m "chore: release obsidian ${VERSION} [skip ci]" | ||
| # git push | ||
| # fi | ||
|
|
||
| - name: Sync Linear release | ||
| uses: linear/linear-release-action@v0 | ||
| with: | ||
| access_key: ${{ secrets.OBSIDIAN_LINEAR_RELEASE_KEY }} | ||
| access_key: ${{ secrets.LINEAR_RELEASES_ACCESS_KEY_OBSIDIAN }} | ||
| command: sync | ||
| version: ${{ env.VERSION }} | ||
| include_paths: "apps/obsidian/**,packages/database/**,packages/utils/**" | ||
|
|
||
| - name: Complete Linear release | ||
| uses: linear/linear-release-action@v0 | ||
| with: | ||
| access_key: ${{ secrets.OBSIDIAN_LINEAR_RELEASE_KEY }} | ||
| access_key: ${{ secrets.LINEAR_RELEASES_ACCESS_KEY_OBSIDIAN }} | ||
| command: complete | ||
| version: ${{ env.VERSION }} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -54,9 +54,10 @@ const BLOB_UPLOAD_BATCH_SIZE = 10; | |
| const MAX_GITHUB_RETRIES = 5; | ||
| const BASE_RETRY_DELAY_MS = 2_000; | ||
|
|
||
| const TARGET_REPO = "DiscourseGraphs/discourse-graph-obsidian"; | ||
| // TODO(ENG-2099): REVERT BEFORE MERGE, restore discourse-graph-obsidian. | ||
| const TARGET_REPO = "DiscourseGraphs/discourse-graph-obsidian-test"; | ||
| const OWNER = "DiscourseGraphs"; | ||
| const REPO = "discourse-graph-obsidian"; | ||
| const REPO = "discourse-graph-obsidian-test"; | ||
|
|
||
| const log = (message: string): void => { | ||
| console.log(`[Obsidian Publisher] ${message}`); | ||
|
|
@@ -215,23 +216,14 @@ const validateVersion = (version: string): void => { | |
| }; | ||
|
|
||
| const isExternalRelease = (version: string): boolean => { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug A: This predicate returned true for beta as well as stable, and one boolean gated two separate decisions: the GitHub The publish repo's Verified across fourteen version inputs, then in five beta runs: every release came out |
||
| // External releases are: | ||
| // 1. Stable releases (x.y.z) | ||
| // 2. Beta releases (x.y.z-beta.n) | ||
|
|
||
| // Stable release pattern (x.y.z) | ||
| // The Obsidian community store reads manifest.json from the publish repo's | ||
| // main branch, so only a finished release may be external. Everything else | ||
| // ships as a GitHub pre-release and leaves that branch untouched. | ||
| const stablePattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/; | ||
| if (stablePattern.test(version)) { | ||
| return true; | ||
| } | ||
|
|
||
| // Beta release pattern (x.y.z-beta.n) | ||
| const betaPattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)-beta(\.\d+)?$/; | ||
| if (betaPattern.test(version)) { | ||
| return true; | ||
| } | ||
|
|
||
| // Everything else (including alpha releases) is internal | ||
| return false; | ||
| }; | ||
|
|
||
|
|
@@ -302,17 +294,23 @@ const execCommand = async ( | |
| } | ||
| }; | ||
|
|
||
| // Patterns match a whole path segment, never a substring of one, and globs are | ||
| // anchored to a single segment. | ||
| const segmentMatchesPattern = (segment: string, pattern: string): boolean => { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug D: source files were silently dropped from the publish repo The old matcher used Confirmed on a real publish: 101 local source files, 99 published. After the fix, 101 of 101. Before committing I diffed old against new across the whole |
||
| if (!pattern.includes("*")) return segment === pattern; | ||
|
|
||
| const escaped = pattern | ||
| .split("*") | ||
| .map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")) | ||
| .join("[^/]*"); | ||
| return new RegExp(`^${escaped}$`).test(segment); | ||
| }; | ||
|
|
||
| const shouldExclude = (filePath: string, baseDir: string): boolean => { | ||
| const relativePath = path.relative(baseDir, filePath); | ||
| return EXCLUDE_PATTERNS.some((pattern) => { | ||
| if (pattern.includes("*")) { | ||
| const regex = new RegExp(pattern.replace(/\*/g, ".*")); | ||
| return regex.test(relativePath) || regex.test(path.basename(filePath)); | ||
| } | ||
| return ( | ||
| relativePath.includes(pattern) || path.basename(filePath) === pattern | ||
| ); | ||
| }); | ||
| const segments = path.relative(baseDir, filePath).split(path.sep); | ||
| return segments.some((segment) => | ||
| EXCLUDE_PATTERNS.some((pattern) => segmentMatchesPattern(segment, pattern)), | ||
| ); | ||
| }; | ||
|
|
||
| const copyDirectory = ({ | ||
|
|
@@ -402,6 +400,18 @@ const sanitizePackageJsonForMirror = (tempDir: string): void => { | |
| } | ||
| }; | ||
|
|
||
| // updateLocalVersion runs after the publish-repo push, so the release version | ||
| // has to be written into the staged copy here as well. | ||
| const updateStagedPackageVersion = (tempDir: string, version: string): void => { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug E: the published
Result on both repos: Low user impact, since Obsidian reads |
||
| const packageJsonPath = path.join(tempDir, "package.json"); | ||
| if (!fs.existsSync(packageJsonPath)) return; | ||
|
|
||
| const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); | ||
| packageJson.version = version; | ||
| fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2)); | ||
| log(`Updated staged package.json version to ${version}`); | ||
| }; | ||
|
|
||
| const updateLocalVersion = (obsidianDir: string, version: string): void => { | ||
| const packageJsonPath = path.join(obsidianDir, "package.json"); | ||
| const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); | ||
|
|
@@ -741,6 +751,7 @@ const publish = async (config: PublishConfig): Promise<void> => { | |
|
|
||
| if (isExternal) { | ||
| updateManifest(tempDir, version); | ||
| updateStagedPackageVersion(tempDir, version); | ||
| await updateMainBranch(tempDir, version); | ||
| updateLocalVersion(obsidianDir, version); | ||
| } else { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug C: the beta counter never incremented
gh release listran without--repo, so it queried the monorepo, which has 0 releases and 0 tags. The lookup always came back empty and the code fell through to-beta.1every time.The failure mode was the quiet kind: the recomputed version already existed,
createGithubReleasetook its early return, and the run exited green having shipped nothing.After the fix the runs produced
beta.2throughbeta.5, incrementing correctly.