mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
Feature/git hash (#1919)
* display git hash in marketplace show and app show. Add additional info to app show * bump marketplace lib version * disbaled links if site not provided, fix bug with license-instructions * fix import * stupid * feat: Add in the packing side git hash * chore: Remove the test that is breaking the build. Co-authored-by: Matt Hill <matthewonthemoon@gmail.com> Co-authored-by: BluJ <mogulslayer@gmail.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
use nom::combinator::success;
|
||||
use sha2_old::{Digest, Sha512};
|
||||
use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt, SeekFrom};
|
||||
use tracing::instrument;
|
||||
|
||||
41
backend/src/s9pk/git_hash.rs
Normal file
41
backend/src/s9pk/git_hash.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use std::path::Path;
|
||||
|
||||
use crate::Error;
|
||||
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct GitHash(String);
|
||||
|
||||
impl GitHash {
|
||||
pub async fn from_path(path: impl AsRef<Path>) -> Result<GitHash, Error> {
|
||||
let hash = tokio::process::Command::new("git")
|
||||
.args(["describe", "--always", "--abbrev=40", "--dirty=-modified"])
|
||||
.current_dir(path)
|
||||
.output()
|
||||
.await?;
|
||||
if !hash.status.success() {
|
||||
return Err(Error::new(
|
||||
color_eyre::eyre::eyre!("Could not get hash: {}", String::from_utf8(hash.stderr)?),
|
||||
crate::ErrorKind::Filesystem,
|
||||
));
|
||||
}
|
||||
Ok(GitHash(String::from_utf8(hash.stdout)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for GitHash {
|
||||
fn as_ref(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
// #[tokio::test]
|
||||
// async fn test_githash_for_current() {
|
||||
// let answer: GitHash = GitHash::from_path(std::env::current_dir().unwrap())
|
||||
// .await
|
||||
// .unwrap();
|
||||
// let answer_str: &str = answer.as_ref();
|
||||
// assert!(
|
||||
// !answer_str.is_empty(),
|
||||
// "Should have a hash for this current working"
|
||||
// );
|
||||
// }
|
||||
@@ -20,6 +20,8 @@ use crate::version::{Current, VersionT};
|
||||
use crate::volume::Volumes;
|
||||
use crate::Error;
|
||||
|
||||
use super::git_hash::GitHash;
|
||||
|
||||
fn current_version() -> Version {
|
||||
Current::new().semver().into()
|
||||
}
|
||||
@@ -30,6 +32,8 @@ pub struct Manifest {
|
||||
#[serde(default = "current_version")]
|
||||
pub eos_version: Version,
|
||||
pub id: PackageId,
|
||||
#[serde(default)]
|
||||
pub git_hash: Option<GitHash>,
|
||||
pub title: String,
|
||||
#[model]
|
||||
pub version: Version,
|
||||
@@ -96,6 +100,11 @@ impl Manifest {
|
||||
.chain(migrations)
|
||||
.chain(actions)
|
||||
}
|
||||
|
||||
pub fn with_git_hash(mut self, git_hash: GitHash) -> Self {
|
||||
self.git_hash = Some(git_hash);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
|
||||
@@ -12,6 +12,7 @@ use tracing::instrument;
|
||||
use crate::context::SdkContext;
|
||||
use crate::s9pk::builder::S9pkPacker;
|
||||
use crate::s9pk::docker::DockerMultiArch;
|
||||
use crate::s9pk::git_hash::GitHash;
|
||||
use crate::s9pk::manifest::Manifest;
|
||||
use crate::s9pk::reader::S9pkReader;
|
||||
use crate::util::display_none;
|
||||
@@ -22,6 +23,7 @@ use crate::{Error, ErrorKind, ResultExt};
|
||||
|
||||
pub mod builder;
|
||||
pub mod docker;
|
||||
pub mod git_hash;
|
||||
pub mod header;
|
||||
pub mod manifest;
|
||||
pub mod reader;
|
||||
@@ -56,8 +58,10 @@ pub async fn pack(#[context] ctx: SdkContext, #[arg] path: Option<PathBuf>) -> R
|
||||
crate::ErrorKind::Pack,
|
||||
));
|
||||
};
|
||||
let manifest: Manifest = serde_json::from_value(manifest_value.clone())
|
||||
.with_kind(crate::ErrorKind::Deserialization)?;
|
||||
|
||||
let manifest: Manifest = serde_json::from_value::<Manifest>(manifest_value.clone())
|
||||
.with_kind(crate::ErrorKind::Deserialization)?
|
||||
.with_git_hash(GitHash::from_path(&path).await?);
|
||||
let extra_keys =
|
||||
enumerate_extra_keys(&serde_json::to_value(&manifest).unwrap(), &manifest_value);
|
||||
for k in extra_keys {
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,16 @@
|
||||
<ion-item-divider>Additional Info</ion-item-divider>
|
||||
<ion-card>
|
||||
<ion-card *ngIf="pkg.manifest as manifest">
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col sizeSm="12" sizeMd="6">
|
||||
<ion-col sizeXs="12" sizeMd="6">
|
||||
<ion-item-group>
|
||||
<ion-item button detail="false" (click)="copy(manifest['git-hash'])">
|
||||
<ion-label>
|
||||
<h2>Git Hash</h2>
|
||||
<p>{{ manifest['git-hash'] }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="copy-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item button detail="false" (click)="presentAlertVersions()">
|
||||
<ion-label>
|
||||
<h2>Other Versions</h2>
|
||||
@@ -14,7 +21,7 @@
|
||||
<ion-item button detail="false" (click)="presentModalMd('license')">
|
||||
<ion-label>
|
||||
<h2>License</h2>
|
||||
<p>{{ pkg.manifest.license }}</p>
|
||||
<p>{{ manifest.license }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="chevron-forward"></ion-icon>
|
||||
</ion-item>
|
||||
@@ -31,41 +38,55 @@
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ion-col>
|
||||
<ion-col sizeSm="12" sizeMd="6">
|
||||
<ion-col sizeXs="12" sizeMd="6">
|
||||
<ion-item-group>
|
||||
<ion-item
|
||||
[href]="pkg.manifest['upstream-repo']"
|
||||
[href]="manifest['upstream-repo']"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
detail="false"
|
||||
>
|
||||
<ion-label>
|
||||
<h2>Source Repository</h2>
|
||||
<p>{{ pkg.manifest['upstream-repo'] }}</p>
|
||||
<p>{{ manifest['upstream-repo'] }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item
|
||||
[href]="pkg.manifest['wrapper-repo']"
|
||||
[href]="manifest['wrapper-repo']"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
detail="false"
|
||||
>
|
||||
<ion-label>
|
||||
<h2>Wrapper Repository</h2>
|
||||
<p>{{ pkg.manifest['wrapper-repo'] }}</p>
|
||||
<p>{{ manifest['wrapper-repo'] }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item
|
||||
[href]="pkg.manifest['support-site']"
|
||||
[href]="manifest['support-site']"
|
||||
[disabled]="!manifest['support-site']"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
detail="false"
|
||||
>
|
||||
<ion-label>
|
||||
<h2>Support Site</h2>
|
||||
<p>{{ pkg.manifest['support-site'] }}</p>
|
||||
<p>{{ manifest['support-site'] || 'Not provided' }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item
|
||||
[href]="manifest['marketing-site']"
|
||||
[disabled]="!manifest['marketing-site']"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
detail="false"
|
||||
>
|
||||
<ion-label>
|
||||
<h2>Marketing Site</h2>
|
||||
<p>{{ manifest['marketing-site'] || 'Not provided' }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
|
||||
@@ -5,8 +5,17 @@ import {
|
||||
Input,
|
||||
Output,
|
||||
} from '@angular/core'
|
||||
import { AlertController, ModalController } from '@ionic/angular'
|
||||
import { displayEmver, Emver, MarkdownComponent } from '@start9labs/shared'
|
||||
import {
|
||||
AlertController,
|
||||
ModalController,
|
||||
ToastController,
|
||||
} from '@ionic/angular'
|
||||
import {
|
||||
copyToClipboard,
|
||||
displayEmver,
|
||||
Emver,
|
||||
MarkdownComponent,
|
||||
} from '@start9labs/shared'
|
||||
import { MarketplacePkg } from '../../../types'
|
||||
import { AbstractMarketplaceService } from '../../../services/marketplace.service'
|
||||
|
||||
@@ -27,8 +36,23 @@ export class AdditionalComponent {
|
||||
private readonly modalCtrl: ModalController,
|
||||
private readonly emver: Emver,
|
||||
private readonly marketplaceService: AbstractMarketplaceService,
|
||||
private readonly toastCtrl: ToastController,
|
||||
) {}
|
||||
|
||||
async copy(address: string): Promise<void> {
|
||||
const success = await copyToClipboard(address)
|
||||
const message = success
|
||||
? 'Copied to clipboard!'
|
||||
: 'Failed to copy to clipboard.'
|
||||
|
||||
const toast = await this.toastCtrl.create({
|
||||
header: message,
|
||||
position: 'bottom',
|
||||
duration: 1000,
|
||||
})
|
||||
await toast.present()
|
||||
}
|
||||
|
||||
async presentAlertVersions() {
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'Versions',
|
||||
|
||||
@@ -36,6 +36,7 @@ export interface MarketplaceManifest<T = unknown> {
|
||||
id: string
|
||||
title: string
|
||||
version: string
|
||||
'git-hash': string
|
||||
description: {
|
||||
short: string
|
||||
long: string
|
||||
|
||||
@@ -14,6 +14,7 @@ import { AppShowStatusComponent } from './components/app-show-status/app-show-st
|
||||
import { AppShowDependenciesComponent } from './components/app-show-dependencies/app-show-dependencies.component'
|
||||
import { AppShowMenuComponent } from './components/app-show-menu/app-show-menu.component'
|
||||
import { AppShowHealthChecksComponent } from './components/app-show-health-checks/app-show-health-checks.component'
|
||||
import { AppShowAdditionalComponent } from './components/app-show-additional/app-show-additional.component'
|
||||
import { HealthColorPipe } from './pipes/health-color.pipe'
|
||||
import { ToHealthChecksPipe } from './pipes/to-health-checks.pipe'
|
||||
import { ToButtonsPipe } from './pipes/to-buttons.pipe'
|
||||
@@ -43,6 +44,7 @@ const routes: Routes = [
|
||||
AppShowDependenciesComponent,
|
||||
AppShowMenuComponent,
|
||||
AppShowHealthChecksComponent,
|
||||
AppShowAdditionalComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
></app-show-dependencies>
|
||||
<!-- ** menu ** -->
|
||||
<app-show-menu [buttons]="pkg | toButtons"></app-show-menu>
|
||||
<!-- ** additional ** -->
|
||||
<app-show-additional [pkg]="pkg"></app-show-additional>
|
||||
</ng-container>
|
||||
</ion-item-group>
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
<ion-item-divider>Additional Info</ion-item-divider>
|
||||
<ion-card *ngIf="pkg.manifest as manifest">
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col sizeXs="12" sizeMd="6">
|
||||
<ion-item-group>
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
<h2>Version</h2>
|
||||
<p>{{ manifest.version | displayEmver }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item button detail="false" (click)="copy(manifest['git-hash'])">
|
||||
<ion-label>
|
||||
<h2>Git Hash</h2>
|
||||
<p>{{ manifest['git-hash'] }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="copy-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item button detail="false" (click)="presentModalLicense()">
|
||||
<ion-label>
|
||||
<h2>License</h2>
|
||||
<p>{{ manifest.license }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="chevron-forward"></ion-icon>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ion-col>
|
||||
<ion-col sizeXs="12" sizeMd="6">
|
||||
<ion-item-group>
|
||||
<ion-item
|
||||
[href]="manifest['upstream-repo']"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
detail="false"
|
||||
>
|
||||
<ion-label>
|
||||
<h2>Source Repository</h2>
|
||||
<p>{{ manifest['upstream-repo'] }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item
|
||||
[href]="manifest['wrapper-repo']"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
detail="false"
|
||||
>
|
||||
<ion-label>
|
||||
<h2>Wrapper Repository</h2>
|
||||
<p>{{ manifest['wrapper-repo'] }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item
|
||||
[href]="manifest['support-site']"
|
||||
[disabled]="!manifest['support-site']"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
detail="false"
|
||||
>
|
||||
<ion-label>
|
||||
<h2>Support Site</h2>
|
||||
<p>{{ manifest['support-site'] || 'Not provided' }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-card>
|
||||
@@ -0,0 +1,48 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
||||
import { ModalController, ToastController } from '@ionic/angular'
|
||||
import { copyToClipboard, MarkdownComponent } from '@start9labs/shared'
|
||||
import { from } from 'rxjs'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
||||
|
||||
@Component({
|
||||
selector: 'app-show-additional',
|
||||
templateUrl: 'app-show-additional.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class AppShowAdditionalComponent {
|
||||
@Input()
|
||||
pkg!: PackageDataEntry
|
||||
|
||||
constructor(
|
||||
private readonly modalCtrl: ModalController,
|
||||
private readonly toastCtrl: ToastController,
|
||||
private readonly api: ApiService,
|
||||
) {}
|
||||
|
||||
async copy(address: string): Promise<void> {
|
||||
const success = await copyToClipboard(address)
|
||||
const message = success
|
||||
? 'Copied to clipboard!'
|
||||
: 'Failed to copy to clipboard.'
|
||||
|
||||
const toast = await this.toastCtrl.create({
|
||||
header: message,
|
||||
position: 'bottom',
|
||||
duration: 1000,
|
||||
})
|
||||
await toast.present()
|
||||
}
|
||||
|
||||
async presentModalLicense() {
|
||||
const modal = await this.modalCtrl.create({
|
||||
componentProps: {
|
||||
title: 'License',
|
||||
content: from(this.api.getStatic(this.pkg['static-files']['license'])),
|
||||
},
|
||||
component: MarkdownComponent,
|
||||
})
|
||||
|
||||
await modal.present()
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ export module Mock {
|
||||
id: 'bitcoind',
|
||||
title: 'Bitcoin Core',
|
||||
version: '0.21.0',
|
||||
'git-hash': 'abcdefgh',
|
||||
description: {
|
||||
short: 'A Bitcoin full node by Bitcoin Core.',
|
||||
long: 'Bitcoin is a decentralized consensus protocol and settlement network.',
|
||||
@@ -347,6 +348,7 @@ export module Mock {
|
||||
id: 'lnd',
|
||||
title: 'Lightning Network Daemon',
|
||||
version: '0.11.1',
|
||||
'git-hash': 'lalalalalala',
|
||||
description: {
|
||||
short: 'A bolt spec compliant client.',
|
||||
long: 'More info about LND. More info about LND. More info about LND.',
|
||||
@@ -500,6 +502,7 @@ export module Mock {
|
||||
id: 'btc-rpc-proxy',
|
||||
title: 'Bitcoin Proxy',
|
||||
version: '0.2.2',
|
||||
'git-hash': 'lmnopqrx',
|
||||
description: {
|
||||
short: 'A super charger for your Bitcoin node.',
|
||||
long: 'More info about Bitcoin Proxy. More info about Bitcoin Proxy. More info about Bitcoin Proxy.',
|
||||
|
||||
@@ -61,6 +61,7 @@ export const mockPatchData: DataModel = {
|
||||
id: 'bitcoind',
|
||||
title: 'Bitcoin Core',
|
||||
version: '0.20.0',
|
||||
'git-hash': 'abcdefgh',
|
||||
description: {
|
||||
short: 'A Bitcoin full node by Bitcoin Core.',
|
||||
long: 'Bitcoin is a decentralized consensus protocol and settlement network.',
|
||||
@@ -452,6 +453,7 @@ export const mockPatchData: DataModel = {
|
||||
id: 'lnd',
|
||||
title: 'Lightning Network Daemon',
|
||||
version: '0.11.1',
|
||||
'git-hash': 'lalalalalala',
|
||||
description: {
|
||||
short: 'A bolt spec compliant client.',
|
||||
long: 'More info about LND. More info about LND. More info about LND.',
|
||||
|
||||
Reference in New Issue
Block a user