feat: use GitHub actions for build and release

This commit is contained in:
kolaente
2025-03-26 16:23:06 +01:00
parent 03ca85aaf1
commit 34d6023248
9 changed files with 787 additions and 106 deletions

23
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
name: ci
on:
pull_request:
push:
tags:
- v*
branches:
- main
jobs:
test:
name: Test
uses: ./.github/workflows/test.yml
secrets: inherit
release:
name: Release
if: ${{ github.ref_type == 'tag' || github.ref_name == 'main' }}
uses: ./.github/workflows/release.yml
needs:
- test
secrets: inherit

30
.github/workflows/crowdin.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Crowdin Sync
on:
schedule:
- cron: '0 0 * * *'
jobs:
synchronize-with-crowdin:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: crowdin action
uses: crowdin/github-action@v2
with:
crowdin_branch_name: main
dryrun_action: true
upload_sources: true
download_translations: true
export_only_approved: true
push_translations: true
localization_branch_name: main
create_pull_request: false
commit_message: 'chore(i18n): update translations via Crowdin'
env:
GITHUB_TOKEN: ${{ secrets.CROWDIN_GH_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}

View File

@@ -1,23 +0,0 @@
name: 'Repo Lockdown'
on:
pull_request_target:
types: opened
permissions:
issues: write
pull-requests: write
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/repo-lockdown@v4
with:
pr-comment: 'Hi! Thank you for your contribution.
This repo is only a mirror and unfortunately we can''t accept PRs made here. Please re-submit your changes to [our Gitea instance](https://kolaente.dev/vikunja/vikunja/pulls).
Also check out the [contribution guidelines](https://vikunja.io/docs/development/#pull-requests).
Thank you for your understanding.'

View File

@@ -1,11 +1,37 @@
name: release
name: Release
on:
push:
branches:
- main
workflow_call:
jobs:
mage:
runs-on: ubuntu-latest
name: prepare-mage
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: stable
- name: Cache Mage
id: cache-mage
uses: actions/cache@v4
with:
key: ${{ runner.os }}-build-mage-${{ hashFiles('magefile.go') }}
path: |
./mage-static
- name: Compile Mage
if: ${{ steps.cache-mage.outputs.cache-hit != 'true' }}
uses: magefile/mage-action@v3
with:
version: latest
args: -compile ./mage-static
- name: Store Mage Binary
uses: actions/upload-artifact@v4
with:
name: mage_bin
path: ./mage-static
docker:
runs-on: ubuntu-latest
steps:
@@ -15,22 +41,220 @@ jobs:
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
- name: Docker meta version
if: ${{ github.ref_type == 'tag' }}
id: meta
uses: docker/metadata-action@v5
with:
images: |
vikunja/vikunja
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest
- name: Build and push unstable
if: ${{ github.ref_type != 'tag' }}
uses: docker/build-push-action@v6
with:
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8
push: true
tags: ghcr.io/go-vikunja/vikunja:unstable
tags: vikunja/vikunja:unstable
build-args: |
RELEASE_VERSION=${{ steps.ghd.outputs.describe }}
- name: Build and push version
if: ${{ github.ref_type == 'tag' }}
uses: docker/build-push-action@v6
with:
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
RELEASE_VERSION=${{ steps.ghd.outputs.describe }}
frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
package_json_file: frontend/package.json
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
cache-dependency-path: frontend/pnpm-lock.yaml
- name: Install dependencies
working-directory: frontend
run: |
pnpm install
pnpm build
- name: Store frontend dist
uses: actions/upload-artifact@v4
with:
name: frontend_dist
path: ./frontend/dist/**/*
binaries:
runs-on: ubuntu-latest
needs:
- mage
- frontend
steps:
- uses: actions/checkout@v4
- name: Git describe
id: ghd
uses: proudust/gh-describe@v2
- uses: actions/setup-go@v5
with:
go-version: stable
- name: Download Mage Binary
uses: actions/download-artifact@v4
with:
name: mage_bin
- name: get frontend
uses: actions/download-artifact@v4
with:
name: frontend_dist
path: frontend/dist
- run: chmod +x ./mage-static
- name: install upx
run: |
wget https://github.com/upx/upx/releases/download/v5.0.0/upx-5.0.0-amd64_linux.tar.xz
echo 'b32abf118d721358a50f1aa60eacdbf3298df379c431c3a86f139173ab8289a1 upx-5.0.0-amd64_linux.tar.xz' > upx-5.0.0-amd64_linux.tar.xz.sha256
sha256sum -c upx-5.0.0-amd64_linux.tar.xz.sha256
tar xf upx-5.0.0-amd64_linux.tar.xz
mv upx-5.0.0-amd64_linux/upx /usr/local/bin
- name: GPG setup
uses: kolaente/action-gpg@main
with:
gpg-passphrase: "${{ secrets.RELEASE_GPG_PASSPHRASE }}"
gpg-sign-key: "${{ secrets.RELEASE_GPG_SIGN_KEY }}"
- name: build and release
env:
RELEASE_VERSION: ${{ steps.ghd.outputs.describe }}
XGO_OUT_NAME: vikunja-${{ github.ref_type == 'tag' && steps.ghd.outputs.describe || 'unstable' }}
run: |
export PATH=$PATH:$GOPATH/bin
./mage-static release
- name: sign
run: |
ls -hal dist/zip/*
for file in dist/zip/*; do
gpg -v --default-key 7D061A4AA61436B40713D42EFF054DACD908493A -b --batch --yes --passphrase "${{ secrets.RELEASE_GPG_PASSPHRASE }}" --pinentry-mode loopback --sign "$file"
done
- name: Upload
uses: kolaente/s3-action@v1.0.1
with:
s3-access-key-id: ${{ secrets.HETZNER_S3_ACCESS_KEY }}
s3-secret-access-key: ${{ secrets.HETZNER_S3_SECRET_KEY }}
s3-endpoint: 'https://fsn1.your-objectstorage.com'
s3-bucket: 'vikunja'
s3-region: 'fsn1'
target-path: /vikunja/${{ github.ref_type == 'tag' && steps.ghd.outputs.describe || 'unstable' }}
files: 'dist/zip/*'
strip-path-prefix: dist/zip/
- name: Store Binaries
uses: actions/upload-artifact@v4
with:
name: vikunja_bins
path: ./dist/binaries/*
os-package:
runs-on: ubuntu-latest
needs:
- binaries
strategy:
matrix:
package:
- rpm
- deb
- apk
- archlinux
steps:
- uses: actions/checkout@v4
- name: Download Vikunja Binary
uses: actions/download-artifact@v4
with:
name: vikunja_bins
pattern: vikunja-*-linux-amd64
- name: Git describe
id: ghd
uses: proudust/gh-describe@v2
- name: Download Mage Binary
uses: actions/download-artifact@v4
with:
name: mage_bin
- name: Prepare
env:
RELEASE_VERSION: ${{ steps.ghd.outputs.describe }}
run: |
chmod +x ./mage-static
./mage-static release:prepare-nfpm-config
mkdir -p ./dist/os-packages
mv ./vikunja-*-linux-amd64 ./vikunja
chmod +x ./vikunja
- name: Create package
id: nfpm
uses: kolaente/action-gh-nfpm@master
with:
packager: ${{ matrix.package }}
target: ./dist/os-packages/vikunja-${{ github.ref_type == 'tag' && steps.ghd.outputs.describe || 'unstable' }}-x86_64.${{ matrix.package }}
config: ./nfpm.yaml
- name: Upload
uses: kolaente/s3-action@v1.0.1
with:
s3-access-key-id: ${{ secrets.HETZNER_S3_ACCESS_KEY }}
s3-secret-access-key: ${{ secrets.HETZNER_S3_SECRET_KEY }}
s3-endpoint: 'https://fsn1.your-objectstorage.com'
s3-bucket: 'vikunja'
s3-region: 'fsn1'
target-path: /vikunja/${{ github.ref_type == 'tag' && steps.ghd.outputs.describe || 'unstable' }}
files: 'dist/os-packages/*'
strip-path-prefix: dist/os-packages/
config-yaml:
runs-on: ubuntu-latest
needs:
- mage
steps:
- uses: actions/checkout@v4
- name: Git describe
id: ghd
uses: proudust/gh-describe@v2
- name: Download Mage Binary
uses: actions/download-artifact@v4
with:
name: mage_bin
- name: generate
run: |
chmod +x ./mage-static
./mage-static generate:config-yaml 1
- name: Upload to S3
uses: kolaente/s3-action@v1.0.1
with:
s3-access-key-id: ${{ secrets.HETZNER_S3_ACCESS_KEY }}
s3-secret-access-key: ${{ secrets.HETZNER_S3_SECRET_KEY }}
s3-endpoint: 'https://fsn1.your-objectstorage.com'
s3-bucket: 'vikunja'
s3-region: 'fsn1'
target-path: /vikunja/${{ github.ref_type == 'tag' && steps.ghd.outputs.describe || 'unstable' }}
files: 'config.yml.sample'
desktop:
needs:
- frontend
strategy:
matrix:
os:
@@ -40,7 +264,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Git describe
id: ghd
uses: proudust/gh-describe@v2
@@ -57,11 +281,15 @@ jobs:
- name: Install Linux dependencies
if: ${{ runner.os == 'Linux' }}
run: sudo apt-get install --no-install-recommends -y libopenjp2-tools rpm libarchive-tools
- name: get frontend
uses: actions/download-artifact@v4
with:
name: frontend_dist
path: frontend/dist
- name: Build desktop app
working-directory: desktop
run: |
pnpm install --fetch-timeout 100000
# TODO use the built output from a previous frontend build step
node build.js "${{ steps.ghd.outputs.describe }}" ${{ github.ref_type == 'tag' }}
- name: Upload to S3
uses: kolaente/s3-action@v1.0.1
@@ -70,8 +298,48 @@ jobs:
s3-secret-access-key: ${{ secrets.HETZNER_S3_SECRET_KEY }}
s3-endpoint: 'https://fsn1.your-objectstorage.com'
s3-bucket: 'vikunja'
s3-region: 'fsn1'
files: 'desktop/dist/Vikunja*'
target-path: /desktop/${{ github.ref_type == 'tag' && steps.ghd.outputs.describe || 'unstable' }}
s3-region: 'fsn1'
strip-path-prefix: desktop/dist/
exclude: 'desktop/dist/*.blockmap'
generate-swagger-docs:
runs-on: ubuntu-latest
permissions:
contents: write
needs:
- mage
steps:
- uses: actions/checkout@v4
- name: Download Mage Binary
uses: actions/download-artifact@v4
with:
name: mage_bin
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: stable
- name: generate
run: |
export PATH=$PATH:$GOPATH/bin
go install github.com/swaggo/swag/cmd/swag
chmod +x ./mage-static
./mage-static generate:swagger-docs
- name: Check for changes
id: check_changes
run: |
git diff --quiet
echo "changes_exist=$?" >> "$GITHUB_OUTPUT"
- name: Commit files
if: steps.check_changes.outputs.changes_exist != '0'
run: |
git config --local user.email "frederik@vikunja.io"
git config --local user.name "Frederick [Bot]"
git commit -am "[skip ci] Updated swagger docs"
- name: Push changes
if: steps.check_changes.outputs.changes_exist != '0'
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.ref }}

344
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,344 @@
name: Test
on:
workflow_call:
jobs:
mage:
runs-on: ubuntu-latest
name: prepare-mage
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: stable
- name: Cache Mage
id: cache-mage
uses: actions/cache@v4
with:
key: ${{ runner.os }}-build-mage-${{ hashFiles('magefile.go') }}
path: |
./mage-static
- name: Compile Mage
if: ${{ steps.cache-mage.outputs.cache-hit != 'true' }}
uses: magefile/mage-action@v3
with:
version: latest
args: -compile ./mage-static
- name: Store Mage Binary
uses: actions/upload-artifact@v4
with:
name: mage_bin
path: ./mage-static
api-build:
runs-on: ubuntu-latest
needs: mage
steps:
- uses: actions/checkout@v4
- name: Download Mage Binary
uses: actions/download-artifact@v4
with:
name: mage_bin
- name: Git describe
id: ghd
uses: proudust/gh-describe@v2
- name: Build
env:
RELEASE_VERSION: ${{ steps.ghd.outputs.describe }}
run: |
mkdir -p frontend/dist
touch frontend/dist/index.html
chmod +x ./mage-static
./mage-static build
- name: Store Vikunja Binary
uses: actions/upload-artifact@v4
with:
name: vikunja_bin
path: ./vikunja
api-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: stable
- name: prepare frontend files
run: |
mkdir -p frontend/dist
touch frontend/dist/index.html
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v1.64.5
api-check-translations:
runs-on: ubuntu-latest
needs: mage
steps:
- uses: actions/checkout@v4
- name: Download Mage Binary
uses: actions/download-artifact@v4
with:
name: mage_bin
- name: Check
run: |
chmod +x ./mage-static
./mage-static check:translations
test-migration-smoke:
runs-on: ubuntu-latest
needs:
- api-build
strategy:
matrix:
db:
- sqlite
- postgres
- mysql
services:
migration-smoke-db-mysql:
image: mariadb:11
env:
MYSQL_ROOT_PASSWORD: vikunjatest
MYSQL_DATABASE: vikunjatest
ports:
- 3307:3306
migration-smoke-db-postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: vikunjatest
POSTGRES_DB: vikunjatest
ports:
- 5433:5432
steps:
- name: Download Unstable
run: |
wget https://dl.vikunja.io/api/unstable/vikunja-unstable-linux-amd64-full.zip -q -O vikunja-latest.zip
unzip vikunja-latest.zip vikunja-unstable-linux-amd64
- name: Download Vikunja Binary
uses: actions/download-artifact@v4
with:
name: vikunja_bin
- name: run migration
env:
VIKUNJA_DATABASE_TYPE: ${{ matrix.db }}
VIKUNJA_DATABASE_PATH: ./vikunja-migration-test.db
VIKUNJA_DATABASE_USER: ${{ matrix.db == 'postgres' && 'postgres' || 'root' }}
VIKUNJA_DATABASE_PASSWORD: vikunjatest
VIKUNJA_DATABASE_DATABASE: vikunjatest
VIKUNJA_DATABASE_SSLMODE: disable
VIKUNJA_DATABASE_PORT: ${{ matrix.db == 'postgres' && 5433 || 3307 }}
VIKUNJA_LOG_DATABASE: stdout
VIKUNJA_LOG_DATABASELEVEL: debug
run: |
./vikunja-unstable-linux-amd64 migrate
# Run the migrations from the binary built in the step before
chmod +x vikunja
./vikunja migrate
test-api:
runs-on: ubuntu-latest
needs:
- mage
strategy:
matrix:
db:
- sqlite-in-memory
- sqlite
- postgres
- mysql
test:
- unit
- integration
services:
db-mysql:
image: mariadb:11
env:
MYSQL_ROOT_PASSWORD: vikunjatest
MYSQL_DATABASE: vikunjatest
ports:
- 3306:3306
db-postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: vikunjatest
POSTGRES_DB: vikunjatest
ports:
- 5432:5432
test-ldap:
image: gitea/test-openldap
ports:
- 389:389
steps:
- uses: actions/checkout@v4
- name: Download Mage Binary
uses: actions/download-artifact@v4
with:
name: mage_bin
- name: test
env:
VIKUNJA_TESTS_USE_CONFIG: ${{ matrix.db != 'sqlite-in-memory' && 1 || 0 }}
VIKUNJA_DATABASE_TYPE: ${{ matrix.db }}
VIKUNJA_DATABASE_USER: ${{ matrix.db == 'postgres' && 'postgres' || 'root' }}
VIKUNJA_DATABASE_PASSWORD: vikunjatest
VIKUNJA_DATABASE_DATABASE: vikunjatest
VIKUNJA_DATABASE_SSLMODE: disable
VIKUNJA_AUTH_LDAP_ENABLED: 1
VIKUNJA_AUTH_LDAP_HOST: localhost
VIKUNJA_AUTH_LDAP_USETLS: 0
VIKUNJA_AUTH_LDAP_BASEDN: dc=planetexpress,dc=com
VIKUNJA_AUTH_LDAP_BINDDN: uid=gitea,ou=service,dc=planetexpress,dc=com
VIKUNJA_AUTH_LDAP_BINDPASSWORD: password
VIKUNJA_AUTH_LDAP_USERFILTER: '(&(objectclass=inetorgperson)(uid=%s))'
run: |
mkdir -p frontend/dist
touch frontend/dist/index.html
chmod +x mage-static
./mage-static test:${{ matrix.test }}
frontend-dependencies:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
package_json_file: frontend/package.json
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
cache-dependency-path: frontend/pnpm-lock.yaml
- name: Install dependencies
run: |
cd frontend
pnpm install
frontend-lint:
runs-on: ubuntu-latest
needs:
- frontend-dependencies
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
package_json_file: frontend/package.json
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
cache-dependency-path: frontend/pnpm-lock.yaml
- name: Lint
run: |
cd frontend
pnpm install
pnpm lint
frontend-typecheck:
runs-on: ubuntu-latest
needs:
- frontend-dependencies
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
package_json_file: frontend/package.json
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
cache-dependency-path: frontend/pnpm-lock.yaml
- name: Typecheck
continue-on-error: true
run: |
cd frontend
pnpm install
pnpm typecheck
test-frontend-unit:
runs-on: ubuntu-latest
needs:
- frontend-dependencies
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
package_json_file: frontend/package.json
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
cache-dependency-path: frontend/pnpm-lock.yaml
- name: Run unit tests
run: |
cd frontend
pnpm install
pnpm test:unit
test-frontend-e2e:
runs-on: ubuntu-latest
needs:
- frontend-dependencies
- api-build
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
package_json_file: frontend/package.json
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
cache-dependency-path: frontend/pnpm-lock.yaml
- name: Download Vikunja Binary
uses: actions/download-artifact@v4
with:
name: vikunja_bin
- name: Build frontend for test
run: |
cd frontend
pnpm install
pnpm cypress install
pnpm build:test
- name: Run api
env:
VIKUNJA_SERVICE_TESTINGTOKEN: averyLongSecretToSe33dtheDB
VIKUNJA_LOG_LEVEL: DEBUG
VIKUNJA_CORS_ENABLE: 1
VIKUNJA_DATABASE_PATH: memory
VIKUNJA_DATABASE_TYPE: sqlite
run: |
chmod +x ./vikunja
./vikunja &
- uses: cypress-io/github-action@v6
with:
working-directory: frontend
browser: chrome
record: true
start: |
pnpm preview:test
wait-on: http://127.0.0.1:4173,http://127.0.0.1:3456/api/v1/info
wait-on-timeout: 10
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
CYPRESS_API_URL: http://127.0.0.1:3456/api/v1
CYPRESS_TEST_SECRET: averyLongSecretToSe33dtheDB
CYPRESS_DEFAULT_COMMAND_TIMEOUT: 60000

21
crowdin.yml Normal file
View File

@@ -0,0 +1,21 @@
"project_id": "462614"
"api_token_env": "CROWDIN_PERSONAL_TOKEN"
"base_path": "."
"base_url": "https://api.crowdin.com"
"preserve_hierarchy": true
files: [
{
"source": "pkg/i18n/lang/en.json",
"translation": "pkg/i18n/lang/%locale%.json",
"dest": "en-api.json",
"type": "json",
},
{
"source": "frontend/src/i18n/lang/en.json",
"translation": "frontend/src/i18n/lang/%locale%.json",
"dest": "en.json",
"type": "json",
},
]

View File

@@ -16,33 +16,30 @@
const fs = require('fs')
const path = require('path')
const https = require('https')
const {execSync} = require('child_process')
const unzipper = require('unzipper')
// Helper function to download a file
async function downloadFile(url, dest) {
return new Promise((resolve, reject) => {
const file = fs.createWriteStream(dest)
https.get(url, (response) => {
if (response.statusCode !== 200) {
return reject(new Error(`Failed to download file: ${response.statusCode}`))
}
response.pipe(file)
file.on('finish', () => {
file.close(resolve)
})
}).on('error', (err) => {
fs.unlink(dest, () => reject(err))
})
})
}
// Helper function to copy directory recursively
async function copyDir(src, dest) {
// Create destination directory if it doesn't exist
if (!fs.existsSync(dest)) {
await fs.promises.mkdir(dest, { recursive: true })
}
// Helper function to unzip a file to a directory
async function unzipFile(zipPath, destDir) {
return fs.createReadStream(zipPath)
.pipe(unzipper.Extract({path: destDir}))
.promise()
// Get all files in source directory
const entries = await fs.promises.readdir(src, { withFileTypes: true })
for (const entry of entries) {
const srcPath = path.join(src, entry.name)
const destPath = path.join(dest, entry.name)
if (entry.isDirectory()) {
// Recursively copy subdirectories
await copyDir(srcPath, destPath)
} else {
// Copy files
await fs.promises.copyFile(srcPath, destPath)
}
}
}
// Helper function to replace text in a file
@@ -78,8 +75,7 @@ async function main() {
const versionPlaceholder = args[0]
const renameDistFiles = args[1] || false
const frontendZipUrl = 'https://dl.vikunja.io/frontend/vikunja-frontend-unstable.zip'
const zipFilePath = path.resolve(__dirname, 'vikunja-frontend-unstable.zip')
const frontendSourceDir = path.resolve(__dirname, '../frontend/dist')
const frontendDir = path.resolve(__dirname, 'frontend')
const indexFilePath = path.join(frontendDir, 'index.html')
const packageJsonPath = path.join(__dirname, 'package.json')
@@ -87,16 +83,19 @@ async function main() {
console.log(`Building version ${versionPlaceholder}`)
try {
console.log('Step 1: Downloading frontend zip...')
await downloadFile(frontendZipUrl, zipFilePath)
console.log('Step 1: Copying frontend files...')
if (fs.existsSync(frontendDir)) {
console.log('Removing existing frontend directory...')
await fs.promises.rm(frontendDir, { recursive: true, force: true })
}
await fs.promises.mkdir(frontendDir, { recursive: true })
await copyDir(frontendSourceDir, frontendDir)
console.log('Step 2: Unzipping frontend package...')
await unzipFile(zipFilePath, frontendDir)
console.log('Step 3: Modifying index.html...')
console.log('Step 2: Modifying index.html...')
await replaceTextInFile(indexFilePath, /\/api\/v1/g, '')
console.log('Step 4: Updating version in package.json...')
console.log('Step 3: Updating version in package.json...')
await replaceTextInFile(packageJsonPath, /\${version}/g, versionPlaceholder)
await replaceTextInFile(
packageJsonPath,
@@ -104,11 +103,11 @@ async function main() {
`"version": "${versionPlaceholder}"`,
)
console.log('Step 5: Installing dependencies and building...')
console.log('Step 4: Installing dependencies and building...')
execSync('pnpm dist', {stdio: 'inherit'})
if (renameDistFiles) {
console.log('Step 6: Renaming release files...')
console.log('Step 5: Renaming release files...')
await renameDistFilesToUnstable(versionPlaceholder)
}
@@ -116,11 +115,6 @@ async function main() {
} catch (err) {
console.error('An error occurred:', err.message)
process.exit(1)
} finally {
// Cleanup the zip file
if (fs.existsSync(zipFilePath)) {
fs.unlinkSync(zipFilePath)
}
}
}

View File

@@ -11,6 +11,7 @@ in {
# General tools
git-cliff
actionlint
crowdin-cli
# API tools
golangci-lint mage
# Desktop

View File

@@ -64,18 +64,19 @@ var (
// Aliases are mage aliases of targets
Aliases = map[string]interface{}{
"build": Build.Build,
"check:got-swag": Check.GotSwag,
"release": Release.Release,
"release:os-package": Release.OsPackage,
"dev:make-migration": Dev.MakeMigration,
"dev:make-event": Dev.MakeEvent,
"dev:make-listener": Dev.MakeListener,
"dev:make-notification": Dev.MakeNotification,
"lint": Check.Golangci,
"lint:fix": Check.GolangciFix,
"generate:config-yaml": Generate.ConfigYAML,
"generate:swagger-docs": Generate.SwaggerDocs,
"build": Build.Build,
"check:got-swag": Check.GotSwag,
"release": Release.Release,
"release:os-package": Release.OsPackage,
"release:prepare-nfpm-config": Release.PrepareNFPMConfig,
"dev:make-migration": Dev.MakeMigration,
"dev:make-event": Dev.MakeEvent,
"dev:make-listener": Dev.MakeListener,
"dev:make-notification": Dev.MakeNotification,
"lint": Check.Golangci,
"lint:fix": Check.GolangciFix,
"generate:config-yaml": Generate.ConfigYAML,
"generate:swagger-docs": Generate.SwaggerDocs,
}
)
@@ -717,13 +718,17 @@ func runXgo(targets string) error {
if strings.HasPrefix(targets, "darwin") {
extraLdflags = ""
}
outName := os.Getenv("XGO_OUT_NAME")
if outName == "" {
outName = Executable + "-" + Version
}
runAndStreamOutput("xgo",
"-dest", RootPath+"/"+DIST+"/binaries",
"-tags", "netgo "+Tags,
"-ldflags", extraLdflags+Ldflags,
"-targets", targets,
"-out", Executable+"-"+Version,
"-out", outName,
RootPath)
if os.Getenv("DRONE_WORKSPACE") != "" {
return filepath.Walk("/build/", func(path string, info os.FileInfo, err error) error {
@@ -790,10 +795,11 @@ func (Release) Compress(ctx context.Context) error {
if !strings.Contains(info.Name(), Executable) {
return nil
}
// No mips or s390x for you today
if strings.Contains(info.Name(), "mips") ||
strings.Contains(info.Name(), "s390x") ||
strings.Contains(info.Name(), "riscv64") { // not supported by upx
strings.Contains(info.Name(), "riscv64") ||
strings.Contains(info.Name(), "darwin") {
// not supported by upx
return nil
}
@@ -917,21 +923,10 @@ func (Release) Reprepro() {
runAndStreamOutput("reprepro_expect", "debian", "includedeb", "buster", RootPath+"/"+DIST+"/os-packages/"+Executable+"_"+strings.ReplaceAll(VersionNumber, "v0", "0")+"_amd64.deb")
}
// Creates deb, rpm and apk packages
func (Release) Packages() error {
// Prepares the nfpm config
func (Release) PrepareNFPMConfig() error {
mg.Deps(initVars)
var err error
binpath := "nfpm"
err = exec.Command(binpath).Run()
if err != nil && strings.Contains(err.Error(), "executable file not found") {
binpath = "/usr/bin/nfpm"
err = exec.Command(binpath).Run()
}
if err != nil && strings.Contains(err.Error(), "executable file not found") {
fmt.Println("Please manually install nfpm by running")
fmt.Println("curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh -s -- -b $(go env GOPATH)/bin")
os.Exit(1)
}
// Because nfpm does not support templating, we replace the values in the config file and restore it after running
nfpmConfigPath := RootPath + "/nfpm.yaml"
@@ -946,18 +941,46 @@ func (Release) Packages() error {
return err
}
generateConfigYAMLFromJSON(DefaultConfigYAMLSamplePath, true)
return nil
}
// Creates deb, rpm and apk packages
func (Release) Packages() error {
mg.Deps(initVars)
var err error
binpath := os.Getenv("NFPM_BIN_PATH")
if binpath == "" {
binpath = "nfpm"
}
err = exec.Command(binpath).Run()
if err != nil && strings.Contains(err.Error(), "executable file not found") {
binpath = "/usr/bin/nfpm"
err = exec.Command(binpath).Run()
}
if err != nil && strings.Contains(err.Error(), "executable file not found") {
fmt.Println("Please manually install nfpm by running")
fmt.Println("curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh -s -- -b $(go env GOPATH)/bin")
os.Exit(1)
}
err = (Release{}).PrepareNFPMConfig()
if err != nil {
return err
}
releasePath := RootPath + "/" + DIST + "/os-packages/"
if err := os.MkdirAll(releasePath, 0755); err != nil {
return err
}
generateConfigYAMLFromJSON(DefaultConfigYAMLSamplePath, true)
runAndStreamOutput(binpath, "pkg", "--packager", "deb", "--target", releasePath)
runAndStreamOutput(binpath, "pkg", "--packager", "rpm", "--target", releasePath)
runAndStreamOutput(binpath, "pkg", "--packager", "apk", "--target", releasePath)
return os.WriteFile(nfpmConfigPath, nfpmconfig, 0)
return nil
}
type Dev mg.Namespace