fix: read tagName if releaseId is provided. fixes incorrect download urls (#332)

* chore: add prettier

* fix: get tag from release if tagName is empty

* use tagName input and fall back to 'latest'

* revert tagname request

* fix link on 'latest' fallback

* starting to feel stupid

* oof

* add note about tagName in readme
This commit is contained in:
Fabian-Lars
2022-12-05 01:39:28 +01:00
committed by GitHub
parent e60a38e362
commit dddfe2eddb
19 changed files with 573 additions and 548 deletions

View File

@@ -2,7 +2,7 @@ name: covector version or publish
on:
push:
branches:
- dev
- dev
jobs:
covector:
@@ -36,7 +36,6 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
branch: release/version-updates
title: Apply Version Updates From Current Changes
commit-message: "apply version updates"
labels: "version updates"
commit-message: 'apply version updates'
labels: 'version updates'
body: ${{ steps.covector.outputs.change }}

View File

@@ -1,4 +1,4 @@
name: "test-action"
name: 'test-action'
on:
workflow_dispatch:
@@ -11,46 +11,46 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- name: setup node
uses: actions/setup-node@v1
with:
node-version: 14
- name: install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf
- name: install example dependencies
run: yarn
working-directory: ./packages/action/__fixtures__/example
- uses: ./
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Updater signature is exposed here to make sure it works in PR's
TAURI_PRIVATE_KEY: dW50cnVzdGVkIGNvbW1lbnQ6IHJzaWduIGVuY3J5cHRlZCBzZWNyZXQga2V5ClJXUlRZMEl5YTBGV3JiTy9lRDZVd3NkL0RoQ1htZmExNDd3RmJaNmRMT1ZGVjczWTBKZ0FBQkFBQUFBQUFBQUFBQUlBQUFBQWdMekUzVkE4K0tWQ1hjeGt1Vkx2QnRUR3pzQjVuV0ZpM2czWXNkRm9hVUxrVnB6TUN3K1NheHJMREhQbUVWVFZRK3NIL1VsMDBHNW5ET1EzQno0UStSb21nRW4vZlpTaXIwZFh5ZmRlL1lSN0dKcHdyOUVPclVvdzFhVkxDVnZrbHM2T1o4Tk1NWEU9Cg==
with:
projectPath: ./packages/action/__fixtures__/example-with-tauri
tagName: example-with-tauri-v__VERSION__
releaseName: "Release example with preconfigured Tauri app v__VERSION__"
releaseBody: "See the assets to download this version and install."
releaseDraft: true
prerelease: false
- uses: ./
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Updater signature is exposed here to make sure it works in PR's
TAURI_PRIVATE_KEY: dW50cnVzdGVkIGNvbW1lbnQ6IHJzaWduIGVuY3J5cHRlZCBzZWNyZXQga2V5ClJXUlRZMEl5YTBGV3JiTy9lRDZVd3NkL0RoQ1htZmExNDd3RmJaNmRMT1ZGVjczWTBKZ0FBQkFBQUFBQUFBQUFBQUlBQUFBQWdMekUzVkE4K0tWQ1hjeGt1Vkx2QnRUR3pzQjVuV0ZpM2czWXNkRm9hVUxrVnB6TUN3K1NheHJMREhQbUVWVFZRK3NIL1VsMDBHNW5ET1EzQno0UStSb21nRW4vZlpTaXIwZFh5ZmRlL1lSN0dKcHdyOUVPclVvdzFhVkxDVnZrbHM2T1o4Tk1NWEU9Cg==
with:
projectPath: ./packages/action/__fixtures__/example
bundleIdentifier: com.tauri.actiontest
# iconPath: ./icon.png
tagName: example-v__VERSION__
releaseName: "Release example app v__VERSION__"
releaseBody: "See the assets to download this version and install."
releaseDraft: true
prerelease: false
- uses: actions/checkout@v2
- name: setup node
uses: actions/setup-node@v1
with:
node-version: 14
- name: install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf
- name: install example dependencies
run: yarn
working-directory: ./packages/action/__fixtures__/example
- uses: ./
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Updater signature is exposed here to make sure it works in PR's
TAURI_PRIVATE_KEY: dW50cnVzdGVkIGNvbW1lbnQ6IHJzaWduIGVuY3J5cHRlZCBzZWNyZXQga2V5ClJXUlRZMEl5YTBGV3JiTy9lRDZVd3NkL0RoQ1htZmExNDd3RmJaNmRMT1ZGVjczWTBKZ0FBQkFBQUFBQUFBQUFBQUlBQUFBQWdMekUzVkE4K0tWQ1hjeGt1Vkx2QnRUR3pzQjVuV0ZpM2czWXNkRm9hVUxrVnB6TUN3K1NheHJMREhQbUVWVFZRK3NIL1VsMDBHNW5ET1EzQno0UStSb21nRW4vZlpTaXIwZFh5ZmRlL1lSN0dKcHdyOUVPclVvdzFhVkxDVnZrbHM2T1o4Tk1NWEU9Cg==
with:
projectPath: ./packages/action/__fixtures__/example-with-tauri
tagName: example-with-tauri-v__VERSION__
releaseName: 'Release example with preconfigured Tauri app v__VERSION__'
releaseBody: 'See the assets to download this version and install.'
releaseDraft: true
prerelease: false
- uses: ./
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Updater signature is exposed here to make sure it works in PR's
TAURI_PRIVATE_KEY: dW50cnVzdGVkIGNvbW1lbnQ6IHJzaWduIGVuY3J5cHRlZCBzZWNyZXQga2V5ClJXUlRZMEl5YTBGV3JiTy9lRDZVd3NkL0RoQ1htZmExNDd3RmJaNmRMT1ZGVjczWTBKZ0FBQkFBQUFBQUFBQUFBQUlBQUFBQWdMekUzVkE4K0tWQ1hjeGt1Vkx2QnRUR3pzQjVuV0ZpM2czWXNkRm9hVUxrVnB6TUN3K1NheHJMREhQbUVWVFZRK3NIL1VsMDBHNW5ET1EzQno0UStSb21nRW4vZlpTaXIwZFh5ZmRlL1lSN0dKcHdyOUVPclVvdzFhVkxDVnZrbHM2T1o4Tk1NWEU9Cg==
with:
projectPath: ./packages/action/__fixtures__/example
bundleIdentifier: com.tauri.actiontest
# iconPath: ./icon.png
tagName: example-v__VERSION__
releaseName: 'Release example app v__VERSION__'
releaseBody: 'See the assets to download this version and install.'
releaseDraft: true
prerelease: false

4
.prettierignore Normal file
View File

@@ -0,0 +1,4 @@
dist/
__fixtures__/
__tests__
node_modules/

3
.prettierrc.json Normal file
View File

@@ -0,0 +1,3 @@
{
"singleQuote": true
}

132
README.md
View File

@@ -10,7 +10,7 @@ This GitHub Action has three main usages: test the build pipeline of your Tauri
## Testing the Build
```yml
name: "test-on-pr"
name: 'test-on-pr'
on: [pull_request]
jobs:
@@ -22,29 +22,29 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- name: setup node
uses: actions/setup-node@v3
with:
node-version: 16
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-20.04'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- name: install app dependencies and build it
run: yarn && yarn build
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v3
- name: setup node
uses: actions/setup-node@v3
with:
node-version: 16
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-20.04'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- name: install app dependencies and build it
run: yarn && yarn build
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
## Creating a release and uploading the Tauri bundles
```yml
name: "publish"
name: 'publish'
on:
push:
branches:
@@ -59,29 +59,29 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- name: setup node
uses: actions/setup-node@v3
with:
node-version: 16
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-20.04'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- name: install app dependencies and build it
run: yarn && yarn build
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tagName: app-v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version
releaseName: "App v__VERSION__"
releaseBody: "See the assets to download this version and install."
releaseDraft: true
prerelease: false
- uses: actions/checkout@v3
- name: setup node
uses: actions/setup-node@v3
with:
node-version: 16
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-20.04'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- name: install app dependencies and build it
run: yarn && yarn build
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tagName: app-v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version
releaseName: 'App v__VERSION__'
releaseBody: 'See the assets to download this version and install.'
releaseDraft: true
prerelease: false
```
## Uploading the artifacts to a release
@@ -119,7 +119,7 @@ jobs:
draft: true,
prerelease: false
})
return data.id
build-tauri:
@@ -131,30 +131,30 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- name: setup node
uses: actions/setup-node@v3
with:
node-version: 16
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-20.04'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- name: install app dependencies and build it
run: yarn && yarn build
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
releaseId: ${{ needs.create-release.outputs.release_id }}
- uses: actions/checkout@v3
- name: setup node
uses: actions/setup-node@v3
with:
node-version: 16
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-20.04'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- name: install app dependencies and build it
run: yarn && yarn build
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
releaseId: ${{ needs.create-release.outputs.release_id }}
publish-release:
runs-on: ubuntu-20.04
needs: [ create-release, build-tauri ]
needs: [create-release, build-tauri]
steps:
- name: publish release
id: publish-release
@@ -180,7 +180,7 @@ jobs:
| `configPath` | false | Path to the tauri.conf.json file if you want a configuration different from the default one | string | tauri.conf.json |
| `distPath` | false | Path to the distributable folder with your index.html and JS/CSS | string | |
| `releaseId` | false | The id of the release to upload artifacts as release assets | string | |
| `tagName` | false | The tag name of the release to create | string | |
| `tagName` | false | The tag name of the release to create or the tag of the release belonging to `releaseId` | string | |
| `releaseName` | false | The name of the release to create | string | |
| `releaseBody` | false | The body of the release to create | string | |
| `releaseDraft` | false | Whether the release to create is a draft or not | bool | false |
@@ -191,7 +191,6 @@ jobs:
| `tauriScript` | false | the script to execute the Tauri CLI | string | `yarn\|npx tauri` |
| `args` | false | Additional arguments to the current build command | string | |
## Outputs
| Name | Description |
@@ -208,3 +207,4 @@ jobs:
- Useful when you need custom build functionality when creating Tauri apps e.g. a `desktop:build` script.
- If you want to add additional arguments to the build command, you can use the `args` option. For example, if you're setting a specific target for your build, you can specify `args: --target your-target-arch`.
- When your app isn't on the root of the repo, use the `projectPath` input.
- If you create the release yourself and provide a `releaseId` but do not set `tagName`, the download url for updater bundles in `latest.json` will point to `releases/latest/download/<bundle>` which can cause issues if your repo contains releases that do not include updater bundles.

View File

@@ -6,6 +6,7 @@
"packages/action"
],
"devDependencies": {
"covector": "0.7.3"
"covector": "0.7.3",
"prettier": "^2.8.0"
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1,28 +1,28 @@
import * as core from '@actions/core'
import { getOctokit, context } from '@actions/github'
import { GitHub } from '@actions/github/lib/utils'
import fs from 'fs'
import * as core from '@actions/core';
import { getOctokit, context } from '@actions/github';
import { GitHub } from '@actions/github/lib/utils';
import fs from 'fs';
interface Release {
id: number
uploadUrl: string
htmlUrl: string
id: number;
uploadUrl: string;
htmlUrl: string;
}
interface GitHubRelease {
id: number
upload_url: string
html_url: string
tag_name: string
id: number;
upload_url: string;
html_url: string;
tag_name: string;
}
function allReleases(
github: InstanceType<typeof GitHub>
): AsyncIterableIterator<{ data: GitHubRelease[] }> {
const params = { per_page: 100, ...context.repo }
const params = { per_page: 100, ...context.repo };
return github.paginate.iterator(
github.rest.repos.listReleases.endpoint.merge(params)
)
);
}
export default async function createRelease(
@@ -34,58 +34,58 @@ export default async function createRelease(
prerelease = true
): Promise<Release> {
if (process.env.GITHUB_TOKEN === undefined) {
throw new Error('GITHUB_TOKEN is required')
throw new Error('GITHUB_TOKEN is required');
}
// Get authenticated GitHub client (Ocktokit): https://github.com/actions/toolkit/tree/master/packages/github#usage
const github = getOctokit(process.env.GITHUB_TOKEN)
const github = getOctokit(process.env.GITHUB_TOKEN);
// Get owner and repo from context of payload that triggered the action
const { owner, repo } = context.repo
const { owner, repo } = context.repo;
const bodyPath = core.getInput('body_path', { required: false })
let bodyFileContent = null
const bodyPath = core.getInput('body_path', { required: false });
let bodyFileContent = null;
if (bodyPath !== '' && !!bodyPath) {
try {
bodyFileContent = fs.readFileSync(bodyPath, { encoding: 'utf8' })
bodyFileContent = fs.readFileSync(bodyPath, { encoding: 'utf8' });
} catch (error) {
core.setFailed(error.message)
core.setFailed(error.message);
}
}
let release: GitHubRelease | null = null
let release: GitHubRelease | null = null;
try {
// you can't get a an existing draft by tag
// so we must find one in the list of all releases
if (draft) {
console.log(`Looking for a draft release with tag ${tagName}...`)
console.log(`Looking for a draft release with tag ${tagName}...`);
for await (const response of allReleases(github)) {
let releaseWithTag = response.data.find(
(release) => release.tag_name === tagName
)
);
if (releaseWithTag) {
release = releaseWithTag
release = releaseWithTag;
console.log(
`Found draft release with tag ${tagName} on the release list.`
)
break
);
break;
}
}
if (!release) {
throw new Error('release not found')
throw new Error('release not found');
}
} else {
const foundRelease = await github.rest.repos.getReleaseByTag({
owner,
repo,
tag: tagName
})
release = foundRelease.data
console.log(`Found release with tag ${tagName}.`)
tag: tagName,
});
release = foundRelease.data;
console.log(`Found release with tag ${tagName}.`);
}
} catch (error) {
if (error.status === 404 || error.message === 'release not found') {
console.log(`Couldn't find release with tag ${tagName}. Creating one.`)
console.log(`Couldn't find release with tag ${tagName}. Creating one.`);
const createdRelease = await github.rest.repos.createRelease({
owner,
repo,
@@ -94,25 +94,25 @@ export default async function createRelease(
body: bodyFileContent || body,
draft,
prerelease,
target_commitish: commitish || context.sha
})
target_commitish: commitish || context.sha,
});
release = createdRelease.data
release = createdRelease.data;
} else {
console.log(
`⚠️ Unexpected error fetching GitHub release for tag ${tagName}: ${error}`
)
throw error
);
throw error;
}
}
if (!release) {
throw new Error('Release not found or created.')
throw new Error('Release not found or created.');
}
return {
id: release.id,
uploadUrl: release.upload_url,
htmlUrl: release.html_url
}
htmlUrl: release.html_url,
};
}

View File

@@ -1,47 +1,50 @@
import { platform } from 'os'
import * as core from '@actions/core'
import { join, resolve, dirname, basename } from 'path'
import { existsSync } from 'fs'
import uploadReleaseAssets from './upload-release-assets'
import uploadVersionJSON from './upload-version-json'
import createRelease from './create-release'
import { platform } from 'os';
import * as core from '@actions/core';
import { join, resolve, dirname, basename } from 'path';
import { existsSync } from 'fs';
import uploadReleaseAssets from './upload-release-assets';
import uploadVersionJSON from './upload-version-json';
import createRelease from './create-release';
import {
getPackageJson,
buildProject,
getInfo,
execCommand
} from '@tauri-apps/action-core'
import type { BuildOptions } from '@tauri-apps/action-core'
import stringArgv from 'string-argv'
execCommand,
} from '@tauri-apps/action-core';
import type { BuildOptions } from '@tauri-apps/action-core';
import stringArgv from 'string-argv';
async function run(): Promise<void> {
try {
const projectPath = resolve(
process.cwd(),
core.getInput('projectPath') || process.argv[2]
)
);
const configPath = join(
projectPath,
core.getInput('configPath') || 'tauri.conf.json'
)
const distPath = core.getInput('distPath')
const iconPath = core.getInput('iconPath')
const includeDebug = core.getBooleanInput('includeDebug')
const tauriScript = core.getInput('tauriScript')
const args = stringArgv(core.getInput('args'))
const bundleIdentifier = core.getInput('bundleIdentifier')
);
const distPath = core.getInput('distPath');
const iconPath = core.getInput('iconPath');
const includeDebug = core.getBooleanInput('includeDebug');
const tauriScript = core.getInput('tauriScript');
const args = stringArgv(core.getInput('args'));
const bundleIdentifier = core.getInput('bundleIdentifier');
let tagName = core.getInput('tagName').replace('refs/tags/', '')
let releaseName = core.getInput('releaseName').replace('refs/tags/', '')
let body = core.getInput('releaseBody')
const draft = core.getBooleanInput('releaseDraft')
const prerelease = core.getBooleanInput('prerelease')
const commitish = core.getInput('releaseCommitish') || null
let tagName = core.getInput('tagName').replace('refs/tags/', '');
let releaseId = Number(core.getInput('releaseId'));
let releaseName = core.getInput('releaseName').replace('refs/tags/', '');
let body = core.getInput('releaseBody');
const draft = core.getBooleanInput('releaseDraft');
const prerelease = core.getBooleanInput('prerelease');
const commitish = core.getInput('releaseCommitish') || null;
if (Boolean(tagName) !== Boolean(releaseName)) {
throw new Error(
'`tag` is required along with `releaseName` when creating a release.'
)
if (!releaseId) {
if (Boolean(tagName) !== Boolean(releaseName)) {
throw new Error(
'`tagName` is required along with `releaseName` when creating a release.'
);
}
}
const options: BuildOptions = {
@@ -50,37 +53,36 @@ async function run(): Promise<void> {
iconPath,
tauriScript,
args,
bundleIdentifier
}
const info = getInfo(projectPath)
const artifacts = await buildProject(projectPath, false, options)
bundleIdentifier,
};
const info = getInfo(projectPath);
const artifacts = await buildProject(projectPath, false, options);
if (includeDebug) {
const debugArtifacts = await buildProject(projectPath, true, options)
artifacts.push(...debugArtifacts)
const debugArtifacts = await buildProject(projectPath, true, options);
artifacts.push(...debugArtifacts);
}
if (artifacts.length === 0) {
throw new Error('No artifacts were found.')
throw new Error('No artifacts were found.');
}
console.log(`Found artifacts:\n${artifacts.map((a) => a.path).join('\n')}`)
console.log(`Found artifacts:\n${artifacts.map((a) => a.path).join('\n')}`);
let releaseId: number
if (tagName) {
const packageJson = getPackageJson(projectPath)
if (tagName && !releaseId) {
const packageJson = getPackageJson(projectPath);
const templates = [
{
key: '__VERSION__',
value: info.version || packageJson.version
}
]
value: info.version || packageJson.version,
},
];
templates.forEach((template) => {
const regex = new RegExp(template.key, 'g')
tagName = tagName.replace(regex, template.value)
releaseName = releaseName.replace(regex, template.value)
body = body.replace(regex, template.value)
})
const regex = new RegExp(template.key, 'g');
tagName = tagName.replace(regex, template.value);
releaseName = releaseName.replace(regex, template.value);
body = body.replace(regex, template.value);
});
const releaseData = await createRelease(
tagName,
@@ -89,18 +91,16 @@ async function run(): Promise<void> {
commitish || undefined,
draft,
prerelease
)
releaseId = releaseData.id
core.setOutput('releaseUploadUrl', releaseData.uploadUrl)
core.setOutput('releaseId', releaseData.id.toString())
core.setOutput('releaseHtmlUrl', releaseData.htmlUrl)
} else {
releaseId = Number(core.getInput('releaseId') || 0)
);
releaseId = releaseData.id;
core.setOutput('releaseUploadUrl', releaseData.uploadUrl);
core.setOutput('releaseId', releaseData.id.toString());
core.setOutput('releaseHtmlUrl', releaseData.htmlUrl);
}
if (releaseId) {
if (platform() === 'darwin') {
let i = 0
let i = 0;
for (const artifact of artifacts) {
// updater provide a .tar.gz, this will prevent duplicate and overwriting of
// signed archive
@@ -113,28 +113,28 @@ async function run(): Promise<void> {
`${artifact.path}.tar.gz`,
'-C',
dirname(artifact.path),
basename(artifact.path)
])
artifact.path += '.tar.gz'
basename(artifact.path),
]);
artifact.path += '.tar.gz';
} else if (artifact.path.endsWith('.app')) {
// we can't upload a directory
artifacts.splice(i, 1)
artifacts.splice(i, 1);
}
i++
i++;
}
}
await uploadReleaseAssets(releaseId, artifacts)
await uploadReleaseAssets(releaseId, artifacts);
await uploadVersionJSON({
version: info.version,
notes: body,
tagName,
releaseId,
artifacts
})
artifacts,
});
}
} catch (error) {
core.setFailed(error.message)
core.setFailed(error.message);
}
}
run()
run();

View File

@@ -1,49 +1,49 @@
import { getOctokit, context } from '@actions/github'
import { Artifact } from '@tauri-apps/action-core'
import fs from 'fs'
import { getAssetName } from './utils'
import { getOctokit, context } from '@actions/github';
import { Artifact } from '@tauri-apps/action-core';
import fs from 'fs';
import { getAssetName } from './utils';
export default async function uploadAssets(
releaseId: number,
assets: Artifact[]
) {
if (process.env.GITHUB_TOKEN === undefined) {
throw new Error('GITHUB_TOKEN is required')
throw new Error('GITHUB_TOKEN is required');
}
const github = getOctokit(process.env.GITHUB_TOKEN)
const github = getOctokit(process.env.GITHUB_TOKEN);
const existingAssets = (
await github.rest.repos.listReleaseAssets({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: releaseId,
per_page: 50
per_page: 50,
})
).data
).data;
// Determine content-length for header to upload asset
const contentLength = (filePath: string) => fs.statSync(filePath).size
const contentLength = (filePath: string) => fs.statSync(filePath).size;
for (const asset of assets) {
const headers = {
'content-type': 'application/zip',
'content-length': contentLength(asset.path)
}
'content-length': contentLength(asset.path),
};
const assetName = getAssetName(asset.path)
const assetName = getAssetName(asset.path);
const existingAsset = existingAssets.find((a) => a.name === assetName)
const existingAsset = existingAssets.find((a) => a.name === assetName);
if (existingAsset) {
console.log(`Deleting existing ${assetName}...`)
console.log(`Deleting existing ${assetName}...`);
await github.rest.repos.deleteReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
asset_id: existingAsset.id
})
asset_id: existingAsset.id,
});
}
console.log(`Uploading ${assetName}...`)
console.log(`Uploading ${assetName}...`);
await github.rest.repos.uploadReleaseAsset({
headers,
@@ -53,7 +53,7 @@ export default async function uploadAssets(
data: fs.readFileSync(asset.path),
owner: context.repo.owner,
repo: context.repo.repo,
release_id: releaseId
})
release_id: releaseId,
});
}
}

View File

@@ -1,47 +1,47 @@
import { getOctokit, context } from '@actions/github'
import { resolve } from 'path'
import { readFileSync, writeFileSync } from 'fs'
import uploadAssets from './upload-release-assets'
import fetch from 'node-fetch'
import { arch, platform } from 'os'
import { getAssetName } from './utils'
import { Artifact } from '@tauri-apps/action-core'
import { getOctokit, context } from '@actions/github';
import { resolve } from 'path';
import { readFileSync, writeFileSync } from 'fs';
import uploadAssets from './upload-release-assets';
import fetch from 'node-fetch';
import { arch, platform } from 'os';
import { getAssetName } from './utils';
import { Artifact } from '@tauri-apps/action-core';
export default async function uploadVersionJSON({
version,
notes,
tagName,
releaseId,
artifacts
artifacts,
}: {
version: string
notes: string
tagName: string
releaseId: number
artifacts: Artifact[]
version: string;
notes: string;
tagName: string;
releaseId: number;
artifacts: Artifact[];
}) {
if (process.env.GITHUB_TOKEN === undefined) {
throw new Error('GITHUB_TOKEN is required')
throw new Error('GITHUB_TOKEN is required');
}
const github = getOctokit(process.env.GITHUB_TOKEN)
const github = getOctokit(process.env.GITHUB_TOKEN);
const versionFilename = 'latest.json'
const versionFile = resolve(process.cwd(), versionFilename)
const versionFilename = 'latest.json';
const versionFile = resolve(process.cwd(), versionFilename);
const versionContent = {
version,
notes,
pub_date: new Date().toISOString(),
platforms: {}
}
platforms: {},
};
const assets = await github.rest.repos.listReleaseAssets({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: releaseId,
per_page: 50
})
const asset = assets.data.find((e) => e.name === versionFilename)
per_page: 50,
});
const asset = assets.data.find((e) => e.name === versionFilename);
if (asset) {
const assetData = (
@@ -52,44 +52,47 @@ export default async function uploadVersionJSON({
repo: context.repo.repo,
asset_id: asset.id,
headers: {
accept: 'application/octet-stream'
}
accept: 'application/octet-stream',
},
}
)
).data as any as ArrayBuffer
).data as any as ArrayBuffer;
versionContent.platforms = JSON.parse(
Buffer.from(assetData).toString()
).platforms
).platforms;
// https://docs.github.com/en/rest/releases/assets#update-a-release-asset
await github.rest.repos.deleteReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: releaseId,
asset_id: asset.id
})
asset_id: asset.id,
});
}
const sigFile = artifacts.find((s) => s.path.endsWith('.sig'))
const assetNames = new Set(artifacts.map((p) => getAssetName(p.path)))
const sigFile = artifacts.find((s) => s.path.endsWith('.sig'));
const assetNames = new Set(artifacts.map((p) => getAssetName(p.path)));
let downloadUrl = assets.data
.filter((e) => assetNames.has(e.name))
.find(
(s) => s.name.endsWith('.tar.gz') || s.name.endsWith('.zip')
)?.browser_download_url
)?.browser_download_url;
// Untagged release downloads won't work after the release was published
downloadUrl = downloadUrl?.replace(
/\/download\/(untagged-[^\/]+)\//,
`/download/${tagName}/`
)
/\/download\/(untagged-[^\/]+)\//,
tagName ? `/download/${tagName}/` : '/latest/download/'
);
let os = platform() as string
if (os === 'win32') os = 'windows'
let os = platform() as string;
if (os === 'win32') {
os = 'windows';
}
if (downloadUrl && sigFile) {
let arch = sigFile.arch
arch =
let arch = sigFile.arch;
arch =
arch === 'amd64' || arch === 'x86_64' || arch === 'x64'
? 'x86_64'
: arch === 'x86' || arch === 'i386'
@@ -98,24 +101,24 @@ export default async function uploadVersionJSON({
? 'armv7'
: arch === 'arm64'
? 'aarch64'
: arch
: arch;
// https://github.com/tauri-apps/tauri/blob/fd125f76d768099dc3d4b2d4114349ffc31ffac9/core/tauri/src/updater/core.rs#L856
versionContent.platforms[`${os}-${arch}`] = {
signature: readFileSync(sigFile.path).toString(),
url: downloadUrl
}
url: downloadUrl,
};
} else {
const missing = downloadUrl
? 'Signature'
: sigFile
? 'Asset'
: 'Asset and signature'
console.warn(`${missing} not found for the updater JSON.`)
: 'Asset and signature';
console.warn(`${missing} not found for the updater JSON.`);
}
writeFileSync(versionFile, JSON.stringify(versionContent, null, 2))
writeFileSync(versionFile, JSON.stringify(versionContent, null, 2));
console.log(`Uploading ${versionFile}...`)
await uploadAssets(releaseId, [{ path: versionFile, arch: '' }])
console.log(`Uploading ${versionFile}...`);
await uploadAssets(releaseId, [{ path: versionFile, arch: '' }]);
}

View File

@@ -10,25 +10,25 @@ const extensions = [
'.deb',
'.msi.zip.sig',
'.msi.zip',
'.msi'
]
'.msi',
];
export function getAssetName(assetPath: string) {
const basename = path.basename(assetPath)
const exts = extensions.filter((s) => basename.includes(s))
const ext = exts[0] || path.extname(assetPath)
const filename = basename.replace(ext, '')
const basename = path.basename(assetPath);
const exts = extensions.filter((s) => basename.includes(s));
const ext = exts[0] || path.extname(assetPath);
const filename = basename.replace(ext, '');
let arch = ''
let arch = '';
if (ext === '.app.tar.gz.sig' || ext === '.app.tar.gz') {
arch = assetPath.includes('universal-apple-darwin')
? '_universal'
: assetPath.includes('aarch64-apple-darwin')
? '_aarch64'
: '_x64'
? '_aarch64'
: '_x64';
}
return assetPath.includes(`${path.sep}debug${path.sep}`)
? `${filename}-debug${arch}${ext}`
: `${filename}${arch}${ext}`
: `${filename}${arch}${ext}`;
}

View File

@@ -1,2 +1,2 @@
import { run } from '../dist/index.js'
run()
import { run } from '../dist/index.js';
run();

View File

@@ -1,43 +1,49 @@
import { join, resolve } from 'path'
import { existsSync } from 'fs'
import { buildProject } from '@tauri-apps/action-core'
import type { BuildOptions } from '@tauri-apps/action-core'
import parseArgs from 'minimist'
import { join, resolve } from 'path';
import { existsSync } from 'fs';
import { buildProject } from '@tauri-apps/action-core';
import type { BuildOptions } from '@tauri-apps/action-core';
import parseArgs from 'minimist';
export async function run(): Promise<void> {
const argv = parseArgs(process.argv.slice(2), {
string: ['project-path', 'config-path', 'dist-path', 'icon-path', 'tauri-script'],
string: [
'project-path',
'config-path',
'dist-path',
'icon-path',
'tauri-script',
],
boolean: ['global-tauri', 'include-debug'],
default: {
'config-path': 'tauri.conf.json',
'project-path': '',
}
})
},
});
const projectPath = resolve(process.cwd(), argv['project-path'])
const configPath = join(projectPath, argv['config-path'])
const distPath = argv['dist-path']
const iconPath = argv['icon-path']
const includeDebug = argv['include-debug']
const tauriScript = argv['tauri-script']
const args = argv._
const projectPath = resolve(process.cwd(), argv['project-path']);
const configPath = join(projectPath, argv['config-path']);
const distPath = argv['dist-path'];
const iconPath = argv['icon-path'];
const includeDebug = argv['include-debug'];
const tauriScript = argv['tauri-script'];
const args = argv._;
const options: BuildOptions = {
configPath: existsSync(configPath) ? configPath : null,
distPath,
iconPath,
tauriScript,
args
}
const artifacts = await buildProject(projectPath, false, options)
args,
};
const artifacts = await buildProject(projectPath, false, options);
if (includeDebug) {
const debugArtifacts = await buildProject(projectPath, true, options)
artifacts.push(...debugArtifacts)
const debugArtifacts = await buildProject(projectPath, true, options);
artifacts.push(...debugArtifacts);
}
if (artifacts.length === 0) {
throw new Error('No artifacts were found.')
throw new Error('No artifacts were found.');
}
console.log(`Artifacts: ${artifacts}.`)
console.log(`Artifacts: ${artifacts}.`);
}

View File

@@ -1,26 +1,25 @@
import typescript from "@rollup/plugin-typescript";
import pkg from "./package.json";
import typescript from '@rollup/plugin-typescript';
import pkg from './package.json';
export default {
treeshake: true,
perf: true,
input: { index: "index.ts" },
input: { index: 'index.ts' },
output: {
dir: "dist",
format: "esm",
entryFileNames: "[name].js",
exports: "named",
dir: 'dist',
format: 'esm',
entryFileNames: '[name].js',
exports: 'named',
},
plugins: [typescript({
allowSyntheticDefaultImports: true
})],
external: [
...Object.keys(pkg.dependencies || {}),
"path",
plugins: [
typescript({
allowSyntheticDefaultImports: true,
}),
],
external: [...Object.keys(pkg.dependencies || {}), 'path'],
watch: {
chokidar: true,
include: "src/**",
exclude: "node_modules/**",
include: 'src/**',
exclude: 'node_modules/**',
},
};

View File

@@ -1 +1 @@
declare module 'glob-gitignore'
declare module 'glob-gitignore';

View File

@@ -1,96 +1,95 @@
import { platform } from 'os'
import { readFileSync, existsSync, copyFileSync, writeFileSync } from 'fs'
import { execa } from 'execa'
import { parse as parseToml } from '@iarna/toml'
import { join, resolve, normalize, sep } from 'path'
import { sync as globSync } from 'glob-gitignore'
import ignore from 'ignore'
import JSON5 from 'json5'
import { platform } from 'os';
import { readFileSync, existsSync, copyFileSync, writeFileSync } from 'fs';
import { execa } from 'execa';
import { parse as parseToml } from '@iarna/toml';
import { join, resolve, normalize, sep } from 'path';
import { sync as globSync } from 'glob-gitignore';
import ignore from 'ignore';
import JSON5 from 'json5';
export function getPackageJson(root: string): any {
const packageJsonPath = join(root, 'package.json')
const packageJsonPath = join(root, 'package.json');
if (existsSync(packageJsonPath)) {
const packageJsonString = readFileSync(packageJsonPath).toString()
const packageJson = JSON.parse(packageJsonString)
return packageJson
const packageJsonString = readFileSync(packageJsonPath).toString();
const packageJson = JSON.parse(packageJsonString);
return packageJson;
}
return null
return null;
}
function getTauriDir(root: string): string | null {
const ignoreRules = ignore()
const gitignorePath = join(root, '.gitignore')
const ignoreRules = ignore();
const gitignorePath = join(root, '.gitignore');
if (existsSync(gitignorePath)) {
ignoreRules.add(readFileSync(gitignorePath).toString())
ignoreRules.add(readFileSync(gitignorePath).toString());
} else {
ignoreRules.add('node_modules').add('target')
ignoreRules.add('node_modules').add('target');
}
const paths = globSync('**/tauri.conf.json', {
cwd: root,
ignore: ignoreRules,
})
const tauriConfPath = paths[0]
return tauriConfPath ? resolve(root, tauriConfPath, '..') : null
});
const tauriConfPath = paths[0];
return tauriConfPath ? resolve(root, tauriConfPath, '..') : null;
}
function getWorkspaceDir(dir: string): string | null {
const rootPath = dir
const rootPath = dir;
while (dir.length && dir[dir.length - 1] !== sep) {
const manifestPath = join(dir, 'Cargo.toml')
const manifestPath = join(dir, 'Cargo.toml');
if (existsSync(manifestPath)) {
const toml = parseToml(readFileSync(manifestPath).toString())
const toml = parseToml(readFileSync(manifestPath).toString());
// @ts-expect-error
if (toml.workspace && toml.workspace.members) {
if (toml.workspace?.members) {
// @ts-expect-error
const members: string[] = toml.workspace.members
const members: string[] = toml.workspace.members;
if (members.some((m) => resolve(dir, m) === rootPath)) {
return dir
return dir;
}
}
}
dir = normalize(join(dir, '..'))
dir = normalize(join(dir, '..'));
}
return null
return null;
}
function getTargetDir(crateDir: string): string {
const def = join(crateDir, 'target')
const def = join(crateDir, 'target');
if ('CARGO_TARGET_DIR' in process.env) {
return process.env.CARGO_TARGET_DIR ?? def
return process.env.CARGO_TARGET_DIR ?? def;
}
let dir = crateDir
let dir = crateDir;
while (dir.length && dir[dir.length - 1] !== sep) {
let cargoConfigPath = join(dir, '.cargo/config')
let cargoConfigPath = join(dir, '.cargo/config');
if (!existsSync(cargoConfigPath)) {
cargoConfigPath = join(dir, '.cargo/config.toml')
cargoConfigPath = join(dir, '.cargo/config.toml');
}
if (existsSync(cargoConfigPath)) {
const cargoConfig = parseToml(readFileSync(cargoConfigPath).toString())
const cargoConfig = parseToml(readFileSync(cargoConfigPath).toString());
// @ts-ignore
if (cargoConfig.build && cargoConfig.build['target-dir']) {
if (cargoConfig.build?.['target-dir']) {
// @ts-ignore
return cargoConfig.build['target-dir']
return cargoConfig.build['target-dir'];
}
}
dir = normalize(join(dir, '..'))
dir = normalize(join(dir, '..'));
}
return def
return def;
}
function hasDependency(dependencyName: string, root: string): boolean {
const packageJson = getPackageJson(root)
const packageJson = getPackageJson(root);
return (
packageJson &&
((packageJson.dependencies && packageJson.dependencies[dependencyName]) ||
(packageJson.devDependencies &&
packageJson.devDependencies[dependencyName]))
)
(packageJson.dependencies?.[dependencyName] ||
packageJson.devDependencies?.[dependencyName])
);
}
function usesYarn(root: string): boolean {
return existsSync(join(root, 'yarn.lock'))
return existsSync(join(root, 'yarn.lock'));
}
export function execCommand(
@@ -98,134 +97,135 @@ export function execCommand(
args: string[],
{ cwd }: { cwd?: string } = {}
): Promise<void> {
console.log(`running ${command}`, args)
console.log(`running ${command}`, args);
return execa(command, args, {
cwd,
stdio: 'inherit',
env: { FORCE_COLOR: '0' },
}).then()
}).then();
}
interface CargoManifestBin {
name: string
name: string;
}
interface CargoManifest {
package: { version: string; name: string; 'default-run': string }
bin: CargoManifestBin[]
package: { version: string; name: string; 'default-run': string };
bin: CargoManifestBin[];
}
interface TauriConfig {
package?: {
productName?: string
version?: string
}
productName?: string;
version?: string;
};
tauri?: {
bundle?: {
identifier: string
identifier: string;
windows?: {
wix?: {
language?: string | string[] | { [language: string]: unknown }
}
}
}
}
language?: string | string[] | { [language: string]: unknown };
};
};
};
};
}
interface Application {
tauriPath: string
runner: Runner
name: string
version: string
wixLanguage: string | string[] | { [language: string]: unknown }
tauriPath: string;
runner: Runner;
name: string;
version: string;
wixLanguage: string | string[] | { [language: string]: unknown };
}
export interface BuildOptions {
configPath: string | null
distPath: string | null
iconPath: string | null
tauriScript: string | null
args: string[] | null
bundleIdentifier: string | null
configPath: string | null;
distPath: string | null;
iconPath: string | null;
tauriScript: string | null;
args: string[] | null;
bundleIdentifier: string | null;
}
export interface Runner {
runnerCommand: string
runnerArgs: string[]
runnerCommand: string;
runnerArgs: string[];
}
interface Info {
tauriPath: string | null
name: string
version: string
wixLanguage: string | string[] | { [language: string]: unknown }
tauriPath: string | null;
name: string;
version: string;
wixLanguage: string | string[] | { [language: string]: unknown };
}
export interface Artifact {
path: string
arch: string
path: string;
arch: string;
}
function _getJson5Config(contents: string): TauriConfig | null {
try {
const config = JSON5.parse(contents) as TauriConfig
return config
const config = JSON5.parse(contents) as TauriConfig;
return config;
} catch (e) {
return null
return null;
}
}
function getConfig(path: string): TauriConfig {
const contents = readFileSync(path).toString()
const contents = readFileSync(path).toString();
try {
const config = JSON.parse(contents) as TauriConfig
return config
const config = JSON.parse(contents) as TauriConfig;
return config;
} catch (e) {
let json5Conf = _getJson5Config(contents)
let json5Conf = _getJson5Config(contents);
if (json5Conf === null) {
json5Conf = _getJson5Config(
readFileSync(join(path, '..', 'tauri.conf.json5')).toString()
)
);
}
if (json5Conf) {
return json5Conf
return json5Conf;
}
throw e
throw e;
}
}
export function getInfo(root: string): Info {
const tauriDir = getTauriDir(root)
const tauriDir = getTauriDir(root);
if (tauriDir !== null) {
const configPath = join(tauriDir, 'tauri.conf.json')
let name
let version
let wixLanguage: string | string[] | { [language: string]: unknown } = 'en-US'
const config = getConfig(configPath)
const configPath = join(tauriDir, 'tauri.conf.json');
let name;
let version;
let wixLanguage: string | string[] | { [language: string]: unknown } =
'en-US';
const config = getConfig(configPath);
if (config.package) {
name = config.package.productName
version = config.package.version
name = config.package.productName;
version = config.package.version;
if (config.package.version?.endsWith('.json')) {
const packageJsonPath = join(tauriDir, config.package.version)
const contents = readFileSync(packageJsonPath).toString()
version = JSON.parse(contents).version
const packageJsonPath = join(tauriDir, config.package.version);
const contents = readFileSync(packageJsonPath).toString();
version = JSON.parse(contents).version;
}
}
if (!(name && version)) {
const manifestPath = join(tauriDir, 'Cargo.toml')
const manifestPath = join(tauriDir, 'Cargo.toml');
const cargoManifest = parseToml(
readFileSync(manifestPath).toString()
) as any as CargoManifest
name = name || cargoManifest.package.name
version = version || cargoManifest.package.version
) as any as CargoManifest;
name = name || cargoManifest.package.name;
version = version || cargoManifest.package.version;
}
if (config.tauri?.bundle?.windows?.wix?.language) {
wixLanguage = config.tauri.bundle.windows.wix.language
wixLanguage = config.tauri.bundle.windows.wix.language;
}
if (!(name && version)) {
console.error('Could not determine package name and version')
process.exit(1)
console.error('Could not determine package name and version');
process.exit(1);
}
return {
@@ -233,31 +233,38 @@ export function getInfo(root: string): Info {
name,
version,
wixLanguage,
}
};
} else {
const packageJson = getPackageJson(root)
const packageJson = getPackageJson(root);
const appName = packageJson
? (packageJson.displayName || packageJson.name).replace(/ /g, '-')
: 'app'
const version = packageJson ? packageJson.version : '0.1.0'
: 'app';
const version = packageJson ? packageJson.version : '0.1.0';
return {
tauriPath: null,
name: appName,
version,
wixLanguage: 'en-US',
}
};
}
}
export async function buildProject(
root: string,
debug: boolean,
{ configPath, distPath, iconPath, tauriScript, args, bundleIdentifier }: BuildOptions
{
configPath,
distPath,
iconPath,
tauriScript,
args,
bundleIdentifier,
}: BuildOptions
): Promise<Artifact[]> {
return new Promise<Runner>((resolve, reject) => {
if (tauriScript) {
const [runnerCommand, ...runnerArgs] = tauriScript.split(' ')
resolve({ runnerCommand, runnerArgs })
const [runnerCommand, ...runnerArgs] = tauriScript.split(' ');
resolve({ runnerCommand, runnerArgs });
} else if (
hasDependency('@tauri-apps/cli', root) ||
hasDependency('vue-cli-plugin-tauri', root)
@@ -266,19 +273,19 @@ export async function buildProject(
usesYarn(root)
? { runnerCommand: 'yarn', runnerArgs: ['tauri'] }
: { runnerCommand: 'npx', runnerArgs: ['tauri'] }
)
);
} else {
execCommand('npm', ['install', '-g', '@tauri-apps/cli'], {
cwd: undefined,
})
.then(() => {
resolve({ runnerCommand: 'tauri', runnerArgs: [] })
resolve({ runnerCommand: 'tauri', runnerArgs: [] });
})
.catch(reject)
.catch(reject);
}
})
.then((runner: Runner) => {
const info = getInfo(root)
const info = getInfo(root);
if (info.tauriPath) {
return {
tauriPath: info.tauriPath,
@@ -286,9 +293,9 @@ export async function buildProject(
name: info.name,
version: info.version,
wixLanguage: info.wixLanguage,
}
};
} else {
const packageJson = getPackageJson(root)
const packageJson = getPackageJson(root);
return execCommand(
runner.runnerCommand,
[...runner.runnerArgs, 'init', '--ci', '--app-name', info.name],
@@ -296,43 +303,43 @@ export async function buildProject(
cwd: root,
}
).then(() => {
const tauriPath = getTauriDir(root)
const tauriPath = getTauriDir(root);
if (tauriPath === null) {
console.error('Failed to resolve Tauri path')
process.exit(1)
console.error('Failed to resolve Tauri path');
process.exit(1);
}
const configPath = join(tauriPath, 'tauri.conf.json')
const config = getConfig(configPath)
const configPath = join(tauriPath, 'tauri.conf.json');
const config = getConfig(configPath);
console.log(
`Replacing tauri.conf.json config - package.version=${info.version}`
)
);
const pkgConfig = {
...config.package,
version: info.version,
}
};
if (packageJson?.productName) {
console.log(
`Replacing tauri.conf.json config - package.productName=${packageJson.productName}`
)
pkgConfig.productName = packageJson.productName
);
pkgConfig.productName = packageJson.productName;
}
config.package = pkgConfig
config.package = pkgConfig;
if (bundleIdentifier) {
console.log(
`Replacing tauri.conf.json config - tauri.bundle.identifier=${bundleIdentifier}`
)
);
config.tauri = {
...config.tauri,
bundle: {
...config.tauri?.bundle,
identifier: bundleIdentifier
}
}
identifier: bundleIdentifier,
},
};
}
writeFileSync(configPath, JSON.stringify(config, null, 2))
writeFileSync(configPath, JSON.stringify(config, null, 2));
const app = {
tauriPath,
@@ -340,7 +347,7 @@ export async function buildProject(
name: info.name,
version: info.version,
wixLanguage: info.wixLanguage,
}
};
if (iconPath) {
return execCommand(
runner.runnerCommand,
@@ -348,76 +355,78 @@ export async function buildProject(
{
cwd: root,
}
).then(() => app)
).then(() => app);
}
return app
})
return app;
});
}
})
.then((app: Application) => {
const tauriConfPath = join(app.tauriPath, 'tauri.conf.json')
const tauriConfPath = join(app.tauriPath, 'tauri.conf.json');
if (configPath !== null) {
copyFileSync(configPath, tauriConfPath)
copyFileSync(configPath, tauriConfPath);
}
if (distPath) {
const tauriConf = JSON.parse(readFileSync(tauriConfPath).toString())
tauriConf.build.distDir = distPath
writeFileSync(tauriConfPath, JSON.stringify(tauriConf))
const tauriConf = JSON.parse(readFileSync(tauriConfPath).toString());
tauriConf.build.distDir = distPath;
writeFileSync(tauriConfPath, JSON.stringify(tauriConf));
}
const tauriArgs = debug ? ['--debug', ...(args ?? [])] : args ?? []
let buildCommand
let buildArgs: string[] = []
const tauriArgs = debug ? ['--debug', ...(args ?? [])] : args ?? [];
let buildCommand;
let buildArgs: string[] = [];
if (hasDependency('vue-cli-plugin-tauri', root)) {
if (usesYarn(root)) {
buildCommand = 'yarn'
buildArgs = ['tauri:build']
buildCommand = 'yarn';
buildArgs = ['tauri:build'];
} else {
buildCommand = 'npm'
buildArgs = ['run', 'tauri:build']
buildCommand = 'npm';
buildArgs = ['run', 'tauri:build'];
}
} else {
buildCommand = app.runner.runnerCommand
buildArgs = [...app.runner.runnerArgs, 'build']
buildCommand = app.runner.runnerCommand;
buildArgs = [...app.runner.runnerArgs, 'build'];
}
return execCommand(buildCommand, [...buildArgs, ...tauriArgs], {
cwd: root,
})
.then(() => {
let fileAppName = app.name
let fileAppName = app.name;
// on Linux, the app product name is converted to kebab-case
if (!['darwin', 'win32'].includes(platform())) {
fileAppName = fileAppName
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
.replace(/([A-Z])([A-Z])(?=[a-z])/g, '$1-$2')
.replace(/[ _.]/g, '-')
.toLowerCase()
.toLowerCase();
}
const cratePath = getWorkspaceDir(app.tauriPath) ?? app.tauriPath
const cratePath = getWorkspaceDir(app.tauriPath) ?? app.tauriPath;
const found = [...tauriArgs].findIndex(
(e) => e === '-t' || e === '--target'
)
const targetPath = found >= 0 ? [...tauriArgs][found + 1] : ''
);
const targetPath = found >= 0 ? [...tauriArgs][found + 1] : '';
const artifactsPath = join(
getTargetDir(cratePath),
targetPath,
debug ? 'debug' : 'release'
)
);
let arch =
targetPath.search('-') >= 0
? targetPath.split('-')[0]
: process.arch
: process.arch;
if (platform() === 'darwin') {
if (arch === "x86_64") arch = "x64"
if (arch === 'x86_64') {
arch = 'x64';
}
return [
join(
@@ -426,60 +435,60 @@ export async function buildProject(
),
join(artifactsPath, `bundle/macos/${fileAppName}.app`),
join(artifactsPath, `bundle/macos/${fileAppName}.app.tar.gz`),
join(artifactsPath, `bundle/macos/${fileAppName}.app.tar.gz.sig`)
].map(path => ({ path, arch }))
join(artifactsPath, `bundle/macos/${fileAppName}.app.tar.gz.sig`),
].map((path) => ({ path, arch }));
} else if (platform() === 'win32') {
arch = arch.startsWith('i') ? 'x86' : 'x64'
arch = arch.startsWith('i') ? 'x86' : 'x64';
// If multiple Wix languages are specified, multiple installers (.msi) will be made
// The .zip and .sig are only generated for the first specified language
let langs
let langs;
if (typeof app.wixLanguage === 'string') {
langs = [app.wixLanguage]
langs = [app.wixLanguage];
} else if (Array.isArray(app.wixLanguage)) {
langs = app.wixLanguage
langs = app.wixLanguage;
} else {
langs = Object.keys(app.wixLanguage)
langs = Object.keys(app.wixLanguage);
}
const artifacts: string[] = []
const artifacts: string[] = [];
langs.forEach((lang) => {
artifacts.push(
join(
artifactsPath,
`bundle/msi/${fileAppName}_${app.version}_${arch}_${lang}.msi`
)
)
);
artifacts.push(
join(
artifactsPath,
`bundle/msi/${fileAppName}_${app.version}_${arch}_${lang}.msi.zip`
)
)
);
artifacts.push(
join(
artifactsPath,
`bundle/msi/${fileAppName}_${app.version}_${arch}_${lang}.msi.zip.sig`
)
)
})
return artifacts.map(path => ({ path, arch }))
);
});
return artifacts.map((path) => ({ path, arch }));
} else {
const debianArch =
arch === 'x64' || arch === 'x86_64'
? 'amd64'
: arch === 'x32' || arch === 'i686'
? 'i386'
: arch === 'arm'
? 'armhf'
: arch === 'aarch64'
? 'arm64'
: arch
? 'i386'
: arch === 'arm'
? 'armhf'
: arch === 'aarch64'
? 'arm64'
: arch;
const appImageArch =
arch === 'x64' || arch === 'x86_64'
? 'amd64'
: arch === 'x32' || arch === 'i686'
? 'i386'
: arch
? 'i386'
: arch;
return [
{
@@ -487,35 +496,39 @@ export async function buildProject(
artifactsPath,
`bundle/deb/${fileAppName}_${app.version}_${debianArch}.deb`
),
arch: debianArch
arch: debianArch,
},
{
path: join(
artifactsPath,
`bundle/appimage/${fileAppName}_${app.version}_${appImageArch}.AppImage`
),
arch: appImageArch
arch: appImageArch,
},
{
path: join(
artifactsPath,
`bundle/appimage/${fileAppName}_${app.version}_${appImageArch}.AppImage.tar.gz`
),
arch: appImageArch
arch: appImageArch,
},
{
path: join(
artifactsPath,
`bundle/appimage/${fileAppName}_${app.version}_${appImageArch}.AppImage.tar.gz.sig`
),
arch: appImageArch
}
]
arch: appImageArch,
},
];
}
})
.then((artifacts) => {
console.log(`Expected artifacts paths:\n${artifacts.map(a => a.path).join('\n')}`)
return artifacts.filter((p) => existsSync(p.path))
})
})
console.log(
`Expected artifacts paths:\n${artifacts
.map((a) => a.path)
.join('\n')}`
);
return artifacts.filter((p) => existsSync(p.path));
});
});
}

View File

@@ -1,26 +1,25 @@
import typescript from "@rollup/plugin-typescript";
import pkg from "./package.json";
import typescript from '@rollup/plugin-typescript';
import pkg from './package.json';
export default {
treeshake: true,
perf: true,
input: { index: "index.ts" },
input: { index: 'index.ts' },
output: {
dir: "dist",
format: "esm",
entryFileNames: "[name].js",
exports: "named",
dir: 'dist',
format: 'esm',
entryFileNames: '[name].js',
exports: 'named',
},
plugins: [typescript({
tsconfig: './tsconfig.json'
})],
external: [
...Object.keys(pkg.dependencies || {}),
"path",
plugins: [
typescript({
tsconfig: './tsconfig.json',
}),
],
external: [...Object.keys(pkg.dependencies || {}), 'path'],
watch: {
chokidar: true,
include: "src/**",
exclude: "node_modules/**",
include: 'src/**',
exclude: 'node_modules/**',
},
};

View File

@@ -1,5 +1,3 @@
{
"extends": [
"config:base"
]
"extends": ["config:base"]
}