@@ -476,7 +476,41 @@ class CmdRun extends CmdBase implements HubOptions {
476476 final revision = scriptFile. repository
477477 ? scriptFile. revisionInfo. toString()
478478 : scriptFile. getScriptId()?. substring(0 ,10 )
479- printLaunchInfo(repo, head, revision)
479+ final commitId = scriptFile. commitId
480+ final commitUrl = scriptFile. repository && commitId
481+ ? getCommitUrl(scriptFile. repository, commitId)
482+ : null
483+ printLaunchInfo(repo, head, revision, commitId, commitUrl)
484+ }
485+
486+ /**
487+ * Constructs a web URL for viewing the repository at a specific commit.
488+ * Supports GitHub, GitLab, Bitbucket, Gitea, and Azure DevOps.
489+ *
490+ * @param repository The repository URL (e.g., https://github.com/nextflow-io/hello)
491+ * @param commitId The commit SHA
492+ * @return The repository tree URL at the commit, or null if the provider is not recognized
493+ */
494+ protected static String getCommitUrl (String repository , String commitId ) {
495+ if ( ! repository || ! commitId )
496+ return null
497+ // GitHub: https://github.com/owner/repo/tree/{sha}
498+ if ( repository. contains(' github.com' ) || repository. contains(' github.' ) )
499+ return " ${ repository} /tree/${ commitId} "
500+ // GitLab: https://gitlab.com/owner/repo/-/tree/{sha}
501+ if ( repository. contains(' gitlab.com' ) || repository. contains(' gitlab.' ) )
502+ return " ${ repository} /-/tree/${ commitId} "
503+ // Bitbucket: https://bitbucket.org/owner/repo/src/{sha}
504+ if ( repository. contains(' bitbucket.org' ) || repository. contains(' bitbucket.' ) )
505+ return " ${ repository} /src/${ commitId} "
506+ // Gitea: https://gitea.example.com/owner/repo/src/commit/{sha}
507+ if ( repository. contains(' gitea.' ) )
508+ return " ${ repository} /src/commit/${ commitId} "
509+ // Azure DevOps: https://dev.azure.com/org/project/_git/repo?version=GC{sha}
510+ if ( repository. contains(' dev.azure.com' ) )
511+ return " ${ repository} ?version=GC${ commitId} "
512+ // Unknown provider
513+ return null
480514 }
481515
482516 static void detectModuleBinaryFeature (ConfigMap config ) {
@@ -498,17 +532,28 @@ class CmdRun extends CmdBase implements HubOptions {
498532 }
499533 }
500534
501- protected void printLaunchInfo (String repo , String head , String revision ) {
535+ protected void printLaunchInfo (String repo , String head , String revision , String commitId = null , String commitUrl = null ) {
502536 if ( launcher. options. ansiLog ){
503537 log. debug " ${ head} [$runName ] - revision: ${ revision} "
504538
505539 def fmt = ansi()
506540 fmt. a(" Launching" ). fg(Color . MAGENTA ). a(" `$repo ` " ). reset()
507541 fmt. a(Attribute . INTENSITY_FAINT ). a(" [" ). reset()
508542 fmt. bold(). fg(Color . CYAN ). a(runName). reset()
509- fmt. a(Attribute . INTENSITY_FAINT ). a(" ]" )
543+ fmt. a(Attribute . INTENSITY_FAINT ). a(" ] " ) . reset( )
510544 fmt. fg(Color . CYAN ). a(" revision: " ). reset()
511- fmt. fg(Color . CYAN ). a(revision). reset()
545+ // Make commit hash a hyperlink if commit URL is available
546+ if ( commitUrl && commitId ) {
547+ final shortCommit = commitId. substring(0 , Math . min(10 , commitId. length()))
548+ fmt. fg(Color . CYAN ). a(" \0 33]8;;${ commitUrl} \0 07${ shortCommit} \0 33]8;;\0 07" ). reset()
549+ // Append the branch/tag name if revision contains more than just the commit
550+ if ( revision && revision != shortCommit && revision. startsWith(shortCommit) ) {
551+ fmt. fg(Color . CYAN ). a(revision. substring(shortCommit. length())). reset()
552+ }
553+ }
554+ else {
555+ fmt. fg(Color . CYAN ). a(revision). reset()
556+ }
512557 fmt. a(" \n " )
513558 AnsiConsole . out(). println (fmt. eraseLine())
514559 }
0 commit comments