diff --git a/.github/steps/setup-playwright/action.yml b/.github/steps/setup-playwright/action.yml new file mode 100644 index 00000000..6e5391e7 --- /dev/null +++ b/.github/steps/setup-playwright/action.yml @@ -0,0 +1,35 @@ +name: Set Up Playwright +description: Sets up Playwright +inputs: + working-directory: + description: Where to run + required: false +runs: + using: composite + steps: + # Adapted from https://playwrightsolutions.com/playwright-github-action-to-cache-the-browser-binaries/ + - name: Get installed Playwright version + id: playwright-version + run: echo version=$(yarn info --json @playwright/test | jq -r '.children.Version') >> $GITHUB_OUTPUT + working-directory: ${{ inputs.working-directory }} + shell: bash + + - name: Cache playwright binaries + uses: actions/cache@v4 + id: playwright-cache + with: + path: | + ~/.cache/ms-playwright + key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }} + + - name: Install Playwright Browsers + run: yarn playwright install --with-deps + working-directory: ${{ inputs.working-directory }} + if: steps.playwright-cache.outputs.cache-hit != 'true' + shell: bash + + - name: Install Playwright OS dependencies + run: npx playwright install-deps + working-directory: ${{ inputs.working-directory }} + if: steps.playwright-cache.outputs.cache-hit == 'true' + shell: bash diff --git a/.github/workflows/build_canary.yml b/.github/workflows/build_canary.yml new file mode 100644 index 00000000..98d055c0 --- /dev/null +++ b/.github/workflows/build_canary.yml @@ -0,0 +1,15 @@ +on: + push: + branches: [main] + +permissions: + contents: write + packages: write + +jobs: + build: + uses: ./.github/workflows/build_shared.yml + with: + ref: ${{ github.ref }} + tag: ${{ github.ref_name }} + strip_rc: true diff --git a/.github/workflows/build_shared.yml b/.github/workflows/build_shared.yml index 9f36d014..7ecddd99 100644 --- a/.github/workflows/build_shared.yml +++ b/.github/workflows/build_shared.yml @@ -8,7 +8,10 @@ on: tag: type: string required: true - description: Docker tag to push + description: Version to build, also the docker tag + strip_rc: + type: boolean + description: Strip -rc suffix from version number permissions: contents: read @@ -34,7 +37,17 @@ jobs: - run: yarn install --immutable - - run: "yarn package" + - name: Set version + shell: pwsh + run: | + $pkg = Get-Content ./desktop/package.json | ConvertFrom-Json + $pkg.version = "${{inputs.tag }}" -replace "^v", "" + if ("${{ inputs.strip_rc }}" -eq "true") { + $pkg.version = $pkg.version -replace "-rc.*", "" + } + $pkg | ConvertTo-Json -Depth 32 | Set-Content ./desktop/package.json + + - run: "yarn package --win --publish never" working-directory: ./desktop env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -67,6 +80,15 @@ jobs: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Set version + run: | + set -x + version=$(echo '${{ inputs.tag }}' | sed 's/^v//') + if [[ '${{ inputs.strip_rc }}' == 'true' ]]; then + version=$(echo $version | sed 's/-rc.*//') + fi + sed -i "s/0.0.0/$version/g" package.json + working-directory: ./server - name: Docker metadata id: meta uses: docker/metadata-action@v5 @@ -74,11 +96,11 @@ jobs: images: ghcr.io/ystv/badger/server flavor: latest=true tags: | - type=semver,pattern={{version}},enable=${{ github.event_name == 'workflow_dispatch' }} - type=raw,value=${{ inputs.tag }},enable=${{ github.event_name == 'workflow_call' }} + type=raw,value=${{ inputs.tag }} - name: Build and push uses: docker/build-push-action@v6 with: + context: . push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} @@ -101,6 +123,14 @@ jobs: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Set version + run: | + version=$(echo '${{ inputs.tag }}' | sed 's/^v//') + if [[ '${{ inputs.strip_rc }}' == 'true' ]]; then + version=$(echo $version | sed 's/-rc.*//') + fi + sed -i "s/0.0.0/$version/g" package.json + working-directory: ./jobrunner - name: Docker metadata id: jr_meta uses: docker/metadata-action@v5 @@ -108,11 +138,11 @@ jobs: images: ghcr.io/ystv/badger/jobrunner flavor: latest=true tags: | - type=semver,pattern={{version}},enable=${{ github.event_name == 'workflow_dispatch' }} - type=raw,value=${{ inputs.tag }},enable=${{ github.event_name == 'workflow_call' }} + type=raw,value=${{ inputs.tag }} - name: Build and push uses: docker/build-push-action@v6 with: + context: . push: true tags: ${{ steps.jr_meta.outputs.tags }} labels: ${{ steps.jr_meta.outputs.labels }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d21ce512..8931f9b3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,16 +3,15 @@ on: tags: - "*-rc*" -permissions: - contents: write - packages: write +permissions: write-all jobs: build: uses: ./.github/workflows/build_shared.yml with: - ref: ${{ github.event.before }} - tag: ${{ github.event.ref }} + ref: ${{ github.ref }} + tag: ${{ github.ref_name }} + strip_rc: true test-e2e-server: needs: [build] @@ -31,36 +30,24 @@ jobs: cache-dependency-path: "yarn.lock" - name: Set ref in docker-compose - run: sed -i "s/__RC_REF__/${{ github.event.ref }}/g" docker-compose-rc-test.yml + run: sed -i "s/__RC_REF__/${{ github.ref_name }}/g" docker-compose-rc-test.yml - name: Start services - run: docker compose up -d -f docker-compose.yml -f docker-compose-rc-test.yml + run: docker compose -f docker-compose.yml -f docker-compose-rc-test.yml up -d - # Adapted from https://playwrightsolutions.com/playwright-github-action-to-cache-the-browser-binaries/ - - name: Get installed Playwright version - id: playwright-version - run: echo version=$(yarn info --json @playwright/test | jq -r '.children.Version') >> $GITHUB_OUTPUT - working-directory: ./server + - run: yarn install --immutable --inline-builds - - name: Cache playwright binaries - uses: actions/cache@v4 - id: playwright-cache + - uses: ./.github/steps/setup-playwright with: - path: | - ~/.cache/ms-playwright - key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }} - - - name: Install Playwright Browsers - run: yarn playwright install --with-deps - working-directory: ./server - if: steps.playwright-cache.outputs.cache-hit != 'true' - - - name: Install Playwright OS dependencies - run: npx playwright install-deps - if: steps.playwright-cache.outputs.cache-hit == 'true' + working-directory: ./server - name: Migrate database - run: yarn prisma:migrateProd + run: | + yarn prisma:migrateProd + + - name: Retart services + run: | + docker compose -f docker-compose.yml -f docker-compose-rc-test.yml restart server jobrunner - name: Run Playwright tests run: yarn ${{ runner.debug && 'test:e2e:debug' || 'test:e2e' }} @@ -75,31 +62,114 @@ jobs: path: ./server/playwright-report/ retention-days: 30 + test-desktop: + runs-on: windows-latest + needs: [build] + steps: + - uses: actions/checkout@v4 + - name: Use Node.js 18.x + uses: actions/setup-node@v4 + with: + node-version: 18.x + cache: "yarn" + cache-dependency-path: "yarn.lock" + - name: Download Desktop build + uses: actions/download-artifact@v4 + with: + name: badger-desktop-windows + - name: Install Badger + run: | + $version = "${{ github.ref_name }}" -replace "^v", "" -replace "-rc.*", "" + Start-Process -FilePath "Badger Desktop-$version.exe" -ArgumentList "/S","/D=${{ runner.temp }}\badger" -Wait + shell: pwsh + - run: yarn install --immutable --inline-builds + - name: Run tests + run: yarn test:e2e --project=standalone + working-directory: ./desktop + env: + TEST_APPLICATION_PATH: ${{ runner.temp }}\badger\Badger Desktop.exe + + linear: + needs: [test-e2e-server, test-desktop] + runs-on: ubuntu-latest + outputs: + issue_id: ${{ steps.issue.outputs.issue_id }} + steps: + - name: Determine version number + run: echo "VERSION=$(echo '${{ github.ref_name }}' | sed 's/-rc.*//')" >> $GITHUB_ENV + - uses: actions/setup-node@v3 + with: + node-version: "20.x" + - run: npm install @linear/sdk + - name: Create Linear release ticket + id: issue + uses: actions/github-script@v7 + with: + script: | + const { LinearClient } = require('@linear/sdk'); + const lin = new LinearClient({ + accessToken: "${{ secrets.LINEAR_ACCESS_TOKEN }}" + }); + const issueCreate = await lin.createIssue({ + teamId: "${{ vars.LINEAR_TEAM_ID }}", + templateId: "${{ vars.LINEAR_RELEASE_ISSUE_TEMPLATE_ID }}", + stateId: "${{ vars.LINEAR_TODO_STATE_ID }}", + title: `Release ${{ github.ref_name }}`, + }); + if (!issueCreate.success) { + throw new Error(`Failed to create issue`); + } + const issue = await issueCreate.issue; + + await lin.createComment({ + issueId: issue.id, + body: `Artifacts: + Server Docker image: \`ghcr.io/ystv/badger/server:${{ github.ref_name }}\` + Jobrunner Docker Image: \`ghcr.io/ystv/badger/jobrunner:${{ github.ref_name }}\` + Desktop Windows installer: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + + Once testing is complete, please approve [this workflow](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) to publish the release. + `.replace(/^\s*/gm, ''), + }); + + core.summary.addHeading('Linear issue'); + core.summary.addLink(issue.identifier, issue.url); + core.setOutput('issue_id', issue.id); + release: - needs: [test-e2e-server, build] + needs: [test-e2e-server, test-desktop, linear] environment: release runs-on: ubuntu-latest + permissions: write-all steps: - name: Determine version number - run: echo "VERSION=$(echo '${{ github.event.ref }}' | sed 's/^refs\/tags\///' | sed 's/-rc.*//')" >> $GITHUB_ENV + run: echo "VERSION=$(echo '${{ github.ref_name }}' | sed 's/-rc.*//')" >> $GITHUB_ENV - name: Download Desktop build uses: actions/download-artifact@v4 with: + pattern: badger-desktop-* path: artifacts - - name: Pull Docker images - run: | - docker pull ghcr.io/ystv/badger/server:${{ github.event.ref }} - docker pull ghcr.io/ystv/badger/jobrunner:${{ github.event.ref }} + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Re-tag and push Docker images - run: - docker tag ghcr.io/ystv/badger/server:${{ github.event.ref }} ghcr.io/ystv/badger/server:$VERSION - docker tag ghcr.io/ystv/badger/jobrunner:${{ github.event.ref }} ghcr.io/ystv/badger/jobrunner:$VERSION - docker push ghcr.io/ystv/badger/server:$VERSION - docker push ghcr.io/ystv/badger/jobrunner:$VERSION + run: | + for img in server jobrunner; do + docker pull ghcr.io/ystv/badger/$img:${{ github.ref_name }} + docker tag ghcr.io/ystv/badger/$img:${{ github.ref_name }} ghcr.io/ystv/badger/$img:$VERSION + docker push ghcr.io/ystv/badger/$img:$VERSION + docker tag ghcr.io/ystv/badger/$img:${{ github.ref_name }} ghcr.io/ystv/badger/$img:latest + docker push ghcr.io/ystv/badger/$img:latest + done + shell: bash - name: Create GitHub release uses: actions/github-script@v7 id: release with: + github-token: ${{ secrets.GH_RELEASE_PAT }} script: | const release = await github.rest.repos.createRelease({ owner: context.repo.owner, @@ -109,21 +179,44 @@ jobs: name: process.env.VERSION, draft: true, generate_release_notes: true, - make_latest: true + prerelease: false, + body: [ + '## Docker images', + `- Server: \`ghcr.io/ystv/badger/server:${process.env.VERSION}\``, + `- Jobrunner: \`ghcr.io/ystv/badger/jobrunner:${process.env.VERSION}\``, + '' + ].join('\n'), }); core.setOutput('id', release.data.id) - core.setOutput('upload_url', release.data.upload_url) core.setOutput('tag_name', release.data.tag_name) - name: Upload artifacts run: | - find artifacts -type f -exec gh release upload ${{ steps.release.outputs.tag_name }} {} \; + find artifacts -type f -not -name '*.yml' -not -name '*.yaml' -print0 | xargs -0 -I{} gh release -R ystv/badger upload --clobber ${{ steps.release.outputs.tag_name }} '{}' + env: + GITHUB_TOKEN: ${{ secrets.GH_RELEASE_PAT }} - name: Publish release uses: actions/github-script@v7 with: + github-token: ${{ secrets.GITHUB_TOKEN }} script: | await github.rest.repos.updateRelease({ owner: context.repo.owner, repo: context.repo.repo, - release_id: ${{ steps.release.outputs.id }}, + release_id: "${{ steps.release.outputs.id }}", draft: false }) + - uses: actions/setup-node@v3 + with: + node-version: "20.x" + - run: npm install @linear/sdk + - name: Close Linear issue + uses: actions/github-script@v7 + with: + script: | + const { LinearClient } = require('@linear/sdk'); + const lin = new LinearClient({ + accessToken: "${{ secrets.LINEAR_ACCESS_TOKEN }}" + }); + await lin.updateIssue("${{ needs.linear.outputs.issue_id }}", { + stateId: "${{ vars.LINEAR_DONE_STATE_ID }}", + }); diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 23985672..d9f938c8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -162,28 +162,9 @@ jobs: cp ../utility/prisma/schema.prisma . working-directory: ./jobrunner - # Adapted from https://playwrightsolutions.com/playwright-github-action-to-cache-the-browser-binaries/ - - name: Get installed Playwright version - id: playwright-version - run: echo version=$(yarn info --json @playwright/test | jq -r '.children.Version') >> $GITHUB_OUTPUT - working-directory: ./server - - - name: Cache playwright binaries - uses: actions/cache@v4 - id: playwright-cache + - uses: ./.github/steps/setup-playwright with: - path: | - ~/.cache/ms-playwright - key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }} - - - name: Install Playwright Browsers - run: yarn playwright install --with-deps - working-directory: ./server - if: steps.playwright-cache.outputs.cache-hit != 'true' - - - name: Install Playwright OS dependencies - run: npx playwright install-deps - if: steps.playwright-cache.outputs.cache-hit == 'true' + working-directory: ./server - name: Migrate database run: yarn prisma:migrateProd diff --git a/desktop/e2e/standalone/base.ts b/desktop/e2e/standalone/base.ts index 0b8e0f77..53bdcb56 100644 --- a/desktop/e2e/standalone/base.ts +++ b/desktop/e2e/standalone/base.ts @@ -35,8 +35,13 @@ const test = base.extend<{ }, app: async ({ scenario, testMediaPath }, use, testInfo) => { + // Allow running tests on a built / installed app + const electronPath = process.env.TEST_APPLICATION_PATH; const app = await electron.launch({ - args: ["--enable-logging", "out/main/index.js"], + args: electronPath + ? ["--enable-logging"] + : ["--enable-logging", "out/main/index.js"], + executablePath: electronPath, env: { ...process.env, NODE_ENV: "test", diff --git a/desktop/package.json b/desktop/package.json index 89f5fa0a..c0f02439 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -1,7 +1,7 @@ { "name": "badger-desktop", "productName": "Badger Desktop", - "version": "1.0.3-canary.8", + "version": "0.0.0", "description": "My Electron application description", "main": "./out/main/index.js", "scripts": { diff --git a/desktop/src/main/media/downloadFile.ts b/desktop/src/main/media/downloadFile.ts index fe248cac..d54ab93d 100644 --- a/desktop/src/main/media/downloadFile.ts +++ b/desktop/src/main/media/downloadFile.ts @@ -65,7 +65,7 @@ const CurlDownloader: Downloader = async function CurlDownloader( ) { invariant(curlPath, "no curl path"); logger.info("Using curl downloader"); - const args = ["-f", "--compressed", "-o", outputPath, url]; + const args = ["-f", "--compressed", "--location", "-o", outputPath, url]; logger.info(`Curl command: ${curlPath} ${args.join(" ")}`); const proc = spawn(curlPath, args); if (progressCB) { diff --git a/docker-compose-rc-test.yml b/docker-compose-rc-test.yml index 5a017e15..7dc39ae0 100644 --- a/docker-compose-rc-test.yml +++ b/docker-compose-rc-test.yml @@ -1,3 +1,4 @@ +# Used by the release GitHub Actions workflow. version: "3" services: server: @@ -14,7 +15,7 @@ services: AWS_SECRET_ACCESS_KEY: "rootroot" AWS_REGION: "us-east-1" STORAGE_BUCKET: "badger" - API_SHARED_SECRET: "password" + API_SHARED_SECRET: "aaa" PUBLIC_URL: "http://localhost:3000" JWT_SIGNING_KEY: "somesecret" NODE_ENV: "test" @@ -24,4 +25,6 @@ services: image: ghcr.io/ystv/badger/jobrunner:__RC_REF__ platform: linux/amd64 command: ["--watch", "--healthPort", "28342"] # matching server/playwright.config.ts + ports: + - "28342:28342" environment: *badger_env diff --git a/jobrunner/package.json b/jobrunner/package.json index 802931fa..946f4986 100644 --- a/jobrunner/package.json +++ b/jobrunner/package.json @@ -1,6 +1,6 @@ { "name": "badger-jobrunner", - "version": "1.0.3-canary.8", + "version": "0.0.0", "packageManager": "yarn@4.4.1", "type": "commonjs", "scripts": { diff --git a/server/app/layout.tsx b/server/app/layout.tsx index 7f103613..b80f725c 100644 --- a/server/app/layout.tsx +++ b/server/app/layout.tsx @@ -9,7 +9,7 @@ import { checkSession } from "@/lib/auth"; import { UserProvider } from "@/components/CurrentUser"; import Script from "next/script"; import { FeatureFlagsProvider } from "@/components/FeatureFlags"; -import { getTusEndpoint } from "@/lib/tus"; +import { getPublicTusEndpoint } from "@/lib/tus"; import { UploadProgress } from "@/components/Uploader"; export const metadata: Metadata = { @@ -32,7 +32,7 @@ export default async function RootLayout({ {`window.ENVIRONMENT = ${JSON.stringify(process.env.ENVIRONMENT)};`}
diff --git a/server/app/shows/[show_id]/rundown/[rundown_id]/page.tsx b/server/app/shows/[show_id]/rundown/[rundown_id]/page.tsx index f843e468..5899a837 100644 --- a/server/app/shows/[show_id]/rundown/[rundown_id]/page.tsx +++ b/server/app/shows/[show_id]/rundown/[rundown_id]/page.tsx @@ -4,7 +4,7 @@ import { RundownItems } from "./RundownItems"; import RundownAssets from "./RundownAssets"; import Link from "next/link"; import { TusEndpointProvider } from "@/components/MediaUpload"; -import { getTusEndpoint } from "@/lib/tus"; +import { getPublicTusEndpoint } from "@/lib/tus"; import { Suspense, cache } from "react"; import { Button } from "@badger/components/button"; import { MetadataTargetType } from "@badger/prisma/client"; @@ -176,7 +176,7 @@ export default async function RundownPage(props: {