ClickOnce rakenduse publitseerimine TFS 2008 Team Build abil

Selle teksti mõte on dokumenteerida enda tarbeks ClickOnce abil publitseeritava rakenduse komplekteerimine TFS build abil, kuna MSDN abitekstid (http://msdn.microsoft.com/en-us/library/xc3tc5xx.aspx) osutusid jällegi puudulikeks, vigasteks ja eksitavateks (jätsin sinna ka kommentaari).

Teiseks, eriti just SCSF rakenduse publitseerimisel ei saa kasutada out-of-the-box TFS Team Buildi, sest see nõuab projekti ülesehitust, kus kogu SCSF mõte kaob. SCSF tugevus seisneb aga selles, et rakendus on võimalik kokku panna erinevate arendajate poolt loodud moodulitest, mis ei pruugi olla ühes versioonikontrolli harus ega isegi mitte samas serveris. Või siis tarnivad mõned arendajad oma mooduli .dllina. Seega on vaja süsteemi, kus Team Build abil on võimalik kogu Smart Client rakendus kokku panna nö. algosadest.

ClickOnce rakenduse publitseerimisel võib olla vähemalt kaks lähtepunkti:

  1. rakendus on kompileeritud (dll-id, konfiguratsioonifailid jms.) ja see on vaja vaid komplekteerida (näiteks SmartClient) lisades/eemaldades komponente.
  2. rakendus on lähtekoodi kujul, vaja on kompileerida ja publitseerida.

Alljärgnev sobib mõlemale juhule, punkt 1. on punkti 2. alamosa.

1. Ettevalmistused

ClickOnce rakendus on kohustuslik signeerida. Selleks on vaja signeerimissertifikaati. Testrakenduse signeerimiseks sobib ka ise genereeritud sertifikaat. Windows SDK-s on selleks tööriist makecert

1. Loo sertifikaat: makecert -sv mykey.pvk -n “CN=myname” mykey.cer genereerib nii privaatvõtme kui ka sertifikaadi. CN=myname on muidugi vaid osa sertifikaadi tunnusest, reaalse sertifikaadi genereerimiseks on vaja rohkem infot.

2. Loo signeerimiseks vajalik võtmefail utiliidiga pvk2pfx: pvk2pfx -pvk mykey.pvk -spc mykey.cer -pfx mykey.pfx -po pfxparool, kus pfx parool on eraldi parool allkirjastamisel pfx võtme avamiseks ja ei tohiks olla sama mis privaatvõtme ja sertifikaadi genereerimisel.

3. Kontrolli, kas masinas (seega siis Team Build masin), kus töötad, on Publisher info olemas. Nimelt on ClickOnce publikatsiooni puhul vajalik Publisher info. Selle võid enne signeerimist kirjutada publikatsiooni manifesti teegina

<description asmv2:publisher=”<fimanimi>” asmv2:product=”<tootenimi>” asmv2:supportUrl=”<tugilehe URL>” xmlns=”urn:schemas-microsoft-com:asm.v1″ />

või siis märkida registrisse võtme
HKEY_LOCAL_MACHINE\SOFTWARE\MIcrosoft\Windows\
WIndowsNT\CurrentVersion\RegisteredOrganization alla.

2. Koodi ja teekide alla laadimine

Et me saaks koodi jms. laadida alla suvalistest versioonikontrolli harudest, peame ise tekitama workspace ja selle mappingud. Defineerime kogu keskkonna põhimuutujad – kuhu lähevad kompileeritud asjad, kuhu tõmmatakse lähtekoodid ja mis on loodava workspace nimi:

<PropertyGroup>
    <
OutputPath>C:\TFSBuilds\projekt\bin\</OutputPath>
    <
RootPath>C:\TFSBuilds\projekt\</RootPath>
    <
WorkspaceName>projektDEV</WorkspaceName>
    <
Tf>tf</Tf>
</
PropertyGroup>

Edasi defineerime versioonikontrolli mappingud töökeskkonda:

<ItemGroup>
<
WorkspaceMapping Include=$/DEV/kood>
    <
LocalPath>$(RootPath)kood</LocalPath>
</
WorkspaceMapping>
</ItemGroup>

Muidugi võib neid mappinguid olla rohkem.

Seejärel tekitame töökeskkonna targetiga CreateWorkspace:

<Target Name=CreateWorkspace>
    <!–
Checking input parameters –>
    <
Error Condition=$(WorkspaceName) == ”           Text=Please specify WorkspaceName property/>
    <
Error Condition=$(RootPath) == ”           Text=Please specify RootPath property/>
    <
Error Condition=!HasTrailingSlash(‘$(RootPath)’)           Text=Please make sure RootPath is slash terminated/>
    <
Exec Command=$(Tf) workspace /delete &quot;$(WorkspaceName)&quot; ContinueOnError=true IgnoreExitCode=true/>
    <!–
Create new workspace–>
    <
Exec Command=$(Tf) workspace /new /noprompt &quot;$(WorkspaceName)&quot; />
    <!–
Remove default mapping –>
    <
Exec Command=$(Tf) workfold /unmap /workspace:&quot;$(WorkspaceName)&quot; $//>
    <!–
Create new mappings (uses MSBuild batching) –>
    <
Exec Command=$(Tf) workfold /map &quot;%(WorkspaceMapping.Identity)&quot; &quot;%(WorkspaceMapping.LocalPath)&quot; /workspace:&quot;$(WorkspaceName)&quot;/>
    <!–
Great success! –>
    <
Message Text=Workspace ‘$(WorkspaceName)’ created sucessfully/>
    <!–
List created mappings –>
    <
Exec Command=$(Tf) workfold /workspace:&quot;$(WorkspaceName)&quot;/>
</
Target>

Laeme alla koodi loodud workspace:

<Target Name=GetProjects DependsOnTargets=CreateWorkspace>

<!– Get the sources for the given workspace–>
<
Get TeamFoundationServerUrl=$(TeamFoundationServerUrl)
     BuildUri=$(BuildUri)
     Workspace=$(WorkspaceName)
     Version=T
     Filespec=$/DEV/kood
     PopulateOutput=$(GetPopulateOutput)
     Overwrite=$(GetOverwrite)
     Preview=$(PreviewGet)
     Recursive=$(RecursiveGet)
     Force=$(ForceGet)>
    <
Output TaskParameter=Gets ItemName=Gets />
    <
Output TaskParameter=Replaces ItemName=Replaces />
    <
Output TaskParameter=Deletes ItemName=Deletes />
    <
Output TaskParameter=Warnings ItemName=GetWarnings />
</
Get>

</Target>

Kus siis Filespec tähistab mingit elementi (haru, fail vms.) versioonikontrollist. Get lõiku kordame nii palju kui vaja, soovi korral võime laadida ka mitte viimase, vaid mingi muu versiooni jne.

Edasi puhastame kompileerimiskoha:

<Target Name=ClearBin>
    <
RemoveDir Directories=$(OutputPath)/>
    <
MakeDir Directories=$(OutputPath)/>
   
</
Target>

Seejärel kompileerime projektid, mille tõmbasime alla lähtekoodina:

<Target Name=CustomBuild DependsOnTargets=CopyLibraries>
   
    <
MSBuild Projects=$(RootPath)kood\kood.csproj
             Properties=OutputPath=$(OutputPath);NoWin32Manifest=true;/>
</Target>

VS2008 ja ClickOnce puhul on eriti oluline kompileerimislipp NoWin32Manifest=true, et kompileerimisel ei lisataks manifesti kompilatsioonidesse. Pärast rakenduse manifesti genereerimisel satub see vastuollu ClickOnce manifestiga ja tulemuseks on müstiline (MS poolt lahti seletamata) veateade “Reference in the manifest does not match the identity of the downloaded assembly”.

Edasi defineerime ClickOnce rakenduse versiooni ja publitseerimise muutujad, kus ShellExe on SCSF rakenduse koorik, DeploymentDir on koht, kuhu publitseeritakse rakendus (NB! versiooni alamkataloog luuakse hiljem), DeployUrl on aga koht, kust rakendus kasutajale paistma hakkab (jälle ilma versiooniharuta):

<PropertyGroup>
    <
Major>1</Major>
    <
Minor>0</Minor>
    <
Build>0</Build>
    <
Revision>0</Revision>
</
PropertyGroup>
<PropertyGroup>
    <
ShellExe>Shell.exe</ShellExe>
    <
DeploymentDir>C:\software\dev\</DeploymentDir>
    <
DeployUrl>http://software.dev.ee/dev/</DeployUrl>
    <
SupportUrl>http://www.dev.ee/</SupportUrl>
</
PropertyGroup>

Edasi defineerime rakenduse koosluse koorikust (exe), teekidest (dll) ja failidest (nii tavalised kui andmefailid):

<ItemGroup>
<
EntryPoint Include=$(OutputPath)$(ShellExe)/>

<Dependency Include=$(OutputPath)Microsoft.Practices.CompositeUI.dll>
    <
AssemblyType>Managed</AssemblyType>
    <
DependencyType>Install</DependencyType>
</
Dependency>

<File Include=$(OutputPath)ProfileCatalog.xml>
    <
TargetPath>ProfileCatalog.xml</TargetPath>
</
File>

<File Include=$(OutputPath)Data\Data.sdf>
    <
TargetPath>Data\Data.sdf</TargetPath>
    <
IsDataFile>true</IsDataFile>
</
File>

</ItemGroup>

Nüüd saame publitseerida rakenduse alamversiooniga kataloogi:

<Target Name=ClickOnceDeploy DependsOnTargets=CustomBuild>
    <
Version VersionFile=$(RootPath)versionnumber.txt BuildType=None RevisionType=Increment>
        <
Output TaskParameter=Major PropertyName=Major />
        <
Output TaskParameter=Minor PropertyName=Minor />
        <
Output TaskParameter=Build PropertyName=Build />
        <
Output TaskParameter=Revision PropertyName=Revision />
    </
Version>
    <
GenerateApplicationManifest
        AssemblyVersion=$(Major).$(Minor).$(Build).$(Revision)
        Dependencies=@(Dependency)
        Description=Shell
        Files=@(File)
        EntryPoint=$(OutputPath)$(ShellExe)
        OutputManifest=$(OutputPath)$(ShellExe).manifest>
        <
Output
            ItemName=ApplicationManifest
            TaskParameter=OutputManifest
            />
    </
GenerateApplicationManifest>
<!– signeerime rakenduse manifesti –>
    <
Exec Command=mage -s $(OutputPath)$(ShellExe).manifest -cf $(RootPath)mykey.pfx -pwd pfxparool/>
<!– genereerime publikatsiooni manifesti –>
    <
GenerateDeploymentManifest
        EntryPoint=@(ApplicationManifest)
        AssemblyName=$(ShellExe).application
        AssemblyVersion=$(Major).$(Minor).$(Build).$(Revision)
        DeploymentUrl=$(DeployUrl)$(Major)_$(Minor)_$(Build)_$(Revision)/$(ShellExe).application
        MapFileExtensions=true
        Install=false
        OutputManifest=$(OutputPath)$(ShellExe).application
        Product=Albert Editor
        Publisher=AS Firma
        SupportUrl=http://www.firma.ee/
        UpdateEnabled=false>
       
        <
Output
            ItemName=DeployManifest
            TaskParameter=OutputManifest
            />
    </
GenerateDeploymentManifest>
<!– signeerime publikatsiooni manifesti –>
    <
Exec Command=mage -s $(OutputPath)$(ShellExe).application -cf $(RootPath)mykey.pfx -pwd pfxparool/>
<!– loendame rakenduse failid –>
    <
CreateItem
       
Include=$(OutputPath)**\*.*
        Exclude=$(OutputPath)**\*.manifest;$(OutputPath)**\*.application
                >
        <
Output ItemName=DeploymentFiles TaskParameter=Include/>
    </
CreateItem>
<!– kopeerime failid, andes laiendi .deploy –>
    <
Copy
       
SourceFiles=@(DeploymentFiles)
        DestinationFiles=@(DeploymentFiles->’$(DeploymentDir)$(Major)_$(Minor)_$(Build)_$(Revision)\%(RecursiveDir)%(Filename)%(Extension).deploy’)/>
    <
Copy SourceFiles=$(OutputPath)$(ShellExe).manifest DestinationFolder=$(DeploymentDir)$(Major)_$(Minor)_$(Build)_$(Revision)/>
    <
Copy SourceFiles=$(OutputPath)$(ShellExe).application DestinationFolder=$(DeploymentDir)$(Major)_$(Minor)_$(Build)_$(Revision)/>
</Target>

Lisa kommentaar

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Muuda )

Twitter picture

You are commenting using your Twitter account. Log Out / Muuda )

Facebook photo

You are commenting using your Facebook account. Log Out / Muuda )

Connecting to %s


Follow

Get every new post delivered to your Inbox.