Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .github/changelog/.gitkeep
Empty file.
75 changes: 75 additions & 0 deletions .github/workflows/changelog-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Changelog Check

on:
pull_request:
types: [opened, synchronize]

jobs:
check:
name: Check for changelog
runs-on: ubuntu-latest

steps:
- name: 📥 Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: 🔍 Check for changelog fragments
id: changelog
run: |
CHANGED_FILES=$(git diff --name-only --diff-filter=A origin/${{ github.event.pull_request.base.ref }}...HEAD -- '.github/changelog/*.yml')
if [ -z "$CHANGED_FILES" ]; then
echo "found=false" >> $GITHUB_OUTPUT
else
echo "found=true" >> $GITHUB_OUTPUT
fi

- name: 💬 Post or minimize changelog comment
uses: actions/github-script@v7
with:
github-token: ${{ secrets.CROWDIN_GH_TOKEN }}
script: |
const marker = '<!-- changelog-check -->';
const body = `${marker}\n> [!NOTE]\n> No changelog fragment was found for this pull request. If this PR includes user-facing changes, run \`pnpm scripts new-changelog\` to create one.`;
const hasChangelog = '${{ steps.changelog.outputs.found }}' === 'true';

// Find existing bot comments with our marker
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});

const botComments = comments.filter(c => c.body.includes(marker));

if (!hasChangelog) {
if (botComments.length > 0) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComments[0].id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}
} else {
// Minimize all existing bot comments
for (const comment of botComments) {
await github.graphql(`
mutation($id: ID!) {
minimizeComment(input: { subjectId: $id, classifier: OUTDATED }) {
minimizedComment {
isMinimized
}
}
}
`, { id: comment.node_id });
}
}
66 changes: 49 additions & 17 deletions .github/workflows/theseus-release.yml
Original file line number Diff line number Diff line change
@@ -1,47 +1,65 @@
name: Modrinth App release
on:
workflow_dispatch:
inputs:
version-tag:
description: Version tag to release to the wide public
type: string
required: true
release-notes:
description: Release notes to include in the Tauri version manifest
default: A new release of the Modrinth App is available!
type: string
required: true
workflow_run:
workflows: ['Modrinth App build']
types: [completed]

jobs:
release:
name: Release Modrinth App
if: >-
github.event.workflow_run.conclusion == 'success' &&
startsWith(github.event.workflow_run.head_branch, 'v')
runs-on: ubuntu-latest

env:
VERSION_TAG: ${{ github.event.workflow_run.head_branch }}
LINUX_X64_BUNDLE_ARTIFACT_NAME: App bundle (x86_64-unknown-linux-gnu)
WINDOWS_X64_BUNDLE_ARTIFACT_NAME: App bundle (x86_64-pc-windows-msvc)
MACOS_UNIVERSAL_BUNDLE_ARTIFACT_NAME: App bundle (universal-apple-darwin)
LAUNCHER_FILES_BUCKET_BASE_URL: https://launcher-files.modrinth.com

steps:
- name: 📥 Check out code
uses: actions/checkout@v4

- name: 🧰 Install pnpm
uses: pnpm/action-setup@v4

- name: 🧰 Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: pnpm

- name: 🧰 Install root dependencies
run: pnpm install -w

- name: 📝 Extract changelog body
id: changelog
run: |
BODY=$(pnpm scripts bake-changelog -- --product app --version "${VERSION_TAG#v}" --extract)
{
echo "body<<CHANGELOG_EOF"
echo "$BODY"
echo "CHANGELOG_EOF"
} >> "$GITHUB_OUTPUT"

- name: 📥 Download Modrinth App artifacts
uses: dawidd6/action-download-artifact@v11
with:
workflow: theseus-build.yml
workflow_conclusion: success
event: push
branch: ${{ inputs.version-tag }}
branch: ${{ env.VERSION_TAG }}
use_unzip: true

- name: 🛠️ Generate version manifest
env:
VERSION_TAG: ${{ inputs.version-tag }}
RELEASE_NOTES: ${{ inputs.release-notes }}
run: |
# Reference: https://tauri.app/plugin/updater/#server-support
jq -nc \
--arg versionTag "${VERSION_TAG#v}" \
--arg releaseNotes "$RELEASE_NOTES" \
--arg releaseNotes "${{ steps.changelog.outputs.body }}" \
--rawfile macOsAarch64UpdateArtifactSignature "${MACOS_UNIVERSAL_BUNDLE_ARTIFACT_NAME}/universal-apple-darwin/release/bundle/macos/Modrinth App.app.tar.gz.sig" \
--rawfile macOsX64UpdateArtifactSignature "${MACOS_UNIVERSAL_BUNDLE_ARTIFACT_NAME}/universal-apple-darwin/release/bundle/macos/Modrinth App.app.tar.gz.sig" \
--rawfile linuxX64UpdateArtifactSignature "${LINUX_X64_BUNDLE_ARTIFACT_NAME}/release/bundle/appimage/Modrinth App_${VERSION_TAG#v}_amd64.AppImage.tar.gz.sig" \
Expand Down Expand Up @@ -83,7 +101,6 @@ jobs:

- name: 📤 Upload release artifacts
env:
VERSION_TAG: ${{ inputs.version-tag }}
AWS_ACCESS_KEY_ID: ${{ secrets.LAUNCHER_FILES_BUCKET_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.LAUNCHER_FILES_BUCKET_SECRET_ACCESS_KEY }}
AWS_BUCKET: ${{ secrets.LAUNCHER_FILES_BUCKET_NAME }}
Expand Down Expand Up @@ -116,3 +133,18 @@ jobs:
done

aws s3 cp updates.json "s3://${AWS_BUCKET}"

- name: 🏷️ Create GitHub release
env:
GH_TOKEN: ${{ github.token }}
run: |
VERSION="${VERSION_TAG#v}"

gh release create "$VERSION_TAG" \
--title "Modrinth App ${VERSION}" \
--notes "${{ steps.changelog.outputs.body }}" \
"${WINDOWS_X64_BUNDLE_ARTIFACT_NAME}/release/bundle/nsis/Modrinth App_${VERSION}_x64-setup.exe" \
"${MACOS_UNIVERSAL_BUNDLE_ARTIFACT_NAME}/universal-apple-darwin/release/bundle/dmg/Modrinth App_${VERSION}_universal.dmg" \
"${LINUX_X64_BUNDLE_ARTIFACT_NAME}/release/bundle/appimage/Modrinth App_${VERSION}_amd64.AppImage" \
"${LINUX_X64_BUNDLE_ARTIFACT_NAME}/release/bundle/deb/Modrinth App_${VERSION}_amd64.deb" \
"${LINUX_X64_BUNDLE_ARTIFACT_NAME}/release/bundle/rpm/Modrinth App-${VERSION}-1.x86_64.rpm"
8 changes: 2 additions & 6 deletions apps/frontend/src/pages/news/changelog/[product]/[date].vue
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
<script setup lang="ts">
import { ChevronLeftIcon } from '@modrinth/assets'
import { getChangelog } from '@modrinth/blog'
import { ChangelogEntry, Timeline } from '@modrinth/ui'
import { getChangelog } from '@modrinth/utils'

const route = useRoute()

const changelogEntry = computed(() =>
route.params.date
? getChangelog().find((x) => {
if (x.product === route.params.product) {
console.log('Found matching product!')

if (x.version && x.version === route.params.date) {
console.log('Found matching version!')
return x
} else if (x.date.unix() === Number(route.params.date as string)) {
console.log('Found matching date!')
return x
}
}
Expand All @@ -27,7 +23,7 @@ const changelogEntry = computed(() =>
const isFirst = computed(() => changelogEntry.value?.date === getChangelog()[0].date)

if (!changelogEntry.value) {
createError({ statusCode: 404, statusMessage: 'Version not found' })
throw createError({ statusCode: 404, statusMessage: 'Version not found' })
}
</script>

Expand Down
12 changes: 3 additions & 9 deletions apps/frontend/src/pages/news/changelog/index.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
<script setup lang="ts">
import { getChangelog, type Product } from '@modrinth/blog'
import { ChangelogEntry } from '@modrinth/ui'
import Timeline from '@modrinth/ui/src/components/base/Timeline.vue'
import { getChangelog, type Product } from '@modrinth/utils'

import NavTabs from '~/components/ui/NavTabs.vue'

const route = useRoute()
const router = useRouter()

const filter = ref<Product | undefined>(undefined)
const allChangelogEntries = ref(getChangelog())

function updateFilter() {
if (route.query.filter) {
let value = route.query.filter
if (route.query.filter === 'servers') {
router.push({ query: { ...route.query, filter: 'hosting' } })
value = 'hosting'
}
filter.value = value as Product
filter.value = route.query.filter as Product
} else {
filter.value = undefined
}
Expand All @@ -44,7 +38,7 @@ const changelogEntries = computed(() =>
href: '',
},
{
label: 'Website',
label: 'Platform',
href: 'web',
},
{
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"scripts": "node scripts/run.mjs"
},
"devDependencies": {
"@clack/prompts": "^1.0.0",
"@modrinth/tooling-config": "workspace:*",
"@types/node": "^20.1.0",
"@vue/compiler-dom": "^3.5.26",
Expand All @@ -34,7 +35,8 @@
"if-ci": "^3.0.0",
"prettier": "^3.3.2",
"turbo": "^2.5.4",
"vue": "^3.5.13"
"vue": "^3.5.13",
"yaml": "^2.8.2"
},
"packageManager": "pnpm@9.15.0",
"pnpm": {
Expand Down
4 changes: 2 additions & 2 deletions packages/assets/generated-icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

import type { FunctionalComponent, SVGAttributes } from 'vue'

export type IconComponent = FunctionalComponent<SVGAttributes>

import _AffiliateIcon from './icons/affiliate.svg?component'
import _AlignLeftIcon from './icons/align-left.svg?component'
import _ArchiveIcon from './icons/archive.svg?component'
Expand Down Expand Up @@ -327,6 +325,8 @@ import _XCircleIcon from './icons/x-circle.svg?component'
import _ZoomInIcon from './icons/zoom-in.svg?component'
import _ZoomOutIcon from './icons/zoom-out.svg?component'

export type IconComponent = FunctionalComponent<SVGAttributes>

export const AffiliateIcon = _AffiliateIcon
export const AlignLeftIcon = _AlignLeftIcon
export const ArchiveIcon = _ArchiveIcon
Expand Down
2 changes: 1 addition & 1 deletion packages/utils/changelog.ts → packages/blog/changelog.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import dayjs from 'dayjs'

export type Product = 'web' | 'hosting' | 'api' | 'app'
export type Product = 'web' | 'hosting' | 'app'

export type VersionEntry = {
date: dayjs.Dayjs
Expand Down
1 change: 1 addition & 0 deletions packages/blog/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './changelog'
export { articles } from './compiled'
1 change: 1 addition & 0 deletions packages/blog/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
},
"dependencies": {
"@modrinth/utils": "workspace:*",
"dayjs": "^1.11.10",
"glob": "^10.2.7",
"gray-matter": "^4.0.3",
"html-minifier-terser": "^7.2.0",
Expand Down
1 change: 1 addition & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"@codemirror/view": "^6.22.1",
"@modrinth/api-client": "workspace:*",
"@modrinth/assets": "workspace:*",
"@modrinth/blog": "workspace:*",
"@modrinth/utils": "workspace:*",
"@tanstack/vue-query": "^5.90.7",
"@tresjs/cientos": "^4.3.0",
Expand Down
8 changes: 2 additions & 6 deletions packages/ui/src/components/changelog/ChangelogEntry.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@
</template>

<script setup lang="ts">
import type { VersionEntry } from '@modrinth/blog/changelog'
import { renderHighlightedString } from '@modrinth/utils'
import type { VersionEntry } from '@modrinth/utils/changelog'
import dayjs from 'dayjs'
import { computed, ref } from 'vue'

Expand Down Expand Up @@ -80,7 +80,7 @@ const versionName = computed(() => props.entry.version ?? longDate.value)
const messages = defineMessages({
web: {
id: 'changelog.product.web',
defaultMessage: 'Website',
defaultMessage: 'Platform',
},
hosting: {
id: 'changelog.product.hosting',
Expand All @@ -90,10 +90,6 @@ const messages = defineMessages({
id: 'changelog.product.app',
defaultMessage: 'App',
},
api: {
id: 'changelog.product.api',
defaultMessage: 'API',
},
justNow: {
id: 'changelog.justNow',
defaultMessage: 'Just now',
Expand Down
5 changes: 1 addition & 4 deletions packages/ui/src/locales/en-US/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,17 +155,14 @@
"changelog.justNow": {
"defaultMessage": "Just now"
},
"changelog.product.api": {
"defaultMessage": "API"
},
"changelog.product.app": {
"defaultMessage": "App"
},
"changelog.product.hosting": {
"defaultMessage": "Hosting"
},
"changelog.product.web": {
"defaultMessage": "Website"
"defaultMessage": "Platform"
},
"collections.label.private": {
"defaultMessage": "Private"
Expand Down
1 change: 0 additions & 1 deletion packages/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export * from './billing'
export * from './changelog'
export * from './highlightjs'
export * from './licenses'
export * from './parse'
Expand Down
Loading