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:
Aiden McClelland
2022-11-09 11:49:18 -07:00
parent 9c363be16f
commit b9e4a66fdc
14 changed files with 245 additions and 15 deletions

View File

@@ -1,3 +1,4 @@
use nom::combinator::success;
use sha2_old::{Digest, Sha512};
use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt, SeekFrom};
use tracing::instrument;

View 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"
// );
// }

View File

@@ -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)]

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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',

View File

@@ -36,6 +36,7 @@ export interface MarketplaceManifest<T = unknown> {
id: string
title: string
version: string
'git-hash': string
description: {
short: string
long: string

View File

@@ -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,

View File

@@ -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>

View File

@@ -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>

View File

@@ -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()
}
}

View File

@@ -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.',

View File

@@ -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.',