diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..8b047a3 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,79 @@ +name: Release + +on: + workflow_dispatch: + push: + branches: + - main + - dev + +jobs: + release: + name: Release + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # Make sure the release step uses its own credentials: + # https://github.com/cycjimmy/semantic-release-action#private-packages + persist-credentials: false + fetch-depth: 0 + + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: '**/node_modules' + key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }} + restore-keys: ${{ runner.os }}-bun- + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Build packages + run: bun run build:packages + + - name: Setup QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: amd64, arm64 + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and release + env: + DOCKER_REGISTRY_USER: ${{ github.actor }} + DOCKER_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} + GITHUB_ACTOR: ${{ github.actor }} + GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }} + run: bunx multi-semantic-release + + - name: Set Portainer stack webhook URL based on branch + run: | + if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then + PORTAINER_WEBHOOK_URL=${{ secrets.PORTAINER_WEBHOOK_MAIN_URL }} + else + PORTAINER_WEBHOOK_URL=${{ secrets.PORTAINER_WEBHOOK_DEV_URL }} + fi + echo "PORTAINER_WEBHOOK_URL=$PORTAINER_WEBHOOK_URL" >> $GITHUB_ENV + + - name: Trigger Portainer stack update + uses: newarifrh/portainer-service-webhook@v1 + with: + webhook_url: ${{ env.PORTAINER_WEBHOOK_URL }} + + - name: Purge outdated images + uses: snok/container-retention-policy@v3.0.0 + with: + account: ${{ github.actor }} + token: ${{ secrets.REPOSITORY_PUSH_ACCESS }} + image-names: "revanced-bot-*" + keep-n-most-recent: 5 + cut-off: 3M diff --git a/.multi-releaserc b/.multi-releaserc new file mode 100644 index 0000000..5a6769e --- /dev/null +++ b/.multi-releaserc @@ -0,0 +1,4 @@ +{ + "ignorePrivate": false, + "ignorePackages": ["!packages/**"] +} \ No newline at end of file diff --git a/.releaserc b/.releaserc new file mode 100644 index 0000000..42d6f0c --- /dev/null +++ b/.releaserc @@ -0,0 +1,54 @@ +{ + "branches": [ + "main", + { + "name": "dev", + "prerelease": true + } + ], + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "releaseRules": [ + { "type": "build", "scope": "Needs bump", "release": "patch"} + ] + } + ], + "@semantic-release/release-notes-generator", + "@semantic-release/changelog", + [ + "@semantic-release/git", + { + "assets": [ + "README.md", + "CHANGELOG.md", + "package.json" + ] + } + ], + [ + "@semantic-release/github", + { + "assets": [ + { + "path": "dist/*" + } + ], + "successComment": false + } + ], + [ + "@saithodev/semantic-release-backmerge", + { + "backmergeBranches": [ + { + "from": "main", + "to": "dev" + } + ], + "clearWorkspace": true + } + ] + ] +} \ No newline at end of file diff --git a/apis/websocket/.releaserc b/apis/websocket/.releaserc new file mode 100644 index 0000000..913e5d4 --- /dev/null +++ b/apis/websocket/.releaserc @@ -0,0 +1,21 @@ +{ + "plugins": [ + [ + "@codedependant/semantic-release-docker", + { + "dockerImage": "revanced-bot-websocket-api", + "dockerRegistry": "ghcr.io", + "dockerProject": "revanced", + "dockerContext": "../..", + "dockerPlatform": [ + "linux/amd64", + "linux/arm64" + ], + "dockerArgs": { + "GITHUB_ACTOR": null, + "GITHUB_TOKEN": null + } + } + ] + ] +} \ No newline at end of file diff --git a/apis/websocket/Dockerfile b/apis/websocket/Dockerfile new file mode 100644 index 0000000..21f5cd4 --- /dev/null +++ b/apis/websocket/Dockerfile @@ -0,0 +1,16 @@ +# This file should be triggered from the monorepo root +FROM oven/bun:latest AS base + +FROM base AS build + +WORKDIR /build +COPY . . +RUN cd apis/websocket && bun run build + +FROM base AS release + +WORKDIR /app +COPY --from=build /build/apis/websocket/dist /app +USER 1000:1000 + +ENTRYPOINT [ "bun", "run", "index.js" ] diff --git a/apis/websocket/docker-compose.example.yml b/apis/websocket/docker-compose.example.yml new file mode 100644 index 0000000..17cddce --- /dev/null +++ b/apis/websocket/docker-compose.example.yml @@ -0,0 +1,11 @@ +services: + websocket-api: + container_name: revanced-bot-websocket-api + image: ghcr.io/revanced/revanced-bot-websocket-api:latest + environment: + - WIT_AI_TOKEN= + volumes: + - /data/revanced-bot-websocket-api:/app + ports: + - 3000:3000 + restart: unless-stopped diff --git a/bots/discord/.releaserc b/bots/discord/.releaserc new file mode 100644 index 0000000..898cfd2 --- /dev/null +++ b/bots/discord/.releaserc @@ -0,0 +1,21 @@ +{ + "plugins": [ + [ + "@codedependant/semantic-release-docker", + { + "dockerImage": "revanced-bot-discord", + "dockerRegistry": "ghcr.io", + "dockerProject": "revanced", + "dockerContext": "../..", + "dockerPlatform": [ + "linux/amd64", + "linux/arm64" + ], + "dockerArgs": { + "GITHUB_ACTOR": null, + "GITHUB_TOKEN": null + } + } + ] + ] +} \ No newline at end of file diff --git a/bots/discord/Dockerfile b/bots/discord/Dockerfile new file mode 100644 index 0000000..9ae2603 --- /dev/null +++ b/bots/discord/Dockerfile @@ -0,0 +1,17 @@ +# This file should be triggered from the monorepo root +FROM oven/bun:latest AS base + +FROM base AS build + +WORKDIR /build +COPY . . +RUN cd bots/discord && bun run build + +FROM base AS release + +WORKDIR /app +COPY --from=build /build/bots/discord/dist /app + +USER 1000:1000 + +ENTRYPOINT [ "bun", "run", "src/index.js" ] diff --git a/bots/discord/docker-compose.example.yml b/bots/discord/docker-compose.example.yml new file mode 100644 index 0000000..c40f9d8 --- /dev/null +++ b/bots/discord/docker-compose.example.yml @@ -0,0 +1,9 @@ +services: + websocket-api: + container_name: revanced-bot-discord + image: ghcr.io/revanced/revanced-bot-discord:latest + volumes: + - /data/revanced-bot-discord:/app + ports: + - 3000:3000 + restart: unless-stopped \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 64e6cbb..5fa9dba 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 566d1e8..fff9d77 100644 --- a/package.json +++ b/package.json @@ -29,18 +29,28 @@ ], "packageManager": "bun@1.1.18", "devDependencies": { + "@anolilab/multi-semantic-release": "^1.1.3", "@biomejs/biome": "^1.8.2", + "@codedependant/semantic-release-docker": "^5.0.3", "@commitlint/cli": "^19.3.0", "@commitlint/config-conventional": "^19.2.2", "@revanced/bot-api": "workspace:*", "@revanced/bot-shared": "workspace:*", + "@saithodev/semantic-release-backmerge": "^4.0.1", + "@semantic-release/changelog": "^6.0.3", + "@semantic-release/git": "^10.0.1", + "@semantic-release/github": "^10.1.0", "@tsconfig/strictest": "^2.0.5", "@types/bun": "^1.1.5", "concurrently": "^8.2.2", "conventional-changelog-conventionalcommits": "^7.0.2", "lefthook": "^1.6.18", + "semantic-release": "^24.0.0", "turbo": "2", "typescript": "^5.5.2" }, - "trustedDependencies": ["@biomejs/biome", "esbuild", "lefthook"] + "trustedDependencies": ["@biomejs/biome", "esbuild", "lefthook"], + "patchedDependencies": { + "@anolilab/multi-semantic-release@1.1.3": "patches/@anolilab%2Fmulti-semantic-release@1.1.3.patch" + } } diff --git a/patches/@anolilab%2Fmulti-semantic-release@1.1.3.patch b/patches/@anolilab%2Fmulti-semantic-release@1.1.3.patch new file mode 100644 index 0000000..24584e7 --- /dev/null +++ b/patches/@anolilab%2Fmulti-semantic-release@1.1.3.patch @@ -0,0 +1,14 @@ +diff --git a/lib/multi-semantic-release.js b/lib/multi-semantic-release.js +index 1247e618244dc35f6d60d1e484fbd1a84e504b2a..4b6f1bb5aae5219db2069412f56094af0e33a664 100644 +--- a/lib/multi-semantic-release.js ++++ b/lib/multi-semantic-release.js +@@ -114,6 +114,9 @@ async function releasePackage(package_, createInlinePlugin, multiContext, flags) + options.ci = flags.ci === undefined ? options.ci : flags.ci; + options.branches = flags.branches ? castArray(flags.branches) : options.branches; + ++ // Patching so plugins from globalOptions are also inherited. ++ options.plugins = [...(multiContext.globalOptions.plugins || []), ...(options.plugins || [])] ++ + // This options are needed for plugins that do not rely on `pluginOptions` and extract them independently. + options._pkgOptions = packageOptions; +